From 80887bf4b5ec3365afe459f694825835a418a7fe Mon Sep 17 00:00:00 2001 From: Jannis Mattheis Date: Sun, 18 Feb 2018 15:15:44 +0100 Subject: [PATCH] Add support for ssl. --- Gopkg.lock | 4 +++- Gopkg.toml | 4 ++++ app.go | 5 ++-- runner/runner.go | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 runner/runner.go diff --git a/Gopkg.lock b/Gopkg.lock index 4da4cf2..a109253 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -161,6 +161,8 @@ branch = "master" name = "golang.org/x/crypto" packages = [ + "acme", + "acme/autocert", "bcrypt", "blowfish" ] @@ -187,6 +189,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "bfae0090e41cf3d9591943f08f86a6f1c68d846e2969817597b5163bd76f4edf" + inputs-digest = "c3c460b8861fdd2b2e1ebd3b9eafda81016511f59d0610308231f41d4111e687" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 91b306d..6d6b064 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -27,5 +27,9 @@ name = "github.com/jmattheis/go-packr-swagger-ui" revision = "v3.10.0" +[[constraint]] + name = "github.com/golang/crypto" + branch = "master" + [prune] unused-packages = true \ No newline at end of file diff --git a/app.go b/app.go index 5485518..ef5c081 100644 --- a/app.go +++ b/app.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "math/rand" "time" @@ -9,6 +8,7 @@ import ( "github.com/gotify/server/config" "github.com/gotify/server/database" "github.com/gotify/server/router" + "github.com/gotify/server/runner" ) func main() { @@ -23,5 +23,6 @@ func main() { gin.SetMode(gin.ReleaseMode) engine, closeable := router.Create(db) defer closeable() - engine.Run(fmt.Sprintf(":%d", conf.Port)) + + runner.Run(engine, conf) } diff --git a/runner/runner.go b/runner/runner.go new file mode 100644 index 0000000..e5c70dd --- /dev/null +++ b/runner/runner.go @@ -0,0 +1,61 @@ +package runner + +import ( + "crypto/tls" + "fmt" + "net" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/gotify/server/config" + "golang.org/x/crypto/acme/autocert" +) + +// Run starts the http server and if configured a https server. +func Run(engine *gin.Engine, conf *config.Configuration) { + var httpHandler http.Handler = engine + + if *conf.Server.SSL.Enabled { + fmt.Println(*conf.Server.SSL.RedirectToHTTPS) + if *conf.Server.SSL.RedirectToHTTPS { + httpHandler = redirectToHTTPS(string(conf.Server.SSL.Port)) + } + + s := &http.Server{ + Addr: fmt.Sprintf(":%d", conf.Server.SSL.Port), + Handler: engine, + } + + if *conf.Server.SSL.LetsEncrypt.Enabled { + certManager := autocert.Manager{ + Prompt: func(tosURL string) bool { return *conf.Server.SSL.LetsEncrypt.AcceptTOS }, + HostPolicy: autocert.HostWhitelist(conf.Server.SSL.LetsEncrypt.Hosts...), + Cache: autocert.DirCache(conf.Server.SSL.LetsEncrypt.Cache), + } + httpHandler = certManager.HTTPHandler(httpHandler) + s.TLSConfig = &tls.Config{GetCertificate: certManager.GetCertificate} + } + go s.ListenAndServeTLS(conf.Server.SSL.CertFile, conf.Server.SSL.CertKey) + } + http.ListenAndServe(fmt.Sprintf(":%d", conf.Server.Port), httpHandler) +} + +func redirectToHTTPS(port string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" && r.Method != "HEAD" { + http.Error(w, "Use HTTPS", http.StatusBadRequest) + return + } + + target := "https://" + changePort(r.Host, port) + r.URL.RequestURI() + http.Redirect(w, r, target, http.StatusFound) + } +} + +func changePort(hostPort string, port string) string { + host, _, err := net.SplitHostPort(hostPort) + if err != nil { + return hostPort + } + return net.JoinHostPort(host, port) +}