logicaffeine_cli/project/
credentials.rs1use std::collections::HashMap;
21use std::fs;
22use std::path::PathBuf;
23
24#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
36pub struct Credentials {
37 #[serde(default)]
39 pub registries: HashMap<String, String>,
40}
41
42impl Credentials {
43 pub fn load() -> Result<Self, CredentialsError> {
45 let path = credentials_path().ok_or(CredentialsError::NoConfigDir)?;
46
47 if !path.exists() {
48 return Ok(Self::default());
49 }
50
51 let content = fs::read_to_string(&path)
52 .map_err(|e| CredentialsError::Io(e.to_string()))?;
53
54 toml::from_str(&content)
55 .map_err(|e| CredentialsError::Parse(e.to_string()))
56 }
57
58 pub fn save(&self) -> Result<(), CredentialsError> {
60 let path = credentials_path().ok_or(CredentialsError::NoConfigDir)?;
61
62 if let Some(parent) = path.parent() {
64 fs::create_dir_all(parent)
65 .map_err(|e| CredentialsError::Io(e.to_string()))?;
66 }
67
68 let content = toml::to_string_pretty(self)
69 .map_err(|e| CredentialsError::Serialize(e.to_string()))?;
70
71 fs::write(&path, content)
72 .map_err(|e| CredentialsError::Io(e.to_string()))?;
73
74 #[cfg(unix)]
76 {
77 use std::os::unix::fs::PermissionsExt;
78 let perms = std::fs::Permissions::from_mode(0o600);
79 fs::set_permissions(&path, perms)
80 .map_err(|e| CredentialsError::Io(e.to_string()))?;
81 }
82
83 Ok(())
84 }
85
86 pub fn get_token(&self, registry_url: &str) -> Option<&str> {
88 self.registries.get(registry_url).map(|s| s.as_str())
89 }
90
91 pub fn set_token(&mut self, registry_url: &str, token: &str) {
93 self.registries.insert(registry_url.to_string(), token.to_string());
94 }
95
96 pub fn remove_token(&mut self, registry_url: &str) {
98 self.registries.remove(registry_url);
99 }
100}
101
102pub fn get_token(registry_url: &str) -> Option<String> {
104 if let Ok(token) = std::env::var("LOGOS_TOKEN") {
106 if !token.is_empty() {
107 return Some(token);
108 }
109 }
110
111 Credentials::load()
113 .ok()
114 .and_then(|c| c.get_token(registry_url).map(String::from))
115}
116
117pub fn credentials_path() -> Option<PathBuf> {
119 if let Ok(path) = std::env::var("LOGOS_CREDENTIALS_PATH") {
121 return Some(PathBuf::from(path));
122 }
123
124 dirs::config_dir().map(|p| p.join("logos").join("credentials.toml"))
126}
127
128#[derive(Debug)]
130pub enum CredentialsError {
131 NoConfigDir,
133 Io(String),
135 Parse(String),
137 Serialize(String),
139}
140
141impl std::fmt::Display for CredentialsError {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 match self {
144 Self::NoConfigDir => write!(f, "Could not determine config directory"),
145 Self::Io(e) => write!(f, "I/O error: {}", e),
146 Self::Parse(e) => write!(f, "Failed to parse credentials: {}", e),
147 Self::Serialize(e) => write!(f, "Failed to serialize credentials: {}", e),
148 }
149 }
150}
151
152impl std::error::Error for CredentialsError {}