eero_api/credential/
file.rs1use std::path::PathBuf;
2
3use crate::error::{Error, Result};
4use crate::credential::CredentialStore;
5
6pub struct FileStore {
9 dir: PathBuf,
10}
11
12impl FileStore {
13 pub fn new() -> Result<Self> {
15 let dir = dirs::config_dir()
16 .ok_or_else(|| Error::CredentialStore("could not determine config directory".into()))?
17 .join("eero");
18 Ok(Self { dir })
19 }
20
21 pub fn with_dir(dir: PathBuf) -> Self {
23 Self { dir }
24 }
25
26 fn session_path(&self) -> PathBuf {
27 self.dir.join("session_token")
28 }
29
30 fn user_path(&self) -> PathBuf {
31 self.dir.join("user_token")
32 }
33
34 async fn read_token(&self, path: PathBuf) -> Result<Option<String>> {
35 match tokio::fs::read_to_string(&path).await {
36 Ok(contents) => {
37 let trimmed = contents.trim().to_string();
38 if trimmed.is_empty() {
39 Ok(None)
40 } else {
41 Ok(Some(trimmed))
42 }
43 }
44 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
45 Err(e) => Err(e.into()),
46 }
47 }
48
49 async fn write_token(&self, path: PathBuf, token: &str) -> Result<()> {
50 tokio::fs::create_dir_all(&self.dir).await?;
51 tokio::fs::write(&path, token).await?;
52 Ok(())
53 }
54
55 async fn delete_token(&self, path: PathBuf) -> Result<()> {
56 match tokio::fs::remove_file(&path).await {
57 Ok(()) => Ok(()),
58 Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
59 Err(e) => Err(e.into()),
60 }
61 }
62}
63
64#[async_trait::async_trait]
65impl CredentialStore for FileStore {
66 async fn get_session_token(&self) -> Result<Option<String>> {
67 self.read_token(self.session_path()).await
68 }
69
70 async fn set_session_token(&self, token: &str) -> Result<()> {
71 self.write_token(self.session_path(), token).await
72 }
73
74 async fn delete_session_token(&self) -> Result<()> {
75 self.delete_token(self.session_path()).await
76 }
77
78 async fn get_user_token(&self) -> Result<Option<String>> {
79 self.read_token(self.user_path()).await
80 }
81
82 async fn set_user_token(&self, token: &str) -> Result<()> {
83 self.write_token(self.user_path(), token).await
84 }
85
86 async fn delete_user_token(&self) -> Result<()> {
87 self.delete_token(self.user_path()).await
88 }
89}