use anyhow::{Context, Result}; use directories::ProjectDirs; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credentials { pub username: String, pub password: String, pub pds_uri: String, } impl Credentials { pub fn new(username: String, password: String, pds_uri: String) -> Self { Self { username, password, pds_uri, } } } pub struct CredentialStore { config_dir: PathBuf, } impl CredentialStore { pub fn new() -> Result { let project_dirs = ProjectDirs::from("com", "thoughtstream", "think") .context("Failed to determine project directories")?; let config_dir = project_dirs.config_dir().to_path_buf(); // Create config directory if it doesn't exist fs::create_dir_all(&config_dir) .context("Failed to create config directory")?; Ok(Self { config_dir }) } fn credentials_path(&self) -> PathBuf { self.config_dir.join("credentials.json") } pub fn store(&self, credentials: &Credentials) -> Result<()> { let json = serde_json::to_string_pretty(credentials) .context("Failed to serialize credentials")?; fs::write(self.credentials_path(), json) .context("Failed to write credentials file")?; println!("Credentials stored successfully"); Ok(()) } pub fn load(&self) -> Result> { let path = self.credentials_path(); if !path.exists() { return Ok(None); } let json = fs::read_to_string(&path) .context("Failed to read credentials file")?; let credentials: Credentials = serde_json::from_str(&json) .context("Failed to parse credentials file")?; Ok(Some(credentials)) } pub fn clear(&self) -> Result<()> { let path = self.credentials_path(); if path.exists() { fs::remove_file(&path) .context("Failed to remove credentials file")?; println!("Credentials cleared successfully"); } else { println!("No credentials found to clear"); } Ok(()) } pub fn exists(&self) -> bool { self.credentials_path().exists() } }