From 2cbe46dc1a546de63f54e3259f84ea87694ed48c Mon Sep 17 00:00:00 2001 From: "Alexander \"PapaTutuWawa" Date: Thu, 11 Jan 2024 16:32:28 +0100 Subject: [PATCH] feat: Spawn another HTTP server for HTTPS upgrades --- .gitignore | 2 +- cmd/rio/main.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index a3ffedb..6693397 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ rio # Testing stuff -*.json \ No newline at end of file +*.json diff --git a/cmd/rio/main.go b/cmd/rio/main.go index 12279b6..4e18dc3 100644 --- a/cmd/rio/main.go +++ b/cmd/rio/main.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "strings" + "sync" "time" "git.polynom.me/rio/internal/acme" @@ -91,6 +92,22 @@ func Handler(pagesDomain, giteaUrl, defaultCsp string, giteaClient *repo.GiteaCl } } +// Handle HTTP redirects to HTTPS. +func httpHandler() http.HandlerFunc { + return func(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Server", "rio") + w.Header().Set("Strict-Transport-Security", "max-age=31536000") + + // Upgrade the URL + req.URL.Scheme = "https" + req.URL.Host = req.Host + w.Header().Set("Location", req.URL.String()) + + // Send the 301 + w.WriteHeader(301) + } +} + func runServer(ctx *cli.Context) error { giteaUrl := ctx.String("gitea-url") domain := ctx.String("pages-domain") @@ -131,6 +148,16 @@ func runServer(ctx *cli.Context) error { return err } + // Listen on the HTTP port + httpAddr := ctx.String("http-host") + ":" + ctx.String("http-port") + httpListener, err := net.Listen("tcp", httpAddr) + if err != nil { + fmt.Println( + fmt.Errorf("Failed to create HTTP listener: %v", err), + ) + return err + } + if !acmeDisable { if acmeEmail == "" || acmeFile == "" || certsFile == "" || acmeDnsProvider == "" { return errors.New("The options acme-dns-provider, acme-file, acme-email, and certs-file are required") @@ -189,11 +216,38 @@ func runServer(ctx *cli.Context) error { listener = tls.NewListener(listener, tlsConfig) } - if err := http.Serve(listener, Handler(domain, giteaUrl, defaultCsp, &giteaClient)); err != nil { - fmt.Printf("Listening failed") - return err + var waitGroup sync.WaitGroup + servers := 2 + if acmeDisable { + servers = 1 + } + waitGroup.Add(servers) + + go func() { + defer waitGroup.Done() + + log.Debug("Listening on main HTTP server") + if err := http.Serve(listener, Handler(domain, giteaUrl, defaultCsp, &giteaClient)); err != nil { + log.Fatal(fmt.Errorf("Listening failed: %v", err)) + } + log.Debug("Listening on main HTTP server done!") + }() + + if !acmeDisable { + go func() { + defer waitGroup.Done() + + log.Debug("Listening on redirect HTTP server") + if err := http.Serve(httpListener, httpHandler()); err != nil { + log.Fatal(fmt.Errorf("Listening failed: %v", err)) + } + log.Debug("Listening on redirect HTTP server done!") + }() } + log.Debug("Waiting...") + waitGroup.Wait() + log.Debug("Done...") return nil } @@ -219,6 +273,18 @@ func main() { EnvVars: []string{"PORT"}, Value: "8888", }, + &cli.StringFlag{ + Name: "http-host", + Usage: "The host to have unencrypted HTTP listen on", + EnvVars: []string{"HTTP_HOST"}, + Value: "127.0.0.1", + }, + &cli.StringFlag{ + Name: "http-port", + Usage: "The port to have unencrypted HTTP listen on", + EnvVars: []string{"HTTP_PORT"}, + Value: "9999", + }, &cli.StringFlag{ Name: "acme-dns-provider", Usage: "The provider to use for DNS01 challenge solving",