bluesky viewer in the terminal
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 121 lines 3.0 kB view raw
1package config 2 3import ( 4 "encoding/json" 5 "errors" 6 "os" 7) 8 9// Config represents the application configuration stored in ~/.skycli/.config.json 10// Tokens are encrypted at rest using AES-256-GCM 11type Config struct { 12 Session *SessionConfig `json:"session,omitempty"` 13} 14 15// SessionConfig holds the current session information with encrypted tokens 16type SessionConfig struct { 17 Handle string `json:"handle"` 18 Did string `json:"did"` 19 ServiceURL string `json:"serviceUrl"` 20 EncryptedAccess string `json:"encryptedAccessToken"` 21 EncryptedRefresh string `json:"encryptedRefreshToken"` 22 Email string `json:"email,omitempty"` 23} 24 25// Load reads and decrypts the configuration from ~/.skycli/.config.json 26// Returns a default empty config if the file doesn't exist 27func Load() (*Config, error) { 28 configPath, err := GetConfigFile() 29 if err != nil { 30 return nil, err 31 } 32 33 data, err := os.ReadFile(configPath) 34 if err != nil { 35 if errors.Is(err, os.ErrNotExist) { 36 return &Config{}, nil 37 } 38 return nil, &ConfigError{Op: "ReadFile", Err: err} 39 } 40 41 var cfg Config 42 if err := json.Unmarshal(data, &cfg); err != nil { 43 return nil, &ConfigError{Op: "Unmarshal", Err: err} 44 } 45 46 return &cfg, nil 47} 48 49// Save encrypts tokens and persists the configuration to ~/.skycli/.config.json 50// Creates the config directory if it doesn't exist 51func (c *Config) Save() error { 52 if err := EnsureConfigDir(); err != nil { 53 return err 54 } 55 56 configPath, err := GetConfigFile() 57 if err != nil { 58 return err 59 } 60 61 data, err := json.MarshalIndent(c, "", " ") 62 if err != nil { 63 return &ConfigError{Op: "Marshal", Err: err} 64 } 65 66 if err := os.WriteFile(configPath, data, 0600); err != nil { 67 return &ConfigError{Op: "WriteFile", Err: err} 68 } 69 70 return nil 71} 72 73// GetAccessToken decrypts and returns the access token 74func (s *SessionConfig) GetAccessToken() (string, error) { 75 if s == nil || s.EncryptedAccess == "" { 76 return "", nil 77 } 78 return DecryptToken(s.EncryptedAccess) 79} 80 81// GetRefreshToken decrypts and returns the refresh token 82func (s *SessionConfig) GetRefreshToken() (string, error) { 83 if s == nil || s.EncryptedRefresh == "" { 84 return "", nil 85 } 86 return DecryptToken(s.EncryptedRefresh) 87} 88 89// SetAccessToken encrypts and stores the access token 90func (s *SessionConfig) SetAccessToken(token string) error { 91 encrypted, err := EncryptToken(token) 92 if err != nil { 93 return err 94 } 95 s.EncryptedAccess = encrypted 96 return nil 97} 98 99// SetRefreshToken encrypts and stores the refresh token 100func (s *SessionConfig) SetRefreshToken(token string) error { 101 encrypted, err := EncryptToken(token) 102 if err != nil { 103 return err 104 } 105 s.EncryptedRefresh = encrypted 106 return nil 107} 108 109// ConfigError represents an error that occurred during config operations 110type ConfigError struct { 111 Op string 112 Err error 113} 114 115func (e *ConfigError) Error() string { 116 return "config." + e.Op + ": " + e.Err.Error() 117} 118 119func (e *ConfigError) Unwrap() error { 120 return e.Err 121}