Merge pull request #148 from lrabane/cli-auth
Add authentification support for subscribing with CLI
This commit is contained in:
commit
43326be637
5 changed files with 62 additions and 5 deletions
|
@ -16,6 +16,10 @@
|
||||||
# command: 'echo "$message"'
|
# command: 'echo "$message"'
|
||||||
# if:
|
# if:
|
||||||
# priority: high,urgent
|
# priority: high,urgent
|
||||||
|
# - topic: secret
|
||||||
|
# command: 'notify-send "$m"'
|
||||||
|
# user: phill
|
||||||
|
# password: mypass
|
||||||
#
|
#
|
||||||
# Variables:
|
# Variables:
|
||||||
# Variable Aliases Description
|
# Variable Aliases Description
|
||||||
|
|
|
@ -14,9 +14,11 @@ const (
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DefaultHost string `yaml:"default-host"`
|
DefaultHost string `yaml:"default-host"`
|
||||||
Subscribe []struct {
|
Subscribe []struct {
|
||||||
Topic string `yaml:"topic"`
|
Topic string `yaml:"topic"`
|
||||||
Command string `yaml:"command"`
|
User string `yaml:"user"`
|
||||||
If map[string]string `yaml:"if"`
|
Password string `yaml:"password"`
|
||||||
|
Command string `yaml:"command"`
|
||||||
|
If map[string]string `yaml:"if"`
|
||||||
} `yaml:"subscribe"`
|
} `yaml:"subscribe"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,9 @@ func TestConfig_Load(t *testing.T) {
|
||||||
require.Nil(t, os.WriteFile(filename, []byte(`
|
require.Nil(t, os.WriteFile(filename, []byte(`
|
||||||
default-host: http://localhost
|
default-host: http://localhost
|
||||||
subscribe:
|
subscribe:
|
||||||
- topic: no-command
|
- topic: no-command-with-auth
|
||||||
|
user: phil
|
||||||
|
password: mypass
|
||||||
- topic: echo-this
|
- topic: echo-this
|
||||||
command: 'echo "Message received: $message"'
|
command: 'echo "Message received: $message"'
|
||||||
- topic: alerts
|
- topic: alerts
|
||||||
|
@ -26,8 +28,10 @@ subscribe:
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, "http://localhost", conf.DefaultHost)
|
require.Equal(t, "http://localhost", conf.DefaultHost)
|
||||||
require.Equal(t, 3, len(conf.Subscribe))
|
require.Equal(t, 3, len(conf.Subscribe))
|
||||||
require.Equal(t, "no-command", conf.Subscribe[0].Topic)
|
require.Equal(t, "no-command-with-auth", conf.Subscribe[0].Topic)
|
||||||
require.Equal(t, "", conf.Subscribe[0].Command)
|
require.Equal(t, "", conf.Subscribe[0].Command)
|
||||||
|
require.Equal(t, "phil", conf.Subscribe[0].User)
|
||||||
|
require.Equal(t, "mypass", conf.Subscribe[0].Password)
|
||||||
require.Equal(t, "echo-this", conf.Subscribe[1].Topic)
|
require.Equal(t, "echo-this", conf.Subscribe[1].Topic)
|
||||||
require.Equal(t, `echo "Message received: $message"`, conf.Subscribe[1].Command)
|
require.Equal(t, `echo "Message received: $message"`, conf.Subscribe[1].Command)
|
||||||
require.Equal(t, "alerts", conf.Subscribe[2].Topic)
|
require.Equal(t, "alerts", conf.Subscribe[2].Topic)
|
||||||
|
|
|
@ -23,6 +23,7 @@ var cmdSubscribe = &cli.Command{
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"},
|
&cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "client config file"},
|
||||||
&cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"},
|
&cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"},
|
||||||
|
&cli.StringFlag{Name: "user", Aliases: []string{"u"}, Usage: "username[:password] used to auth against the server"},
|
||||||
&cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"},
|
&cli.BoolFlag{Name: "from-config", Aliases: []string{"C"}, Usage: "read subscriptions from config file (service mode)"},
|
||||||
&cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"},
|
&cli.BoolFlag{Name: "poll", Aliases: []string{"p"}, Usage: "return events and exit, do not listen for new events"},
|
||||||
&cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"},
|
&cli.BoolFlag{Name: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"},
|
||||||
|
@ -40,6 +41,7 @@ ntfy subscribe TOPIC
|
||||||
ntfy subscribe mytopic # Prints JSON for incoming messages for ntfy.sh/mytopic
|
ntfy subscribe mytopic # Prints JSON for incoming messages for ntfy.sh/mytopic
|
||||||
ntfy sub home.lan/backups # Subscribe to topic on different server
|
ntfy sub home.lan/backups # Subscribe to topic on different server
|
||||||
ntfy sub --poll home.lan/backups # Just query for latest messages and exit
|
ntfy sub --poll home.lan/backups # Just query for latest messages and exit
|
||||||
|
ntfy sub -u phil:mypass secret # Subscribe with username/password
|
||||||
|
|
||||||
ntfy subscribe TOPIC COMMAND
|
ntfy subscribe TOPIC COMMAND
|
||||||
This executes COMMAND for every incoming messages. The message fields are passed to the
|
This executes COMMAND for every incoming messages. The message fields are passed to the
|
||||||
|
@ -81,6 +83,7 @@ func execSubscribe(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
cl := client.New(conf)
|
cl := client.New(conf)
|
||||||
since := c.String("since")
|
since := c.String("since")
|
||||||
|
user := c.String("user")
|
||||||
poll := c.Bool("poll")
|
poll := c.Bool("poll")
|
||||||
scheduled := c.Bool("scheduled")
|
scheduled := c.Bool("scheduled")
|
||||||
fromConfig := c.Bool("from-config")
|
fromConfig := c.Bool("from-config")
|
||||||
|
@ -93,6 +96,23 @@ func execSubscribe(c *cli.Context) error {
|
||||||
if since != "" {
|
if since != "" {
|
||||||
options = append(options, client.WithSince(since))
|
options = append(options, client.WithSince(since))
|
||||||
}
|
}
|
||||||
|
if user != "" {
|
||||||
|
var pass string
|
||||||
|
parts := strings.SplitN(user, ":", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
user = parts[0]
|
||||||
|
pass = parts[1]
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(c.App.ErrWriter, "Enter Password: ")
|
||||||
|
p, err := util.ReadPassword(c.App.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pass = string(p)
|
||||||
|
fmt.Fprintf(c.App.ErrWriter, "\r%s\r", strings.Repeat(" ", 20))
|
||||||
|
}
|
||||||
|
options = append(options, client.WithBasicAuth(user, pass))
|
||||||
|
}
|
||||||
if poll {
|
if poll {
|
||||||
options = append(options, client.WithPoll())
|
options = append(options, client.WithPoll())
|
||||||
}
|
}
|
||||||
|
@ -142,6 +162,9 @@ func doSubscribe(c *cli.Context, cl *client.Client, conf *client.Config, topic,
|
||||||
for filter, value := range s.If {
|
for filter, value := range s.If {
|
||||||
topicOptions = append(topicOptions, client.WithFilter(filter, value))
|
topicOptions = append(topicOptions, client.WithFilter(filter, value))
|
||||||
}
|
}
|
||||||
|
if s.User != "" && s.Password != "" {
|
||||||
|
topicOptions = append(topicOptions, client.WithBasicAuth(s.User, s.Password))
|
||||||
|
}
|
||||||
subscriptionID := cl.Subscribe(s.Topic, topicOptions...)
|
subscriptionID := cl.Subscribe(s.Topic, topicOptions...)
|
||||||
commands[subscriptionID] = s.Command
|
commands[subscriptionID] = s.Command
|
||||||
}
|
}
|
||||||
|
|
|
@ -196,3 +196,27 @@ EOF
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo systemctl restart ntfy-client
|
sudo systemctl restart ntfy-client
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Authentication
|
||||||
|
Depending on whether the server is configured to support [access control](../config.md#access-control), some topics
|
||||||
|
may be read/write protected so that only users with the correct credentials can subscribe or publish to them.
|
||||||
|
To publish/subscribe to protected topics, you can use [Basic Auth](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
||||||
|
with a valid username/password. For your self-hosted server, **be sure to use HTTPS to avoid eavesdropping** and exposing
|
||||||
|
your password.
|
||||||
|
|
||||||
|
You can either add your username and password to the configuration file:
|
||||||
|
=== "~/.config/ntfy/client.yml"
|
||||||
|
```yaml
|
||||||
|
- topic: secret
|
||||||
|
command: 'notify-send "$m"'
|
||||||
|
user: phill
|
||||||
|
password: mypass
|
||||||
|
```
|
||||||
|
|
||||||
|
Or with the `ntfy subscibe` command:
|
||||||
|
```
|
||||||
|
ntfy subscribe \
|
||||||
|
-u phil:mypass \
|
||||||
|
ntfy.example.com/mysecrets
|
||||||
|
```
|
||||||
|
|
Loading…
Reference in a new issue