atlassian_cli_auth/
lib.rs

1use anyhow::{Context, Result};
2use std::collections::HashMap;
3use std::fs::{self, OpenOptions};
4use std::path::PathBuf;
5
6#[cfg(unix)]
7use std::os::unix::fs::OpenOptionsExt;
8
9/// Helper to construct a key for profile secrets.
10pub fn token_key(profile: &str) -> String {
11    profile.to_string()
12}
13
14fn credentials_path() -> Option<PathBuf> {
15    dirs::home_dir().map(|h| h.join(".atlassian-cli").join("credentials"))
16}
17
18/// Store a secret in the credentials file with 600 permissions.
19pub fn set_secret(account: &str, secret: &str) -> Result<()> {
20    let path = credentials_path().context("Cannot determine home directory")?;
21    if let Some(parent) = path.parent() {
22        fs::create_dir_all(parent)?;
23    }
24
25    let mut creds: HashMap<String, String> = if path.exists() {
26        let content = fs::read_to_string(&path)?;
27        serde_json::from_str(&content).unwrap_or_default()
28    } else {
29        HashMap::new()
30    };
31
32    creds.insert(account.to_string(), secret.to_string());
33
34    #[cfg(unix)]
35    {
36        use std::io::Write;
37        let mut file = OpenOptions::new()
38            .write(true)
39            .create(true)
40            .truncate(true)
41            .mode(0o600)
42            .open(&path)?;
43        let json = serde_json::to_string_pretty(&creds)?;
44        file.write_all(json.as_bytes())?;
45    }
46
47    #[cfg(not(unix))]
48    {
49        let file = OpenOptions::new()
50            .write(true)
51            .create(true)
52            .truncate(true)
53            .open(&path)?;
54        serde_json::to_writer_pretty(file, &creds)?;
55    }
56
57    Ok(())
58}
59
60/// Get a secret from the credentials file.
61pub fn get_secret(account: &str) -> Result<Option<String>> {
62    let path = credentials_path().context("Cannot determine home directory")?;
63    if !path.exists() {
64        return Ok(None);
65    }
66    let content = fs::read_to_string(&path)?;
67    let creds: HashMap<String, String> = serde_json::from_str(&content)?;
68    Ok(creds.get(account).cloned())
69}
70
71/// Delete a secret from the credentials file.
72pub fn delete_secret(account: &str) -> Result<()> {
73    let path = credentials_path().context("Cannot determine home directory")?;
74    if !path.exists() {
75        return Ok(());
76    }
77    let content = fs::read_to_string(&path)?;
78    let mut creds: HashMap<String, String> = serde_json::from_str(&content).unwrap_or_default();
79    creds.remove(account);
80
81    #[cfg(unix)]
82    {
83        use std::io::Write;
84        let mut file = OpenOptions::new()
85            .write(true)
86            .create(true)
87            .truncate(true)
88            .mode(0o600)
89            .open(&path)?;
90        let json = serde_json::to_string_pretty(&creds)?;
91        file.write_all(json.as_bytes())?;
92    }
93
94    #[cfg(not(unix))]
95    {
96        let file = OpenOptions::new()
97            .write(true)
98            .create(true)
99            .truncate(true)
100            .open(&path)?;
101        serde_json::to_writer_pretty(file, &creds)?;
102    }
103
104    Ok(())
105}