1418 lines
56 KiB
Go
1418 lines
56 KiB
Go
// Package config loads process-level gateway configuration from environment
|
|
// variables.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
// shutdownTimeoutEnvVar names the environment variable that controls the
|
|
// maximum time granted to each component shutdown call.
|
|
shutdownTimeoutEnvVar = "GATEWAY_SHUTDOWN_TIMEOUT"
|
|
|
|
// logLevelEnvVar names the environment variable that configures the process
|
|
// log level used by structured JSON logging.
|
|
logLevelEnvVar = "GATEWAY_LOG_LEVEL"
|
|
|
|
// publicHTTPAddrEnvVar names the environment variable that configures the
|
|
// public REST listener address.
|
|
publicHTTPAddrEnvVar = "GATEWAY_PUBLIC_HTTP_ADDR"
|
|
|
|
// publicHTTPReadHeaderTimeoutEnvVar names the environment variable that
|
|
// configures the maximum time allowed to read public REST request headers.
|
|
publicHTTPReadHeaderTimeoutEnvVar = "GATEWAY_PUBLIC_HTTP_READ_HEADER_TIMEOUT"
|
|
|
|
// publicHTTPReadTimeoutEnvVar names the environment variable that configures
|
|
// the maximum time allowed to read the full public REST request.
|
|
publicHTTPReadTimeoutEnvVar = "GATEWAY_PUBLIC_HTTP_READ_TIMEOUT"
|
|
|
|
// publicHTTPIdleTimeoutEnvVar names the environment variable that configures
|
|
// the keep-alive idle timeout for the public REST listener.
|
|
publicHTTPIdleTimeoutEnvVar = "GATEWAY_PUBLIC_HTTP_IDLE_TIMEOUT"
|
|
|
|
// publicAuthUpstreamTimeoutEnvVar names the environment variable that
|
|
// configures the timeout budget used for public auth upstream calls.
|
|
publicAuthUpstreamTimeoutEnvVar = "GATEWAY_PUBLIC_AUTH_UPSTREAM_TIMEOUT"
|
|
|
|
// authServiceBaseURLEnvVar names the environment variable that configures
|
|
// the optional Auth / Session Service public HTTP base URL used by gateway
|
|
// public-auth delegation.
|
|
authServiceBaseURLEnvVar = "GATEWAY_AUTH_SERVICE_BASE_URL"
|
|
|
|
// userServiceBaseURLEnvVar names the environment variable that configures
|
|
// the optional User Service internal HTTP base URL used by authenticated
|
|
// gateway self-service delegation.
|
|
userServiceBaseURLEnvVar = "GATEWAY_USER_SERVICE_BASE_URL"
|
|
|
|
// adminHTTPAddrEnvVar names the environment variable that configures the
|
|
// private admin HTTP listener address. When it is empty, the admin listener
|
|
// remains disabled.
|
|
adminHTTPAddrEnvVar = "GATEWAY_ADMIN_HTTP_ADDR"
|
|
|
|
// adminHTTPReadHeaderTimeoutEnvVar names the environment variable that
|
|
// configures the maximum time allowed to read admin listener request
|
|
// headers.
|
|
adminHTTPReadHeaderTimeoutEnvVar = "GATEWAY_ADMIN_HTTP_READ_HEADER_TIMEOUT"
|
|
|
|
// adminHTTPReadTimeoutEnvVar names the environment variable that configures
|
|
// the maximum time allowed to read one admin listener request.
|
|
adminHTTPReadTimeoutEnvVar = "GATEWAY_ADMIN_HTTP_READ_TIMEOUT"
|
|
|
|
// adminHTTPIdleTimeoutEnvVar names the environment variable that configures
|
|
// the keep-alive idle timeout for the admin listener.
|
|
adminHTTPIdleTimeoutEnvVar = "GATEWAY_ADMIN_HTTP_IDLE_TIMEOUT"
|
|
|
|
// authenticatedGRPCAddrEnvVar names the environment variable that configures
|
|
// the authenticated gRPC listener address.
|
|
authenticatedGRPCAddrEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ADDR"
|
|
|
|
// authenticatedGRPCConnectionTimeoutEnvVar names the environment variable
|
|
// that configures the inbound connection handshake timeout for the
|
|
// authenticated gRPC listener.
|
|
authenticatedGRPCConnectionTimeoutEnvVar = "GATEWAY_AUTHENTICATED_GRPC_CONNECTION_TIMEOUT"
|
|
|
|
// authenticatedGRPCDownstreamTimeoutEnvVar names the environment variable
|
|
// that configures the timeout budget used for downstream unary execution.
|
|
authenticatedGRPCDownstreamTimeoutEnvVar = "GATEWAY_AUTHENTICATED_DOWNSTREAM_TIMEOUT"
|
|
|
|
// authenticatedGRPCFreshnessWindowEnvVar names the environment variable that
|
|
// configures the accepted client timestamp skew window for authenticated
|
|
// gRPC requests.
|
|
authenticatedGRPCFreshnessWindowEnvVar = "GATEWAY_AUTHENTICATED_GRPC_FRESHNESS_WINDOW"
|
|
|
|
// authenticatedGRPCIPRateLimitRequestsEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-IP request budget per
|
|
// window.
|
|
authenticatedGRPCIPRateLimitRequestsEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_REQUESTS"
|
|
|
|
// authenticatedGRPCIPRateLimitWindowEnvVar names the environment variable
|
|
// that configures the authenticated gRPC per-IP rate-limit window.
|
|
authenticatedGRPCIPRateLimitWindowEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_WINDOW"
|
|
|
|
// authenticatedGRPCIPRateLimitBurstEnvVar names the environment variable
|
|
// that configures the authenticated gRPC per-IP rate-limit burst.
|
|
authenticatedGRPCIPRateLimitBurstEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_IP_RATE_LIMIT_BURST"
|
|
|
|
// authenticatedGRPCSessionRateLimitRequestsEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-session request
|
|
// budget per window.
|
|
authenticatedGRPCSessionRateLimitRequestsEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_REQUESTS"
|
|
|
|
// authenticatedGRPCSessionRateLimitWindowEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-session rate-limit
|
|
// window.
|
|
authenticatedGRPCSessionRateLimitWindowEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_WINDOW"
|
|
|
|
// authenticatedGRPCSessionRateLimitBurstEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-session rate-limit
|
|
// burst.
|
|
authenticatedGRPCSessionRateLimitBurstEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_SESSION_RATE_LIMIT_BURST"
|
|
|
|
// authenticatedGRPCUserRateLimitRequestsEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-user request budget
|
|
// per window.
|
|
authenticatedGRPCUserRateLimitRequestsEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_REQUESTS"
|
|
|
|
// authenticatedGRPCUserRateLimitWindowEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-user rate-limit
|
|
// window.
|
|
authenticatedGRPCUserRateLimitWindowEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_WINDOW"
|
|
|
|
// authenticatedGRPCUserRateLimitBurstEnvVar names the environment variable
|
|
// that configures the authenticated gRPC per-user rate-limit burst.
|
|
authenticatedGRPCUserRateLimitBurstEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_USER_RATE_LIMIT_BURST"
|
|
|
|
// authenticatedGRPCMessageClassRateLimitRequestsEnvVar names the
|
|
// environment variable that configures the authenticated gRPC per-message
|
|
// class request budget per window.
|
|
authenticatedGRPCMessageClassRateLimitRequestsEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_REQUESTS"
|
|
|
|
// authenticatedGRPCMessageClassRateLimitWindowEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-message-class
|
|
// rate-limit window.
|
|
authenticatedGRPCMessageClassRateLimitWindowEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_WINDOW"
|
|
|
|
// authenticatedGRPCMessageClassRateLimitBurstEnvVar names the environment
|
|
// variable that configures the authenticated gRPC per-message-class
|
|
// rate-limit burst.
|
|
authenticatedGRPCMessageClassRateLimitBurstEnvVar = "GATEWAY_AUTHENTICATED_GRPC_ANTI_ABUSE_MESSAGE_CLASS_RATE_LIMIT_BURST"
|
|
|
|
// sessionCacheRedisAddrEnvVar names the environment variable that configures
|
|
// the Redis address used for SessionCache lookups.
|
|
sessionCacheRedisAddrEnvVar = "GATEWAY_SESSION_CACHE_REDIS_ADDR"
|
|
|
|
// sessionCacheRedisUsernameEnvVar names the environment variable that
|
|
// configures the Redis username used for SessionCache lookups.
|
|
sessionCacheRedisUsernameEnvVar = "GATEWAY_SESSION_CACHE_REDIS_USERNAME"
|
|
|
|
// sessionCacheRedisPasswordEnvVar names the environment variable that
|
|
// configures the Redis password used for SessionCache lookups.
|
|
sessionCacheRedisPasswordEnvVar = "GATEWAY_SESSION_CACHE_REDIS_PASSWORD"
|
|
|
|
// sessionCacheRedisDBEnvVar names the environment variable that configures
|
|
// the Redis logical database used for SessionCache lookups.
|
|
sessionCacheRedisDBEnvVar = "GATEWAY_SESSION_CACHE_REDIS_DB"
|
|
|
|
// sessionCacheRedisKeyPrefixEnvVar names the environment variable that
|
|
// configures the Redis key prefix used for SessionCache records.
|
|
sessionCacheRedisKeyPrefixEnvVar = "GATEWAY_SESSION_CACHE_REDIS_KEY_PREFIX"
|
|
|
|
// sessionCacheRedisLookupTimeoutEnvVar names the environment variable that
|
|
// configures the timeout used for SessionCache Redis lookups and startup
|
|
// connectivity checks.
|
|
sessionCacheRedisLookupTimeoutEnvVar = "GATEWAY_SESSION_CACHE_REDIS_LOOKUP_TIMEOUT"
|
|
|
|
// sessionCacheRedisTLSEnabledEnvVar names the environment variable that
|
|
// configures whether SessionCache Redis connections use TLS.
|
|
sessionCacheRedisTLSEnabledEnvVar = "GATEWAY_SESSION_CACHE_REDIS_TLS_ENABLED"
|
|
|
|
// replayRedisKeyPrefixEnvVar names the environment variable that configures
|
|
// the Redis key prefix used for authenticated replay reservations.
|
|
replayRedisKeyPrefixEnvVar = "GATEWAY_REPLAY_REDIS_KEY_PREFIX"
|
|
|
|
// replayRedisReserveTimeoutEnvVar names the environment variable that
|
|
// configures the timeout used for authenticated replay reservations and
|
|
// startup connectivity checks.
|
|
replayRedisReserveTimeoutEnvVar = "GATEWAY_REPLAY_REDIS_RESERVE_TIMEOUT"
|
|
|
|
// sessionEventsRedisStreamEnvVar names the environment variable that
|
|
// configures the Redis Stream key consumed for session lifecycle updates.
|
|
sessionEventsRedisStreamEnvVar = "GATEWAY_SESSION_EVENTS_REDIS_STREAM"
|
|
|
|
// sessionEventsRedisReadBlockTimeoutEnvVar names the environment variable
|
|
// that configures the blocking read timeout used by the session event
|
|
// subscriber.
|
|
sessionEventsRedisReadBlockTimeoutEnvVar = "GATEWAY_SESSION_EVENTS_REDIS_READ_BLOCK_TIMEOUT"
|
|
|
|
// clientEventsRedisStreamEnvVar names the environment variable that
|
|
// configures the Redis Stream key consumed for client-facing push events.
|
|
clientEventsRedisStreamEnvVar = "GATEWAY_CLIENT_EVENTS_REDIS_STREAM"
|
|
|
|
// clientEventsRedisReadBlockTimeoutEnvVar names the environment variable
|
|
// that configures the blocking read timeout used by the client-event
|
|
// subscriber.
|
|
clientEventsRedisReadBlockTimeoutEnvVar = "GATEWAY_CLIENT_EVENTS_REDIS_READ_BLOCK_TIMEOUT"
|
|
|
|
// responseSignerPrivateKeyPEMPathEnvVar names the environment variable that
|
|
// configures the path to the PKCS#8 PEM-encoded Ed25519 private key used to
|
|
// sign authenticated unary responses and stream events.
|
|
responseSignerPrivateKeyPEMPathEnvVar = "GATEWAY_RESPONSE_SIGNER_PRIVATE_KEY_PEM_PATH"
|
|
|
|
// publicAuthMaxBodyBytesEnvVar names the environment variable that
|
|
// configures the maximum accepted request body size for public_auth.
|
|
publicAuthMaxBodyBytesEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_MAX_BODY_BYTES"
|
|
|
|
// publicAuthRateLimitRequestsEnvVar names the environment variable that
|
|
// configures the public_auth request budget per window.
|
|
publicAuthRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_REQUESTS"
|
|
|
|
// publicAuthRateLimitWindowEnvVar names the environment variable that
|
|
// configures the public_auth rate-limit window.
|
|
publicAuthRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_WINDOW"
|
|
|
|
// publicAuthRateLimitBurstEnvVar names the environment variable that
|
|
// configures the public_auth rate-limit burst.
|
|
publicAuthRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_AUTH_RATE_LIMIT_BURST"
|
|
|
|
// browserBootstrapMaxBodyBytesEnvVar names the environment variable that
|
|
// configures the maximum accepted request body size for browser_bootstrap.
|
|
browserBootstrapMaxBodyBytesEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_BOOTSTRAP_MAX_BODY_BYTES"
|
|
|
|
// browserBootstrapRateLimitRequestsEnvVar names the environment variable
|
|
// that configures the browser_bootstrap request budget per window.
|
|
browserBootstrapRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_BOOTSTRAP_RATE_LIMIT_REQUESTS"
|
|
|
|
// browserBootstrapRateLimitWindowEnvVar names the environment variable that
|
|
// configures the browser_bootstrap rate-limit window.
|
|
browserBootstrapRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_BOOTSTRAP_RATE_LIMIT_WINDOW"
|
|
|
|
// browserBootstrapRateLimitBurstEnvVar names the environment variable that
|
|
// configures the browser_bootstrap rate-limit burst.
|
|
browserBootstrapRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_BOOTSTRAP_RATE_LIMIT_BURST"
|
|
|
|
// browserAssetMaxBodyBytesEnvVar names the environment variable that
|
|
// configures the maximum accepted request body size for browser_asset.
|
|
browserAssetMaxBodyBytesEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_ASSET_MAX_BODY_BYTES"
|
|
|
|
// browserAssetRateLimitRequestsEnvVar names the environment variable that
|
|
// configures the browser_asset request budget per window.
|
|
browserAssetRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_ASSET_RATE_LIMIT_REQUESTS"
|
|
|
|
// browserAssetRateLimitWindowEnvVar names the environment variable that
|
|
// configures the browser_asset rate-limit window.
|
|
browserAssetRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_ASSET_RATE_LIMIT_WINDOW"
|
|
|
|
// browserAssetRateLimitBurstEnvVar names the environment variable that
|
|
// configures the browser_asset rate-limit burst.
|
|
browserAssetRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_BROWSER_ASSET_RATE_LIMIT_BURST"
|
|
|
|
// publicMiscMaxBodyBytesEnvVar names the environment variable that
|
|
// configures the maximum accepted request body size for public_misc.
|
|
publicMiscMaxBodyBytesEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_MAX_BODY_BYTES"
|
|
|
|
// publicMiscRateLimitRequestsEnvVar names the environment variable that
|
|
// configures the public_misc request budget per window.
|
|
publicMiscRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_REQUESTS"
|
|
|
|
// publicMiscRateLimitWindowEnvVar names the environment variable that
|
|
// configures the public_misc rate-limit window.
|
|
publicMiscRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_WINDOW"
|
|
|
|
// publicMiscRateLimitBurstEnvVar names the environment variable that
|
|
// configures the public_misc rate-limit burst.
|
|
publicMiscRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_PUBLIC_MISC_RATE_LIMIT_BURST"
|
|
|
|
// sendEmailCodeIdentityRateLimitRequestsEnvVar names the environment
|
|
// variable that configures the send-email-code identity request budget per
|
|
// window.
|
|
sendEmailCodeIdentityRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS"
|
|
|
|
// sendEmailCodeIdentityRateLimitWindowEnvVar names the environment variable
|
|
// that configures the send-email-code identity rate-limit window.
|
|
sendEmailCodeIdentityRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_WINDOW"
|
|
|
|
// sendEmailCodeIdentityRateLimitBurstEnvVar names the environment variable
|
|
// that configures the send-email-code identity rate-limit burst.
|
|
sendEmailCodeIdentityRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_SEND_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST"
|
|
|
|
// confirmEmailCodeIdentityRateLimitRequestsEnvVar names the environment
|
|
// variable that configures the confirm-email-code identity request budget
|
|
// per window.
|
|
confirmEmailCodeIdentityRateLimitRequestsEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_REQUESTS"
|
|
|
|
// confirmEmailCodeIdentityRateLimitWindowEnvVar names the environment
|
|
// variable that configures the confirm-email-code identity rate-limit
|
|
// window.
|
|
confirmEmailCodeIdentityRateLimitWindowEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_WINDOW"
|
|
|
|
// confirmEmailCodeIdentityRateLimitBurstEnvVar names the environment
|
|
// variable that configures the confirm-email-code identity rate-limit burst.
|
|
confirmEmailCodeIdentityRateLimitBurstEnvVar = "GATEWAY_PUBLIC_HTTP_ANTI_ABUSE_CONFIRM_EMAIL_CODE_IDENTITY_RATE_LIMIT_BURST"
|
|
|
|
// defaultShutdownTimeout is applied when shutdownTimeoutEnvVar is absent.
|
|
defaultShutdownTimeout = 5 * time.Second
|
|
|
|
// defaultLogLevel is applied when logLevelEnvVar is absent.
|
|
defaultLogLevel = "info"
|
|
|
|
// defaultPublicHTTPAddr is applied when publicHTTPAddrEnvVar is absent.
|
|
defaultPublicHTTPAddr = ":8080"
|
|
|
|
defaultPublicHTTPReadHeaderTimeout = 2 * time.Second
|
|
defaultPublicHTTPReadTimeout = 10 * time.Second
|
|
defaultPublicHTTPIdleTimeout = time.Minute
|
|
defaultPublicAuthUpstreamTimeout = 3 * time.Second
|
|
|
|
defaultAdminHTTPReadHeaderTimeout = 2 * time.Second
|
|
defaultAdminHTTPReadTimeout = 10 * time.Second
|
|
defaultAdminHTTPIdleTimeout = time.Minute
|
|
|
|
// defaultAuthenticatedGRPCAddr is applied when
|
|
// authenticatedGRPCAddrEnvVar is absent.
|
|
defaultAuthenticatedGRPCAddr = ":9090"
|
|
|
|
defaultAuthenticatedGRPCConnectionTimeout = 5 * time.Second
|
|
defaultAuthenticatedGRPCDownstreamTimeout = 5 * time.Second
|
|
defaultAuthenticatedGRPCFreshnessWindow = 5 * time.Minute
|
|
|
|
defaultAuthenticatedGRPCIPRateLimitRequests = 120
|
|
defaultAuthenticatedGRPCIPRateLimitBurst = 40
|
|
|
|
defaultAuthenticatedGRPCSessionRateLimitRequests = 60
|
|
defaultAuthenticatedGRPCSessionRateLimitBurst = 20
|
|
|
|
defaultAuthenticatedGRPCUserRateLimitRequests = 120
|
|
defaultAuthenticatedGRPCUserRateLimitBurst = 40
|
|
|
|
defaultAuthenticatedGRPCMessageClassRateLimitRequests = 60
|
|
defaultAuthenticatedGRPCMessageClassRateLimitBurst = 20
|
|
|
|
defaultSessionCacheRedisDB = 0
|
|
defaultSessionCacheRedisKeyPrefix = "gateway:session:"
|
|
defaultSessionCacheRedisLookupTimeout = 250 * time.Millisecond
|
|
|
|
defaultReplayRedisKeyPrefix = "gateway:replay:"
|
|
defaultReplayRedisReserveTimeout = 250 * time.Millisecond
|
|
|
|
defaultSessionEventsRedisReadBlockTimeout = time.Second
|
|
defaultClientEventsRedisReadBlockTimeout = time.Second
|
|
|
|
defaultPublicAuthMaxBodyBytes = int64(8192)
|
|
|
|
defaultPublicAuthRateLimitRequests = 30
|
|
defaultPublicAuthRateLimitBurst = 10
|
|
|
|
defaultBrowserBootstrapRateLimitRequests = 60
|
|
defaultBrowserBootstrapRateLimitBurst = 20
|
|
|
|
defaultBrowserAssetRateLimitRequests = 300
|
|
defaultBrowserAssetRateLimitBurst = 80
|
|
|
|
defaultPublicMiscRateLimitRequests = 30
|
|
defaultPublicMiscRateLimitBurst = 10
|
|
|
|
defaultSendEmailCodeIdentityRateLimitRequests = 3
|
|
defaultSendEmailCodeIdentityRateLimitBurst = 1
|
|
|
|
defaultConfirmEmailCodeIdentityRateLimitRequests = 6
|
|
defaultConfirmEmailCodeIdentityRateLimitBurst = 2
|
|
)
|
|
|
|
var (
|
|
defaultClassRateLimitWindow = time.Minute
|
|
|
|
defaultIdentityRateLimitWindow = 10 * time.Minute
|
|
)
|
|
|
|
// RateLimitConfig describes a single rate-limit budget.
|
|
type RateLimitConfig struct {
|
|
// Requests is the number of accepted requests replenished per Window.
|
|
Requests int
|
|
|
|
// Window is the interval over which Requests are replenished.
|
|
Window time.Duration
|
|
|
|
// Burst is the maximum number of immediately available tokens.
|
|
Burst int
|
|
}
|
|
|
|
// PublicRateLimitConfig identifies the generic rate-limit budget shape used by
|
|
// public REST policy.
|
|
type PublicRateLimitConfig = RateLimitConfig
|
|
|
|
// AuthenticatedRateLimitConfig identifies the generic rate-limit budget shape
|
|
// used by authenticated gRPC policy.
|
|
type AuthenticatedRateLimitConfig = RateLimitConfig
|
|
|
|
// PublicRoutePolicyConfig describes the anti-abuse policy enforced for one
|
|
// stable public REST traffic class.
|
|
type PublicRoutePolicyConfig struct {
|
|
// MaxBodyBytes is the maximum accepted request body size. Zero means that
|
|
// the request must not carry a body.
|
|
MaxBodyBytes int64
|
|
|
|
// RateLimit configures the per-IP budget for the route class.
|
|
RateLimit PublicRateLimitConfig
|
|
}
|
|
|
|
// PublicAuthIdentityPolicyConfig describes the additional identity-based
|
|
// limiter applied to one public auth command.
|
|
type PublicAuthIdentityPolicyConfig struct {
|
|
// RateLimit configures the accepted request budget for one normalized public
|
|
// auth identity key.
|
|
RateLimit PublicRateLimitConfig
|
|
}
|
|
|
|
// PublicHTTPAntiAbuseConfig describes the public REST anti-abuse policy used
|
|
// before route handling.
|
|
type PublicHTTPAntiAbuseConfig struct {
|
|
// PublicAuth applies to the stable public_auth route class.
|
|
PublicAuth PublicRoutePolicyConfig
|
|
|
|
// BrowserBootstrap applies to the stable browser_bootstrap route class.
|
|
BrowserBootstrap PublicRoutePolicyConfig
|
|
|
|
// BrowserAsset applies to the stable browser_asset route class.
|
|
BrowserAsset PublicRoutePolicyConfig
|
|
|
|
// PublicMisc applies to the stable public_misc route class.
|
|
PublicMisc PublicRoutePolicyConfig
|
|
|
|
// SendEmailCodeIdentity applies the additional identity limiter for
|
|
// send-email-code.
|
|
SendEmailCodeIdentity PublicAuthIdentityPolicyConfig
|
|
|
|
// ConfirmEmailCodeIdentity applies the additional identity limiter for
|
|
// confirm-email-code.
|
|
ConfirmEmailCodeIdentity PublicAuthIdentityPolicyConfig
|
|
}
|
|
|
|
// AuthenticatedGRPCAntiAbuseConfig describes the authenticated gRPC
|
|
// rate-limit budgets enforced after request authenticity has been established.
|
|
type AuthenticatedGRPCAntiAbuseConfig struct {
|
|
// IP applies to the transport peer IP derived from the gRPC connection.
|
|
IP AuthenticatedRateLimitConfig
|
|
|
|
// Session applies to the authenticated device_session_id.
|
|
Session AuthenticatedRateLimitConfig
|
|
|
|
// User applies to the authenticated user_id resolved from SessionCache.
|
|
User AuthenticatedRateLimitConfig
|
|
|
|
// MessageClass applies to the current authenticated message class. The
|
|
// gateway uses the full message_type literal as the stable v1 class key.
|
|
MessageClass AuthenticatedRateLimitConfig
|
|
}
|
|
|
|
// PublicHTTPConfig describes the public unauthenticated REST listener exposed
|
|
// by the gateway.
|
|
type PublicHTTPConfig struct {
|
|
// Addr is the TCP listen address used by the public REST server.
|
|
Addr string
|
|
|
|
// ReadHeaderTimeout bounds how long the listener may spend reading request
|
|
// headers before the gateway rejects the connection.
|
|
ReadHeaderTimeout time.Duration
|
|
|
|
// ReadTimeout bounds how long the listener may spend reading one public
|
|
// request.
|
|
ReadTimeout time.Duration
|
|
|
|
// IdleTimeout bounds how long the listener keeps an idle keep-alive
|
|
// connection open.
|
|
IdleTimeout time.Duration
|
|
|
|
// AuthUpstreamTimeout bounds one public auth adapter call.
|
|
AuthUpstreamTimeout time.Duration
|
|
|
|
// AntiAbuse configures the public REST anti-abuse middleware.
|
|
AntiAbuse PublicHTTPAntiAbuseConfig
|
|
}
|
|
|
|
// AuthServiceConfig describes the optional public-auth upstream used by the
|
|
// gateway runtime.
|
|
type AuthServiceConfig struct {
|
|
// BaseURL is the absolute base URL of the Auth / Session Service public
|
|
// HTTP API. When BaseURL is empty, the gateway keeps using its built-in
|
|
// unavailable public-auth adapter.
|
|
BaseURL string
|
|
}
|
|
|
|
// UserServiceConfig describes the optional authenticated self-service upstream
|
|
// used by the gateway runtime.
|
|
type UserServiceConfig struct {
|
|
// BaseURL is the absolute base URL of the User Service internal HTTP API.
|
|
// When BaseURL is empty, the gateway keeps using its built-in unavailable
|
|
// downstream adapter for the reserved `user.*` routes.
|
|
BaseURL string
|
|
}
|
|
|
|
// AdminHTTPConfig describes the private operational HTTP listener used for
|
|
// metrics exposure. The listener remains disabled when Addr is empty.
|
|
type AdminHTTPConfig struct {
|
|
// Addr is the TCP listen address used by the admin HTTP server. An empty
|
|
// value disables the listener.
|
|
Addr string
|
|
|
|
// ReadHeaderTimeout bounds how long the listener may spend reading request
|
|
// headers before the gateway rejects the connection.
|
|
ReadHeaderTimeout time.Duration
|
|
|
|
// ReadTimeout bounds how long the listener may spend reading one admin
|
|
// request.
|
|
ReadTimeout time.Duration
|
|
|
|
// IdleTimeout bounds how long the listener keeps an idle keep-alive
|
|
// connection open.
|
|
IdleTimeout time.Duration
|
|
}
|
|
|
|
// AuthenticatedGRPCConfig describes the authenticated gRPC listener exposed by
|
|
// the gateway.
|
|
type AuthenticatedGRPCConfig struct {
|
|
// Addr is the TCP listen address used by the authenticated gRPC server.
|
|
Addr string
|
|
|
|
// ConnectionTimeout bounds one inbound connection handshake.
|
|
ConnectionTimeout time.Duration
|
|
|
|
// DownstreamTimeout bounds one downstream unary execution after the request
|
|
// has passed the full authenticated ingress pipeline.
|
|
DownstreamTimeout time.Duration
|
|
|
|
// FreshnessWindow is the accepted skew window around current server time
|
|
// used for client request timestamps.
|
|
FreshnessWindow time.Duration
|
|
|
|
// AntiAbuse configures the authenticated gRPC rate limits enforced after
|
|
// the request passes the transport authenticity checks.
|
|
AntiAbuse AuthenticatedGRPCAntiAbuseConfig
|
|
}
|
|
|
|
// SessionCacheRedisConfig describes the Redis connection used for authenticated
|
|
// SessionCache lookups.
|
|
type SessionCacheRedisConfig struct {
|
|
// Addr is the Redis endpoint used for SessionCache requests.
|
|
Addr string
|
|
|
|
// Username is the optional Redis ACL username used for authentication.
|
|
Username string
|
|
|
|
// Password is the optional Redis password used for authentication.
|
|
Password string
|
|
|
|
// DB is the Redis logical database number used for SessionCache keys.
|
|
DB int
|
|
|
|
// KeyPrefix is prepended to every SessionCache Redis key.
|
|
KeyPrefix string
|
|
|
|
// LookupTimeout bounds individual SessionCache Redis operations.
|
|
LookupTimeout time.Duration
|
|
|
|
// TLSEnabled reports whether SessionCache Redis connections should use TLS.
|
|
TLSEnabled bool
|
|
}
|
|
|
|
// ReplayRedisConfig describes the Redis namespace and timeout used for
|
|
// authenticated replay reservations.
|
|
type ReplayRedisConfig struct {
|
|
// KeyPrefix is prepended to every ReplayStore Redis key.
|
|
KeyPrefix string
|
|
|
|
// ReserveTimeout bounds individual ReplayStore Redis operations.
|
|
ReserveTimeout time.Duration
|
|
}
|
|
|
|
// SessionEventsRedisConfig describes the Redis Stream consumed by the gateway
|
|
// to keep the process-local session cache synchronized with session lifecycle
|
|
// updates.
|
|
type SessionEventsRedisConfig struct {
|
|
// Stream is the Redis Stream key carrying full session snapshot events.
|
|
Stream string
|
|
|
|
// ReadBlockTimeout bounds one blocking XREAD call so shutdown remains
|
|
// responsive even when the stream is idle.
|
|
ReadBlockTimeout time.Duration
|
|
}
|
|
|
|
// ClientEventsRedisConfig describes the Redis Stream consumed by the gateway
|
|
// to deliver client-facing events to active push streams.
|
|
type ClientEventsRedisConfig struct {
|
|
// Stream is the Redis Stream key carrying client-facing event entries.
|
|
Stream string
|
|
|
|
// ReadBlockTimeout bounds one blocking XREAD call so shutdown remains
|
|
// responsive even when the stream is idle.
|
|
ReadBlockTimeout time.Duration
|
|
}
|
|
|
|
// ResponseSignerConfig describes the private-key material used to sign
|
|
// authenticated unary responses and stream events.
|
|
type ResponseSignerConfig struct {
|
|
// PrivateKeyPEMPath is the filesystem path to the PKCS#8 PEM-encoded
|
|
// Ed25519 private key loaded during startup.
|
|
PrivateKeyPEMPath string
|
|
}
|
|
|
|
// LoggingConfig describes the process-wide structured logging settings.
|
|
type LoggingConfig struct {
|
|
// Level is the configured minimum log level literal.
|
|
Level string
|
|
}
|
|
|
|
// Config describes process-wide settings required to start and stop the
|
|
// gateway safely.
|
|
type Config struct {
|
|
// ShutdownTimeout limits how long each component may spend in Shutdown
|
|
// before the gateway reports a timeout.
|
|
ShutdownTimeout time.Duration
|
|
|
|
// Logging configures the process-wide structured logger.
|
|
Logging LoggingConfig
|
|
|
|
// PublicHTTP configures the public unauthenticated REST listener.
|
|
PublicHTTP PublicHTTPConfig
|
|
|
|
// AuthService configures the optional public-auth delegation to the Auth /
|
|
// Session Service.
|
|
AuthService AuthServiceConfig
|
|
|
|
// UserService configures the optional authenticated self-service
|
|
// delegation to User Service.
|
|
UserService UserServiceConfig
|
|
|
|
// AdminHTTP configures the optional private admin listener used for metrics
|
|
// exposure.
|
|
AdminHTTP AdminHTTPConfig
|
|
|
|
// AuthenticatedGRPC configures the authenticated gRPC listener.
|
|
AuthenticatedGRPC AuthenticatedGRPCConfig
|
|
|
|
// SessionCacheRedis configures the Redis-backed authenticated SessionCache.
|
|
SessionCacheRedis SessionCacheRedisConfig
|
|
|
|
// ReplayRedis configures the Redis-backed authenticated ReplayStore.
|
|
ReplayRedis ReplayRedisConfig
|
|
|
|
// SessionEventsRedis configures the Redis Stream consumed for session cache
|
|
// updates and revocations.
|
|
SessionEventsRedis SessionEventsRedisConfig
|
|
|
|
// ClientEventsRedis configures the Redis Stream consumed for client-facing
|
|
// push delivery.
|
|
ClientEventsRedis ClientEventsRedisConfig
|
|
|
|
// ResponseSigner configures the authenticated response and event signer
|
|
// loaded during startup.
|
|
ResponseSigner ResponseSignerConfig
|
|
}
|
|
|
|
// DefaultPublicHTTPConfig returns the default listener and anti-abuse settings
|
|
// for the public REST surface.
|
|
func DefaultPublicHTTPConfig() PublicHTTPConfig {
|
|
return PublicHTTPConfig{
|
|
Addr: defaultPublicHTTPAddr,
|
|
ReadHeaderTimeout: defaultPublicHTTPReadHeaderTimeout,
|
|
ReadTimeout: defaultPublicHTTPReadTimeout,
|
|
IdleTimeout: defaultPublicHTTPIdleTimeout,
|
|
AuthUpstreamTimeout: defaultPublicAuthUpstreamTimeout,
|
|
AntiAbuse: PublicHTTPAntiAbuseConfig{
|
|
PublicAuth: PublicRoutePolicyConfig{
|
|
MaxBodyBytes: defaultPublicAuthMaxBodyBytes,
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultPublicAuthRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultPublicAuthRateLimitBurst,
|
|
},
|
|
},
|
|
BrowserBootstrap: PublicRoutePolicyConfig{
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultBrowserBootstrapRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultBrowserBootstrapRateLimitBurst,
|
|
},
|
|
},
|
|
BrowserAsset: PublicRoutePolicyConfig{
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultBrowserAssetRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultBrowserAssetRateLimitBurst,
|
|
},
|
|
},
|
|
PublicMisc: PublicRoutePolicyConfig{
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultPublicMiscRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultPublicMiscRateLimitBurst,
|
|
},
|
|
},
|
|
SendEmailCodeIdentity: PublicAuthIdentityPolicyConfig{
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultSendEmailCodeIdentityRateLimitRequests,
|
|
Window: defaultIdentityRateLimitWindow,
|
|
Burst: defaultSendEmailCodeIdentityRateLimitBurst,
|
|
},
|
|
},
|
|
ConfirmEmailCodeIdentity: PublicAuthIdentityPolicyConfig{
|
|
RateLimit: PublicRateLimitConfig{
|
|
Requests: defaultConfirmEmailCodeIdentityRateLimitRequests,
|
|
Window: defaultIdentityRateLimitWindow,
|
|
Burst: defaultConfirmEmailCodeIdentityRateLimitBurst,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// DefaultAdminHTTPConfig returns the default settings for the optional private
|
|
// admin listener. The zero address keeps the listener disabled by default.
|
|
func DefaultAdminHTTPConfig() AdminHTTPConfig {
|
|
return AdminHTTPConfig{
|
|
ReadHeaderTimeout: defaultAdminHTTPReadHeaderTimeout,
|
|
ReadTimeout: defaultAdminHTTPReadTimeout,
|
|
IdleTimeout: defaultAdminHTTPIdleTimeout,
|
|
}
|
|
}
|
|
|
|
// DefaultAuthenticatedGRPCConfig returns the default listener, freshness, and
|
|
// anti-abuse settings for the authenticated gRPC surface.
|
|
func DefaultAuthenticatedGRPCConfig() AuthenticatedGRPCConfig {
|
|
return AuthenticatedGRPCConfig{
|
|
Addr: defaultAuthenticatedGRPCAddr,
|
|
ConnectionTimeout: defaultAuthenticatedGRPCConnectionTimeout,
|
|
DownstreamTimeout: defaultAuthenticatedGRPCDownstreamTimeout,
|
|
FreshnessWindow: defaultAuthenticatedGRPCFreshnessWindow,
|
|
AntiAbuse: AuthenticatedGRPCAntiAbuseConfig{
|
|
IP: AuthenticatedRateLimitConfig{
|
|
Requests: defaultAuthenticatedGRPCIPRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultAuthenticatedGRPCIPRateLimitBurst,
|
|
},
|
|
Session: AuthenticatedRateLimitConfig{
|
|
Requests: defaultAuthenticatedGRPCSessionRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultAuthenticatedGRPCSessionRateLimitBurst,
|
|
},
|
|
User: AuthenticatedRateLimitConfig{
|
|
Requests: defaultAuthenticatedGRPCUserRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultAuthenticatedGRPCUserRateLimitBurst,
|
|
},
|
|
MessageClass: AuthenticatedRateLimitConfig{
|
|
Requests: defaultAuthenticatedGRPCMessageClassRateLimitRequests,
|
|
Window: defaultClassRateLimitWindow,
|
|
Burst: defaultAuthenticatedGRPCMessageClassRateLimitBurst,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// DefaultLoggingConfig returns the default structured logging settings.
|
|
func DefaultLoggingConfig() LoggingConfig {
|
|
return LoggingConfig{Level: defaultLogLevel}
|
|
}
|
|
|
|
// DefaultSessionCacheRedisConfig returns the default optional settings for the
|
|
// Redis-backed authenticated SessionCache. Addr remains empty and must be
|
|
// supplied explicitly.
|
|
func DefaultSessionCacheRedisConfig() SessionCacheRedisConfig {
|
|
return SessionCacheRedisConfig{
|
|
DB: defaultSessionCacheRedisDB,
|
|
KeyPrefix: defaultSessionCacheRedisKeyPrefix,
|
|
LookupTimeout: defaultSessionCacheRedisLookupTimeout,
|
|
}
|
|
}
|
|
|
|
// DefaultReplayRedisConfig returns the default Redis key namespace and timeout
|
|
// used for authenticated replay reservations.
|
|
func DefaultReplayRedisConfig() ReplayRedisConfig {
|
|
return ReplayRedisConfig{
|
|
KeyPrefix: defaultReplayRedisKeyPrefix,
|
|
ReserveTimeout: defaultReplayRedisReserveTimeout,
|
|
}
|
|
}
|
|
|
|
// DefaultSessionEventsRedisConfig returns the default optional settings for the
|
|
// session lifecycle event subscriber. Stream remains empty and must be
|
|
// supplied explicitly.
|
|
func DefaultSessionEventsRedisConfig() SessionEventsRedisConfig {
|
|
return SessionEventsRedisConfig{
|
|
ReadBlockTimeout: defaultSessionEventsRedisReadBlockTimeout,
|
|
}
|
|
}
|
|
|
|
// DefaultClientEventsRedisConfig returns the default optional settings for the
|
|
// client-facing event subscriber. Stream remains empty and must be supplied
|
|
// explicitly.
|
|
func DefaultClientEventsRedisConfig() ClientEventsRedisConfig {
|
|
return ClientEventsRedisConfig{
|
|
ReadBlockTimeout: defaultClientEventsRedisReadBlockTimeout,
|
|
}
|
|
}
|
|
|
|
// DefaultResponseSignerConfig returns the default response-signer settings.
|
|
// The private key path remains empty and must be supplied explicitly.
|
|
func DefaultResponseSignerConfig() ResponseSignerConfig {
|
|
return ResponseSignerConfig{}
|
|
}
|
|
|
|
// DefaultAuthServiceConfig returns the default public-auth upstream settings.
|
|
// The zero value keeps the built-in unavailable adapter active.
|
|
func DefaultAuthServiceConfig() AuthServiceConfig {
|
|
return AuthServiceConfig{}
|
|
}
|
|
|
|
// DefaultUserServiceConfig returns the default authenticated self-service
|
|
// upstream settings. The zero value keeps the built-in unavailable adapter
|
|
// active for reserved `user.*` routes.
|
|
func DefaultUserServiceConfig() UserServiceConfig {
|
|
return UserServiceConfig{}
|
|
}
|
|
|
|
// LoadFromEnv loads Config from the process environment, applies defaults for
|
|
// omitted settings, and validates the resulting values.
|
|
func LoadFromEnv() (Config, error) {
|
|
cfg := Config{
|
|
ShutdownTimeout: defaultShutdownTimeout,
|
|
Logging: DefaultLoggingConfig(),
|
|
PublicHTTP: DefaultPublicHTTPConfig(),
|
|
AuthService: DefaultAuthServiceConfig(),
|
|
UserService: DefaultUserServiceConfig(),
|
|
AdminHTTP: DefaultAdminHTTPConfig(),
|
|
AuthenticatedGRPC: DefaultAuthenticatedGRPCConfig(),
|
|
SessionCacheRedis: DefaultSessionCacheRedisConfig(),
|
|
ReplayRedis: DefaultReplayRedisConfig(),
|
|
SessionEventsRedis: DefaultSessionEventsRedisConfig(),
|
|
ClientEventsRedis: DefaultClientEventsRedisConfig(),
|
|
ResponseSigner: DefaultResponseSignerConfig(),
|
|
}
|
|
|
|
rawShutdownTimeout, ok := os.LookupEnv(shutdownTimeoutEnvVar)
|
|
if ok {
|
|
shutdownTimeout, err := time.ParseDuration(rawShutdownTimeout)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", shutdownTimeoutEnvVar, err)
|
|
}
|
|
cfg.ShutdownTimeout = shutdownTimeout
|
|
}
|
|
|
|
rawLogLevel, ok := os.LookupEnv(logLevelEnvVar)
|
|
if ok {
|
|
cfg.Logging.Level = rawLogLevel
|
|
}
|
|
|
|
rawPublicHTTPAddr, ok := os.LookupEnv(publicHTTPAddrEnvVar)
|
|
if ok {
|
|
cfg.PublicHTTP.Addr = rawPublicHTTPAddr
|
|
}
|
|
|
|
publicHTTPReadHeaderTimeout, err := loadDurationEnvWithDefault(publicHTTPReadHeaderTimeoutEnvVar, cfg.PublicHTTP.ReadHeaderTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.ReadHeaderTimeout = publicHTTPReadHeaderTimeout
|
|
|
|
publicHTTPReadTimeout, err := loadDurationEnvWithDefault(publicHTTPReadTimeoutEnvVar, cfg.PublicHTTP.ReadTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.ReadTimeout = publicHTTPReadTimeout
|
|
|
|
publicHTTPIdleTimeout, err := loadDurationEnvWithDefault(publicHTTPIdleTimeoutEnvVar, cfg.PublicHTTP.IdleTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.IdleTimeout = publicHTTPIdleTimeout
|
|
|
|
publicAuthUpstreamTimeout, err := loadDurationEnvWithDefault(publicAuthUpstreamTimeoutEnvVar, cfg.PublicHTTP.AuthUpstreamTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AuthUpstreamTimeout = publicAuthUpstreamTimeout
|
|
|
|
rawAuthServiceBaseURL, ok := os.LookupEnv(authServiceBaseURLEnvVar)
|
|
if ok {
|
|
cfg.AuthService.BaseURL = rawAuthServiceBaseURL
|
|
}
|
|
|
|
rawUserServiceBaseURL, ok := os.LookupEnv(userServiceBaseURLEnvVar)
|
|
if ok {
|
|
cfg.UserService.BaseURL = rawUserServiceBaseURL
|
|
}
|
|
|
|
rawAdminHTTPAddr, ok := os.LookupEnv(adminHTTPAddrEnvVar)
|
|
if ok {
|
|
cfg.AdminHTTP.Addr = rawAdminHTTPAddr
|
|
}
|
|
|
|
adminHTTPReadHeaderTimeout, err := loadDurationEnvWithDefault(adminHTTPReadHeaderTimeoutEnvVar, cfg.AdminHTTP.ReadHeaderTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AdminHTTP.ReadHeaderTimeout = adminHTTPReadHeaderTimeout
|
|
|
|
adminHTTPReadTimeout, err := loadDurationEnvWithDefault(adminHTTPReadTimeoutEnvVar, cfg.AdminHTTP.ReadTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AdminHTTP.ReadTimeout = adminHTTPReadTimeout
|
|
|
|
adminHTTPIdleTimeout, err := loadDurationEnvWithDefault(adminHTTPIdleTimeoutEnvVar, cfg.AdminHTTP.IdleTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AdminHTTP.IdleTimeout = adminHTTPIdleTimeout
|
|
|
|
rawAuthenticatedGRPCAddr, ok := os.LookupEnv(authenticatedGRPCAddrEnvVar)
|
|
if ok {
|
|
cfg.AuthenticatedGRPC.Addr = rawAuthenticatedGRPCAddr
|
|
}
|
|
|
|
authenticatedGRPCConnectionTimeout, err := loadDurationEnvWithDefault(authenticatedGRPCConnectionTimeoutEnvVar, cfg.AuthenticatedGRPC.ConnectionTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.ConnectionTimeout = authenticatedGRPCConnectionTimeout
|
|
|
|
authenticatedGRPCDownstreamTimeout, err := loadDurationEnvWithDefault(authenticatedGRPCDownstreamTimeoutEnvVar, cfg.AuthenticatedGRPC.DownstreamTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.DownstreamTimeout = authenticatedGRPCDownstreamTimeout
|
|
|
|
authenticatedGRPCFreshnessWindow, err := loadDurationEnvWithDefault(authenticatedGRPCFreshnessWindowEnvVar, cfg.AuthenticatedGRPC.FreshnessWindow)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.FreshnessWindow = authenticatedGRPCFreshnessWindow
|
|
|
|
authenticatedGRPCIPRateLimit, err := loadRateLimitConfigFromEnv(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.IP,
|
|
authenticatedGRPCIPRateLimitRequestsEnvVar,
|
|
authenticatedGRPCIPRateLimitWindowEnvVar,
|
|
authenticatedGRPCIPRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.AntiAbuse.IP = authenticatedGRPCIPRateLimit
|
|
|
|
authenticatedGRPCSessionRateLimit, err := loadRateLimitConfigFromEnv(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.Session,
|
|
authenticatedGRPCSessionRateLimitRequestsEnvVar,
|
|
authenticatedGRPCSessionRateLimitWindowEnvVar,
|
|
authenticatedGRPCSessionRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.AntiAbuse.Session = authenticatedGRPCSessionRateLimit
|
|
|
|
authenticatedGRPCUserRateLimit, err := loadRateLimitConfigFromEnv(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.User,
|
|
authenticatedGRPCUserRateLimitRequestsEnvVar,
|
|
authenticatedGRPCUserRateLimitWindowEnvVar,
|
|
authenticatedGRPCUserRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.AntiAbuse.User = authenticatedGRPCUserRateLimit
|
|
|
|
messageClassRateLimit, err := loadRateLimitConfigFromEnv(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.MessageClass,
|
|
authenticatedGRPCMessageClassRateLimitRequestsEnvVar,
|
|
authenticatedGRPCMessageClassRateLimitWindowEnvVar,
|
|
authenticatedGRPCMessageClassRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.AuthenticatedGRPC.AntiAbuse.MessageClass = messageClassRateLimit
|
|
|
|
rawSessionCacheRedisAddr, ok := os.LookupEnv(sessionCacheRedisAddrEnvVar)
|
|
if ok {
|
|
cfg.SessionCacheRedis.Addr = rawSessionCacheRedisAddr
|
|
}
|
|
|
|
rawSessionCacheRedisUsername, ok := os.LookupEnv(sessionCacheRedisUsernameEnvVar)
|
|
if ok {
|
|
cfg.SessionCacheRedis.Username = rawSessionCacheRedisUsername
|
|
}
|
|
|
|
rawSessionCacheRedisPassword, ok := os.LookupEnv(sessionCacheRedisPasswordEnvVar)
|
|
if ok {
|
|
cfg.SessionCacheRedis.Password = rawSessionCacheRedisPassword
|
|
}
|
|
|
|
sessionCacheRedisDB, err := loadIntEnvWithDefault(sessionCacheRedisDBEnvVar, cfg.SessionCacheRedis.DB)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.SessionCacheRedis.DB = sessionCacheRedisDB
|
|
|
|
rawSessionCacheRedisKeyPrefix, ok := os.LookupEnv(sessionCacheRedisKeyPrefixEnvVar)
|
|
if ok {
|
|
cfg.SessionCacheRedis.KeyPrefix = rawSessionCacheRedisKeyPrefix
|
|
}
|
|
|
|
sessionCacheRedisLookupTimeout, err := loadDurationEnvWithDefault(sessionCacheRedisLookupTimeoutEnvVar, cfg.SessionCacheRedis.LookupTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.SessionCacheRedis.LookupTimeout = sessionCacheRedisLookupTimeout
|
|
|
|
sessionCacheRedisTLSEnabled, err := loadBoolEnvWithDefault(sessionCacheRedisTLSEnabledEnvVar, cfg.SessionCacheRedis.TLSEnabled)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.SessionCacheRedis.TLSEnabled = sessionCacheRedisTLSEnabled
|
|
|
|
rawReplayRedisKeyPrefix, ok := os.LookupEnv(replayRedisKeyPrefixEnvVar)
|
|
if ok {
|
|
cfg.ReplayRedis.KeyPrefix = rawReplayRedisKeyPrefix
|
|
}
|
|
|
|
replayRedisReserveTimeout, err := loadDurationEnvWithDefault(replayRedisReserveTimeoutEnvVar, cfg.ReplayRedis.ReserveTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.ReplayRedis.ReserveTimeout = replayRedisReserveTimeout
|
|
|
|
rawSessionEventsRedisStream, ok := os.LookupEnv(sessionEventsRedisStreamEnvVar)
|
|
if ok {
|
|
cfg.SessionEventsRedis.Stream = rawSessionEventsRedisStream
|
|
}
|
|
|
|
sessionEventsRedisReadBlockTimeout, err := loadDurationEnvWithDefault(sessionEventsRedisReadBlockTimeoutEnvVar, cfg.SessionEventsRedis.ReadBlockTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.SessionEventsRedis.ReadBlockTimeout = sessionEventsRedisReadBlockTimeout
|
|
|
|
rawClientEventsRedisStream, ok := os.LookupEnv(clientEventsRedisStreamEnvVar)
|
|
if ok {
|
|
cfg.ClientEventsRedis.Stream = rawClientEventsRedisStream
|
|
}
|
|
|
|
clientEventsRedisReadBlockTimeout, err := loadDurationEnvWithDefault(clientEventsRedisReadBlockTimeoutEnvVar, cfg.ClientEventsRedis.ReadBlockTimeout)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.ClientEventsRedis.ReadBlockTimeout = clientEventsRedisReadBlockTimeout
|
|
|
|
rawSignerKeyPath, ok := os.LookupEnv(responseSignerPrivateKeyPEMPathEnvVar)
|
|
if ok {
|
|
cfg.ResponseSigner.PrivateKeyPEMPath = rawSignerKeyPath
|
|
}
|
|
|
|
publicAuthPolicy, err := loadPublicRoutePolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.PublicAuth,
|
|
publicAuthMaxBodyBytesEnvVar,
|
|
publicAuthRateLimitRequestsEnvVar,
|
|
publicAuthRateLimitWindowEnvVar,
|
|
publicAuthRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.PublicAuth = publicAuthPolicy
|
|
|
|
browserBootstrapPolicy, err := loadPublicRoutePolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.BrowserBootstrap,
|
|
browserBootstrapMaxBodyBytesEnvVar,
|
|
browserBootstrapRateLimitRequestsEnvVar,
|
|
browserBootstrapRateLimitWindowEnvVar,
|
|
browserBootstrapRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.BrowserBootstrap = browserBootstrapPolicy
|
|
|
|
browserAssetPolicy, err := loadPublicRoutePolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.BrowserAsset,
|
|
browserAssetMaxBodyBytesEnvVar,
|
|
browserAssetRateLimitRequestsEnvVar,
|
|
browserAssetRateLimitWindowEnvVar,
|
|
browserAssetRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.BrowserAsset = browserAssetPolicy
|
|
|
|
publicMiscPolicy, err := loadPublicRoutePolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.PublicMisc,
|
|
publicMiscMaxBodyBytesEnvVar,
|
|
publicMiscRateLimitRequestsEnvVar,
|
|
publicMiscRateLimitWindowEnvVar,
|
|
publicMiscRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.PublicMisc = publicMiscPolicy
|
|
|
|
sendIdentityPolicy, err := loadPublicAuthIdentityPolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.SendEmailCodeIdentity,
|
|
sendEmailCodeIdentityRateLimitRequestsEnvVar,
|
|
sendEmailCodeIdentityRateLimitWindowEnvVar,
|
|
sendEmailCodeIdentityRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.SendEmailCodeIdentity = sendIdentityPolicy
|
|
|
|
confirmIdentityPolicy, err := loadPublicAuthIdentityPolicyConfigFromEnv(
|
|
cfg.PublicHTTP.AntiAbuse.ConfirmEmailCodeIdentity,
|
|
confirmEmailCodeIdentityRateLimitRequestsEnvVar,
|
|
confirmEmailCodeIdentityRateLimitWindowEnvVar,
|
|
confirmEmailCodeIdentityRateLimitBurstEnvVar,
|
|
)
|
|
if err != nil {
|
|
return Config{}, err
|
|
}
|
|
cfg.PublicHTTP.AntiAbuse.ConfirmEmailCodeIdentity = confirmIdentityPolicy
|
|
|
|
if cfg.ShutdownTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", shutdownTimeoutEnvVar)
|
|
}
|
|
if err := validateLogLevel(cfg.Logging.Level); err != nil {
|
|
return Config{}, fmt.Errorf("load gateway config: %w", err)
|
|
}
|
|
if strings.TrimSpace(cfg.PublicHTTP.Addr) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", publicHTTPAddrEnvVar)
|
|
}
|
|
if cfg.PublicHTTP.ReadHeaderTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", publicHTTPReadHeaderTimeoutEnvVar)
|
|
}
|
|
if cfg.PublicHTTP.ReadTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", publicHTTPReadTimeoutEnvVar)
|
|
}
|
|
if cfg.PublicHTTP.IdleTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", publicHTTPIdleTimeoutEnvVar)
|
|
}
|
|
if cfg.PublicHTTP.AuthUpstreamTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", publicAuthUpstreamTimeoutEnvVar)
|
|
}
|
|
cfg.AuthService.BaseURL = strings.TrimSpace(cfg.AuthService.BaseURL)
|
|
if cfg.AuthService.BaseURL != "" {
|
|
parsedAuthServiceBaseURL, err := url.Parse(cfg.AuthService.BaseURL)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", authServiceBaseURLEnvVar, err)
|
|
}
|
|
if parsedAuthServiceBaseURL.Scheme == "" || parsedAuthServiceBaseURL.Host == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be an absolute URL", authServiceBaseURLEnvVar)
|
|
}
|
|
cfg.AuthService.BaseURL = strings.TrimRight(parsedAuthServiceBaseURL.String(), "/")
|
|
}
|
|
cfg.UserService.BaseURL = strings.TrimSpace(cfg.UserService.BaseURL)
|
|
if cfg.UserService.BaseURL != "" {
|
|
parsedUserServiceBaseURL, err := url.Parse(cfg.UserService.BaseURL)
|
|
if err != nil {
|
|
return Config{}, fmt.Errorf("load gateway config: parse %s: %w", userServiceBaseURLEnvVar, err)
|
|
}
|
|
if parsedUserServiceBaseURL.Scheme == "" || parsedUserServiceBaseURL.Host == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be an absolute URL", userServiceBaseURLEnvVar)
|
|
}
|
|
cfg.UserService.BaseURL = strings.TrimRight(parsedUserServiceBaseURL.String(), "/")
|
|
}
|
|
if addr := strings.TrimSpace(cfg.AdminHTTP.Addr); addr != "" {
|
|
cfg.AdminHTTP.Addr = addr
|
|
}
|
|
if cfg.AdminHTTP.ReadHeaderTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", adminHTTPReadHeaderTimeoutEnvVar)
|
|
}
|
|
if cfg.AdminHTTP.ReadTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", adminHTTPReadTimeoutEnvVar)
|
|
}
|
|
if cfg.AdminHTTP.IdleTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", adminHTTPIdleTimeoutEnvVar)
|
|
}
|
|
if strings.TrimSpace(cfg.AuthenticatedGRPC.Addr) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", authenticatedGRPCAddrEnvVar)
|
|
}
|
|
if cfg.AuthenticatedGRPC.ConnectionTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", authenticatedGRPCConnectionTimeoutEnvVar)
|
|
}
|
|
if cfg.AuthenticatedGRPC.DownstreamTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", authenticatedGRPCDownstreamTimeoutEnvVar)
|
|
}
|
|
if cfg.AuthenticatedGRPC.FreshnessWindow <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", authenticatedGRPCFreshnessWindowEnvVar)
|
|
}
|
|
if err := validateRateLimitConfig(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.IP,
|
|
authenticatedGRPCIPRateLimitRequestsEnvVar,
|
|
authenticatedGRPCIPRateLimitWindowEnvVar,
|
|
authenticatedGRPCIPRateLimitBurstEnvVar,
|
|
); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validateRateLimitConfig(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.Session,
|
|
authenticatedGRPCSessionRateLimitRequestsEnvVar,
|
|
authenticatedGRPCSessionRateLimitWindowEnvVar,
|
|
authenticatedGRPCSessionRateLimitBurstEnvVar,
|
|
); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validateRateLimitConfig(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.User,
|
|
authenticatedGRPCUserRateLimitRequestsEnvVar,
|
|
authenticatedGRPCUserRateLimitWindowEnvVar,
|
|
authenticatedGRPCUserRateLimitBurstEnvVar,
|
|
); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validateRateLimitConfig(
|
|
cfg.AuthenticatedGRPC.AntiAbuse.MessageClass,
|
|
authenticatedGRPCMessageClassRateLimitRequestsEnvVar,
|
|
authenticatedGRPCMessageClassRateLimitWindowEnvVar,
|
|
authenticatedGRPCMessageClassRateLimitBurstEnvVar,
|
|
); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if strings.TrimSpace(cfg.SessionCacheRedis.Addr) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", sessionCacheRedisAddrEnvVar)
|
|
}
|
|
if cfg.SessionCacheRedis.DB < 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be negative", sessionCacheRedisDBEnvVar)
|
|
}
|
|
if cfg.SessionCacheRedis.LookupTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", sessionCacheRedisLookupTimeoutEnvVar)
|
|
}
|
|
if strings.TrimSpace(cfg.ReplayRedis.KeyPrefix) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", replayRedisKeyPrefixEnvVar)
|
|
}
|
|
if cfg.ReplayRedis.ReserveTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", replayRedisReserveTimeoutEnvVar)
|
|
}
|
|
if strings.TrimSpace(cfg.SessionEventsRedis.Stream) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", sessionEventsRedisStreamEnvVar)
|
|
}
|
|
if cfg.SessionEventsRedis.ReadBlockTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", sessionEventsRedisReadBlockTimeoutEnvVar)
|
|
}
|
|
if strings.TrimSpace(cfg.ClientEventsRedis.Stream) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", clientEventsRedisStreamEnvVar)
|
|
}
|
|
if cfg.ClientEventsRedis.ReadBlockTimeout <= 0 {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must be positive", clientEventsRedisReadBlockTimeoutEnvVar)
|
|
}
|
|
if strings.TrimSpace(cfg.ResponseSigner.PrivateKeyPEMPath) == "" {
|
|
return Config{}, fmt.Errorf("load gateway config: %s must not be empty", responseSignerPrivateKeyPEMPathEnvVar)
|
|
}
|
|
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.PublicAuth, publicAuthMaxBodyBytesEnvVar, publicAuthRateLimitRequestsEnvVar, publicAuthRateLimitWindowEnvVar, publicAuthRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.BrowserBootstrap, browserBootstrapMaxBodyBytesEnvVar, browserBootstrapRateLimitRequestsEnvVar, browserBootstrapRateLimitWindowEnvVar, browserBootstrapRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.BrowserAsset, browserAssetMaxBodyBytesEnvVar, browserAssetRateLimitRequestsEnvVar, browserAssetRateLimitWindowEnvVar, browserAssetRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validatePublicRoutePolicyConfig(cfg.PublicHTTP.AntiAbuse.PublicMisc, publicMiscMaxBodyBytesEnvVar, publicMiscRateLimitRequestsEnvVar, publicMiscRateLimitWindowEnvVar, publicMiscRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validatePublicAuthIdentityPolicyConfig(cfg.PublicHTTP.AntiAbuse.SendEmailCodeIdentity, sendEmailCodeIdentityRateLimitRequestsEnvVar, sendEmailCodeIdentityRateLimitWindowEnvVar, sendEmailCodeIdentityRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
if err := validatePublicAuthIdentityPolicyConfig(cfg.PublicHTTP.AntiAbuse.ConfirmEmailCodeIdentity, confirmEmailCodeIdentityRateLimitRequestsEnvVar, confirmEmailCodeIdentityRateLimitWindowEnvVar, confirmEmailCodeIdentityRateLimitBurstEnvVar); err != nil {
|
|
return Config{}, err
|
|
}
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func loadPublicRoutePolicyConfigFromEnv(defaults PublicRoutePolicyConfig, maxBodyEnvVar string, requestsEnvVar string, windowEnvVar string, burstEnvVar string) (PublicRoutePolicyConfig, error) {
|
|
policy := defaults
|
|
|
|
maxBodyBytes, err := loadInt64EnvWithDefault(maxBodyEnvVar, defaults.MaxBodyBytes)
|
|
if err != nil {
|
|
return PublicRoutePolicyConfig{}, err
|
|
}
|
|
policy.MaxBodyBytes = maxBodyBytes
|
|
|
|
rateLimit, err := loadRateLimitConfigFromEnv(defaults.RateLimit, requestsEnvVar, windowEnvVar, burstEnvVar)
|
|
if err != nil {
|
|
return PublicRoutePolicyConfig{}, err
|
|
}
|
|
policy.RateLimit = rateLimit
|
|
|
|
return policy, nil
|
|
}
|
|
|
|
func loadPublicAuthIdentityPolicyConfigFromEnv(defaults PublicAuthIdentityPolicyConfig, requestsEnvVar string, windowEnvVar string, burstEnvVar string) (PublicAuthIdentityPolicyConfig, error) {
|
|
rateLimit, err := loadRateLimitConfigFromEnv(defaults.RateLimit, requestsEnvVar, windowEnvVar, burstEnvVar)
|
|
if err != nil {
|
|
return PublicAuthIdentityPolicyConfig{}, err
|
|
}
|
|
|
|
return PublicAuthIdentityPolicyConfig{RateLimit: rateLimit}, nil
|
|
}
|
|
|
|
func loadRateLimitConfigFromEnv(defaults RateLimitConfig, requestsEnvVar string, windowEnvVar string, burstEnvVar string) (RateLimitConfig, error) {
|
|
cfg := defaults
|
|
|
|
requests, err := loadIntEnvWithDefault(requestsEnvVar, defaults.Requests)
|
|
if err != nil {
|
|
return RateLimitConfig{}, err
|
|
}
|
|
cfg.Requests = requests
|
|
|
|
window, err := loadDurationEnvWithDefault(windowEnvVar, defaults.Window)
|
|
if err != nil {
|
|
return RateLimitConfig{}, err
|
|
}
|
|
cfg.Window = window
|
|
|
|
burst, err := loadIntEnvWithDefault(burstEnvVar, defaults.Burst)
|
|
if err != nil {
|
|
return RateLimitConfig{}, err
|
|
}
|
|
cfg.Burst = burst
|
|
|
|
return cfg, nil
|
|
}
|
|
|
|
func validateLogLevel(level string) error {
|
|
switch strings.ToLower(strings.TrimSpace(level)) {
|
|
case "debug", "info", "warn", "error", "dpanic", "panic", "fatal":
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("%s must be one of debug, info, warn, error, dpanic, panic, fatal", logLevelEnvVar)
|
|
}
|
|
}
|
|
|
|
func loadIntEnvWithDefault(envVar string, fallback int) (int, error) {
|
|
rawValue, ok := os.LookupEnv(envVar)
|
|
if !ok {
|
|
return fallback, nil
|
|
}
|
|
|
|
value, err := strconv.Atoi(rawValue)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("load gateway config: parse %s: %w", envVar, err)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
func loadInt64EnvWithDefault(envVar string, fallback int64) (int64, error) {
|
|
rawValue, ok := os.LookupEnv(envVar)
|
|
if !ok {
|
|
return fallback, nil
|
|
}
|
|
|
|
value, err := strconv.ParseInt(rawValue, 10, 64)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("load gateway config: parse %s: %w", envVar, err)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
func loadDurationEnvWithDefault(envVar string, fallback time.Duration) (time.Duration, error) {
|
|
rawValue, ok := os.LookupEnv(envVar)
|
|
if !ok {
|
|
return fallback, nil
|
|
}
|
|
|
|
value, err := time.ParseDuration(rawValue)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("load gateway config: parse %s: %w", envVar, err)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
func loadBoolEnvWithDefault(envVar string, fallback bool) (bool, error) {
|
|
rawValue, ok := os.LookupEnv(envVar)
|
|
if !ok {
|
|
return fallback, nil
|
|
}
|
|
|
|
value, err := strconv.ParseBool(rawValue)
|
|
if err != nil {
|
|
return false, fmt.Errorf("load gateway config: parse %s: %w", envVar, err)
|
|
}
|
|
|
|
return value, nil
|
|
}
|
|
|
|
func validatePublicRoutePolicyConfig(cfg PublicRoutePolicyConfig, maxBodyEnvVar string, requestsEnvVar string, windowEnvVar string, burstEnvVar string) error {
|
|
if cfg.MaxBodyBytes < 0 {
|
|
return fmt.Errorf("load gateway config: %s must not be negative", maxBodyEnvVar)
|
|
}
|
|
|
|
return validateRateLimitConfig(cfg.RateLimit, requestsEnvVar, windowEnvVar, burstEnvVar)
|
|
}
|
|
|
|
func validatePublicAuthIdentityPolicyConfig(cfg PublicAuthIdentityPolicyConfig, requestsEnvVar string, windowEnvVar string, burstEnvVar string) error {
|
|
return validateRateLimitConfig(cfg.RateLimit, requestsEnvVar, windowEnvVar, burstEnvVar)
|
|
}
|
|
|
|
func validateRateLimitConfig(cfg RateLimitConfig, requestsEnvVar string, windowEnvVar string, burstEnvVar string) error {
|
|
if cfg.Requests <= 0 {
|
|
return fmt.Errorf("load gateway config: %s must be positive", requestsEnvVar)
|
|
}
|
|
if cfg.Window <= 0 {
|
|
return fmt.Errorf("load gateway config: %s must be positive", windowEnvVar)
|
|
}
|
|
if cfg.Burst <= 0 {
|
|
return fmt.Errorf("load gateway config: %s must be positive", burstEnvVar)
|
|
}
|
|
|
|
return nil
|
|
}
|