use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde_json::Value;
use vta_sdk::sealed_transfer::ExternalCredentialPayload;
use crate::model::AccountRecord;
use crate::scope::RequestedScope;
pub struct IssueRequest<'a> {
pub account: &'a AccountRecord,
pub secret: Option<&'a str>,
pub scope: &'a RequestedScope,
pub ttl_seconds: u32,
pub source_cidrs: &'a [String],
pub now: DateTime<Utc>,
}
pub struct Issued {
pub credential: ExternalCredentialPayload,
pub expires_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SettingsError {
pub member: &'static str,
pub why: String,
}
impl SettingsError {
pub fn new(member: &'static str, why: impl Into<String>) -> Self {
Self {
member,
why: why.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DriverError {
SetupRequired(String),
Refused(String),
Unavailable(String),
Internal(String),
}
impl std::fmt::Display for DriverError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SetupRequired(m)
| Self::Refused(m)
| Self::Unavailable(m)
| Self::Internal(m) => f.write_str(m),
}
}
}
#[async_trait]
pub trait ExternalAuthDriver: Send + Sync {
fn model(&self) -> &'static str;
fn brokered(&self) -> bool;
fn holds_secret(&self) -> bool;
fn validate_settings(&self, settings: &Value) -> Result<(), SettingsError>;
fn egress_hosts(&self, settings: &Value) -> Vec<String>;
fn setup(&self, account: &AccountRecord) -> Value;
async fn issue(&self, req: IssueRequest<'_>) -> Result<Issued, DriverError>;
async fn probe(
&self,
account: &AccountRecord,
secret: Option<&str>,
http: &reqwest::Client,
now: DateTime<Utc>,
) -> Value;
}
pub fn driver_for(model: &str) -> Option<&'static dyn ExternalAuthDriver> {
static S3_PRESIGN: crate::s3_presign::S3StaticPresign = crate::s3_presign::S3StaticPresign;
match model {
"s3-static-presign" => Some(&S3_PRESIGN),
_ => None,
}
}
pub const SUPPORTED_MODELS: &[&str] = &["s3-static-presign"];
pub fn probe_client() -> &'static reqwest::Client {
static CLIENT: std::sync::OnceLock<reqwest::Client> = std::sync::OnceLock::new();
CLIENT.get_or_init(vta_sdk::http::foreign_fetch_client)
}