use serde::{Deserialize, Serialize};
use crate::oauth::OAuthCredential;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Credential {
Oauth(OAuthCredential),
Apikey { key: String },
}
impl Credential {
pub fn bearer_token(&self) -> &str {
match self {
Credential::Oauth(c) => c.id_token.as_deref().unwrap_or(&c.access_token),
Credential::Apikey { key } => key,
}
}
pub fn access_token(&self) -> &str {
match self {
Credential::Oauth(c) => &c.access_token,
Credential::Apikey { key } => key,
}
}
pub fn needs_refresh(&self) -> bool {
match self {
Credential::Oauth(c) => c.needs_refresh(),
Credential::Apikey { .. } => false,
}
}
pub fn email(&self) -> Option<&str> {
match self {
Credential::Oauth(c) => c.email.as_deref(),
Credential::Apikey { .. } => None,
}
}
pub fn has_refresh_token(&self) -> bool {
match self {
Credential::Oauth(c) => !c.refresh_token.is_empty(),
Credential::Apikey { .. } => false,
}
}
pub fn as_oauth(&self) -> Option<&OAuthCredential> {
match self {
Credential::Oauth(c) => Some(c),
Credential::Apikey { .. } => None,
}
}
pub fn as_oauth_mut(&mut self) -> Option<&mut OAuthCredential> {
match self {
Credential::Oauth(c) => Some(c),
Credential::Apikey { .. } => None,
}
}
pub fn masked_display(&self) -> String {
match self {
Credential::Oauth(c) => c.email.clone().unwrap_or_else(|| "oauth".to_owned()),
Credential::Apikey { key } => {
let suffix = &key[key.len().saturating_sub(4)..];
format!("···{suffix}")
}
}
}
}
impl From<OAuthCredential> for Credential {
fn from(c: OAuthCredential) -> Self {
Credential::Oauth(c)
}
}
pub fn deserialize_credential_map<'de, D>(
deserializer: D,
) -> Result<std::collections::HashMap<String, Credential>, D::Error>
where
D: serde::Deserializer<'de>,
{
use std::collections::HashMap;
let raw: HashMap<String, serde_json::Value> = HashMap::deserialize(deserializer)?;
let mut out = HashMap::with_capacity(raw.len());
for (k, v) in raw {
let cred = if v.get("type").is_some() {
serde_json::from_value::<Credential>(v).map_err(serde::de::Error::custom)?
} else {
serde_json::from_value::<OAuthCredential>(v)
.map(Credential::Oauth)
.map_err(serde::de::Error::custom)?
};
out.insert(k, cred);
}
Ok(out)
}