mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-17 08:19:53 +00:00
83 lines
1.9 KiB
Go
83 lines
1.9 KiB
Go
package utils
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
const cspNonceContextKey = "csp_nonce"
|
|
|
|
// GetCSPNonce returns the CSP nonce generated for this request, if any.
|
|
func GetCSPNonce(c *gin.Context) string {
|
|
if v, ok := c.Get(cspNonceContextKey); ok {
|
|
if s, ok := v.(string); ok {
|
|
return s
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// SetCSPNonce stores a per-request CSP nonce so handlers can reference it in
|
|
// Content-Security-Policy headers they emit themselves.
|
|
func SetCSPNonce(c *gin.Context, nonce string) {
|
|
c.Set(cspNonceContextKey, nonce)
|
|
}
|
|
|
|
func BuildCSP(nonce string) string {
|
|
return buildCSP(nonce, nil, nil)
|
|
}
|
|
|
|
// BuildFormPostCSP builds the Content-Security-Policy for an OIDC response_mode=form_post page
|
|
func BuildFormPostCSP(nonce, redirectURI, scriptHash string) string {
|
|
return buildCSP(nonce, []string{redirectURI}, []string{scriptHash})
|
|
}
|
|
|
|
func buildCSP(nonce string, formActionExtra, scriptSrcExtra []string) string {
|
|
formAction := "'self'"
|
|
scriptSrc := "script-src 'self'"
|
|
if nonce != "" {
|
|
scriptSrc += " 'nonce-" + nonce + "'"
|
|
}
|
|
|
|
for _, extra := range scriptSrcExtra {
|
|
if extra != "" {
|
|
scriptSrc += " " + extra
|
|
}
|
|
}
|
|
|
|
if len(formActionExtra) > 0 {
|
|
b := strings.Builder{}
|
|
|
|
for _, extra := range formActionExtra {
|
|
if extra != "" {
|
|
b.WriteByte(' ')
|
|
b.WriteString(extra)
|
|
}
|
|
}
|
|
|
|
formAction += b.String()
|
|
}
|
|
|
|
return "default-src 'self'; " +
|
|
"base-uri 'self'; " +
|
|
"object-src 'none'; " +
|
|
"frame-ancestors 'none'; " +
|
|
"form-action " + formAction + "; " +
|
|
"img-src * blob:;" +
|
|
"font-src 'self'; " +
|
|
"style-src 'self' 'unsafe-inline'; " +
|
|
scriptSrc
|
|
}
|
|
|
|
// GenerateCSPNonce returns a random base64 nonce for use in a CSP header.
|
|
func GenerateCSPNonce() string {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "" // if generation fails, return empty; policy will omit nonce
|
|
}
|
|
return base64.RawURLEncoding.EncodeToString(b)
|
|
}
|