use std::{pin::Pin, sync::Arc};
use bon::Builder;
use http::HeaderMap;
use crate::{
BoxedError, EndpointUrl,
crypto::verifier::{
BoxedJwsVerifier, CreateVerifierError, JwsVerifierFactory, JwsVerifierPlatform,
MultiKeyVerifier, RetryingVerifier, ScheduledRefreshVerifier,
},
http::HttpClient,
jwk::PublicJwks,
platform::MaybeSendFuture,
};
#[derive(Builder, Debug, Clone)]
pub struct JwksSource<C: HttpClient + Clone + 'static> {
http_client: C,
}
impl<C: HttpClient + Clone + 'static> JwsVerifierFactory for JwksSource<C> {
fn build(
&self,
jwks_uri: Option<&EndpointUrl>,
platform: Arc<dyn JwsVerifierPlatform>,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<BoxedJwsVerifier, BoxedError>>>> {
let client = self.http_client.clone();
let Some(uri) = jwks_uri.cloned() else {
return Box::pin(async {
Err(BoxedError::from_err(CreateVerifierError::MissingJwksUri))
});
};
Box::pin(async move {
let refreshing = ScheduledRefreshVerifier::builder()
.factory(move || {
let client = client.clone();
let uri = uri.clone();
let platform = platform.clone();
Box::pin(async move {
let jwks: PublicJwks =
crate::http::get(&client, uri.as_uri().clone(), HeaderMap::new())
.await
.map_err(BoxedError::from_err)?;
MultiKeyVerifier::from_jwks(&jwks, platform.as_ref())
.await
.map_err(BoxedError::from_err)
})
})
.build()
.await?;
Ok(BoxedJwsVerifier::new(RetryingVerifier::new(refreshing)))
})
}
}