bitbucket_cli/auth/
file_store.rs1use anyhow::{Context, Result};
2use std::fs;
3use std::path::PathBuf;
4
5use super::Credential;
6
7pub struct FileStore {
9 path: PathBuf,
10}
11
12impl FileStore {
13 pub fn new() -> Result<Self> {
14 let config_dir = dirs::config_dir()
15 .context("Could not determine config directory")?
16 .join("bitbucket");
17
18 fs::create_dir_all(&config_dir).context("Failed to create config directory")?;
20
21 let path = config_dir.join("credentials.json");
22
23 Ok(Self { path })
24 }
25
26 pub fn store_credential(&self, credential: &Credential) -> Result<()> {
28 let json =
29 serde_json::to_string_pretty(credential).context("Failed to serialize credential")?;
30
31 #[cfg(unix)]
33 {
34 use std::fs::OpenOptions;
35 use std::os::unix::fs::OpenOptionsExt;
36
37 OpenOptions::new()
38 .write(true)
39 .create(true)
40 .truncate(true)
41 .mode(0o600)
42 .open(&self.path)
43 .and_then(|mut file| {
44 use std::io::Write;
45 file.write_all(json.as_bytes())
46 })
47 .context("Failed to write credential file")?;
48 }
49
50 #[cfg(not(unix))]
51 {
52 fs::write(&self.path, json).context("Failed to write credential file")?;
53 }
54
55 Ok(())
56 }
57
58 pub fn get_credential(&self) -> Result<Option<Credential>> {
60 if !self.path.exists() {
61 return Ok(None);
62 }
63
64 let json = fs::read_to_string(&self.path).context("Failed to read credential file")?;
65
66 let credential: Credential =
67 serde_json::from_str(&json).context("Failed to parse stored credential")?;
68
69 Ok(Some(credential))
70 }
71
72 pub fn delete_credential(&self) -> Result<()> {
74 if self.path.exists() {
75 fs::remove_file(&self.path).context("Failed to delete credential file")?;
76 }
77 Ok(())
78 }
79}