Merge branch 'main' of github.com:binwiederhier/ntfy into macos-server
This commit is contained in:
		
						commit
						60c5ccf34b
					
				
					 23 changed files with 643 additions and 308 deletions
				
			
		|  | @ -26,7 +26,7 @@ var cmdAccess = &cli.Command{ | |||
| 	Usage:     "Grant/revoke access to a topic, or show access", | ||||
| 	UsageText: "ntfy access [USERNAME [TOPIC [PERMISSION]]]", | ||||
| 	Flags:     flagsAccess, | ||||
| 	Before:    initConfigFileInputSource("config", flagsAccess), | ||||
| 	Before:    initConfigFileInputSourceFunc("config", flagsAccess), | ||||
| 	Action:    execUserAccess, | ||||
| 	Category:  categoryServer, | ||||
| 	Description: `Manage the access control list for the ntfy server. | ||||
|  |  | |||
							
								
								
									
										21
									
								
								cmd/app.go
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								cmd/app.go
									
										
									
									
									
								
							|  | @ -2,10 +2,7 @@ | |||
| package cmd | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"github.com/urfave/cli/v2/altsrc" | ||||
| 	"heckel.io/ntfy/util" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
|  | @ -30,21 +27,3 @@ func New() *cli.App { | |||
| 		Commands:               commands, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // initConfigFileInputSource is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks | ||||
| // if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails. | ||||
| func initConfigFileInputSource(configFlag string, flags []cli.Flag) cli.BeforeFunc { | ||||
| 	return func(context *cli.Context) error { | ||||
| 		configFile := context.String(configFlag) | ||||
| 		if context.IsSet(configFlag) && !util.FileExists(configFile) { | ||||
| 			return fmt.Errorf("config file %s does not exist", configFile) | ||||
| 		} else if !context.IsSet(configFlag) && !util.FileExists(configFile) { | ||||
| 			return nil | ||||
| 		} | ||||
| 		inputSource, err := altsrc.NewYamlSourceFromFile(configFile) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return altsrc.ApplyInputSourceValues(context, inputSource, flags) | ||||
| 	} | ||||
| } | ||||
|  |  | |||
							
								
								
									
										52
									
								
								cmd/config_loader.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								cmd/config_loader.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | |||
| package cmd | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"github.com/urfave/cli/v2/altsrc" | ||||
| 	"gopkg.in/yaml.v2" | ||||
| 	"heckel.io/ntfy/util" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| // initConfigFileInputSourceFunc is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks | ||||
| // if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails. | ||||
| func initConfigFileInputSourceFunc(configFlag string, flags []cli.Flag) cli.BeforeFunc { | ||||
| 	return func(context *cli.Context) error { | ||||
| 		configFile := context.String(configFlag) | ||||
| 		if context.IsSet(configFlag) && !util.FileExists(configFile) { | ||||
| 			return fmt.Errorf("config file %s does not exist", configFile) | ||||
| 		} else if !context.IsSet(configFlag) && !util.FileExists(configFile) { | ||||
| 			return nil | ||||
| 		} | ||||
| 		inputSource, err := newYamlSourceFromFile(configFile, flags) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return altsrc.ApplyInputSourceValues(context, inputSource, flags) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // newYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath. | ||||
| // | ||||
| // This function also maps aliases, so a .yml file can contain short options, or options with underscores | ||||
| // instead of dashes. See https://github.com/binwiederhier/ntfy/issues/255. | ||||
| func newYamlSourceFromFile(file string, flags []cli.Flag) (altsrc.InputSourceContext, error) { | ||||
| 	var rawConfig map[interface{}]interface{} | ||||
| 	b, err := os.ReadFile(file) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if err := yaml.Unmarshal(b, &rawConfig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, f := range flags { | ||||
| 		flagName := f.Names()[0] | ||||
| 		for _, flagAlias := range f.Names()[1:] { | ||||
| 			if _, ok := rawConfig[flagAlias]; ok { | ||||
| 				rawConfig[flagName] = rawConfig[flagAlias] | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return altsrc.NewMapInputSource(file, rawConfig), nil | ||||
| } | ||||
							
								
								
									
										38
									
								
								cmd/config_loader_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								cmd/config_loader_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| package cmd | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestNewYamlSourceFromFile(t *testing.T) { | ||||
| 	filename := filepath.Join(t.TempDir(), "server.yml") | ||||
| 	contents := ` | ||||
| # Normal options | ||||
| listen-https: ":10443" | ||||
| 
 | ||||
| # Note the underscore! | ||||
| listen_http: ":1080" | ||||
| 
 | ||||
| # OMG this is allowed now ... | ||||
| K: /some/file.pem | ||||
| ` | ||||
| 	require.Nil(t, os.WriteFile(filename, []byte(contents), 0600)) | ||||
| 
 | ||||
| 	ctx, err := newYamlSourceFromFile(filename, flagsServe) | ||||
| 	require.Nil(t, err) | ||||
| 
 | ||||
| 	listenHTTPS, err := ctx.String("listen-https") | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, ":10443", listenHTTPS) | ||||
| 
 | ||||
| 	listenHTTP, err := ctx.String("listen-http") // No underscore! | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, ":1080", listenHTTP) | ||||
| 
 | ||||
| 	keyFile, err := ctx.String("key-file") // Long option! | ||||
| 	require.Nil(t, err) | ||||
| 	require.Equal(t, "/some/file.pem", keyFile) | ||||
| } | ||||
							
								
								
									
										88
									
								
								cmd/serve.go
									
										
									
									
									
								
							
							
						
						
									
										88
									
								
								cmd/serve.go
									
										
									
									
									
								
							|  | @ -5,15 +5,16 @@ package cmd | |||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"github.com/urfave/cli/v2/altsrc" | ||||
| 	"heckel.io/ntfy/server" | ||||
| 	"heckel.io/ntfy/util" | ||||
| 	"log" | ||||
| 	"math" | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"github.com/urfave/cli/v2/altsrc" | ||||
| 	"heckel.io/ntfy/server" | ||||
| 	"heckel.io/ntfy/util" | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
|  | @ -22,41 +23,41 @@ func init() { | |||
| 
 | ||||
| var flagsServe = []cli.Flag{ | ||||
| 	&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: "base-url", Aliases: []string{"B"}, EnvVars: []string{"NTFY_BASE_URL"}, Usage: "externally visible base URL for this host (e.g. https://ntfy.sh)"}), | ||||
| 	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: "listen-unix", Aliases: []string{"U"}, EnvVars: []string{"NTFY_LISTEN_UNIX"}, Usage: "listen on unix socket path"}), | ||||
| 	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: server.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-cache-dir", EnvVars: []string{"NTFY_ATTACHMENT_CACHE_DIR"}, Usage: "cache directory for attached files"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-total-size-limit", Aliases: []string{"A"}, EnvVars: []string{"NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT"}, DefaultText: "5G", Usage: "limit of the on-disk attachment cache"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-file-size-limit", Aliases: []string{"Y"}, EnvVars: []string{"NTFY_ATTACHMENT_FILE_SIZE_LIMIT"}, DefaultText: "15M", Usage: "per-file attachment size limit (e.g. 300k, 2M, 100M)"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "attachment-expiry-duration", Aliases: []string{"X"}, EnvVars: []string{"NTFY_ATTACHMENT_EXPIRY_DURATION"}, Value: server.DefaultAttachmentExpiryDuration, DefaultText: "3h", Usage: "duration after which uploaded attachments will be deleted (e.g. 3h, 20h)"}), | ||||
| 	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.NewStringFlag(&cli.StringFlag{Name: "web-root", EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "app", Usage: "sets web root to landing page (home) or web app (app)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-addr", EnvVars: []string{"NTFY_SMTP_SENDER_ADDR"}, Usage: "SMTP server address (host:port) for outgoing emails"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-user", EnvVars: []string{"NTFY_SMTP_SENDER_USER"}, Usage: "SMTP user (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-pass", EnvVars: []string{"NTFY_SMTP_SENDER_PASS"}, Usage: "SMTP password (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-from", EnvVars: []string{"NTFY_SMTP_SENDER_FROM"}, Usage: "SMTP sender address (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-listen", EnvVars: []string{"NTFY_SMTP_SERVER_LISTEN"}, Usage: "SMTP server address (ip:port) for incoming emails, e.g. :25"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-domain", EnvVars: []string{"NTFY_SMTP_SERVER_DOMAIN"}, Usage: "SMTP domain for incoming e-mail, e.g. ntfy.sh"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-addr-prefix", EnvVars: []string{"NTFY_SMTP_SERVER_ADDR_PREFIX"}, Usage: "SMTP email address prefix for topics to prevent spam (e.g. 'ntfy-')"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: server.DefaultTotalTopicLimit, Usage: "total number of topics allowed"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: server.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-total-size-limit", EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: "100M", Usage: "total storage limit used for attachments per visitor"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-daily-bandwidth-limit", EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT"}, Value: "500M", Usage: "total daily attachment download/upload bandwidth limit per visitor"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-request-limit-burst", 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", EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: server.DefaultVisitorRequestLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-request-limit-exempt-hosts", EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS"}, Value: "", Usage: "hostnames and/or IP addresses of hosts that will be exempt from the visitor request limit"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-email-limit-burst", EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_BURST"}, Value: server.DefaultVisitorEmailLimitBurst, Usage: "initial limit of e-mails per visitor"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-email-limit-replenish", EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_REPLENISH"}, Value: server.DefaultVisitorEmailLimitReplenish, 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)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "base-url", Aliases: []string{"base_url", "B"}, EnvVars: []string{"NTFY_BASE_URL"}, Usage: "externally visible base URL for this host (e.g. https://ntfy.sh)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"listen_http", "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{"listen_https", "L"}, EnvVars: []string{"NTFY_LISTEN_HTTPS"}, Usage: "ip:port used to as HTTPS listen address"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-unix", Aliases: []string{"listen_unix", "U"}, EnvVars: []string{"NTFY_LISTEN_UNIX"}, Usage: "listen on unix socket path"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "key-file", Aliases: []string{"key_file", "K"}, EnvVars: []string{"NTFY_KEY_FILE"}, Usage: "private key file, if listen-https is set"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "cert-file", Aliases: []string{"cert_file", "E"}, EnvVars: []string{"NTFY_CERT_FILE"}, Usage: "certificate file, if listen-https is set"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "firebase-key-file", Aliases: []string{"firebase_key_file", "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{"cache_file", "C"}, EnvVars: []string{"NTFY_CACHE_FILE"}, Usage: "cache file used for message caching"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "cache-duration", Aliases: []string{"cache_duration", "b"}, EnvVars: []string{"NTFY_CACHE_DURATION"}, Value: server.DefaultCacheDuration, Usage: "buffer messages for this time to allow `since` requests"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-file", Aliases: []string{"auth_file", "H"}, EnvVars: []string{"NTFY_AUTH_FILE"}, Usage: "auth database file used for access control"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "auth-default-access", Aliases: []string{"auth_default_access", "p"}, EnvVars: []string{"NTFY_AUTH_DEFAULT_ACCESS"}, Value: "read-write", Usage: "default permissions if no matching entries in the auth database are found"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-cache-dir", Aliases: []string{"attachment_cache_dir"}, EnvVars: []string{"NTFY_ATTACHMENT_CACHE_DIR"}, Usage: "cache directory for attached files"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-total-size-limit", Aliases: []string{"attachment_total_size_limit", "A"}, EnvVars: []string{"NTFY_ATTACHMENT_TOTAL_SIZE_LIMIT"}, DefaultText: "5G", Usage: "limit of the on-disk attachment cache"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "attachment-file-size-limit", Aliases: []string{"attachment_file_size_limit", "Y"}, EnvVars: []string{"NTFY_ATTACHMENT_FILE_SIZE_LIMIT"}, DefaultText: "15M", Usage: "per-file attachment size limit (e.g. 300k, 2M, 100M)"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "attachment-expiry-duration", Aliases: []string{"attachment_expiry_duration", "X"}, EnvVars: []string{"NTFY_ATTACHMENT_EXPIRY_DURATION"}, Value: server.DefaultAttachmentExpiryDuration, DefaultText: "3h", Usage: "duration after which uploaded attachments will be deleted (e.g. 3h, 20h)"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"keepalive_interval", "k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: server.DefaultKeepaliveInterval, Usage: "interval of keepalive messages"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "manager-interval", Aliases: []string{"manager_interval", "m"}, EnvVars: []string{"NTFY_MANAGER_INTERVAL"}, Value: server.DefaultManagerInterval, Usage: "interval of for message pruning and stats printing"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "web-root", Aliases: []string{"web_root"}, EnvVars: []string{"NTFY_WEB_ROOT"}, Value: "app", Usage: "sets web root to landing page (home), web app (app) or disabled (disable)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-addr", Aliases: []string{"smtp_sender_addr"}, EnvVars: []string{"NTFY_SMTP_SENDER_ADDR"}, Usage: "SMTP server address (host:port) for outgoing emails"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-user", Aliases: []string{"smtp_sender_user"}, EnvVars: []string{"NTFY_SMTP_SENDER_USER"}, Usage: "SMTP user (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-pass", Aliases: []string{"smtp_sender_pass"}, EnvVars: []string{"NTFY_SMTP_SENDER_PASS"}, Usage: "SMTP password (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-sender-from", Aliases: []string{"smtp_sender_from"}, EnvVars: []string{"NTFY_SMTP_SENDER_FROM"}, Usage: "SMTP sender address (if e-mail sending is enabled)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-listen", Aliases: []string{"smtp_server_listen"}, EnvVars: []string{"NTFY_SMTP_SERVER_LISTEN"}, Usage: "SMTP server address (ip:port) for incoming emails, e.g. :25"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-domain", Aliases: []string{"smtp_server_domain"}, EnvVars: []string{"NTFY_SMTP_SERVER_DOMAIN"}, Usage: "SMTP domain for incoming e-mail, e.g. ntfy.sh"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "smtp-server-addr-prefix", Aliases: []string{"smtp_server_addr_prefix"}, EnvVars: []string{"NTFY_SMTP_SERVER_ADDR_PREFIX"}, Usage: "SMTP email address prefix for topics to prevent spam (e.g. 'ntfy-')"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "global-topic-limit", Aliases: []string{"global_topic_limit", "T"}, EnvVars: []string{"NTFY_GLOBAL_TOPIC_LIMIT"}, Value: server.DefaultTotalTopicLimit, Usage: "total number of topics allowed"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-subscription-limit", Aliases: []string{"visitor_subscription_limit"}, EnvVars: []string{"NTFY_VISITOR_SUBSCRIPTION_LIMIT"}, Value: server.DefaultVisitorSubscriptionLimit, Usage: "number of subscriptions per visitor"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-total-size-limit", Aliases: []string{"visitor_attachment_total_size_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_TOTAL_SIZE_LIMIT"}, Value: "100M", Usage: "total storage limit used for attachments per visitor"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-attachment-daily-bandwidth-limit", Aliases: []string{"visitor_attachment_daily_bandwidth_limit"}, EnvVars: []string{"NTFY_VISITOR_ATTACHMENT_DAILY_BANDWIDTH_LIMIT"}, Value: "500M", Usage: "total daily attachment download/upload bandwidth limit per visitor"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-request-limit-burst", Aliases: []string{"visitor_request_limit_burst"}, 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{"visitor_request_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_REPLENISH"}, Value: server.DefaultVisitorRequestLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), | ||||
| 	altsrc.NewStringFlag(&cli.StringFlag{Name: "visitor-request-limit-exempt-hosts", Aliases: []string{"visitor_request_limit_exempt_hosts"}, EnvVars: []string{"NTFY_VISITOR_REQUEST_LIMIT_EXEMPT_HOSTS"}, Value: "", Usage: "hostnames and/or IP addresses of hosts that will be exempt from the visitor request limit"}), | ||||
| 	altsrc.NewIntFlag(&cli.IntFlag{Name: "visitor-email-limit-burst", Aliases: []string{"visitor_email_limit_burst"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_BURST"}, Value: server.DefaultVisitorEmailLimitBurst, Usage: "initial limit of e-mails per visitor"}), | ||||
| 	altsrc.NewDurationFlag(&cli.DurationFlag{Name: "visitor-email-limit-replenish", Aliases: []string{"visitor_email_limit_replenish"}, EnvVars: []string{"NTFY_VISITOR_EMAIL_LIMIT_REPLENISH"}, Value: server.DefaultVisitorEmailLimitReplenish, Usage: "interval at which burst limit is replenished (one per x)"}), | ||||
| 	altsrc.NewBoolFlag(&cli.BoolFlag{Name: "behind-proxy", Aliases: []string{"behind_proxy", "P"}, EnvVars: []string{"NTFY_BEHIND_PROXY"}, Value: false, Usage: "if set, use X-Forwarded-For header to determine visitor IP address (for rate limiting)"}), | ||||
| } | ||||
| 
 | ||||
| var cmdServe = &cli.Command{ | ||||
|  | @ -66,7 +67,7 @@ var cmdServe = &cli.Command{ | |||
| 	Action:    execServe, | ||||
| 	Category:  categoryServer, | ||||
| 	Flags:     flagsServe, | ||||
| 	Before:    initConfigFileInputSource("config", flagsServe), | ||||
| 	Before:    initConfigFileInputSourceFunc("config", flagsServe), | ||||
| 	Description: `Run the ntfy server and listen for incoming requests | ||||
| 
 | ||||
| The command will load the configuration from /etc/ntfy/server.yml. Config options can  | ||||
|  | @ -144,12 +145,14 @@ func execServe(c *cli.Context) error { | |||
| 		return errors.New("if set, base-url must start with http:// or https://") | ||||
| 	} else if !util.InStringList([]string{"read-write", "read-only", "write-only", "deny-all"}, authDefaultAccess) { | ||||
| 		return errors.New("if set, auth-default-access must start set to 'read-write', 'read-only', 'write-only' or 'deny-all'") | ||||
| 	} else if !util.InStringList([]string{"app", "home"}, webRoot) { | ||||
| 	} else if !util.InStringList([]string{"app", "home", "disable"}, webRoot) { | ||||
| 		return errors.New("if set, web-root must be 'home' or 'app'") | ||||
| 	} | ||||
| 
 | ||||
| 	// Default auth permissions | ||||
| 	webRootIsApp := webRoot == "app" | ||||
| 	enableWeb := webRoot != "disable" | ||||
| 
 | ||||
| 	// Default auth permissions | ||||
| 	authDefaultRead := authDefaultAccess == "read-write" || authDefaultAccess == "read-only" | ||||
| 	authDefaultWrite := authDefaultAccess == "read-write" || authDefaultAccess == "write-only" | ||||
| 
 | ||||
|  | @ -229,6 +232,7 @@ func execServe(c *cli.Context) error { | |||
| 	conf.VisitorEmailLimitBurst = visitorEmailLimitBurst | ||||
| 	conf.VisitorEmailLimitReplenish = visitorEmailLimitReplenish | ||||
| 	conf.BehindProxy = behindProxy | ||||
| 	conf.EnableWeb = enableWeb | ||||
| 	s, err := server.New(conf) | ||||
| 	if err != nil { | ||||
| 		log.Fatalln(err) | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ var cmdUser = &cli.Command{ | |||
| 	Usage:     "Manage/show users", | ||||
| 	UsageText: "ntfy user [list|add|remove|change-pass|change-role] ...", | ||||
| 	Flags:     flagsUser, | ||||
| 	Before:    initConfigFileInputSource("config", flagsUser), | ||||
| 	Before:    initConfigFileInputSourceFunc("config", flagsUser), | ||||
| 	Category:  categoryServer, | ||||
| 	Subcommands: []*cli.Command{ | ||||
| 		{ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue