diff --git a/src/v3/mod.rs b/src/v3/mod.rs index 26c880c..ec0b5a5 100644 --- a/src/v3/mod.rs +++ b/src/v3/mod.rs @@ -41,7 +41,7 @@ pub struct Cacao { skip_serializing_if = "Option::is_none", default = "Option::default" )] - facts: Option, + facts: Option>, #[serde(rename = "s", bound = "S: VarSigTrait")] signature: VarSig, } @@ -80,7 +80,7 @@ impl Cacao { } pub fn facts(&self) -> Option<&F> { - self.facts.as_ref() + self.facts.as_ref().map(|f| &f.f) } pub fn signature(&self) -> &VarSig { @@ -101,7 +101,7 @@ impl Cacao { pub async fn verify(&self, verifier: &VE) -> Result<(), VE::Error> where - VE: CacaoVerifier, + VE: CacaoVerifier, NB: Send + Sync, { verifier.verify(self).await @@ -110,8 +110,14 @@ impl Cacao { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait CacaoVerifier { +pub trait CacaoVerifier { type Error: std::error::Error; - async fn verify(&self, cacao: &Cacao) -> Result<(), Self::Error>; + async fn verify(&self, cacao: &C) -> Result<(), Self::Error>; +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] +struct Flattener { + #[serde(flatten)] + pub f: T, } diff --git a/src/v3/payload.rs b/src/v3/payload.rs index 249c9b0..edc2af7 100644 --- a/src/v3/payload.rs +++ b/src/v3/payload.rs @@ -1,4 +1,4 @@ -use super::Cacao; +use super::{Cacao, Flattener}; use libipld::cid::Cid; use multidid::MultiDid; use serde::{Deserialize, Serialize}; @@ -7,9 +7,9 @@ use ucan_capabilities_object::Capabilities; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, Hash)] #[serde(deny_unknown_fields)] -pub struct Payload { +pub struct Payload { #[serde(rename = "iss")] - pub issuer: MultiDid, + pub issuer: I, #[serde(rename = "aud")] pub audience: MultiDid, #[serde(rename = "v")] @@ -34,8 +34,8 @@ pub struct Payload { pub facts: Option, } -impl Payload { - pub(crate) fn new(issuer: MultiDid, audience: MultiDid, version: V) -> Self { +impl Payload { + pub(crate) fn new(issuer: I, audience: MultiDid, version: V) -> Self { Self { issuer, audience, @@ -86,9 +86,9 @@ impl Payload { } #[derive(Debug, Clone, PartialEq, Serialize, Eq, Hash)] -pub(crate) struct BorrowedPayload<'a, V, F, NB> { +pub(crate) struct BorrowedPayload<'a, V, F, NB, I = MultiDid> { #[serde(rename = "iss")] - issuer: &'a MultiDid, + issuer: &'a I, #[serde(rename = "aud")] audience: &'a MultiDid, #[serde(rename = "v")] @@ -110,7 +110,7 @@ pub(crate) struct BorrowedPayload<'a, V, F, NB> { skip_serializing_if = "Option::is_none", default = "Option::default" )] - facts: &'a Option, + facts: Option>, } impl<'a, V, S, F, NB> From<&'a Cacao> for BorrowedPayload<'a, V, F, NB> { @@ -125,7 +125,7 @@ impl<'a, V, S, F, NB> From<&'a Cacao> for BorrowedPayload<'a, V, F, issued_at: &cacao.issued_at, not_before: &cacao.not_before, expiration: &cacao.expiration, - facts: &cacao.facts, + facts: cacao.facts.as_ref().map(|f| Flattener { f: &f.f }), } } } @@ -142,7 +142,7 @@ impl<'a, V, F, NB> From<&'a Payload> for BorrowedPayload<'a, V, F, NB> issued_at: &payload.issued_at, not_before: &payload.not_before, expiration: &payload.expiration, - facts: &payload.facts, + facts: payload.facts.as_ref().map(|f| Flattener { f }), } } } diff --git a/src/v3/recap_cacao.rs b/src/v3/recap_cacao.rs index 401a442..75441c6 100644 --- a/src/v3/recap_cacao.rs +++ b/src/v3/recap_cacao.rs @@ -1,4 +1,4 @@ -use super::{payload::Payload, Cacao, CacaoVerifier}; +use super::{payload::Payload, Cacao, CacaoVerifier, Flattener}; use async_trait::async_trait; use http::uri::Authority; use iri_string::types::UriString; @@ -119,14 +119,16 @@ where issued_at: Some(issued_at), not_before, expiration, - facts: Some(RecapFacts { - iat_info, - nbf_info, - exp_info, - domain: siwe.domain, - request_id: siwe.request_id, - resources, - statement, + facts: Some(Flattener { + f: RecapFacts { + iat_info, + nbf_info, + exp_info, + domain: siwe.domain, + request_id: siwe.request_id, + resources, + statement, + }, }), signature: VarSig::new(Ethereum::new(sig)), }) @@ -146,7 +148,7 @@ where Method::Pkh(DidPkhTypes::Eip155(eip155)) => eip155.into_inner(), m => return Err(Error::IncorrectDidType(m)), }; - let facts = cacao.facts.ok_or(Error::MissingFacts)?; + let facts = cacao.facts.ok_or(Error::MissingFacts)?.f; let mut cap = Capability::new().with_proofs(cacao.proof.unwrap_or_default().iter()); for (resource, actions) in cacao.attenuations.into_inner() { cap.with_actions(resource, actions); @@ -201,7 +203,7 @@ pub struct RecapVerify(()); #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl CacaoVerifier for RecapVerify +impl CacaoVerifier> for RecapVerify where NB: Send + Sync + Serialize + Clone, { @@ -232,7 +234,7 @@ impl Payload { issued_at: self.issued_at, not_before: self.not_before, expiration: self.expiration, - facts: self.facts, + facts: self.facts.map(|f| Flattener { f }), signature: VarSig::new(sig), } } diff --git a/src/v3/ucan_cacao.rs b/src/v3/ucan_cacao.rs index 4351d33..e8e8ba0 100644 --- a/src/v3/ucan_cacao.rs +++ b/src/v3/ucan_cacao.rs @@ -1,4 +1,4 @@ -use super::{payload::Payload, Cacao, CacaoVerifier}; +use super::{payload::Payload, Cacao, CacaoVerifier, Flattener}; use async_trait::async_trait; use multidid::MultiDid; use serde::{Deserialize, Serialize}; @@ -18,8 +18,8 @@ use varsig::{ }; pub type UcanSignature = JoseSig; -pub type UcanFacts = BTreeMap; -pub type UcanCacao = Cacao, NB>; +pub type UcanCacao, NB = Value> = + Cacao; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -37,7 +37,7 @@ impl From for Error { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl CacaoVerifier, NB> for &R +impl CacaoVerifier, NB>> for &R where R: DIDResolver, F: Send + Sync + for<'a> Deserialize<'a> + Serialize + Clone, @@ -45,14 +45,14 @@ where { type Error = Error; - async fn verify(&self, cacao: &UcanCacao) -> Result<(), Error> { + async fn verify(&self, cacao: &UcanCacao, NB>) -> Result<(), Error> { let ucan = Ucan::::from(cacao.clone()).encode()?; Ucan::::decode_and_verify_jwt(&ucan, *self, None).await?; Ok(()) } } -impl TryFrom> for UcanCacao { +impl TryFrom> for UcanCacao, NB> { type Error = Error; fn try_from(ucan: Ucan) -> Result { let (payload, signature) = ucan.into_inner(); @@ -66,7 +66,7 @@ impl TryFrom> for UcanCacao { issued_at: payload.issued_at, not_before: payload.not_before, expiration: payload.expiration, - facts: payload.facts, + facts: payload.facts.map(|f| Flattener { f }), signature: VarSig::new(match signature { Signature::ES256(sig) => JoseSig::Es256(Es256::new(sig)), Signature::ES512(sig) => JoseSig::Es512(Es512::new(sig)), @@ -79,8 +79,8 @@ impl TryFrom> for UcanCacao { } } -impl From> for Ucan { - fn from(cacao: UcanCacao) -> Self { +impl From, NB>> for Ucan { + fn from(cacao: UcanCacao, NB>) -> Self { let signature = match cacao.signature.into_inner() { JoseSig::EdDSA(s) => Signature::EdDSA(s.into_inner()), JoseSig::Es256(s) => Signature::ES256(s.into_inner()), @@ -96,7 +96,7 @@ impl From> for Ucan { payload.issued_at = cacao.issued_at; payload.not_before = cacao.not_before; payload.expiration = cacao.expiration; - payload.facts = cacao.facts; + payload.facts = cacao.facts.map(|f| f.f); payload.sign(signature) } } @@ -107,7 +107,7 @@ impl UcanCacao { } } -impl Payload, NB> { +impl Payload { pub fn sign(self, sig: UcanSignature) -> UcanCacao { Cacao { issuer: self.issuer, @@ -119,7 +119,7 @@ impl Payload, NB> { issued_at: self.issued_at, not_before: self.not_before, expiration: self.expiration, - facts: self.facts, + facts: self.facts.map(|f| Flattener { f }), signature: VarSig::new(sig), } } diff --git a/src/v3/webauthn.rs b/src/v3/webauthn.rs index 14cf1cc..613b3fe 100644 --- a/src/v3/webauthn.rs +++ b/src/v3/webauthn.rs @@ -1,4 +1,4 @@ -use super::{Cacao, CacaoVerifier}; +use super::{Cacao, CacaoVerifier, Flattener}; use async_trait::async_trait; use libipld::cid::{ multihash::{Code, Multihash, MultihashDigest}, @@ -44,7 +44,7 @@ pub enum Error { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl CacaoVerifier for &R +impl CacaoVerifier> for &R where R: DIDResolver, F: Send + Sync + for<'a> Deserialize<'a> + Serialize, @@ -184,7 +184,7 @@ impl Payload { issued_at: self.issued_at, not_before: self.not_before, expiration: self.expiration, - facts: self.facts, + facts: self.facts.map(|f| Flattener { f }), signature: VarSig::new(sig), } } @@ -224,7 +224,7 @@ pub(crate) struct BorrowedPayload<'a, F, NB> { skip_serializing_if = "Option::is_none", default = "Option::default" )] - facts: &'a Option, + facts: Option<&'a F>, } impl<'a, F, NB> BorrowedPayload<'a, F, NB> { @@ -255,7 +255,7 @@ impl<'a, F, NB> From<&'a WebauthnCacao> for BorrowedPayload<'a, F, NB> { issued_at: &cacao.issued_at, not_before: &cacao.not_before, expiration: &cacao.expiration, - facts: &cacao.facts, + facts: cacao.facts.as_ref().map(|f| &f.f), } } } @@ -271,7 +271,7 @@ impl<'a, F, NB> From<&'a Payload> for BorrowedPayload<'a, F, NB> { issued_at: &payload.issued_at, not_before: &payload.not_before, expiration: &payload.expiration, - facts: &payload.facts, + facts: payload.facts.as_ref(), } } }