bitbucket_cli/auth/
mod.rs1pub mod file_store;
2pub mod keyring_store;
3pub mod oauth;
4
5use anyhow::Result;
6use serde::{Deserialize, Serialize};
7
8pub use file_store::*;
9pub use keyring_store::*;
10pub use oauth::*;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub enum Credential {
15 OAuth {
16 access_token: String,
17 refresh_token: Option<String>,
18 expires_at: Option<i64>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 client_id: Option<String>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 client_secret: Option<String>,
23 },
24}
25
26impl Credential {
27 #[inline]
29 pub fn auth_header(&self) -> String {
30 match self {
31 Credential::OAuth { access_token, .. } => {
32 let mut result = String::with_capacity(7 + access_token.len());
33 result.push_str("Bearer ");
34 result.push_str(access_token);
35 result
36 }
37 }
38 }
39
40 #[inline]
42 pub fn type_name(&self) -> &'static str {
43 "OAuth 2.0"
44 }
45
46 #[inline]
48 pub fn needs_refresh(&self) -> bool {
49 match self {
50 Credential::OAuth {
51 expires_at: Some(expires),
52 ..
53 } => {
54 *expires < chrono::Utc::now().timestamp() + 300
56 }
57 _ => false,
58 }
59 }
60
61 pub fn oauth_consumer_credentials(&self) -> Option<(&str, &str)> {
63 match self {
64 Credential::OAuth {
65 client_id: Some(id),
66 client_secret: Some(secret),
67 ..
68 } => Some((id, secret)),
69 _ => None,
70 }
71 }
72}
73
74pub struct AuthManager {
76 store: FileStore,
77}
78
79impl AuthManager {
80 pub fn new() -> Result<Self> {
81 Ok(Self {
82 store: FileStore::new()?,
83 })
84 }
85
86 pub fn get_credentials(&self) -> Result<Option<Credential>> {
88 self.store.get_credential()
89 }
90
91 pub fn store_credentials(&self, credential: &Credential) -> Result<()> {
93 self.store.store_credential(credential)
94 }
95
96 pub fn clear_credentials(&self) -> Result<()> {
98 self.store.delete_credential()
99 }
100
101 pub fn is_authenticated(&self) -> bool {
103 self.get_credentials().map(|c| c.is_some()).unwrap_or(false)
104 }
105}
106
107impl Default for AuthManager {
108 fn default() -> Self {
109 Self::new().expect("Failed to create auth manager")
110 }
111}