use core::fmt;
#[cfg(feature = "dev")]
use arbitrary::Arbitrary;
use meadowcap::DoesNotAuthorise;
use ufotofu::codec::{Blame, Decodable, DecodeError, Encodable};
use ufotofu::codec_relative::{RelativeDecodable, RelativeEncodable};
use willow_data_model::prelude as wdm;
use crate::prelude::*;
wrapper! {
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "dev", derive(Arbitrary))]
AuthorisationToken; meadowcap::McAuthorisationToken<MCL, MCC, MPL, NamespaceId, NamespaceSignature, SubspaceId, SubspaceSignature, SubspaceSecret>
}
impl fmt::Debug for AuthorisationToken {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl AuthorisationToken {
pub fn new(capability: WriteCapability, signature: SubspaceSignature) -> Self {
meadowcap::McAuthorisationToken::new(capability.into(), signature).into()
}
pub fn capability(&self) -> &WriteCapability {
self.0.capability().into()
}
pub fn signature(&self) -> &SubspaceSignature {
self.0.signature()
}
pub fn into_parts(self) -> (WriteCapability, SubspaceSignature) {
let (cap, sig) = self.0.into_parts();
(cap.into(), sig)
}
pub fn new_for_entry<E>(
entry: &E,
write_capability: &WriteCapability,
secret: &SubspaceSecret,
) -> Result<Self, DoesNotAuthorise>
where
E: EntrylikeExt + ?Sized,
{
match McIngredients::new(write_capability.clone(), secret.clone()) {
Some(ingredients) => wdm::AuthorisationToken::<
MCL,
MCC,
MPL,
NamespaceId,
SubspaceId,
PayloadDigest,
>::new_for_entry(entry, &ingredients),
None => Err(DoesNotAuthorise),
}
}
pub fn does_authorise<E>(&self, entry: &E) -> bool
where
E: wdm::EntrylikeExt<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest> + ?Sized,
{
wdm::AuthorisationToken::<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest>::does_authorise(&self.0, entry)
}
}
impl wdm::AuthorisationToken<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest>
for AuthorisationToken
{
type Ingredients = McIngredients;
type CreationError = DoesNotAuthorise;
fn new_for_entry<E>(
entry: &E,
ingredients: &Self::Ingredients,
) -> Result<Self, Self::CreationError>
where
E: wdm::EntrylikeExt<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest> + ?Sized,
{
meadowcap::McAuthorisationToken::<
MCL,
MCC,
MPL,
NamespaceId,
NamespaceSignature,
SubspaceId,
SubspaceSignature,
SubspaceSecret,
>::new_for_entry(entry, ingredients.into())
.map(Into::into)
}
fn does_authorise<E>(&self, entry: &E) -> bool
where
E: wdm::EntrylikeExt<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest> + ?Sized,
{
self.0.does_authorise(entry)
}
}
wrapper! {
#[derive(PartialEq, Eq, Clone)]
McIngredients; meadowcap::McIngredients<MCL, MCC, MPL, NamespaceId, NamespaceSignature, SubspaceId, SubspaceSignature, SubspaceSecret>
}
impl fmt::Debug for McIngredients {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl McIngredients {
pub fn capability(&self) -> &WriteCapability {
self.0.capability().into()
}
pub fn keypair(&self) -> &SubspaceSecret {
self.0.keypair()
}
pub fn into_parts(self) -> (WriteCapability, SubspaceSecret) {
let (cap, secret) = self.0.into_parts();
(cap.into(), secret)
}
pub fn new(capability: WriteCapability, secret: SubspaceSecret) -> Option<Self> {
meadowcap::McIngredients::<
MCL,
MCC,
MPL,
NamespaceId,
NamespaceSignature,
SubspaceId,
SubspaceSignature,
SubspaceSecret,
>::new(capability.into(), secret)
.map(Into::into)
}
}
#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "dev", derive(Arbitrary))]
pub struct PriorAuthedEntryEntryPair {
prior_authed_entry: AuthorisedEntry,
entry: Entry,
}
impl PriorAuthedEntryEntryPair {
pub fn new(prior_authed_entry: AuthorisedEntry, entry: Entry) -> Self {
Self {
prior_authed_entry,
entry,
}
}
pub fn prior_authed_entry(&self) -> &AuthorisedEntry {
&self.prior_authed_entry
}
pub fn entry(&self) -> &Entry {
&self.entry
}
}
impl RelativeEncodable<PriorAuthedEntryEntryPair> for AuthorisationToken {
async fn relative_encode<C>(
&self,
rel: &PriorAuthedEntryEntryPair,
consumer: &mut C,
) -> Result<(), C::Error>
where
C: ufotofu::BulkConsumer<Item = u8> + ?Sized,
{
let prev = &rel.prior_authed_entry;
let entry = &rel.entry;
let pair = crate::authorisation::PriorCapEntryPair::new(
prev.authorisation_token().capability().clone(),
entry.clone(),
);
self.capability().relative_encode(&pair, consumer).await?;
self.signature().encode(consumer).await?;
Ok(())
}
fn can_be_encoded_relative_to(&self, rel: &PriorAuthedEntryEntryPair) -> bool {
self.capability().granted_namespace() == rel.entry.namespace_id()
&& self.capability().granted_area().includes(&rel.entry)
}
}
impl RelativeDecodable<PriorAuthedEntryEntryPair> for AuthorisationToken {
type ErrorReason = Blame;
async fn relative_decode<P>(
rel: &PriorAuthedEntryEntryPair,
producer: &mut P,
) -> Result<Self, ufotofu::codec::DecodeError<P::Final, P::Error, Self::ErrorReason>>
where
P: ufotofu::BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
let prev = &rel.prior_authed_entry;
let entry = &rel.entry;
let pair = crate::authorisation::PriorCapEntryPair::new(
prev.authorisation_token().capability().clone(),
entry.clone(),
);
let write_cap = WriteCapability::relative_decode(&pair, producer).await?;
let signature = SubspaceSignature::decode(producer)
.await
.map_err(|_| DecodeError::Other(Blame::TheirFault))?;
Ok(Self::new(write_cap, signature))
}
}