// Package config provides TOML configuration loading and validation. package config import ( "fmt" mcdslauth "git.wntrmute.dev/kyle/mcdsl/auth" mcdslconfig "git.wntrmute.dev/kyle/mcdsl/config" ) // Config is the top-level configuration for Metacrypt. type Config struct { Server ServerConfig `toml:"server"` Web WebConfig `toml:"web"` MCIAS MCIASConfig `toml:"mcias"` Database mcdslconfig.DatabaseConfig `toml:"database"` Log mcdslconfig.LogConfig `toml:"log"` Seal SealConfig `toml:"seal"` Audit AuditConfig `toml:"audit"` } // ServerConfig holds HTTP/gRPC server settings. It embeds the standard // mcdsl server config and adds the ACME external URL. type ServerConfig struct { mcdslconfig.ServerConfig ExternalURL string `toml:"external_url"` // public base URL for ACME directory } // MCIASConfig holds MCIAS integration settings. It embeds the standard // mcdsl auth config and adds the service token for web UI login. type MCIASConfig struct { mcdslauth.Config ServiceToken string `toml:"service_token"` } // WebConfig holds settings for the standalone web UI server (metacrypt-web). type WebConfig struct { // ListenAddr is the address the web server listens on (default: 127.0.0.1:8080). ListenAddr string `toml:"listen_addr"` // VaultGRPC is the gRPC address of the vault server (e.g. "127.0.0.1:9443"). VaultGRPC string `toml:"vault_grpc"` // VaultCACert is the path to the CA certificate used to verify the vault's TLS cert. VaultCACert string `toml:"vault_ca_cert"` // VaultSNI overrides the TLS server name used to verify the vault's // certificate. Use when the dial address (e.g., a container hostname) // does not match any SAN on the vault's TLS certificate. VaultSNI string `toml:"vault_sni"` // TLSCert and TLSKey are optional. If empty, the web server uses plain HTTP // (suitable for deployment behind a TLS-terminating reverse proxy). TLSCert string `toml:"tls_cert"` TLSKey string `toml:"tls_key"` } // AuditConfig holds audit logging settings. type AuditConfig struct { // Mode controls audit log output: "file", "stdout", or "" (disabled). Mode string `toml:"mode"` // Path is the audit log file path (required when mode is "file"). Path string `toml:"path"` // IncludeReads enables audit logging for read-only operations. IncludeReads bool `toml:"include_reads"` } // SealConfig holds Argon2id parameters for the seal process. type SealConfig struct { Argon2Time uint32 `toml:"argon2_time"` Argon2Memory uint32 `toml:"argon2_memory"` Argon2Threads uint8 `toml:"argon2_threads"` } // Load reads and parses a TOML config file with METACRYPT_ env var overrides. func Load(path string) (*Config, error) { return mcdslconfig.Load[Config](path, "METACRYPT") } // Validate implements mcdslconfig.Validator for metacrypt-specific rules. func (c *Config) Validate() error { // Required fields. if c.Server.ListenAddr == "" { return fmt.Errorf("server.listen_addr is required") } if c.Server.TLSCert == "" { return fmt.Errorf("server.tls_cert is required") } if c.Server.TLSKey == "" { return fmt.Errorf("server.tls_key is required") } if c.Database.Path == "" { return fmt.Errorf("database.path is required") } if c.MCIAS.ServerURL == "" { return fmt.Errorf("mcias.server_url is required") } // Seal defaults. if c.Seal.Argon2Time == 0 { c.Seal.Argon2Time = 3 } if c.Seal.Argon2Memory == 0 { c.Seal.Argon2Memory = 128 * 1024 } if c.Seal.Argon2Threads == 0 { c.Seal.Argon2Threads = 4 } // Log default. if c.Log.Level == "" { c.Log.Level = "info" } // Web default. if c.Web.ListenAddr == "" { c.Web.ListenAddr = "127.0.0.1:8080" } // Audit validation. switch c.Audit.Mode { case "", "stdout": // ok case "file": if c.Audit.Path == "" { return fmt.Errorf("audit.path is required when audit.mode is \"file\"") } default: return fmt.Errorf("audit.mode must be \"file\", \"stdout\", or empty") } return nil }