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)
20 .context("Failed to create config directory")?;
21
22 let path = config_dir.join("credentials.json");
23
24 Ok(Self { path })
25 }
26
27 pub fn store_credential(&self, credential: &Credential) -> Result<()> {
29 let json = serde_json::to_string_pretty(credential)
30 .context("Failed to serialize credential")?;
31
32 #[cfg(unix)]
34 {
35 use std::fs::OpenOptions;
36 use std::os::unix::fs::OpenOptionsExt;
37
38 OpenOptions::new()
39 .write(true)
40 .create(true)
41 .truncate(true)
42 .mode(0o600)
43 .open(&self.path)
44 .and_then(|mut file| {
45 use std::io::Write;
46 file.write_all(json.as_bytes())
47 })
48 .context("Failed to write credential file")?;
49 }
50
51 #[cfg(not(unix))]
52 {
53 fs::write(&self.path, json).context("Failed to write credential file")?;
54 }
55
56 Ok(())
57 }
58
59 pub fn get_credential(&self) -> Result<Option<Credential>> {
61 if !self.path.exists() {
62 return Ok(None);
63 }
64
65 let json = fs::read_to_string(&self.path)
66 .context("Failed to read credential file")?;
67
68 let credential: Credential =
69 serde_json::from_str(&json).context("Failed to parse stored credential")?;
70
71 Ok(Some(credential))
72 }
73
74 pub fn delete_credential(&self) -> Result<()> {
76 if self.path.exists() {
77 fs::remove_file(&self.path).context("Failed to delete credential file")?;
78 }
79 Ok(())
80 }
81}