diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-03-16 20:49:54 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-03-16 20:49:54 +0000 |
| commit | 48aec51b531d995574c5788e5f474343cc6e5c87 (patch) | |
| tree | 72590561f22185707e9bac65d6d14c21f69f309f /internal/cli | |
| parent | 7f920ca63af5329c19a0e5a879c649c594beea35 (diff) | |
fix: persist VAPID keys in DB instead of config file
The service runs as www-data which cannot write to the root-owned
config file. VAPID keys are now stored in the settings table in
SQLite (which is writable), loaded on startup, and generated once.
Removes saveVAPIDToConfig and the stale warning on every restart.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/cli')
| -rw-r--r-- | internal/cli/serve.go | 78 |
1 files changed, 16 insertions, 62 deletions
diff --git a/internal/cli/serve.go b/internal/cli/serve.go index 1753a64..efac719 100644 --- a/internal/cli/serve.go +++ b/internal/cli/serve.go @@ -1,7 +1,6 @@ package cli import ( - "bytes" "context" "fmt" "net/http" @@ -11,7 +10,6 @@ import ( "syscall" "time" - "github.com/BurntSushi/toml" "github.com/thepeterstone/claudomator/internal/api" "github.com/thepeterstone/claudomator/internal/executor" "github.com/thepeterstone/claudomator/internal/notify" @@ -46,29 +44,28 @@ func serve(addr string) error { return fmt.Errorf("creating dirs: %w", err) } - // Auto-generate VAPID keys if not configured. - if cfg.VAPIDPublicKey == "" || cfg.VAPIDPrivateKey == "" { - pub, priv, err := notify.GenerateVAPIDKeys() - if err != nil { - return fmt.Errorf("generating VAPID keys: %w", err) - } - cfg.VAPIDPublicKey = pub - cfg.VAPIDPrivateKey = priv - // Write new keys back to config file. - if cfgFile != "" { - if err := saveVAPIDToConfig(cfgFile, pub, priv); err != nil { - // Non-fatal: log but continue. - fmt.Fprintf(os.Stderr, "warning: failed to persist VAPID keys to %s: %v\n", cfgFile, err) - } - } - } - store, err := storage.Open(cfg.DBPath) if err != nil { return fmt.Errorf("opening db: %w", err) } defer store.Close() + // Load VAPID keys from DB; generate and persist if missing. + if cfg.VAPIDPublicKey == "" || cfg.VAPIDPrivateKey == "" { + pub, _ := store.GetSetting("vapid_public_key") + priv, _ := store.GetSetting("vapid_private_key") + if pub == "" || priv == "" { + pub, priv, err = notify.GenerateVAPIDKeys() + if err != nil { + return fmt.Errorf("generating VAPID keys: %w", err) + } + _ = store.SetSetting("vapid_public_key", pub) + _ = store.SetSetting("vapid_private_key", priv) + } + cfg.VAPIDPublicKey = pub + cfg.VAPIDPrivateKey = priv + } + logger := newLogger(verbose) apiURL := "http://localhost" + addr @@ -164,46 +161,3 @@ func serve(addr string) error { return nil } -// saveVAPIDToConfig appends VAPID key assignments to the config file. -// It reads the existing file (if any), then writes a complete TOML file with -// the new keys merged in. Uses toml encoder for correctness. -func saveVAPIDToConfig(path, pub, priv string) error { - existing := cfg // already loaded - - // Marshal the full config back including the new VAPID keys. - // We use a struct alias to only encode fields we want persisted. - type persistedConfig struct { - DataDir string `toml:"data_dir,omitempty"` - ClaudeBinaryPath string `toml:"claude_binary_path,omitempty"` - GeminiBinaryPath string `toml:"gemini_binary_path,omitempty"` - MaxConcurrent int `toml:"max_concurrent,omitempty"` - DefaultTimeout string `toml:"default_timeout,omitempty"` - ServerAddr string `toml:"server_addr,omitempty"` - WebhookURL string `toml:"webhook_url,omitempty"` - WorkspaceRoot string `toml:"workspace_root,omitempty"` - WebhookSecret string `toml:"webhook_secret,omitempty"` - VAPIDPublicKey string `toml:"vapid_public_key,omitempty"` - VAPIDPrivateKey string `toml:"vapid_private_key,omitempty"` - VAPIDEmail string `toml:"vapid_email,omitempty"` - } - pc := persistedConfig{ - DataDir: existing.DataDir, - ClaudeBinaryPath: existing.ClaudeBinaryPath, - GeminiBinaryPath: existing.GeminiBinaryPath, - MaxConcurrent: existing.MaxConcurrent, - DefaultTimeout: existing.DefaultTimeout, - ServerAddr: existing.ServerAddr, - WebhookURL: existing.WebhookURL, - WorkspaceRoot: existing.WorkspaceRoot, - WebhookSecret: existing.WebhookSecret, - VAPIDPublicKey: pub, - VAPIDPrivateKey: priv, - VAPIDEmail: existing.VAPIDEmail, - } - - var buf bytes.Buffer - if err := toml.NewEncoder(&buf).Encode(pc); err != nil { - return fmt.Errorf("encoding config: %w", err) - } - return os.WriteFile(path, buf.Bytes(), 0600) -} |
