mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-20 12:42:34 +02:00
69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package httpheaders
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// AppendCSP appends a CSP header to specific directives in the response writer.
|
|
//
|
|
// Directives other than the ones in cspDirectives will be kept as is.
|
|
//
|
|
// It will replace 'none' with the sources.
|
|
//
|
|
// It will append 'self' to the sources if it's not already present.
|
|
func AppendCSP(w http.ResponseWriter, r *http.Request, cspDirectives []string, sources []string) {
|
|
csp := make(map[string]string)
|
|
cspValues := r.Header.Values("Content-Security-Policy")
|
|
if len(cspValues) == 1 {
|
|
cspValues = strings.Split(cspValues[0], ";")
|
|
for i, cspString := range cspValues {
|
|
cspValues[i] = strings.TrimSpace(cspString)
|
|
}
|
|
}
|
|
|
|
for _, cspString := range cspValues {
|
|
parts := strings.SplitN(cspString, " ", 2)
|
|
if len(parts) == 2 {
|
|
csp[parts[0]] = parts[1]
|
|
}
|
|
}
|
|
|
|
for _, directive := range cspDirectives {
|
|
value, ok := csp[directive]
|
|
if !ok {
|
|
value = "'self'"
|
|
}
|
|
switch value {
|
|
case "'self'":
|
|
csp[directive] = value + " " + strings.Join(sources, " ")
|
|
case "'none'":
|
|
csp[directive] = strings.Join(sources, " ")
|
|
default:
|
|
for _, source := range sources {
|
|
if !strings.Contains(value, source) {
|
|
value += " " + source
|
|
}
|
|
}
|
|
if !strings.Contains(value, "'self'") {
|
|
value = "'self' " + value
|
|
}
|
|
csp[directive] = value
|
|
}
|
|
}
|
|
|
|
values := make([]string, 0, len(csp))
|
|
for directive, value := range csp {
|
|
values = append(values, directive+" "+value)
|
|
}
|
|
|
|
// Remove existing CSP header, case insensitive
|
|
for k := range w.Header() {
|
|
if strings.EqualFold(k, "Content-Security-Policy") {
|
|
delete(w.Header(), k)
|
|
}
|
|
}
|
|
|
|
// Set new CSP header
|
|
w.Header()["Content-Security-Policy"] = values
|
|
}
|