Adding upstream version 2.52.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
a960158181
commit
6d002e9543
441 changed files with 95392 additions and 0 deletions
154
middleware/helmet/config.go
Normal file
154
middleware/helmet/config.go
Normal 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
|
||||
}
|
94
middleware/helmet/helmet.go
Normal file
94
middleware/helmet/helmet.go
Normal 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()
|
||||
}
|
||||
}
|
201
middleware/helmet/helmet_test.go
Normal file
201
middleware/helmet/helmet_test.go
Normal 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))
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue