Merge branch 'next' of github.com:OliveTin/OliveTin into next
This commit is contained in:
commit
5cbcf29704
|
|
@ -107,6 +107,15 @@ type PrometheusConfig struct {
|
||||||
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecurityConfig allows users to fine tune the security related HTTP headers.
|
||||||
|
type SecurityConfig struct {
|
||||||
|
HeaderContentSecurityPolicy bool `koanf:"headerContentSecurityPolicy"`
|
||||||
|
ContentSecurityPolicy string `koanf:"contentSecurityPolicy"`
|
||||||
|
HeaderXContentTypeOptions bool `koanf:"headerXContentTypeOptions"`
|
||||||
|
HeaderXFrameOptions bool `koanf:"headerXFrameOptions"`
|
||||||
|
XFrameOptions string `koanf:"xFrameOptions"`
|
||||||
|
}
|
||||||
|
|
||||||
// Config is the global config used through the whole app.
|
// Config is the global config used through the whole app.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
UseSingleHTTPFrontend bool `koanf:"useSingleHTTPFrontend"`
|
UseSingleHTTPFrontend bool `koanf:"useSingleHTTPFrontend"`
|
||||||
|
|
@ -160,6 +169,7 @@ type Config struct {
|
||||||
InsecureAllowDumpActionMap bool `koanf:"insecureAllowDumpActionMap"`
|
InsecureAllowDumpActionMap bool `koanf:"insecureAllowDumpActionMap"`
|
||||||
InsecureAllowDumpJwtClaims bool `koanf:"insecureAllowDumpJwtClaims"`
|
InsecureAllowDumpJwtClaims bool `koanf:"insecureAllowDumpJwtClaims"`
|
||||||
Prometheus PrometheusConfig `koanf:"prometheus"`
|
Prometheus PrometheusConfig `koanf:"prometheus"`
|
||||||
|
Security SecurityConfig `koanf:"security"`
|
||||||
SaveLogs SaveLogsConfig `koanf:"saveLogs"`
|
SaveLogs SaveLogsConfig `koanf:"saveLogs"`
|
||||||
DefaultIconForActions string `koanf:"defaultIconForActions"`
|
DefaultIconForActions string `koanf:"defaultIconForActions"`
|
||||||
DefaultIconForDirectories string `koanf:"defaultIconForDirectories"`
|
DefaultIconForDirectories string `koanf:"defaultIconForDirectories"`
|
||||||
|
|
@ -268,6 +278,11 @@ func DefaultConfigWithBasePort(basePort int) *Config {
|
||||||
config.InsecureAllowDumpJwtClaims = false
|
config.InsecureAllowDumpJwtClaims = false
|
||||||
config.Prometheus.Enabled = false
|
config.Prometheus.Enabled = false
|
||||||
config.Prometheus.DefaultGoMetrics = false
|
config.Prometheus.DefaultGoMetrics = false
|
||||||
|
config.Security.HeaderContentSecurityPolicy = true
|
||||||
|
config.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||||
|
config.Security.HeaderXContentTypeOptions = true
|
||||||
|
config.Security.HeaderXFrameOptions = true
|
||||||
|
config.Security.XFrameOptions = "DENY"
|
||||||
config.DefaultIconForActions = "😀"
|
config.DefaultIconForActions = "😀"
|
||||||
config.DefaultIconForDirectories = "📁"
|
config.DefaultIconForDirectories = "📁"
|
||||||
config.DefaultIconForBack = "«"
|
config.DefaultIconForBack = "«"
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ func (cfg *Config) Sanitize() {
|
||||||
cfg.sanitizeAuthRequireGuestsToLogin()
|
cfg.sanitizeAuthRequireGuestsToLogin()
|
||||||
cfg.sanitizeLogHistoryPageSize()
|
cfg.sanitizeLogHistoryPageSize()
|
||||||
cfg.sanitizeLocalUserPasswords()
|
cfg.sanitizeLocalUserPasswords()
|
||||||
|
cfg.sanitizeSecurityHeaders()
|
||||||
|
|
||||||
// log.Infof("cfg %p", cfg)
|
// log.Infof("cfg %p", cfg)
|
||||||
|
|
||||||
|
|
@ -183,6 +184,25 @@ func (cfg *Config) sanitizeLocalUserPasswords() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) sanitizeSecurityHeaders() {
|
||||||
|
cfg.sanitizeSecurityHeadersCSP()
|
||||||
|
cfg.sanitizeSecurityHeadersXFrameOptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) sanitizeSecurityHeadersCSP() {
|
||||||
|
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.Security.ContentSecurityPolicy = "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none'; base-uri 'self'"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) sanitizeSecurityHeadersXFrameOptions() {
|
||||||
|
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions != "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg.Security.XFrameOptions = "DENY"
|
||||||
|
}
|
||||||
|
|
||||||
// parsePasswordTemplate expands {{ .Env.VAR }} in local user password fields using the process environment.
|
// parsePasswordTemplate expands {{ .Env.VAR }} in local user password fields using the process environment.
|
||||||
func parsePasswordTemplate(source string) string {
|
func parsePasswordTemplate(source string) string {
|
||||||
t, err := template.New("password").Option("missingkey=error").Parse(source)
|
t, err := template.New("password").Option("missingkey=error").Parse(source)
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,40 @@ import (
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func applySecurityHeaders(cfg *config.Config, w http.ResponseWriter) {
|
||||||
|
applyCSP(cfg, w)
|
||||||
|
applyXContentTypeOptions(cfg, w)
|
||||||
|
applyXFrameOptions(cfg, w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyCSP(cfg *config.Config, w http.ResponseWriter) {
|
||||||
|
if !cfg.Security.HeaderContentSecurityPolicy || cfg.Security.ContentSecurityPolicy == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Security-Policy", cfg.Security.ContentSecurityPolicy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyXContentTypeOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||||
|
if !cfg.Security.HeaderXContentTypeOptions {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
}
|
||||||
|
|
||||||
|
func applyXFrameOptions(cfg *config.Config, w http.ResponseWriter) {
|
||||||
|
if !cfg.Security.HeaderXFrameOptions || cfg.Security.XFrameOptions == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("X-Frame-Options", cfg.Security.XFrameOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func securityHeadersMiddleware(cfg *config.Config, next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
applySecurityHeaders(cfg, w)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func logDebugRequest(cfg *config.Config, source string, r *http.Request) {
|
func logDebugRequest(cfg *config.Config, source string, r *http.Request) {
|
||||||
if cfg.LogDebugOptions.SingleFrontendRequests {
|
if cfg.LogDebugOptions.SingleFrontendRequests {
|
||||||
log.Debugf("SingleFrontend HTTP Req URL %v: %q", source, r.URL)
|
log.Debugf("SingleFrontend HTTP Req URL %v: %q", source, r.URL)
|
||||||
|
|
@ -96,7 +130,7 @@ func StartFrontendMux(cfg *config.Config, ex *executor.Executor) {
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
Addr: cfg.ListenAddressSingleHTTPFrontend,
|
||||||
Handler: mux,
|
Handler: securityHeadersMiddleware(cfg, mux),
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Fatal(srv.ListenAndServe())
|
log.Fatal(srv.ListenAndServe())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue