use anyhow::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
pub struct Creds {
pub client_id: String,
pub client_secret: String,
}
#[derive(Deserialize)]
pub struct TokenResponse {
pub access_token: String,
pub id_token: String,
#[serde(default)]
pub refresh_token: Option<String>,
pub expires_in: i64,
}
#[derive(Serialize)]
pub struct TokenOutput<'a> {
pub access_token: &'a str,
pub id_token: &'a str,
pub token_expiry: DateTime<Utc>,
}
#[derive(Serialize, Deserialize)]
pub struct SavedToken {
pub refresh_token: String,
pub access_token: String,
pub id_token: String,
pub token_expiry: DateTime<Utc>,
}
pub fn load_creds() -> Result<Creds> {
let path = dirs::home_dir()
.ok_or("Could not determine home directory")
.map_err(|_| anyhow::anyhow!("Home directory not found"))?
.join(".config/gcloud/application_default_credentials.json");
let creds = std::fs::read_to_string(path)?;
Ok(serde_json::from_str(&creds)?)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_valid_creds() {
let json = r#"{
"client_id": "abc123",
"client_secret": "secret"
}"#;
let creds: Creds = serde_json::from_str(json).unwrap();
assert_eq!(creds.client_id, "abc123");
}
#[test]
fn test_missing_field_fails() {
let json = r#"{
"client_id": "abc123"
}"#;
let result: Result<Creds, _> = serde_json::from_str(json);
assert!(result.is_err());
}
}