use std::{pin::Pin, sync::Arc};
use crate::{
BoxedError, EndpointUrl,
crypto::{
KeyMatchStrength,
verifier::error::{CreateVerifierError, VerifyError},
},
jwk::PublicJwk,
platform::{MaybeSend, MaybeSendFuture, MaybeSendSync},
};
#[derive(Debug, Clone)]
pub struct BoxedJwsVerifier {
inner: Arc<dyn DynJwsVerifier>,
}
impl BoxedJwsVerifier {
pub fn new<V: JwsVerifier + std::fmt::Debug + 'static>(verifier: V) -> Self {
Self {
inner: Arc::new(verifier),
}
}
}
impl JwsVerifier for BoxedJwsVerifier {
type Error = BoxedError;
fn key_match(&self, key_match: &KeyMatch<'_>) -> Option<KeyMatchStrength> {
self.inner.key_match(key_match)
}
async fn verify(
&self,
input: &[u8],
signature: &[u8],
key_match: &KeyMatch<'_>,
) -> Result<(), VerifyError<BoxedError>> {
self.inner.verify(input, signature, key_match).await
}
async fn try_refresh(&self) -> bool {
self.inner.try_refresh().await
}
}
trait DynJwsVerifier: std::fmt::Debug + MaybeSendSync {
fn key_match(&self, key_match: &KeyMatch<'_>) -> Option<KeyMatchStrength>;
fn verify<'a>(
&'a self,
input: &'a [u8],
signature: &'a [u8],
key_match: &'a KeyMatch,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<(), VerifyError<BoxedError>>> + 'a>>;
fn try_refresh(&self) -> Pin<Box<dyn MaybeSendFuture<Output = bool> + '_>>;
}
impl<V: JwsVerifier + std::fmt::Debug> DynJwsVerifier for V {
fn key_match(&self, key_match: &KeyMatch<'_>) -> Option<KeyMatchStrength> {
JwsVerifier::key_match(self, key_match)
}
fn verify<'a>(
&'a self,
input: &'a [u8],
signature: &'a [u8],
key_match: &'a KeyMatch,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<(), VerifyError<BoxedError>>> + 'a>> {
Box::pin(async move {
JwsVerifier::verify(self, input, signature, key_match)
.await
.map_err(|err| match err {
VerifyError::NoMatchingKey => VerifyError::NoMatchingKey,
VerifyError::AmbiguousKeyMatch => VerifyError::AmbiguousKeyMatch,
VerifyError::SignatureMismatch => VerifyError::SignatureMismatch,
VerifyError::Other { source } => VerifyError::Other {
source: BoxedError::from_err(source),
},
})
})
}
fn try_refresh(&self) -> Pin<Box<dyn MaybeSendFuture<Output = bool> + '_>> {
Box::pin(JwsVerifier::try_refresh(self))
}
}
#[derive(Debug, Clone, Copy)]
pub struct KeyMatch<'a> {
pub alg: &'a str,
pub kid: Option<&'a str>,
}
pub trait JwsVerifier: MaybeSendSync {
type Error: crate::Error;
fn key_match(&self, key_match: &KeyMatch<'_>) -> Option<KeyMatchStrength>;
fn verify(
&self,
input: &[u8],
signature: &[u8],
key_match: &KeyMatch<'_>,
) -> impl Future<Output = Result<(), VerifyError<Self::Error>>> + MaybeSend;
fn try_refresh(&self) -> impl Future<Output = bool> + MaybeSend {
async { false }
}
}
pub trait JwsVerifierPlatform: std::fmt::Debug + MaybeSendSync {
fn create_verifier_from_jwk(
&self,
jwk: PublicJwk,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<BoxedJwsVerifier, CreateVerifierError>>>>;
}
pub trait JwsVerifierFactory: MaybeSendSync {
fn build(
&self,
jwks_uri: Option<&EndpointUrl>,
factory: Arc<dyn JwsVerifierPlatform>,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<BoxedJwsVerifier, BoxedError>>>>;
}
impl<F> JwsVerifierFactory for F
where
F: Fn(
Option<&EndpointUrl>,
Arc<dyn JwsVerifierPlatform>,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<BoxedJwsVerifier, BoxedError>>>>
+ MaybeSendSync,
{
fn build(
&self,
jwks_uri: Option<&EndpointUrl>,
factory: Arc<dyn JwsVerifierPlatform>,
) -> Pin<Box<dyn MaybeSendFuture<Output = Result<BoxedJwsVerifier, BoxedError>>>> {
self(jwks_uri, factory)
}
}