diff --git a/cmd/app.go b/cmd/app.go index 6ef9f942..50f80564 100644 --- a/cmd/app.go +++ b/cmd/app.go @@ -18,7 +18,10 @@ import ( func New() *cli.App { flags := []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 listen address"}), + 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"}), + 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"}), @@ -50,6 +53,9 @@ func New() *cli.App { func execRun(c *cli.Context) error { // Read all the options listenHTTP := c.String("listen-http") + listenHTTPS := c.String("listen-https") + keyFile := c.String("key-file") + certFile := c.String("cert-file") firebaseKeyFile := c.String("firebase-key-file") cacheFile := c.String("cache-file") cacheDuration := c.Duration("cache-duration") @@ -70,10 +76,19 @@ func execRun(c *cli.Context) error { return errors.New("manager interval cannot be lower than five seconds") } else if cacheDuration < managerInterval { return errors.New("cache duration cannot be lower than manager interval") + } else if keyFile != "" && !util.FileExists(keyFile) { + return errors.New("if set, key file must exist") + } else if certFile != "" && !util.FileExists(certFile) { + return errors.New("if set, certificate file must exist") + } else if listenHTTPS != "" && (keyFile == "" || certFile == "") { + return errors.New("if listen-https is set, both key-file and cert-file must be set") } // Run server conf := config.New(listenHTTP) + conf.ListenHTTPS = listenHTTPS + conf.KeyFile = keyFile + conf.CertFile = certFile conf.FirebaseKeyFile = firebaseKeyFile conf.CacheFile = cacheFile conf.CacheDuration = cacheDuration diff --git a/config/config.go b/config/config.go index 902f23bd..bffa9782 100644 --- a/config/config.go +++ b/config/config.go @@ -27,6 +27,9 @@ const ( // Config is the main config struct for the application. Use New to instantiate a default config struct. type Config struct { ListenHTTP string + ListenHTTPS string + KeyFile string + CertFile string FirebaseKeyFile string CacheFile string CacheDuration time.Duration @@ -43,6 +46,9 @@ type Config struct { func New(listenHTTP string) *Config { return &Config{ ListenHTTP: listenHTTP, + ListenHTTPS: "", + KeyFile: "", + CertFile: "", FirebaseKeyFile: "", CacheFile: "", CacheDuration: DefaultCacheDuration, diff --git a/config/config.yml b/config/config.yml index 695d41d2..89f8ad55 100644 --- a/config/config.yml +++ b/config/config.yml @@ -5,6 +5,21 @@ # # listen-http: ":80" +# Listen address for the HTTPS web server. If set, you must also set "key-file" and "cert-file". +# Format: : +# +# listen-https: + +# Path to the private key file for the HTTPS web server. Not used if "listen-https" is not set. +# Format: +# +# key-file: + +# Path to the cert file for the HTTPS web server. Not used if "listen-https" is not set. +# Format: +# +# cert-file: + # If set, also publish messages to a Firebase Cloud Messaging (FCM) topic for your app. # This is optional and only required to save battery when using the Android app. # diff --git a/server/server.go b/server/server.go index ab46dbcc..29a10370 100644 --- a/server/server.go +++ b/server/server.go @@ -173,13 +173,23 @@ func (s *Server) Run() error { s.updateStatsAndExpire() } }() - return s.listenAndServe() -} + listenStr := fmt.Sprintf("%s/http", s.config.ListenHTTP) + if s.config.ListenHTTPS != "" { + listenStr += fmt.Sprintf(" %s/https", s.config.ListenHTTPS) + } + log.Printf("Listening on %s", listenStr) -func (s *Server) listenAndServe() error { - log.Printf("Listening on %s", s.config.ListenHTTP) http.HandleFunc("/", s.handle) - return http.ListenAndServe(s.config.ListenHTTP, nil) + errChan := make(chan error) + go func() { + errChan <- http.ListenAndServe(s.config.ListenHTTP, nil) + }() + if s.config.ListenHTTPS != "" { + go func() { + errChan <- http.ListenAndServeTLS(s.config.ListenHTTPS, s.config.CertFile, s.config.KeyFile, nil) + }() + } + return <-errChan } func (s *Server) handle(w http.ResponseWriter, r *http.Request) {