From fa9d6444f5318c040b803c1a0fd785f6f99e15dc Mon Sep 17 00:00:00 2001 From: Philipp Heckel <pheckel@datto.com> Date: Sat, 18 Dec 2021 22:02:36 -0500 Subject: [PATCH] Move config files and folders --- .goreleaser.yml | 18 +++++++++++++----- Makefile | 2 +- client/client.go | 3 ++- {config => client}/ntfy-client.service | 0 cmd/serve.go | 23 +++++++++++------------ cmd/subscribe.go | 14 ++++++++------ docs/config.md | 12 ++++++------ docs/faq.md | 2 +- docs/install.md | 6 +++--- scripts/postinst.sh | 2 +- scripts/postrm.sh | 2 +- scripts/preinst.sh | 11 +++++++++++ {config => server}/config.go | 5 ++--- {config => server}/config_test.go | 6 +++--- {config => server}/ntfy.service | 0 server/server.go | 9 ++++----- config/config.yml => server/server.yml | 2 +- server/visitor.go | 5 ++--- 18 files changed, 70 insertions(+), 52 deletions(-) rename {config => client}/ntfy-client.service (100%) create mode 100755 scripts/preinst.sh rename {config => server}/config.go (96%) rename {config => server}/config_test.go (64%) rename {config => server}/ntfy.service (100%) rename config/config.yml => server/server.yml (98%) diff --git a/.goreleaser.yml b/.goreleaser.yml index 7148ef6..d0cc958 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -47,14 +47,20 @@ nfpms: - rpm bindir: /usr/bin contents: - - src: config/config.yml - dst: /etc/ntfy/config.yml + - src: server/server.yml + dst: /etc/ntfy/server.yml type: config - - src: config/ntfy.service + - src: server/ntfy.service dst: /lib/systemd/system/ntfy.service + - src: client/client.yml + dst: /etc/ntfy/client.yml + type: config + - src: client/ntfy-client.service + dst: /lib/systemd/system/ntfy-client.service - dst: /var/cache/ntfy type: dir scripts: + preinstall: "scripts/preinst.sh" postinstall: "scripts/postinst.sh" preremove: "scripts/prerm.sh" postremove: "scripts/postrm.sh" @@ -64,8 +70,10 @@ archives: files: - LICENSE - README.md - - config/config.yml - - config/ntfy.service + - server/server.yml + - server/ntfy.service + - client/client.yml + - client/ntfy-client.service replacements: 386: i386 amd64: x86_64 diff --git a/Makefile b/Makefile index 006e638..1744dfd 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,7 @@ build-simple: clean "-linkmode=external -extldflags=-static -s -w -X main.version=$(VERSION) -X main.commit=$(shell git rev-parse --short HEAD) -X main.date=$(shell date +%s)" clean: .PHONY - rm -rf dist build + rm -rf dist build server/docs # Releasing targets diff --git a/client/client.go b/client/client.go index 31e7c89..3b83f28 100644 --- a/client/client.go +++ b/client/client.go @@ -50,7 +50,8 @@ func New(config *Config) *Client { } } -func (c *Client) Publish(topicURL, message string, options ...PublishOption) error { +func (c *Client) Publish(topic, message string, options ...PublishOption) error { + topicURL := c.expandTopicURL(topic) req, _ := http.NewRequest("POST", topicURL, strings.NewReader(message)) for _, option := range options { if err := option(req); err != nil { diff --git a/config/ntfy-client.service b/client/ntfy-client.service similarity index 100% rename from config/ntfy-client.service rename to client/ntfy-client.service diff --git a/cmd/serve.go b/cmd/serve.go index 2cdc842..ef963eb 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -5,7 +5,6 @@ import ( "errors" "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" - "heckel.io/ntfy/config" "heckel.io/ntfy/server" "heckel.io/ntfy/util" "log" @@ -13,20 +12,20 @@ import ( ) var flagsServe = []cli.Flag{ - &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/config.yml", DefaultText: "/etc/ntfy/config.yml", Usage: "config file"}, - altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: config.DefaultListenHTTP, Usage: "ip:port used to as HTTP listen address"}), + &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/server.yml", DefaultText: "/etc/ntfy/server.yml", Usage: "config file"}, + altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: server.DefaultListenHTTP, Usage: "ip:port used to as HTTP listen address"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-https", Aliases: []string{"L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used to as HTTPS listen address"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "key-file", Aliases: []string{"K"}, EnvVars: []string{"NTFY_KEY_FILE"}, Usage: "private key file, if listen-https is set"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "cert-file", Aliases: []string{"E"}, EnvVars: []string{"NTFY_CERT_FILE"}, Usage: "certificate file, if listen-https is set"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "firebase-key-file", Aliases: []string{"F"}, EnvVars: []string{"NTFY_FIREBASE_KEY_FILE"}, Usage: "Firebase credentials file; if set additionally publish to FCM topic"}), altsrc.NewStringFlag(&cli.StringFlag{Name: "cache-file", Aliases: []string{"C"}, EnvVars: []string{"NTFY_CACHE_FILE"}, Usage: "cache file used for message caching"}), - altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-duration", Aliases: []string{"b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: config.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}), - altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: config.DefaultKeepaliveInterval, Usage: "interval of keepalive messages"}), - altsrc.NewDurationFlag(&cli.DurationFlag{Name: "manager-interval", Aliases: []string{"m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: config.DefaultManagerInterval, Usage: "interval of for message pruning and stats printing"}), - altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: config.DefaultGlobalTopicLimit, Usage: "total number of topics allowed"}), - altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", Aliases: []string{"V"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: config.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}), - altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-request-limit-burst", Aliases: []string{"B"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_BURST"}, Value: config.DefaultVisitorRequestLimitBurst, Usage: "initial limit of requests per visitor"}), - altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-request-limit-replenish", Aliases: []string{"R"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: config.DefaultVisitorRequestLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), + altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-duration", Aliases: []string{"b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: server.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}), + altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: server.DefaultKeepaliveInterval, Usage: "interval of keepalive messages"}), + altsrc.NewDurationFlag(&cli.DurationFlag{Name: "manager-interval", Aliases: []string{"m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: server.DefaultManagerInterval, Usage: "interval of for message pruning and stats printing"}), + altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: server.DefaultGlobalTopicLimit, Usage: "total number of topics allowed"}), + altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", Aliases: []string{"V"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: server.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}), + altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-request-limit-burst", Aliases: []string{"B"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_BURST"}, Value: server.DefaultVisitorRequestLimitBurst, Usage: "initial limit of requests per visitor"}), + altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-request-limit-replenish", Aliases: []string{"R"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: server.DefaultVisitorRequestLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), altsrc.NewBoolFlag(&cli.BoolFlag{Name: "behind-proxy", Aliases: []string{"P"}, EnvVars: []string{"NTFY_BEHIND_PROXY"}, Value: false, Usage: "if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting)"}), } @@ -39,7 +38,7 @@ var cmdServe = &cli.Command{ Before: initConfigFileInputSource("config", flagsServe), Description: `Run the ntfy server and listen for incoming requests -The command will load the configuration from /etc/ntfy/config.yml. Config options can +The command will load the configuration from /etc/ntfy/server.yml. Config options can be overridden using the command line options. Examples: @@ -82,7 +81,7 @@ func execServe(c *cli.Context) error { } // Run server - conf := config.New(listenHTTP) + conf := server.NewConfig(listenHTTP) conf.ListenHTTPS = listenHTTPS conf.KeyFile = keyFile conf.CertFile = certFile diff --git a/cmd/subscribe.go b/cmd/subscribe.go index bbc36d2..a967dae 100644 --- a/cmd/subscribe.go +++ b/cmd/subscribe.go @@ -20,10 +20,14 @@ var cmdSubscribe = &cli.Command{ Usage: "Subscribe to one or more topics on a ntfy server", UsageText: "ntfy subscribe [OPTIONS..] [TOPIC]", Action: execSubscribe, + OnUsageError: func(context *cli.Context, err error, isSubcommand bool) error { + println("ee") + return nil + }, + Flags: []cli.Flag{ - &cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "config file"}, - &cli.StringFlag{Name: "exec", Aliases: []string{"e"}, Usage: "execute command for each message event"}, - &cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since (Unix timestamp, or all)"}, + &cli.StringFlag{Name: "config", Aliases: []string{"c"}, Usage: "config file `FILE`"}, + &cli.StringFlag{Name: "since", Aliases: []string{"s"}, Usage: "return events since `SINCE` (Unix timestamp, or all)"}, &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: "scheduled", Aliases: []string{"sched", "S"}, Usage: "also return scheduled/delayed events"}, @@ -72,8 +76,6 @@ ntfy subscribe --from-config } func execSubscribe(c *cli.Context) error { - fmt.Fprintln(c.App.ErrWriter, "\x1b[1;33mThis command is incubating. The interface may change without notice.\x1b[0m") - // Read config and options conf, err := loadConfig(c) if err != nil { @@ -100,7 +102,7 @@ func execSubscribe(c *cli.Context) error { options = append(options, client.WithScheduled()) } if topic == "" && len(conf.Subscribe) == 0 { - return errors.New("must specify topic, or have at least one topic defined in config") + return errors.New("must specify topic, type 'ntfy subscribe --help' for help") } // Execute poll or subscribe diff --git a/docs/config.md b/docs/config.md index 4f83e96..3917825 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,6 +1,6 @@ # Configuring the ntfy server -The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/config.yml`, -see [config.yml](https://github.com/binwiederhier/ntfy/blob/main/config/config.yml)), via command line arguments +The ntfy server can be configured in three ways: using a config file (typically at `/etc/ntfy/server.yml`, +see [server.yml](https://github.com/binwiederhier/ntfy/blob/main/config/server.yml)), via command line arguments or using environment variables. ## Quick start @@ -50,7 +50,7 @@ flag. This will instruct the [rate limiting](#rate-limiting) logic to use the `X identifier for a visitor, as opposed to the remote IP address. If the `behind-proxy` flag is not set, all visitors will be counted as one, because from the perspective of the ntfy server, they all share the proxy's IP address. -=== "/etc/ntfy/config.yml" +=== "/etc/ntfy/server.yml" ``` # Tell ntfy to use "X-Forwarded-For" to identify visitors behind-proxy: true @@ -200,7 +200,7 @@ To configure FCM for your self-hosted instance of the ntfy server, follow these 1. Sign up for a [Firebase account](https://console.firebase.google.com/) 2. Create a Firebase app and download the key file (e.g. `myapp-firebase-adminsdk-...json`) -3. Place the key file in `/etc/ntfy`, set the `firebase-key-file` in `config.yml` accordingly and restart the ntfy server +3. Place the key file in `/etc/ntfy`, set the `firebase-key-file` in `server.yml` accordingly and restart the ntfy server 4. Build your own Android .apk following [these instructions](develop.md#android-app) Example: @@ -294,7 +294,7 @@ to maintain the client connection and the connection to ntfy. ``` ## Config options -Each config option can be set in the config file `/etc/ntfy/config.yml` (e.g. `listen-http: :80`) or as a +Each config option can be set in the config file `/etc/ntfy/server.yml` (e.g. `listen-http: :80`) or as a CLI option (e.g. `--listen-http :80`. Here's a list of all available options. Alternatively, you can set an environment variable before running the `ntfy` command (e.g. `export NTFY_LISTEN_HTTP=:80`). @@ -327,7 +327,7 @@ USAGE: ntfy [OPTION..] GLOBAL OPTIONS: - --config value, -c value config file (default: /etc/ntfy/config.yml) [$NTFY_CONFIG_FILE] + --config value, -c value config file (default: /etc/ntfy/server.yml) [$NTFY_CONFIG_FILE] --listen-http value, -l value ip:port used to as listen address (default: ":80") [$NTFY_LISTEN_HTTP] --firebase-key-file value, -F value Firebase credentials file; if set additionally publish to FCM topic [$NTFY_FIREBASE_KEY_FILE] --cache-file value, -C value cache file used for message caching [$NTFY_CACHE_FILE] diff --git a/docs/faq.md b/docs/faq.md index 351ad5e..5105cc8 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -17,7 +17,7 @@ subscribed to a topic. ## Will you know what topics exist, can you spy on me? If you don't trust me or your messages are sensitive, run your own server. It's <a href="https://github.com/binwiederhier/ntfy">open source</a>. That said, the logs do not contain any topic names or other details about you. -Messages are cached for the duration configured in `config.yml` (12h by default) to facilitate service restarts, message polling and to overcome +Messages are cached for the duration configured in `server.yml` (12h by default) to facilitate service restarts, message polling and to overcome client network disruptions. ## Can I self-host it? diff --git a/docs/install.md b/docs/install.md index 4f3eea1..379f855 100644 --- a/docs/install.md +++ b/docs/install.md @@ -13,7 +13,7 @@ The ntfy server comes as a statically linked binary and is shipped as tarball, d We support amd64, armv7 and arm64. 1. Install ntfy using one of the methods described below -2. Then (optionally) edit `/etc/ntfy/config.yml` (see [configuration](config.md)) +2. Then (optionally) edit `/etc/ntfy/server.yml` (see [configuration](config.md)) To run the ntfy server, then just run `ntfy serve` (or `systemctl start ntfy` when using the deb/rpm). To send messages, use `ntfy publish`. To subscribe to topics, use `ntfy subscribe` (see [subscribing via CLI][subscribe/cli.md] @@ -138,7 +138,7 @@ straight forward to use. The server exposes its web UI and the API on port 80, so you need to expose that in Docker. To use the persistent [message cache](config.md#message-cache), you also need to map a volume to `/var/cache/ntfy`. To change other settings, -you should map `/etc/ntfy`, so you can edit `/etc/ntfy/config.yml`. +you should map `/etc/ntfy`, so you can edit `/etc/ntfy/server.yml`. Basic usage (no cache or additional config): ``` @@ -156,7 +156,7 @@ docker run \ serve ``` -With other config options (configured via `/etc/ntfy/config.yml`, see [configuration](config.md) for details): +With other config options (configured via `/etc/ntfy/server.yml`, see [configuration](config.md) for details): ```bash docker run \ -v /etc/ntfy:/etc/ntfy \ diff --git a/scripts/postinst.sh b/scripts/postinst.sh index 843805c..dabc0a1 100755 --- a/scripts/postinst.sh +++ b/scripts/postinst.sh @@ -13,7 +13,7 @@ if [ "$1" = "configure" ] && [ -d /run/systemd/system ]; then chmod 700 /var/cache/ntfy # Hack to change permissions on cache file - configfile="/etc/ntfy/config.yml" + configfile="/etc/ntfy/server.yml" if [ -f "$configfile" ]; then cachefile="$(cat "$configfile" | perl -n -e'/^\s*cache-file: ["'"'"']?([^"'"'"']+)["'"'"']?/ && print $1')" # Oh my, see #47 if [ -n "$cachefile" ]; then diff --git a/scripts/postrm.sh b/scripts/postrm.sh index 78db62e..696e8a1 100755 --- a/scripts/postrm.sh +++ b/scripts/postrm.sh @@ -4,7 +4,7 @@ set -e # Delete the config if package is purged if [ "$1" = "purge" ]; then id ntfy >/dev/null 2>&1 && userdel ntfy - rm -f /etc/ntfy/config.yml + rm -f /etc/ntfy/server.yml rmdir /etc/ntfy || true fi diff --git a/scripts/preinst.sh b/scripts/preinst.sh new file mode 100755 index 0000000..d09528c --- /dev/null +++ b/scripts/preinst.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -e + +if [ "$1" = "install" ] || [ "$1" = "upgrade" ]; then + # Migration of old to new config file name + oldconfigfile="/etc/ntfy/config.yml" + configfile="/etc/ntfy/server.yml" + if [ -f "$oldconfigfile" ] && [ ! -f "$configfile" ]; then + mv "$oldconfigfile" "$configfile" || true + fi +fi diff --git a/config/config.go b/server/config.go similarity index 96% rename from config/config.go rename to server/config.go index a78ec5a..fac1658 100644 --- a/config/config.go +++ b/server/config.go @@ -1,5 +1,4 @@ -// Package config provides the main configuration -package config +package server import ( "time" @@ -53,7 +52,7 @@ type Config struct { } // New instantiates a default new config -func New(listenHTTP string) *Config { +func NewConfig(listenHTTP string) *Config { return &Config{ ListenHTTP: listenHTTP, ListenHTTPS: "", diff --git a/config/config_test.go b/server/config_test.go similarity index 64% rename from config/config_test.go rename to server/config_test.go index d728251..902549d 100644 --- a/config/config_test.go +++ b/server/config_test.go @@ -1,12 +1,12 @@ -package config_test +package server_test import ( "github.com/stretchr/testify/assert" - "heckel.io/ntfy/config" + "heckel.io/ntfy/server" "testing" ) func TestConfig_New(t *testing.T) { - c := config.New(":1234") + c := server.NewConfig(":1234") assert.Equal(t, ":1234", c.ListenHTTP) } diff --git a/config/ntfy.service b/server/ntfy.service similarity index 100% rename from config/ntfy.service rename to server/ntfy.service diff --git a/server/server.go b/server/server.go index 3034209..d4b9f93 100644 --- a/server/server.go +++ b/server/server.go @@ -9,7 +9,6 @@ import ( "firebase.google.com/go/messaging" "fmt" "google.golang.org/api/option" - "heckel.io/ntfy/config" "heckel.io/ntfy/util" "html/template" "io" @@ -28,7 +27,7 @@ import ( // Server is the main server, providing the UI and API for ntfy type Server struct { - config *config.Config + config *Config topics map[string]*topic visitors map[string]*visitor firebase subscriber @@ -112,7 +111,7 @@ const ( // New instantiates a new Server. It creates the cache and adds a Firebase // subscriber (if configured). -func New(conf *config.Config) (*Server, error) { +func New(conf *Config) (*Server, error) { var firebaseSubscriber subscriber if conf.FirebaseKeyFile != "" { var err error @@ -138,7 +137,7 @@ func New(conf *config.Config) (*Server, error) { }, nil } -func createCache(conf *config.Config) (cache, error) { +func createCache(conf *Config) (cache, error) { if conf.CacheDuration == 0 { return newNopCache(), nil } else if conf.CacheFile != "" { @@ -147,7 +146,7 @@ func createCache(conf *config.Config) (cache, error) { return newMemCache(), nil } -func createFirebaseSubscriber(conf *config.Config) (subscriber, error) { +func createFirebaseSubscriber(conf *Config) (subscriber, error) { fb, err := firebase.NewApp(context.Background(), nil, option.WithCredentialsFile(conf.FirebaseKeyFile)) if err != nil { return nil, err diff --git a/config/config.yml b/server/server.yml similarity index 98% rename from config/config.yml rename to server/server.yml index 0829778..1ecc5de 100644 --- a/config/config.yml +++ b/server/server.yml @@ -1,4 +1,4 @@ -# ntfy config file +# ntfy server config file # Listen address for the HTTP & HTTPS web server. If "listen-https" is set, you must also # set "key-file" and "cert-file". diff --git a/server/visitor.go b/server/visitor.go index 7c23f89..9d99e94 100644 --- a/server/visitor.go +++ b/server/visitor.go @@ -2,7 +2,6 @@ package server import ( "golang.org/x/time/rate" - "heckel.io/ntfy/config" "heckel.io/ntfy/util" "sync" "time" @@ -14,14 +13,14 @@ const ( // visitor represents an API user, and its associated rate.Limiter used for rate limiting type visitor struct { - config *config.Config + config *Config limiter *rate.Limiter subscriptions *util.Limiter seen time.Time mu sync.Mutex } -func newVisitor(conf *config.Config) *visitor { +func newVisitor(conf *Config) *visitor { return &visitor{ config: conf, limiter: rate.NewLimiter(rate.Every(conf.VisitorRequestLimitReplenish), conf.VisitorRequestLimitBurst), -- GitLab