Skip to main content

dot/auth/
mod.rs

1mod login;
2mod oauth;
3mod ui;
4
5pub use login::login_flow;
6
7use anyhow::{Context, Result};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::path::PathBuf;
11
12#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13pub struct Credentials {
14    pub providers: HashMap<String, ProviderCredential>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(tag = "type", rename_all = "snake_case")]
19pub enum ProviderCredential {
20    ApiKey {
21        key: String,
22    },
23    OAuth {
24        access_token: String,
25        refresh_token: Option<String>,
26        expires_at: Option<i64>,
27        api_key: Option<String>,
28    },
29}
30
31impl ProviderCredential {
32    pub fn api_key(&self) -> Option<&str> {
33        match self {
34            ProviderCredential::ApiKey { key } => Some(key.as_str()),
35            ProviderCredential::OAuth {
36                api_key: Some(k), ..
37            } => Some(k.as_str()),
38            ProviderCredential::OAuth { access_token, .. } => Some(access_token.as_str()),
39        }
40    }
41}
42
43impl Credentials {
44    fn path() -> PathBuf {
45        crate::config::Config::config_dir().join("credentials.json")
46    }
47
48    pub fn load() -> Result<Self> {
49        let path = Self::path();
50        if path.exists() {
51            let content = std::fs::read_to_string(&path).context("reading credentials file")?;
52            serde_json::from_str(&content).context("parsing credentials file")
53        } else {
54            Ok(Self::default())
55        }
56    }
57
58    pub fn save(&self) -> Result<()> {
59        let path = Self::path();
60        if let Some(parent) = path.parent() {
61            std::fs::create_dir_all(parent)?;
62        }
63        std::fs::write(&path, serde_json::to_string_pretty(self)?)
64            .context("writing credentials file")
65    }
66
67    pub fn get(&self, provider: &str) -> Option<&ProviderCredential> {
68        self.providers.get(provider)
69    }
70
71    pub fn set(&mut self, provider: &str, cred: ProviderCredential) {
72        self.providers.insert(provider.to_string(), cred);
73    }
74}