Files
shorebird-server/internal/config/config.go
T
Tony 774954fce7 feat: implement patch expiration and encryption features
- Add offline expiration handling for patch artifacts in the database.
- Update CreatePatchArtifact and related functions to accept and return offline expiration timestamps.
- Enhance patch check responses to include offline expiration metadata.
- Introduce device-specific encryption for patches, allowing for secure delivery.
- Implement tests for patch check functionality, including scenarios for expired patches and encrypted delivery.
- Modify router and configuration to support new patch delivery settings.
- Update database schema and migrations to accommodate new fields for offline expiration.
2026-06-24 03:02:09 +08:00

166 lines
4.8 KiB
Go

package config
import (
"os"
"time"
)
// Config holds all configuration for the Shorebird server.
type Config struct {
Server ServerConfig
DB DBConfig
Storage StorageConfig
Auth AuthConfig
Email EmailConfig
Admin AdminConfig
Redis RedisConfig
PatchDelivery PatchDeliveryConfig
}
// ServerConfig holds HTTP server configuration.
type ServerConfig struct {
Host string
Port string
BaseURL string // public-facing URL, used for download links
ReadTimeout time.Duration
WriteTimeout time.Duration
}
// DBConfig holds database configuration.
type DBConfig struct {
// Driver is "postgres" or "sqlite". Empty defaults to "sqlite".
Driver string
// URL is the PostgreSQL connection string (used when driver=postgres).
URL string
// Path is the SQLite database file path (used when driver=sqlite).
Path string
}
// StorageConfig holds object storage configuration.
type StorageConfig struct {
// Driver is "local" or "s3". Empty defaults to "local".
Driver string
// Local settings
LocalDir string
// S3/MinIO settings
S3Endpoint string
S3AccessKey string
S3SecretKey string
S3UseSSL bool
S3ReleaseBucket string
S3PatchBucket string
}
// AuthConfig holds JWT authentication configuration.
type AuthConfig struct {
JWTSecret string
TokenDuration time.Duration
}
// EmailConfig holds SMTP configuration for account emails.
type EmailConfig struct {
Host string
Port string
Username string
Password string
From string
}
// AdminConfig holds bootstrap admin configuration.
type AdminConfig struct {
Email string
Password string
Name string
}
// RedisConfig holds Redis connection configuration.
type RedisConfig struct {
Addr string
Password string
DB int
}
// PatchDeliveryConfig controls optional device-facing patch encryption.
type PatchDeliveryConfig struct {
// EncryptionMode is "off" or "per_device_aes_gcm".
EncryptionMode string
// AESSecret is a server-side secret used to derive per-device AES keys.
AESSecret string
// CacheEncryptedPatches stores derived ciphertext objects for reuse.
CacheEncryptedPatches bool
}
// Load reads configuration from environment variables with sensible defaults.
func Load() *Config {
port := envOrDefault("SERVER_PORT", "8080")
baseURL := envOrDefault("SERVER_BASE_URL", "http://localhost:"+port)
return &Config{
Server: ServerConfig{
Host: envOrDefault("SERVER_HOST", "0.0.0.0"),
Port: port,
BaseURL: baseURL,
ReadTimeout: 15 * time.Second,
WriteTimeout: 30 * time.Second,
},
DB: DBConfig{
Driver: envOrDefault("DB_DRIVER", "sqlite"),
URL: envOrDefault("DATABASE_URL", "postgres://shorebird:shorebird@localhost:5432/shorebird?sslmode=disable"),
Path: envOrDefault("DB_PATH", "data/shorebird.db"),
},
Storage: StorageConfig{
Driver: envOrDefault("STORAGE_DRIVER", "local"),
LocalDir: envOrDefault("STORAGE_LOCAL_DIR", "data/storage"),
S3Endpoint: envOrDefault("STORAGE_S3_ENDPOINT", "localhost:9000"),
S3AccessKey: envOrDefault("STORAGE_S3_ACCESS_KEY", "minioadmin"),
S3SecretKey: envOrDefault("STORAGE_S3_SECRET_KEY", "minioadmin"),
S3UseSSL: os.Getenv("STORAGE_S3_USE_SSL") == "true",
S3ReleaseBucket: envOrDefault("STORAGE_S3_RELEASE_BUCKET", "shorebird-releases"),
S3PatchBucket: envOrDefault("STORAGE_S3_PATCH_BUCKET", "shorebird-patches"),
},
Auth: AuthConfig{
JWTSecret: envOrDefault("JWT_SECRET", "change-me-in-production-use-a-long-random-string"),
TokenDuration: 24 * time.Hour,
},
Email: EmailConfig{
Host: envOrDefault("SMTP_HOST", ""),
Port: envOrDefault("SMTP_PORT", "587"),
Username: envOrDefault("SMTP_USERNAME", ""),
Password: envOrDefault("SMTP_PASSWORD", ""),
From: envOrDefault("SMTP_FROM", "shorebird@localhost"),
},
Admin: AdminConfig{
Email: envOrDefault("DEFAULT_ADMIN_EMAIL", "admin@example.com"),
Password: envOrDefault("DEFAULT_ADMIN_PASSWORD", "admin123"),
Name: envOrDefault("DEFAULT_ADMIN_NAME", "Administrator"),
},
Redis: RedisConfig{
Addr: envOrDefault("REDIS_ADDR", "localhost:6379"),
Password: envOrDefault("REDIS_PASSWORD", ""),
DB: 0,
},
PatchDelivery: PatchDeliveryConfig{
EncryptionMode: envOrDefault("PATCH_DELIVERY_ENCRYPTION", "off"),
AESSecret: envOrDefault("PATCH_DELIVERY_AES_SECRET", ""),
CacheEncryptedPatches: envBoolOrDefault("PATCH_DELIVERY_CACHE_ENCRYPTED", true),
},
}
}
func envOrDefault(key, defaultVal string) string {
if v := os.Getenv(key); v != "" {
return v
}
return defaultVal
}
func envBoolOrDefault(key string, defaultVal bool) bool {
v := os.Getenv(key)
if v == "" {
return defaultVal
}
return v == "true" || v == "1" || v == "yes"
}