Skip to main content

dot/auth/
mod.rs

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