Merge branch 'main' of github.com:binwiederhier/ntfy into main

This commit is contained in:
Philipp Heckel 2022-02-27 14:58:18 -05:00
commit 10c69a722f
6 changed files with 80 additions and 5 deletions

View file

@ -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

View file

@ -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"`
} }

View file

@ -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)

View file

@ -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
} }

View file

@ -75,3 +75,21 @@ One of my co-workers uses the following Ansible task to let him know when things
method: POST method: POST
body: "{{ inventory_hostname }} reseeding complete" body: "{{ inventory_hostname }} reseeding complete"
``` ```
## Watchtower notifications (shoutrrr)
You can use `shoutrrr` generic webhook support to send watchtower notifications to your ntfy topic.
Example docker-compose.yml:
```yml
services:
watchtower:
image: containrrr/watchtower
environment:
- WATCHTOWER_NOTIFICATIONS=shoutrrr
- WATCHTOWER_NOTIFICATION_URL=generic+https://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates
```
Or, if you only want to send notifications using shoutrrr:
```
shoutrrr send -u "generic+https://ntfy.sh/my_watchtower_topic?title=WatchtowerUpdates" -m "testMessage"
```

View file

@ -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
```