package middleware import ( "fmt" "net/http" "git.avsdev.uk/Go/job-search/internal/config" ) // DefaultHeaders sets a number of security related response headers. Using // configuration settings any extra headers are added and any headers to be // removed are stripped. func DefaultHeaders( conf config.JSCServerHeaders, ) func(http.Handler) http.Handler { type header struct { name, value string } var static []header addHeader := func(name, value string) { if value != "" { static = append(static, header{ name: http.CanonicalHeaderKey(name), value: value, }) } } addHeader("Content-Security-Policy", conf.ContentSecurityPolicy) addHeader("X-Frame-Options", conf.FrameOptions) addHeader("Referrer-Policy", conf.ReferrerPolicy) addHeader("Permissions-Policy", conf.PermissionsPolicy) addHeader("Cross-Origin-Opener-Policy", conf.CrossOriginOpenerPolicy) addHeader("Cross-Origin-Resource-Policy", conf.CrossOriginResourcePolicy) addHeader("X-Content-Type-Options", "nosniff") for _, extra := range conf.ExtraResponseHeaders { addHeader(extra.Header, extra.Value) } hsts := "" if seconds := int64(conf.HSTS.MaxAge.Seconds()); seconds > 0 { hsts = fmt.Sprintf("max-age=%d", seconds) if conf.HSTS.IncludeSubdomains { hsts += "; includeSubDomains" } if conf.HSTS.Preload { hsts += "; preload" } } remove := make([]string, 0, len(conf.RemoveResponseHeaders)) for _, name := range conf.RemoveResponseHeaders { remove = append(remove, http.CanonicalHeaderKey(name)) } strip := func(headers http.Header) { for _, name := range remove { headers.Del(name) } } return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { headers := w.Header() for _, staticHeader := range static { headers.Set(staticHeader.name, staticHeader.value) } // HSTS is only meaningful (and only honoured) over HTTPS. if hsts != "" && IsSecure(r) { headers.Set("Strict-Transport-Security", hsts) } if len(remove) == 0 { next.ServeHTTP(w, r) return } next.ServeHTTP(&responseRecorder{ ResponseWriter: w, beforeHeader: strip, }, r) }) } }