summaryrefslogtreecommitdiffstats
path: root/internal/config/config.go
diff options
context:
space:
mode:
authorbndw <ben@bdw.to>2026-02-14 10:11:16 -0800
committerbndw <ben@bdw.to>2026-02-14 10:11:16 -0800
commit606e0a3329a3534a00889eee19c25e7d432f7d2d (patch)
tree526b1419eaa6b9b91126adbfa5990ec47f5d3a07 /internal/config/config.go
parenta90009e6b887a8a7ca67f49566af2caffb807776 (diff)
refactor: restructure auth config for better UX
Changed from flat structure to hierarchical read/write config: Before: auth: enabled: bool required: bool allowed_npubs_read: [] allowed_npubs_write: [] After: auth: read: enabled: bool allowed_npubs: [] write: enabled: bool allowed_npubs: [] Three states per operation: - enabled=false: no auth, allow all - enabled=true, allowed_npubs=[]: auth required, any valid signature - enabled=true, allowed_npubs=[...]: auth required, whitelist only Much clearer semantics and easier to reason about.
Diffstat (limited to 'internal/config/config.go')
-rw-r--r--internal/config/config.go57
1 files changed, 35 insertions, 22 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index 3e52272..294510d 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -39,12 +39,19 @@ type DatabaseConfig struct {
39 39
40// AuthConfig holds authentication configuration. 40// AuthConfig holds authentication configuration.
41type AuthConfig struct { 41type AuthConfig struct {
42 Enabled bool `yaml:"enabled"` 42 Read AuthOperationConfig `yaml:"read"`
43 Required bool `yaml:"required"` 43 Write AuthOperationConfig `yaml:"write"`
44 TimestampWindow int64 `yaml:"timestamp_window"` 44 TimestampWindow int64 `yaml:"timestamp_window"`
45 AllowedNpubsRead []string `yaml:"allowed_npubs_read"` // npub format only (bech32) - normalized to hex internally 45 SkipMethods []string `yaml:"skip_methods"`
46 AllowedNpubsWrite []string `yaml:"allowed_npubs_write"` // npub format only (bech32) - normalized to hex internally 46}
47 SkipMethods []string `yaml:"skip_methods"` 47
48// AuthOperationConfig configures auth for a specific operation type (read or write).
49type AuthOperationConfig struct {
50 Enabled bool `yaml:"enabled"` // false = no auth required, true = auth required
51 AllowedNpubs []string `yaml:"allowed_npubs"` // npub format only - normalized to hex internally
52 // If enabled=false: no auth, allow all
53 // If enabled=true && allowed_npubs=[]: auth required, any valid signature accepted
54 // If enabled=true && allowed_npubs=[...]: auth required, only whitelisted npubs
48} 55}
49 56
50// RateLimitConfig holds rate limiting configuration. 57// RateLimitConfig holds rate limiting configuration.
@@ -111,8 +118,14 @@ func Default() *Config {
111 Path: "relay.db", 118 Path: "relay.db",
112 }, 119 },
113 Auth: AuthConfig{ 120 Auth: AuthConfig{
114 Enabled: false, 121 Read: AuthOperationConfig{
115 Required: false, 122 Enabled: false,
123 AllowedNpubs: nil,
124 },
125 Write: AuthOperationConfig{
126 Enabled: false,
127 AllowedNpubs: nil,
128 },
116 TimestampWindow: 60, 129 TimestampWindow: 60,
117 }, 130 },
118 RateLimit: RateLimitConfig{ 131 RateLimit: RateLimitConfig{
@@ -184,15 +197,15 @@ func normalizeNpubs(cfg *Config) error {
184 var err error 197 var err error
185 198
186 // Normalize read allowlist 199 // Normalize read allowlist
187 cfg.Auth.AllowedNpubsRead, err = normalizeNpubList(cfg.Auth.AllowedNpubsRead) 200 cfg.Auth.Read.AllowedNpubs, err = normalizeNpubList(cfg.Auth.Read.AllowedNpubs)
188 if err != nil { 201 if err != nil {
189 return fmt.Errorf("allowed_npubs_read: %w", err) 202 return fmt.Errorf("auth.read.allowed_npubs: %w", err)
190 } 203 }
191 204
192 // Normalize write allowlist 205 // Normalize write allowlist
193 cfg.Auth.AllowedNpubsWrite, err = normalizeNpubList(cfg.Auth.AllowedNpubsWrite) 206 cfg.Auth.Write.AllowedNpubs, err = normalizeNpubList(cfg.Auth.Write.AllowedNpubs)
194 if err != nil { 207 if err != nil {
195 return fmt.Errorf("allowed_npubs_write: %w", err) 208 return fmt.Errorf("auth.write.allowed_npubs: %w", err)
196 } 209 }
197 210
198 return nil 211 return nil
@@ -299,11 +312,17 @@ func applyEnvOverrides(cfg *Config) {
299 } 312 }
300 313
301 // Auth 314 // Auth
302 if val := os.Getenv("MUXSTR_AUTH_ENABLED"); val != "" { 315 if val := os.Getenv("MUXSTR_AUTH_READ_ENABLED"); val != "" {
303 cfg.Auth.Enabled = parseBool(val) 316 cfg.Auth.Read.Enabled = parseBool(val)
317 }
318 if val := os.Getenv("MUXSTR_AUTH_READ_ALLOWED_NPUBS"); val != "" {
319 cfg.Auth.Read.AllowedNpubs = strings.Split(val, ",")
304 } 320 }
305 if val := os.Getenv("MUXSTR_AUTH_REQUIRED"); val != "" { 321 if val := os.Getenv("MUXSTR_AUTH_WRITE_ENABLED"); val != "" {
306 cfg.Auth.Required = parseBool(val) 322 cfg.Auth.Write.Enabled = parseBool(val)
323 }
324 if val := os.Getenv("MUXSTR_AUTH_WRITE_ALLOWED_NPUBS"); val != "" {
325 cfg.Auth.Write.AllowedNpubs = strings.Split(val, ",")
307 } 326 }
308 if val := os.Getenv("MUXSTR_AUTH_TIMESTAMP_WINDOW"); val != "" { 327 if val := os.Getenv("MUXSTR_AUTH_TIMESTAMP_WINDOW"); val != "" {
309 var n int64 328 var n int64
@@ -311,12 +330,6 @@ func applyEnvOverrides(cfg *Config) {
311 cfg.Auth.TimestampWindow = n 330 cfg.Auth.TimestampWindow = n
312 } 331 }
313 } 332 }
314 if val := os.Getenv("MUXSTR_AUTH_ALLOWED_NPUBS_READ"); val != "" {
315 cfg.Auth.AllowedNpubsRead = strings.Split(val, ",")
316 }
317 if val := os.Getenv("MUXSTR_AUTH_ALLOWED_NPUBS_WRITE"); val != "" {
318 cfg.Auth.AllowedNpubsWrite = strings.Split(val, ",")
319 }
320 333
321 // Rate limit 334 // Rate limit
322 if val := os.Getenv("MUXSTR_RATE_LIMIT_ENABLED"); val != "" { 335 if val := os.Getenv("MUXSTR_RATE_LIMIT_ENABLED"); val != "" {