From 21554def3ae1e39e6fc6d399d393a89b9f8daa3a Mon Sep 17 00:00:00 2001 From: Drew Edwards Date: Tue, 16 Jan 2024 19:13:17 +0000 Subject: [PATCH 1/2] feat: HTTP->HTTPS redirects on all sites --- .gitignore | 1 + caskethttp/httpserver/https.go | 10 ++++++++-- caskettls/config.go | 4 ++++ caskettls/setup.go | 2 ++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index b1f1c6a8..033753b9 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ access.log /*.conf Casketfile +Casketfile.* !casketfile/ casket/go.mod casket/go.sum diff --git a/caskethttp/httpserver/https.go b/caskethttp/httpserver/https.go index 1c80a825..5cf2ce3a 100644 --- a/caskethttp/httpserver/https.go +++ b/caskethttp/httpserver/https.go @@ -29,7 +29,7 @@ func activateHTTPS(cctx casket.Context) error { operatorPresent := !casket.Started() if !casket.Quiet && operatorPresent { - fmt.Print("Activating privacy features... ") + fmt.Println("Activating privacy features... ") } ctx := cctx.(*httpContext) @@ -147,7 +147,8 @@ func makePlaintextRedirects(allConfigs []*SiteConfig) []*SiteConfig { httpPort := strconv.Itoa(certmagic.HTTPPort) httpsPort := strconv.Itoa(certmagic.HTTPSPort) for i, cfg := range allConfigs { - if cfg.TLS.Managed && + if cfg.TLS.Enabled && + !cfg.TLS.NoRedirect && !hostHasOtherPort(allConfigs, i, httpPort) && (cfg.Addr.Port == httpsPort || !hostHasOtherPort(allConfigs, i, httpsPort)) { allConfigs = append(allConfigs, redirPlaintextHost(cfg)) @@ -193,6 +194,11 @@ func redirPlaintextHost(cfg *SiteConfig) *SiteConfig { redirPort = "" } + operatorPresent := !casket.Started() + if !casket.Quiet && operatorPresent { + fmt.Println("[INFO] Creating automatic HTTP->HTTPS redirect for", cfg.Addr.Host) + } + redirMiddleware := func(next Handler) Handler { return HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) { // Construct the URL to which to redirect. Note that the Host in a diff --git a/caskettls/config.go b/caskettls/config.go index 1d44e5d9..b1d9f27f 100644 --- a/caskettls/config.go +++ b/caskettls/config.go @@ -84,6 +84,10 @@ type Config struct { // Manager is how certificates are managed Manager *certmagic.Config + // NoRedirect will disable the automatic HTTP->HTTPS redirect, regardless + // of whether the site is managed or not. + NoRedirect bool + // SelfSigned means that this hostname is // served with a self-signed certificate // that we generated in memory for convenience diff --git a/caskettls/setup.go b/caskettls/setup.go index dbf833f4..88100874 100644 --- a/caskettls/setup.go +++ b/caskettls/setup.go @@ -278,6 +278,8 @@ func setupTLS(c *casket.Controller) error { } parts[0] = "*" config.Hostname = strings.Join(parts, ".") + case "no_redirect": + config.NoRedirect = true default: return c.Errf("Unknown subdirective '%s'", c.Val()) } From 68cef098ae5d0ee90d5deded29262b551887a2c4 Mon Sep 17 00:00:00 2001 From: Drew Edwards Date: Tue, 16 Jan 2024 19:26:38 +0000 Subject: [PATCH 2/2] test: update plaintext redirects --- caskethttp/httpserver/https_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/caskethttp/httpserver/https_test.go b/caskethttp/httpserver/https_test.go index c5f763b4..28a2fd04 100644 --- a/caskethttp/httpserver/https_test.go +++ b/caskethttp/httpserver/https_test.go @@ -23,8 +23,8 @@ import ( "strconv" "testing" - "github.com/tmpim/certmagic" "github.com/tmpim/casket/caskettls" + "github.com/tmpim/certmagic" ) func TestRedirPlaintextHost(t *testing.T) { @@ -153,18 +153,18 @@ func TestHostHasOtherPort(t *testing.T) { func TestMakePlaintextRedirects(t *testing.T) { configs := []*SiteConfig{ // Happy path = standard redirect from 80 to 443 - {Addr: Address{Host: "example.com"}, TLS: &caskettls.Config{Managed: true}}, + {Addr: Address{Host: "example.com"}, TLS: &caskettls.Config{Managed: true, Enabled: true}}, // Host on port 80 already defined; don't change it (no redirect) {Addr: Address{Host: "sub1.example.com", Port: "80", Scheme: "http"}, TLS: new(caskettls.Config)}, - {Addr: Address{Host: "sub1.example.com"}, TLS: &caskettls.Config{Managed: true}}, + {Addr: Address{Host: "sub1.example.com"}, TLS: &caskettls.Config{Managed: true, Enabled: true}}, // Redirect from port 80 to port 5000 in this case - {Addr: Address{Host: "sub2.example.com", Port: "5000"}, TLS: &caskettls.Config{Managed: true}}, + {Addr: Address{Host: "sub2.example.com", Port: "5000"}, TLS: &caskettls.Config{Managed: true, Enabled: true}}, // Can redirect from 80 to either 443 or 5001, but choose 443 - {Addr: Address{Host: "sub3.example.com", Port: "443"}, TLS: &caskettls.Config{Managed: true}}, - {Addr: Address{Host: "sub3.example.com", Port: "5001", Scheme: "https"}, TLS: &caskettls.Config{Managed: true}}, + {Addr: Address{Host: "sub3.example.com", Port: "443"}, TLS: &caskettls.Config{Managed: true, Enabled: true}}, + {Addr: Address{Host: "sub3.example.com", Port: "5001", Scheme: "https"}, TLS: &caskettls.Config{Managed: true, Enabled: true}}, } result := makePlaintextRedirects(configs)