package main import ( "embed" "html/template" "log" "net/http" "net/url" "strings" ) func securityHeaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin") imgSrc := "'self' data:" if strings.HasPrefix(brandLogo, "http://") || strings.HasPrefix(brandLogo, "https://") { if u, err := url.Parse(brandLogo); err == nil { imgSrc += " " + u.Scheme + "://" + u.Host } } csp := "default-src 'self'; script-src 'self' 'wasm-unsafe-eval' 'unsafe-inline'; style-src 'self' 'sha256-W6z8OR2iqpPyNGe72eRXH58H75H3UVJDuwHoKA6pX98='; img-src " + imgSrc + "; worker-src blob:" w.Header().Set("Content-Security-Policy", csp) if !devMode { w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains") } next.ServeHTTP(w, r) }) } //go:embed all:static var assets embed.FS func serveStyleCSS(w http.ResponseWriter, r *http.Request) { data, err := assets.ReadFile("static/style.css") if err != nil { http.NotFound(w, r) return } w.Header().Set("Content-Type", "text/css; charset=utf-8") w.Header().Set("Cache-Control", "public, max-age=3600") w.Write(data) } func displayTmpl(w http.ResponseWriter, page string, vars map[string]any) { if vars == nil { vars = map[string]any{} } vars["brand_name"] = brandName if brandLogo != "" { vars["brand_logo"] = brandLogo } data, err := assets.ReadFile("static/" + page) if err != nil { log.Fatalf("Unable to find %q: %s", page, err.Error()) } footer, err := assets.ReadFile("static/footer.html") if err != nil { log.Fatalf("Unable to find %q: %s", "footer.html", err.Error()) } header, err := assets.ReadFile("static/header.html") if err != nil { log.Fatalf("Unable to find %q: %s", "header.html", err.Error()) } tpl := template.Must(template.New("page").Parse(string(data))) tpl.New("footer.html").Parse(string(footer)) tpl.New("header.html").Parse(string(header)) tpl.ExecuteTemplate(w, "page", vars) } func displayTmplError(w http.ResponseWriter, statusCode int, page string, vars map[string]any) { w.WriteHeader(statusCode) displayTmpl(w, page, vars) } func displayMsg(w http.ResponseWriter, msg string, statusCode int) { w.WriteHeader(statusCode) label := "error" if statusCode < 400 { label = "message" } displayTmpl(w, "message.html", map[string]any{label: msg}) }