package config import ( "fmt" "os" "path/filepath" "gopkg.in/yaml.v3" ) // Config lives at .verstak/config.yml inside the vault. type Config struct { Engine EngineConfig `yaml:"engine"` Sync SyncConfig `yaml:"sync"` Browser BrowserConfig `yaml:"browser"` } type EngineConfig struct { Version int `yaml:"version"` VaultID string `yaml:"vault_id"` CreatedAt string `yaml:"created_at"` VaultRoot string `yaml:"vault_root"` } type SyncConfig struct { ServerURL string `yaml:"server_url"` APIKey string `yaml:"api_key"` DeviceID string `yaml:"device_id"` AutoSync bool `yaml:"auto_sync"` SyncInterval int `yaml:"sync_interval"` } type BrowserConfig struct { Enabled bool `yaml:"enabled"` LocalPort int `yaml:"local_port"` } // Load reads .verstak/config.yml from the vault root. func Load(vaultRoot string) (*Config, error) { path := filepath.Join(vaultRoot, ".verstak", "config.yml") data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("read config: %w", err) } var cfg Config if err := yaml.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("parse config: %w", err) } return &cfg, nil } // Save writes the config file. func Save(vaultRoot string, cfg *Config) error { path := filepath.Join(vaultRoot, ".verstak", "config.yml") dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o750); err != nil { return err } data, err := yaml.Marshal(cfg) if err != nil { return err } return os.WriteFile(path, data, 0o640) } // MetaPath returns the path inside the vault for sqlite db etc. func MetaDir(vaultRoot string) string { return filepath.Join(vaultRoot, ".verstak") } // DeviceTokenPath returns the path to the device_token file. func DeviceTokenPath(vaultRoot string) string { return filepath.Join(vaultRoot, ".verstak", "device_token.json") } // SaveDeviceToken writes the device token to a separate file with 0600 perms. func SaveDeviceToken(vaultRoot, token string) error { path := DeviceTokenPath(vaultRoot) dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0o750); err != nil { return err } data := fmt.Sprintf(`{"device_token":%q}`, token) return os.WriteFile(path, []byte(data), 0o600) } // LoadDeviceToken reads the device token from the separate file. func LoadDeviceToken(vaultRoot string) string { path := DeviceTokenPath(vaultRoot) data, err := os.ReadFile(path) if err != nil { return "" } var v struct { DeviceToken string `yaml:"device_token"` } if err := yaml.Unmarshal(data, &v); err != nil { return "" } return v.DeviceToken } // RemoveDeviceToken deletes the device token file. func RemoveDeviceToken(vaultRoot string) error { path := DeviceTokenPath(vaultRoot) return os.Remove(path) }