Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
514
cloud/maplepress-backend/config/config.go
Normal file
514
cloud/maplepress-backend/config/config.go
Normal file
|
|
@ -0,0 +1,514 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Config holds all application configuration
|
||||
type Config struct {
|
||||
App AppConfig
|
||||
Server ServerConfig
|
||||
HTTP HTTPConfig
|
||||
Security SecurityConfig
|
||||
Database DatabaseConfig
|
||||
Cache CacheConfig
|
||||
AWS AWSConfig
|
||||
Logger LoggerConfig
|
||||
Mailgun MailgunConfig
|
||||
Meilisearch MeilisearchConfig
|
||||
Scheduler SchedulerConfig
|
||||
RateLimit RateLimitConfig
|
||||
LeaderElection LeaderElectionConfig
|
||||
}
|
||||
|
||||
// AppConfig holds application-level configuration
|
||||
type AppConfig struct {
|
||||
Environment string
|
||||
Version string
|
||||
JWTSecret string
|
||||
GeoLiteDBPath string
|
||||
BannedCountries []string
|
||||
}
|
||||
|
||||
// IsTestMode returns true if the environment is development
|
||||
func (c *AppConfig) IsTestMode() bool {
|
||||
return c.Environment == "development"
|
||||
}
|
||||
|
||||
// ServerConfig holds HTTP server configuration
|
||||
type ServerConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
}
|
||||
|
||||
// HTTPConfig holds HTTP request handling configuration
|
||||
type HTTPConfig struct {
|
||||
MaxRequestBodySize int64 // Maximum request body size in bytes
|
||||
ReadTimeout time.Duration // Maximum duration for reading the entire request
|
||||
WriteTimeout time.Duration // Maximum duration before timing out writes of the response
|
||||
IdleTimeout time.Duration // Maximum amount of time to wait for the next request
|
||||
}
|
||||
|
||||
// SecurityConfig holds security-related configuration
|
||||
type SecurityConfig struct {
|
||||
TrustedProxies []string // CIDR blocks of trusted reverse proxies for X-Forwarded-For validation
|
||||
IPEncryptionKey string // 32-character hex key (16 bytes) for IP address encryption (GDPR compliance)
|
||||
AllowedOrigins []string // CORS allowed origins (e.g., https://getmaplepress.com)
|
||||
}
|
||||
|
||||
// DatabaseConfig holds Cassandra database configuration
|
||||
type DatabaseConfig struct {
|
||||
Hosts []string
|
||||
Keyspace string
|
||||
Consistency string
|
||||
Replication int
|
||||
MigrationsPath string
|
||||
}
|
||||
|
||||
// CacheConfig holds Redis cache configuration
|
||||
type CacheConfig struct {
|
||||
Host string
|
||||
Port int
|
||||
Password string
|
||||
DB int
|
||||
}
|
||||
|
||||
// AWSConfig holds AWS S3 configuration
|
||||
type AWSConfig struct {
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
Endpoint string
|
||||
Region string
|
||||
BucketName string
|
||||
}
|
||||
|
||||
// LoggerConfig holds logging configuration
|
||||
type LoggerConfig struct {
|
||||
Level string
|
||||
Format string
|
||||
}
|
||||
|
||||
// MailgunConfig holds Mailgun email service configuration
|
||||
type MailgunConfig struct {
|
||||
APIKey string
|
||||
Domain string
|
||||
APIBase string
|
||||
SenderEmail string
|
||||
MaintenanceEmail string
|
||||
FrontendDomain string
|
||||
BackendDomain string
|
||||
}
|
||||
|
||||
// MeilisearchConfig holds Meilisearch configuration
|
||||
type MeilisearchConfig struct {
|
||||
Host string
|
||||
APIKey string
|
||||
IndexPrefix string
|
||||
}
|
||||
|
||||
// SchedulerConfig holds scheduler configuration
|
||||
type SchedulerConfig struct {
|
||||
QuotaResetEnabled bool
|
||||
QuotaResetSchedule string // Cron format: "0 0 1 * *" = first day of month at midnight
|
||||
IPCleanupEnabled bool
|
||||
IPCleanupSchedule string // Cron format: "0 2 * * *" = daily at 2 AM
|
||||
}
|
||||
|
||||
// RateLimitConfig holds rate limiting configuration
|
||||
type RateLimitConfig struct {
|
||||
// Registration endpoint rate limiting
|
||||
// CWE-307: Prevents automated account creation and bot signups
|
||||
RegistrationEnabled bool
|
||||
RegistrationMaxRequests int
|
||||
RegistrationWindow time.Duration
|
||||
|
||||
// Login endpoint rate limiting
|
||||
// CWE-307: Dual protection (IP-based + account lockout) against brute force attacks
|
||||
LoginEnabled bool
|
||||
LoginMaxAttemptsPerIP int
|
||||
LoginIPWindow time.Duration
|
||||
LoginMaxFailedAttemptsPerAccount int
|
||||
LoginAccountLockoutDuration time.Duration
|
||||
|
||||
// Generic CRUD endpoints rate limiting
|
||||
// CWE-770: Protects authenticated endpoints (tenant/user/site management) from resource exhaustion
|
||||
GenericEnabled bool
|
||||
GenericMaxRequests int
|
||||
GenericWindow time.Duration
|
||||
|
||||
// Plugin API endpoints rate limiting
|
||||
// CWE-770: Lenient limits for core business endpoints (WordPress plugin integration)
|
||||
PluginAPIEnabled bool
|
||||
PluginAPIMaxRequests int
|
||||
PluginAPIWindow time.Duration
|
||||
}
|
||||
|
||||
// LeaderElectionConfig holds leader election configuration
|
||||
type LeaderElectionConfig struct {
|
||||
Enabled bool
|
||||
LockTTL time.Duration
|
||||
HeartbeatInterval time.Duration
|
||||
RetryInterval time.Duration
|
||||
}
|
||||
|
||||
// Load loads configuration from environment variables
|
||||
func Load() (*Config, error) {
|
||||
cfg := &Config{
|
||||
App: AppConfig{
|
||||
Environment: getEnv("APP_ENVIRONMENT", "development"),
|
||||
Version: getEnv("APP_VERSION", "0.1.0"),
|
||||
JWTSecret: getEnv("APP_JWT_SECRET", "change-me-in-production"),
|
||||
GeoLiteDBPath: getEnv("APP_GEOLITE_DB_PATH", ""),
|
||||
BannedCountries: getEnvAsSlice("APP_BANNED_COUNTRIES", []string{}),
|
||||
},
|
||||
Server: ServerConfig{
|
||||
Host: getEnv("SERVER_HOST", "0.0.0.0"),
|
||||
Port: getEnvAsInt("SERVER_PORT", 8000),
|
||||
},
|
||||
HTTP: HTTPConfig{
|
||||
MaxRequestBodySize: getEnvAsInt64("HTTP_MAX_REQUEST_BODY_SIZE", 10*1024*1024), // 10 MB default
|
||||
ReadTimeout: getEnvAsDuration("HTTP_READ_TIMEOUT", 30*time.Second),
|
||||
WriteTimeout: getEnvAsDuration("HTTP_WRITE_TIMEOUT", 30*time.Second),
|
||||
IdleTimeout: getEnvAsDuration("HTTP_IDLE_TIMEOUT", 60*time.Second),
|
||||
},
|
||||
Security: SecurityConfig{
|
||||
// CWE-348: Trusted proxies for X-Forwarded-For validation
|
||||
// Example: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" for private networks
|
||||
// Leave empty to disable X-Forwarded-For trust (most secure for direct connections)
|
||||
TrustedProxies: getEnvAsSlice("SECURITY_TRUSTED_PROXIES", []string{}),
|
||||
// CWE-359: IP encryption key for GDPR compliance
|
||||
// Must be 32 hex characters (16 bytes). Generate with: openssl rand -hex 16
|
||||
IPEncryptionKey: getEnv("SECURITY_IP_ENCRYPTION_KEY", "00112233445566778899aabbccddeeff"),
|
||||
// CORS allowed origins (comma-separated)
|
||||
// Example: "https://getmaplepress.com,https://www.getmaplepress.com"
|
||||
// In development, localhost origins are automatically added
|
||||
AllowedOrigins: getEnvAsSlice("SECURITY_CORS_ALLOWED_ORIGINS", []string{}),
|
||||
},
|
||||
Database: DatabaseConfig{
|
||||
Hosts: getEnvAsSlice("DATABASE_HOSTS", []string{"localhost"}),
|
||||
Keyspace: getEnv("DATABASE_KEYSPACE", "maplepress"),
|
||||
Consistency: getEnv("DATABASE_CONSISTENCY", "QUORUM"),
|
||||
Replication: getEnvAsInt("DATABASE_REPLICATION", 3),
|
||||
MigrationsPath: getEnv("DATABASE_MIGRATIONS_PATH", "file://migrations"),
|
||||
},
|
||||
Cache: CacheConfig{
|
||||
Host: getEnv("CACHE_HOST", "localhost"),
|
||||
Port: getEnvAsInt("CACHE_PORT", 6379),
|
||||
Password: getEnv("CACHE_PASSWORD", ""),
|
||||
DB: getEnvAsInt("CACHE_DB", 0),
|
||||
},
|
||||
AWS: AWSConfig{
|
||||
AccessKey: getEnv("AWS_ACCESS_KEY", ""),
|
||||
SecretKey: getEnv("AWS_SECRET_KEY", ""),
|
||||
Endpoint: getEnv("AWS_ENDPOINT", ""),
|
||||
Region: getEnv("AWS_REGION", "us-east-1"),
|
||||
BucketName: getEnv("AWS_BUCKET_NAME", ""),
|
||||
},
|
||||
Logger: LoggerConfig{
|
||||
Level: getEnv("LOGGER_LEVEL", "info"),
|
||||
Format: getEnv("LOGGER_FORMAT", "json"),
|
||||
},
|
||||
Mailgun: MailgunConfig{
|
||||
APIKey: getEnv("MAILGUN_API_KEY", ""),
|
||||
Domain: getEnv("MAILGUN_DOMAIN", ""),
|
||||
APIBase: getEnv("MAILGUN_API_BASE", "https://api.mailgun.net/v3"),
|
||||
SenderEmail: getEnv("MAILGUN_SENDER_EMAIL", "noreply@maplepress.app"),
|
||||
MaintenanceEmail: getEnv("MAILGUN_MAINTENANCE_EMAIL", "admin@maplepress.app"),
|
||||
FrontendDomain: getEnv("MAILGUN_FRONTEND_DOMAIN", "https://maplepress.app"),
|
||||
BackendDomain: getEnv("MAILGUN_BACKEND_DOMAIN", "https://api.maplepress.app"),
|
||||
},
|
||||
Meilisearch: MeilisearchConfig{
|
||||
Host: getEnv("MEILISEARCH_HOST", "http://localhost:7700"),
|
||||
APIKey: getEnv("MEILISEARCH_API_KEY", ""),
|
||||
IndexPrefix: getEnv("MEILISEARCH_INDEX_PREFIX", "site_"),
|
||||
},
|
||||
Scheduler: SchedulerConfig{
|
||||
QuotaResetEnabled: getEnvAsBool("SCHEDULER_QUOTA_RESET_ENABLED", true),
|
||||
QuotaResetSchedule: getEnv("SCHEDULER_QUOTA_RESET_SCHEDULE", "0 0 1 * *"), // 1st of month at midnight
|
||||
IPCleanupEnabled: getEnvAsBool("SCHEDULER_IP_CLEANUP_ENABLED", true), // CWE-359: GDPR compliance
|
||||
IPCleanupSchedule: getEnv("SCHEDULER_IP_CLEANUP_SCHEDULE", "0 2 * * *"), // Daily at 2 AM
|
||||
},
|
||||
RateLimit: RateLimitConfig{
|
||||
// Registration rate limiting (CWE-307)
|
||||
RegistrationEnabled: getEnvAsBool("RATELIMIT_REGISTRATION_ENABLED", true),
|
||||
RegistrationMaxRequests: getEnvAsInt("RATELIMIT_REGISTRATION_MAX_REQUESTS", 5),
|
||||
RegistrationWindow: getEnvAsDuration("RATELIMIT_REGISTRATION_WINDOW", time.Hour),
|
||||
|
||||
// Login rate limiting (CWE-307)
|
||||
LoginEnabled: getEnvAsBool("RATELIMIT_LOGIN_ENABLED", true),
|
||||
LoginMaxAttemptsPerIP: getEnvAsInt("RATELIMIT_LOGIN_MAX_ATTEMPTS_PER_IP", 10),
|
||||
LoginIPWindow: getEnvAsDuration("RATELIMIT_LOGIN_IP_WINDOW", 15*time.Minute),
|
||||
LoginMaxFailedAttemptsPerAccount: getEnvAsInt("RATELIMIT_LOGIN_MAX_FAILED_ATTEMPTS_PER_ACCOUNT", 10),
|
||||
LoginAccountLockoutDuration: getEnvAsDuration("RATELIMIT_LOGIN_ACCOUNT_LOCKOUT_DURATION", 30*time.Minute),
|
||||
|
||||
// Generic CRUD endpoints rate limiting (CWE-770)
|
||||
GenericEnabled: getEnvAsBool("RATELIMIT_GENERIC_ENABLED", true),
|
||||
GenericMaxRequests: getEnvAsInt("RATELIMIT_GENERIC_MAX_REQUESTS", 100),
|
||||
GenericWindow: getEnvAsDuration("RATELIMIT_GENERIC_WINDOW", time.Hour),
|
||||
|
||||
// Plugin API endpoints rate limiting (CWE-770) - Anti-abuse only
|
||||
// Generous limits for usage-based billing (no hard quotas)
|
||||
PluginAPIEnabled: getEnvAsBool("RATELIMIT_PLUGIN_API_ENABLED", true),
|
||||
PluginAPIMaxRequests: getEnvAsInt("RATELIMIT_PLUGIN_API_MAX_REQUESTS", 10000),
|
||||
PluginAPIWindow: getEnvAsDuration("RATELIMIT_PLUGIN_API_WINDOW", time.Hour),
|
||||
},
|
||||
LeaderElection: LeaderElectionConfig{
|
||||
Enabled: getEnvAsBool("LEADER_ELECTION_ENABLED", true),
|
||||
LockTTL: getEnvAsDuration("LEADER_ELECTION_LOCK_TTL", 10*time.Second),
|
||||
HeartbeatInterval: getEnvAsDuration("LEADER_ELECTION_HEARTBEAT_INTERVAL", 3*time.Second),
|
||||
RetryInterval: getEnvAsDuration("LEADER_ELECTION_RETRY_INTERVAL", 2*time.Second),
|
||||
},
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if err := cfg.validate(); err != nil {
|
||||
return nil, fmt.Errorf("invalid configuration: %w", err)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// GetSchedulerConfig returns scheduler configuration values
|
||||
func (c *Config) GetSchedulerConfig() (enabled bool, schedule string) {
|
||||
return c.Scheduler.QuotaResetEnabled, c.Scheduler.QuotaResetSchedule
|
||||
}
|
||||
|
||||
// validate checks if the configuration is valid
|
||||
func (c *Config) validate() error {
|
||||
if c.Server.Port < 1 || c.Server.Port > 65535 {
|
||||
return fmt.Errorf("invalid server port: %d", c.Server.Port)
|
||||
}
|
||||
|
||||
if c.Database.Keyspace == "" {
|
||||
return fmt.Errorf("database keyspace is required")
|
||||
}
|
||||
|
||||
if len(c.Database.Hosts) == 0 {
|
||||
return fmt.Errorf("at least one database host is required")
|
||||
}
|
||||
|
||||
if c.App.JWTSecret == "" {
|
||||
return fmt.Errorf("APP_JWT_SECRET is required")
|
||||
}
|
||||
|
||||
// Security validation for credentials (CWE-798: Use of Hard-coded Credentials)
|
||||
if err := c.validateSecurityCredentials(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateSecurityCredentials performs security validation on credentials
|
||||
// This addresses CWE-798 (Use of Hard-coded Credentials)
|
||||
func (c *Config) validateSecurityCredentials() error {
|
||||
// Check if JWT secret is using the default hard-coded value
|
||||
if strings.Contains(strings.ToLower(c.App.JWTSecret), "change-me") ||
|
||||
strings.Contains(strings.ToLower(c.App.JWTSecret), "changeme") {
|
||||
|
||||
if c.App.Environment == "production" {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: JWT secret is using default/placeholder value in production. " +
|
||||
"Generate a secure secret with: openssl rand -base64 64",
|
||||
)
|
||||
}
|
||||
|
||||
// Warn in development
|
||||
log.Printf(
|
||||
"[WARNING] JWT secret is using default/placeholder value. " +
|
||||
"This is acceptable for development but MUST be changed for production. " +
|
||||
"Generate a secure secret with: openssl rand -base64 64",
|
||||
)
|
||||
}
|
||||
|
||||
// Validate IP encryption key format (CWE-359: GDPR compliance)
|
||||
if c.Security.IPEncryptionKey != "" {
|
||||
if len(c.Security.IPEncryptionKey) != 32 {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: IP encryption key must be exactly 32 hex characters (16 bytes). " +
|
||||
"Generate with: openssl rand -hex 16",
|
||||
)
|
||||
}
|
||||
// Check if valid hex
|
||||
for _, char := range c.Security.IPEncryptionKey {
|
||||
if !((char >= '0' && char <= '9') || (char >= 'a' && char <= 'f') || (char >= 'A' && char <= 'F')) {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: IP encryption key must contain only hex characters (0-9, a-f). " +
|
||||
"Generate with: openssl rand -hex 16",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In production, enforce additional security checks
|
||||
if c.App.Environment == "production" {
|
||||
// Check IP encryption key is not using default value
|
||||
if c.Security.IPEncryptionKey == "00112233445566778899aabbccddeeff" {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: IP encryption key is using default value in production. " +
|
||||
"Generate a secure key with: openssl rand -hex 16",
|
||||
)
|
||||
}
|
||||
|
||||
// Check JWT secret minimum length
|
||||
if len(c.App.JWTSecret) < 32 {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: JWT secret is too short for production (%d characters). "+
|
||||
"Minimum required: 32 characters (256 bits). "+
|
||||
"Generate a secure secret with: openssl rand -base64 64",
|
||||
len(c.App.JWTSecret),
|
||||
)
|
||||
}
|
||||
|
||||
// Check for common weak secrets
|
||||
weakSecrets := []string{"secret", "password", "12345", "admin", "test", "default"}
|
||||
secretLower := strings.ToLower(c.App.JWTSecret)
|
||||
for _, weak := range weakSecrets {
|
||||
if secretLower == weak {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: JWT secret is using a common weak value: '%s'. "+
|
||||
"Generate a secure secret with: openssl rand -base64 64",
|
||||
weak,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Check Meilisearch API key in production
|
||||
if c.Meilisearch.APIKey == "" {
|
||||
return fmt.Errorf("SECURITY ERROR: Meilisearch API key must be set in production")
|
||||
}
|
||||
|
||||
meilisearchKeyLower := strings.ToLower(c.Meilisearch.APIKey)
|
||||
if strings.Contains(meilisearchKeyLower, "change") ||
|
||||
strings.Contains(meilisearchKeyLower, "dev") ||
|
||||
strings.Contains(meilisearchKeyLower, "test") {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: Meilisearch API key appears to be a development/placeholder value",
|
||||
)
|
||||
}
|
||||
|
||||
// Check database hosts are not using localhost in production
|
||||
for _, host := range c.Database.Hosts {
|
||||
hostLower := strings.ToLower(host)
|
||||
if strings.Contains(hostLower, "localhost") || host == "127.0.0.1" {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: Database hosts should not use localhost in production. Found: %s",
|
||||
host,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Check cache host is not localhost in production
|
||||
cacheLower := strings.ToLower(c.Cache.Host)
|
||||
if strings.Contains(cacheLower, "localhost") || c.Cache.Host == "127.0.0.1" {
|
||||
return fmt.Errorf(
|
||||
"SECURITY ERROR: Cache host should not use localhost in production. Found: %s",
|
||||
c.Cache.Host,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper functions to get environment variables
|
||||
|
||||
func getEnv(key, defaultValue string) string {
|
||||
value := os.Getenv(key)
|
||||
if value == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvAsInt(key string, defaultValue int) int {
|
||||
valueStr := os.Getenv(key)
|
||||
if valueStr == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(valueStr)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvAsInt64(key string, defaultValue int64) int64 {
|
||||
valueStr := os.Getenv(key)
|
||||
if valueStr == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
value, err := strconv.ParseInt(valueStr, 10, 64)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvAsBool(key string, defaultValue bool) bool {
|
||||
valueStr := os.Getenv(key)
|
||||
if valueStr == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
value, err := strconv.ParseBool(valueStr)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getEnvAsSlice(key string, defaultValue []string) []string {
|
||||
valueStr := os.Getenv(key)
|
||||
if valueStr == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// Simple comma-separated parsing
|
||||
// For production, consider using a proper CSV parser
|
||||
var result []string
|
||||
current := ""
|
||||
for _, char := range valueStr {
|
||||
if char == ',' {
|
||||
if current != "" {
|
||||
result = append(result, current)
|
||||
current = ""
|
||||
}
|
||||
} else {
|
||||
current += string(char)
|
||||
}
|
||||
}
|
||||
if current != "" {
|
||||
result = append(result, current)
|
||||
}
|
||||
|
||||
if len(result) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getEnvAsDuration(key string, defaultValue time.Duration) time.Duration {
|
||||
valueStr := os.Getenv(key)
|
||||
if valueStr == "" {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
value, err := time.ParseDuration(valueStr)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
27
cloud/maplepress-backend/config/constants/constants.go
Normal file
27
cloud/maplepress-backend/config/constants/constants.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package constants
|
||||
|
||||
const (
|
||||
// Application constants
|
||||
AppName = "MaplePress Backend"
|
||||
|
||||
// HTTP constants
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderAuthorization = "Authorization"
|
||||
MIMEApplicationJSON = "application/json"
|
||||
|
||||
// Context keys
|
||||
ContextKeyTenantID = "tenant_id"
|
||||
ContextKeyUserID = "user_id"
|
||||
ContextKeyJWTClaims = "jwt_claims"
|
||||
|
||||
// Site context keys (API key authentication)
|
||||
SiteIsAuthenticated = "site_is_authenticated"
|
||||
SiteID = "site_id"
|
||||
SiteTenantID = "site_tenant_id"
|
||||
SiteDomain = "site_domain"
|
||||
SitePlanTier = "site_plan_tier"
|
||||
|
||||
// Default values
|
||||
DefaultPageSize = 20
|
||||
MaxPageSize = 100
|
||||
)
|
||||
14
cloud/maplepress-backend/config/constants/session.go
Normal file
14
cloud/maplepress-backend/config/constants/session.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package constants
|
||||
|
||||
type key int
|
||||
|
||||
const (
|
||||
SessionIsAuthorized key = iota
|
||||
SessionID
|
||||
SessionUserID
|
||||
SessionUserUUID
|
||||
SessionUserEmail
|
||||
SessionUserName
|
||||
SessionUserRole
|
||||
SessionTenantID
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue