From c98fe735ad48004f4e8d5c49dd75d37172d867bd Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Fri, 6 Mar 2026 15:27:39 +0700 Subject: [PATCH] feat: add -dev flag for local HTTP testing In development mode (-dev): - HSTS header is omitted (prevents browser caching HTTPS-only requirement) - CSRF cookie Secure flag is cleared (allows cookies over plain HTTP) - A warning is logged on startup Co-Authored-By: Claude Sonnet 4.6 --- csrf.go | 1 + main.go | 6 ++++++ static.go | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/csrf.go b/csrf.go index a94be83..42f46d6 100644 --- a/csrf.go +++ b/csrf.go @@ -25,6 +25,7 @@ func setCSRFToken(w http.ResponseWriter) (string, error) { Path: "/", HttpOnly: false, // must be readable via form hidden field comparison SameSite: http.SameSiteStrictMode, + Secure: !devMode, }) return token, nil } diff --git a/main.go b/main.go index ec6e888..36ab61d 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ import ( ) var myPublicURL = "https://ldap.nemunai.re" +var devMode bool // dockerRegistrySecret is required for X-Special-Auth anonymous access. // If empty, the feature is disabled. @@ -80,9 +81,14 @@ func main() { var baseURL = flag.String("baseurl", "/", "URL prepended to each URL") var configfile = flag.String("config", "", "path to the configuration file") var publicURL = flag.String("public-url", myPublicURL, "Public base URL used in password reset emails") + var dev = flag.Bool("dev", false, "Development mode: disables HSTS and cookie Secure flag for local HTTP testing") flag.Parse() myPublicURL = *publicURL + devMode = *dev + if devMode { + log.Println("WARNING: running in development mode — security features relaxed, do not use in production") + } // Sanitize options log.Println("Checking paths...") diff --git a/static.go b/static.go index 6fd5ff6..4946083 100644 --- a/static.go +++ b/static.go @@ -13,7 +13,9 @@ func securityHeaders(next http.Handler) http.Handler { w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'wasm-unsafe-eval' 'unsafe-inline' https://stackpath.bootstrapcdn.com; style-src https://stackpath.bootstrapcdn.com; img-src 'self'; font-src https://stackpath.bootstrapcdn.com") - w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains") + if !devMode { + w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains") + } next.ServeHTTP(w, r) }) }