mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-15 21:48:13 +03:00
feat: add support for CIDR and IP address lists in TRUST_PROXY
This commit is contained in:
@@ -68,7 +68,10 @@ func initEngine() (*gin.Engine, error) {
|
||||
|
||||
r := gin.New()
|
||||
initLogger(r)
|
||||
configureEngine(r)
|
||||
err := configureEngine(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registerGlobalMiddleware(r)
|
||||
|
||||
return r, nil
|
||||
@@ -86,9 +89,10 @@ func setGinMode() {
|
||||
}
|
||||
}
|
||||
|
||||
func configureEngine(r *gin.Engine) {
|
||||
if !common.EnvConfig.TrustProxy {
|
||||
_ = r.SetTrustedProxies(nil)
|
||||
func configureEngine(r *gin.Engine) error {
|
||||
err := r.SetTrustedProxies(common.EnvConfig.TrustProxy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to configure trusted proxies: %w", err)
|
||||
}
|
||||
|
||||
if common.EnvConfig.TrustedPlatform != "" {
|
||||
@@ -99,6 +103,8 @@ func configureEngine(r *gin.Engine) {
|
||||
common.Name,
|
||||
otelgin.WithFilter(shouldTraceRequest)),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// shouldTraceRequest reports whether an incoming request should be traced.
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/caarlos0/env/v11"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
|
||||
type AppEnv string
|
||||
type DbProvider string
|
||||
type TrustProxyConfig []string
|
||||
|
||||
const (
|
||||
// TracerName should be passed to otel.Tracer, trace.SpanFromContext when creating custom spans.
|
||||
@@ -42,18 +44,18 @@ type EnvConfigSchema struct {
|
||||
EncryptionKey []byte `env:"ENCRYPTION_KEY" options:"file"`
|
||||
AppURL string `env:"APP_URL" options:"toLower,trimTrailingSlash"`
|
||||
DbProvider DbProvider
|
||||
DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"`
|
||||
TrustProxy bool `env:"TRUST_PROXY"`
|
||||
TrustedPlatform string `env:"TRUSTED_PLATFORM"`
|
||||
AuditLogRetentionDays int `env:"AUDIT_LOG_RETENTION_DAYS"`
|
||||
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
|
||||
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
||||
AllowInsecureCallbackURLs bool `env:"ALLOW_INSECURE_CALLBACK_URLS"`
|
||||
InternalAppURL string `env:"INTERNAL_APP_URL"`
|
||||
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
|
||||
DisableRateLimiting bool `env:"DISABLE_RATE_LIMITING"`
|
||||
VersionCheckDisabled bool `env:"VERSION_CHECK_DISABLED"`
|
||||
StaticApiKey string `env:"STATIC_API_KEY" options:"file"`
|
||||
DbConnectionString string `env:"DB_CONNECTION_STRING" options:"file"`
|
||||
TrustProxy TrustProxyConfig `env:"TRUST_PROXY"`
|
||||
TrustedPlatform string `env:"TRUSTED_PLATFORM"`
|
||||
AuditLogRetentionDays int `env:"AUDIT_LOG_RETENTION_DAYS"`
|
||||
AnalyticsDisabled bool `env:"ANALYTICS_DISABLED"`
|
||||
AllowDowngrade bool `env:"ALLOW_DOWNGRADE"`
|
||||
AllowInsecureCallbackURLs bool `env:"ALLOW_INSECURE_CALLBACK_URLS"`
|
||||
InternalAppURL string `env:"INTERNAL_APP_URL"`
|
||||
UiConfigDisabled bool `env:"UI_CONFIG_DISABLED"`
|
||||
DisableRateLimiting bool `env:"DISABLE_RATE_LIMITING"`
|
||||
VersionCheckDisabled bool `env:"VERSION_CHECK_DISABLED"`
|
||||
StaticApiKey string `env:"STATIC_API_KEY" options:"file"`
|
||||
|
||||
FileBackend string `env:"FILE_BACKEND" options:"toLower"`
|
||||
UploadPath string `env:"UPLOAD_PATH"`
|
||||
@@ -392,3 +394,29 @@ func (a AppEnv) IsProduction() bool {
|
||||
func (a AppEnv) IsTest() bool {
|
||||
return a == AppEnvTest
|
||||
}
|
||||
|
||||
func (config *TrustProxyConfig) UnmarshalText(text []byte) error {
|
||||
value := strings.TrimSpace(string(text))
|
||||
|
||||
// Support boolean values for completely enabling or disabling trust proxy
|
||||
enabled, err := strconv.ParseBool(value)
|
||||
if err == nil {
|
||||
if enabled {
|
||||
*config = TrustProxyConfig{"0.0.0.0/0", "::/0"}
|
||||
} else {
|
||||
*config = nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalize and validate each explicit proxy before the server starts
|
||||
proxies := strings.Split(value, ",")
|
||||
for i, proxy := range proxies {
|
||||
proxy = strings.TrimSpace(proxy)
|
||||
proxies[i] = proxy
|
||||
}
|
||||
|
||||
*config = proxies
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -124,11 +124,33 @@ func TestParseEnvConfig(t *testing.T) {
|
||||
err := parseAndValidateEnvConfig(t)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, EnvConfig.UiConfigDisabled)
|
||||
assert.True(t, EnvConfig.TrustProxy)
|
||||
assert.Equal(t, TrustProxyConfig{"0.0.0.0/0", "::/0"}, EnvConfig.TrustProxy)
|
||||
assert.False(t, EnvConfig.AnalyticsDisabled)
|
||||
assert.False(t, EnvConfig.AllowInsecureCallbackURLs)
|
||||
})
|
||||
|
||||
t.Run("should parse trusted proxy IP addresses and CIDR ranges", func(t *testing.T) {
|
||||
EnvConfig = defaultConfig()
|
||||
t.Setenv("TRUST_PROXY", "10.0.0.0/8, 192.168.1.10, ::1/128")
|
||||
|
||||
err := parseAndValidateEnvConfig(t)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, TrustProxyConfig{"10.0.0.0/8", "192.168.1.10", "::1/128"}, EnvConfig.TrustProxy)
|
||||
})
|
||||
|
||||
t.Run("should disable trusted proxies when set to false", func(t *testing.T) {
|
||||
EnvConfig = defaultConfig()
|
||||
t.Setenv("TRUST_PROXY", "false")
|
||||
|
||||
err := parseAndValidateEnvConfig(t)
|
||||
require.NoError(t, err)
|
||||
assert.Nil(t, EnvConfig.TrustProxy)
|
||||
})
|
||||
|
||||
t.Run("should allow insecure callback URLs by default", func(t *testing.T) {
|
||||
assert.True(t, defaultConfig().AllowInsecureCallbackURLs)
|
||||
})
|
||||
|
||||
t.Run("should default audit log retention days to 90", func(t *testing.T) {
|
||||
EnvConfig = defaultConfig()
|
||||
t.Setenv("DB_PROVIDER", "sqlite")
|
||||
|
||||
Reference in New Issue
Block a user