1
0
Fork 0

Adding upstream version 2.52.6.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-17 06:50:16 +02:00
parent a960158181
commit 6d002e9543
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
441 changed files with 95392 additions and 0 deletions

154
middleware/helmet/config.go Normal file
View file

@ -0,0 +1,154 @@
package helmet
import (
"github.com/gofiber/fiber/v2"
)
// Config defines the config for middleware.
type Config struct {
// Next defines a function to skip middleware.
// Optional. Default: nil
Next func(*fiber.Ctx) bool
// XSSProtection
// Optional. Default value "0".
XSSProtection string
// ContentTypeNosniff
// Optional. Default value "nosniff".
ContentTypeNosniff string
// XFrameOptions
// Optional. Default value "SAMEORIGIN".
// Possible values: "SAMEORIGIN", "DENY", "ALLOW-FROM uri"
XFrameOptions string
// HSTSMaxAge
// Optional. Default value 0.
HSTSMaxAge int
// HSTSExcludeSubdomains
// Optional. Default value false.
HSTSExcludeSubdomains bool
// ContentSecurityPolicy
// Optional. Default value "".
ContentSecurityPolicy string
// CSPReportOnly
// Optional. Default value false.
CSPReportOnly bool
// HSTSPreloadEnabled
// Optional. Default value false.
HSTSPreloadEnabled bool
// ReferrerPolicy
// Optional. Default value "ReferrerPolicy".
ReferrerPolicy string
// Permissions-Policy
// Optional. Default value "".
PermissionPolicy string
// Cross-Origin-Embedder-Policy
// Optional. Default value "require-corp".
CrossOriginEmbedderPolicy string
// Cross-Origin-Opener-Policy
// Optional. Default value "same-origin".
CrossOriginOpenerPolicy string
// Cross-Origin-Resource-Policy
// Optional. Default value "same-origin".
CrossOriginResourcePolicy string
// Origin-Agent-Cluster
// Optional. Default value "?1".
OriginAgentCluster string
// X-DNS-Prefetch-Control
// Optional. Default value "off".
XDNSPrefetchControl string
// X-Download-Options
// Optional. Default value "noopen".
XDownloadOptions string
// X-Permitted-Cross-Domain-Policies
// Optional. Default value "none".
XPermittedCrossDomain string
}
// ConfigDefault is the default config
var ConfigDefault = Config{
XSSProtection: "0",
ContentTypeNosniff: "nosniff",
XFrameOptions: "SAMEORIGIN",
ReferrerPolicy: "no-referrer",
CrossOriginEmbedderPolicy: "require-corp",
CrossOriginOpenerPolicy: "same-origin",
CrossOriginResourcePolicy: "same-origin",
OriginAgentCluster: "?1",
XDNSPrefetchControl: "off",
XDownloadOptions: "noopen",
XPermittedCrossDomain: "none",
}
// Helper function to set default values
func configDefault(config ...Config) Config {
// Return default config if nothing provided
if len(config) < 1 {
return ConfigDefault
}
// Override default config
cfg := config[0]
// Set default values
if cfg.XSSProtection == "" {
cfg.XSSProtection = ConfigDefault.XSSProtection
}
if cfg.ContentTypeNosniff == "" {
cfg.ContentTypeNosniff = ConfigDefault.ContentTypeNosniff
}
if cfg.XFrameOptions == "" {
cfg.XFrameOptions = ConfigDefault.XFrameOptions
}
if cfg.ReferrerPolicy == "" {
cfg.ReferrerPolicy = ConfigDefault.ReferrerPolicy
}
if cfg.CrossOriginEmbedderPolicy == "" {
cfg.CrossOriginEmbedderPolicy = ConfigDefault.CrossOriginEmbedderPolicy
}
if cfg.CrossOriginOpenerPolicy == "" {
cfg.CrossOriginOpenerPolicy = ConfigDefault.CrossOriginOpenerPolicy
}
if cfg.CrossOriginResourcePolicy == "" {
cfg.CrossOriginResourcePolicy = ConfigDefault.CrossOriginResourcePolicy
}
if cfg.OriginAgentCluster == "" {
cfg.OriginAgentCluster = ConfigDefault.OriginAgentCluster
}
if cfg.XDNSPrefetchControl == "" {
cfg.XDNSPrefetchControl = ConfigDefault.XDNSPrefetchControl
}
if cfg.XDownloadOptions == "" {
cfg.XDownloadOptions = ConfigDefault.XDownloadOptions
}
if cfg.XPermittedCrossDomain == "" {
cfg.XPermittedCrossDomain = ConfigDefault.XPermittedCrossDomain
}
return cfg
}

View file

@ -0,0 +1,94 @@
package helmet
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
// New creates a new middleware handler
func New(config ...Config) fiber.Handler {
// Init config
cfg := configDefault(config...)
// Return middleware handler
return func(c *fiber.Ctx) error {
// Next request to skip middleware
if cfg.Next != nil && cfg.Next(c) {
return c.Next()
}
// Set headers
if cfg.XSSProtection != "" {
c.Set(fiber.HeaderXXSSProtection, cfg.XSSProtection)
}
if cfg.ContentTypeNosniff != "" {
c.Set(fiber.HeaderXContentTypeOptions, cfg.ContentTypeNosniff)
}
if cfg.XFrameOptions != "" {
c.Set(fiber.HeaderXFrameOptions, cfg.XFrameOptions)
}
if cfg.CrossOriginEmbedderPolicy != "" {
c.Set("Cross-Origin-Embedder-Policy", cfg.CrossOriginEmbedderPolicy)
}
if cfg.CrossOriginOpenerPolicy != "" {
c.Set("Cross-Origin-Opener-Policy", cfg.CrossOriginOpenerPolicy)
}
if cfg.CrossOriginResourcePolicy != "" {
c.Set("Cross-Origin-Resource-Policy", cfg.CrossOriginResourcePolicy)
}
if cfg.OriginAgentCluster != "" {
c.Set("Origin-Agent-Cluster", cfg.OriginAgentCluster)
}
if cfg.ReferrerPolicy != "" {
c.Set("Referrer-Policy", cfg.ReferrerPolicy)
}
if cfg.XDNSPrefetchControl != "" {
c.Set("X-DNS-Prefetch-Control", cfg.XDNSPrefetchControl)
}
if cfg.XDownloadOptions != "" {
c.Set("X-Download-Options", cfg.XDownloadOptions)
}
if cfg.XPermittedCrossDomain != "" {
c.Set("X-Permitted-Cross-Domain-Policies", cfg.XPermittedCrossDomain)
}
// Handle HSTS headers
if c.Protocol() == "https" && cfg.HSTSMaxAge != 0 {
subdomains := ""
if !cfg.HSTSExcludeSubdomains {
subdomains = "; includeSubDomains"
}
if cfg.HSTSPreloadEnabled {
subdomains = fmt.Sprintf("%s; preload", subdomains)
}
c.Set(fiber.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", cfg.HSTSMaxAge, subdomains))
}
// Handle Content-Security-Policy headers
if cfg.ContentSecurityPolicy != "" {
if cfg.CSPReportOnly {
c.Set(fiber.HeaderContentSecurityPolicyReportOnly, cfg.ContentSecurityPolicy)
} else {
c.Set(fiber.HeaderContentSecurityPolicy, cfg.ContentSecurityPolicy)
}
}
// Handle Permissions-Policy headers
if cfg.PermissionPolicy != "" {
c.Set(fiber.HeaderPermissionsPolicy, cfg.PermissionPolicy)
}
return c.Next()
}
}

View file

@ -0,0 +1,201 @@
package helmet
import (
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/utils"
)
func Test_Default(t *testing.T) {
app := fiber.New()
app.Use(New())
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
utils.AssertEqual(t, "nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
utils.AssertEqual(t, "SAMEORIGIN", resp.Header.Get(fiber.HeaderXFrameOptions))
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderPermissionsPolicy))
utils.AssertEqual(t, "require-corp", resp.Header.Get("Cross-Origin-Embedder-Policy"))
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Opener-Policy"))
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Resource-Policy"))
utils.AssertEqual(t, "?1", resp.Header.Get("Origin-Agent-Cluster"))
utils.AssertEqual(t, "off", resp.Header.Get("X-DNS-Prefetch-Control"))
utils.AssertEqual(t, "noopen", resp.Header.Get("X-Download-Options"))
utils.AssertEqual(t, "none", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
}
func Test_CustomValues_AllHeaders(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
// Custom values for all headers
XSSProtection: "0",
ContentTypeNosniff: "custom-nosniff",
XFrameOptions: "DENY",
HSTSExcludeSubdomains: true,
ContentSecurityPolicy: "default-src 'none'",
CSPReportOnly: true,
HSTSPreloadEnabled: true,
ReferrerPolicy: "origin",
PermissionPolicy: "geolocation=(self)",
CrossOriginEmbedderPolicy: "custom-value",
CrossOriginOpenerPolicy: "custom-value",
CrossOriginResourcePolicy: "custom-value",
OriginAgentCluster: "custom-value",
XDNSPrefetchControl: "custom-control",
XDownloadOptions: "custom-options",
XPermittedCrossDomain: "custom-policies",
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
// Assertions for custom header values
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
utils.AssertEqual(t, "custom-nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
utils.AssertEqual(t, "DENY", resp.Header.Get(fiber.HeaderXFrameOptions))
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicyReportOnly))
utils.AssertEqual(t, "origin", resp.Header.Get(fiber.HeaderReferrerPolicy))
utils.AssertEqual(t, "geolocation=(self)", resp.Header.Get(fiber.HeaderPermissionsPolicy))
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Embedder-Policy"))
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Opener-Policy"))
utils.AssertEqual(t, "custom-value", resp.Header.Get("Cross-Origin-Resource-Policy"))
utils.AssertEqual(t, "custom-value", resp.Header.Get("Origin-Agent-Cluster"))
utils.AssertEqual(t, "custom-control", resp.Header.Get("X-DNS-Prefetch-Control"))
utils.AssertEqual(t, "custom-options", resp.Header.Get("X-Download-Options"))
utils.AssertEqual(t, "custom-policies", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
}
func Test_RealWorldValues_AllHeaders(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
// Real-world values for all headers
XSSProtection: "0",
ContentTypeNosniff: "nosniff",
XFrameOptions: "SAMEORIGIN",
HSTSExcludeSubdomains: false,
ContentSecurityPolicy: "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests",
CSPReportOnly: false,
HSTSPreloadEnabled: true,
ReferrerPolicy: "no-referrer",
PermissionPolicy: "geolocation=(self)",
CrossOriginEmbedderPolicy: "require-corp",
CrossOriginOpenerPolicy: "same-origin",
CrossOriginResourcePolicy: "same-origin",
OriginAgentCluster: "?1",
XDNSPrefetchControl: "off",
XDownloadOptions: "noopen",
XPermittedCrossDomain: "none",
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
// Assertions for real-world header values
utils.AssertEqual(t, "0", resp.Header.Get(fiber.HeaderXXSSProtection))
utils.AssertEqual(t, "nosniff", resp.Header.Get(fiber.HeaderXContentTypeOptions))
utils.AssertEqual(t, "SAMEORIGIN", resp.Header.Get(fiber.HeaderXFrameOptions))
utils.AssertEqual(t, "default-src 'self';base-uri 'self';font-src 'self' https: data:;form-action 'self';frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
utils.AssertEqual(t, "geolocation=(self)", resp.Header.Get(fiber.HeaderPermissionsPolicy))
utils.AssertEqual(t, "require-corp", resp.Header.Get("Cross-Origin-Embedder-Policy"))
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Opener-Policy"))
utils.AssertEqual(t, "same-origin", resp.Header.Get("Cross-Origin-Resource-Policy"))
utils.AssertEqual(t, "?1", resp.Header.Get("Origin-Agent-Cluster"))
utils.AssertEqual(t, "off", resp.Header.Get("X-DNS-Prefetch-Control"))
utils.AssertEqual(t, "noopen", resp.Header.Get("X-Download-Options"))
utils.AssertEqual(t, "none", resp.Header.Get("X-Permitted-Cross-Domain-Policies"))
}
func Test_Next(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
Next: func(ctx *fiber.Ctx) bool {
return ctx.Path() == "/next"
},
ReferrerPolicy: "no-referrer",
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
app.Get("/next", func(c *fiber.Ctx) error {
return c.SendString("Skipped!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "no-referrer", resp.Header.Get(fiber.HeaderReferrerPolicy))
resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/next", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderReferrerPolicy))
}
func Test_ContentSecurityPolicy(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
ContentSecurityPolicy: "default-src 'none'",
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
}
func Test_ContentSecurityPolicyReportOnly(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
ContentSecurityPolicy: "default-src 'none'",
CSPReportOnly: true,
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "default-src 'none'", resp.Header.Get(fiber.HeaderContentSecurityPolicyReportOnly))
utils.AssertEqual(t, "", resp.Header.Get(fiber.HeaderContentSecurityPolicy))
}
func Test_PermissionsPolicy(t *testing.T) {
app := fiber.New()
app.Use(New(Config{
PermissionPolicy: "microphone=()",
}))
app.Get("/", func(c *fiber.Ctx) error {
return c.SendString("Hello, World!")
})
resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "microphone=()", resp.Header.Get(fiber.HeaderPermissionsPolicy))
}