129 lines
3.0 KiB
Go
Raw Normal View History

package middleware
import (
"fmt"
"strings"
)
type CSP struct {
DefaultSrc CSPSourceOptions
ScriptSrc CSPSourceOptions
ObjectSrc CSPSourceOptions
StyleSrc CSPSourceOptions
ImgSrc CSPSourceOptions
MediaSrc CSPSourceOptions
FrameSrc CSPSourceOptions
FontSrc CSPSourceOptions
ManifestSrc CSPSourceOptions
ConnectSrc CSPSourceOptions
FormAction CSPSourceOptions
}
var (
DefaultSCP = CSP{
DefaultSrc: CSPSourceOptsNone(),
ScriptSrc: CSPSourceOptsSelf(),
ObjectSrc: CSPSourceOptsNone(),
StyleSrc: CSPSourceOptsSelf(),
ImgSrc: CSPSourceOptsSelf(),
MediaSrc: CSPSourceOptsNone(),
FrameSrc: CSPSourceOptsNone(),
FontSrc: CSPSourceOptsSelf(),
ManifestSrc: CSPSourceOptsSelf(),
ConnectSrc: CSPSourceOptsSelf(),
}
)
func (csp *CSP) Value(nonce string) string {
valuesMap := csp.asMap()
values := make([]string, 0, len(valuesMap))
for k, v := range valuesMap {
if v == nil {
continue
}
values = append(values, fmt.Sprintf("%v %v", k, v.String(nonce)))
}
return strings.Join(values, ";")
}
func (csp *CSP) asMap() map[string]CSPSourceOptions {
return map[string]CSPSourceOptions{
"default-src": csp.DefaultSrc,
"script-src": csp.ScriptSrc,
"object-src": csp.ObjectSrc,
"style-src": csp.StyleSrc,
"img-src": csp.ImgSrc,
"media-src": csp.MediaSrc,
"frame-src": csp.FrameSrc,
"font-src": csp.FontSrc,
"manifest-src": csp.ManifestSrc,
"connect-src": csp.ConnectSrc,
"form-action": csp.FormAction,
}
}
type CSPSourceOptions []string
func CSPSourceOpts() CSPSourceOptions {
return CSPSourceOptions{}
}
func CSPSourceOptsNone() CSPSourceOptions {
return []string{"'none'"}
}
func CSPSourceOptsSelf() CSPSourceOptions {
return []string{"'self'"}
}
func (srcOpts CSPSourceOptions) AddSelf() CSPSourceOptions {
return append(srcOpts, "'self'")
}
func (srcOpts CSPSourceOptions) AddInline() CSPSourceOptions {
return append(srcOpts, "'unsafe-inline'")
}
func (srcOpts CSPSourceOptions) AddEval() CSPSourceOptions {
return append(srcOpts, "'unsafe-eval'")
}
func (srcOpts CSPSourceOptions) AddStrictDynamic() CSPSourceOptions {
return append(srcOpts, "'strict-dynamic'")
}
func (srcOpts CSPSourceOptions) AddHost(h ...string) CSPSourceOptions {
return append(srcOpts, h...)
}
func (srcOpts CSPSourceOptions) AddScheme(s ...string) CSPSourceOptions {
return srcOpts.add(s, "%v:")
}
func (srcOpts CSPSourceOptions) AddNonce() CSPSourceOptions {
return append(srcOpts, "'nonce-%v'")
}
func (srcOpts CSPSourceOptions) AddHash(alg, b64v string) CSPSourceOptions {
return append(srcOpts, fmt.Sprintf("'%v-%v'", alg, b64v))
}
func (srcOpts CSPSourceOptions) String(nonce string) string {
value := strings.Join(srcOpts, " ")
if !strings.Contains(value, "%v") {
return value
}
return fmt.Sprintf(value, nonce)
}
func (srcOpts CSPSourceOptions) add(values []string, format string) CSPSourceOptions {
for i, v := range values {
values[i] = fmt.Sprintf(format, v)
}
return append(srcOpts, values...)
}