use core::fmt;
#[cfg(feature = "dev")]
use arbitrary::Arbitrary;
use signature::{Keypair, Signer};
use ufotofu::codec_prelude::*;
use crate::{
authorisation::raw::{
AccessMode, Delegation, Genesis, InvalidCapability, PossiblyValidReadCapability,
owned_genesis_data_to_sign,
},
prelude::*,
};
#[derive(Clone, PartialEq, Eq)]
pub struct ReadCapability {
pub(crate) inner: PossiblyValidReadCapability,
}
impl fmt::Debug for ReadCapability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReadCapability")
.field("genesis", &self.inner.inner.genesis)
.field("delegations", &self.inner.inner.delegations)
.finish()
}
}
impl ReadCapability {
pub fn receiver(&self) -> &SubspaceId {
self.inner.receiver()
}
pub fn granted_namespace(&self) -> &NamespaceId {
self.inner.granted_namespace()
}
pub fn granted_area_ref(&self) -> Option<&Area> {
self.inner.granted_area_ref()
}
pub fn genesis(&self) -> &Genesis {
self.inner.genesis()
}
pub fn is_owned(&self) -> bool {
self.inner.is_owned()
}
pub fn delegations(&self) -> &[Delegation] {
self.inner.delegations()
}
pub fn new_communal(namespace_key: NamespaceId, user_key: SubspaceId) -> Self {
Self {
inner: PossiblyValidReadCapability::new_communal(namespace_key, user_key),
}
}
pub fn new_owned<NamespaceKeypair>(keypair: &NamespaceKeypair, user_key: SubspaceId) -> Self
where
NamespaceKeypair: Signer<NamespaceSignature> + Keypair<VerifyingKey = NamespaceId>,
{
let data_to_sign = owned_genesis_data_to_sign(AccessMode::Read, &user_key);
let initial_authorisation = keypair.sign(&data_to_sign[..]);
Self {
inner: PossiblyValidReadCapability::new_owned(
keypair.verifying_key(),
user_key,
initial_authorisation,
),
}
}
pub fn includes_area(&self, area: &Area) -> bool {
self.inner.includes_area(area)
}
pub fn granted_area(&self) -> Area {
self.inner.granted_area()
}
pub fn includes<T>(&self, t: &T) -> bool
where
T: Namespaced + Coordinatelike + ?Sized,
{
self.inner.includes(t)
}
pub fn try_delegate<UserKeypair>(
&mut self,
keypair: &UserKeypair,
new_area: Area,
new_receiver: SubspaceId,
) -> Result<(), InvalidCapability>
where
UserKeypair: Signer<SubspaceSignature> + Keypair<VerifyingKey = SubspaceId>,
{
if !self.granted_area().includes_grouping(&new_area) {
return Err(InvalidCapability);
}
let handover =
self.inner
.inner
.create_handover(&new_area, &new_receiver, self.delegations().last());
let prev_receiver = self.receiver();
if prev_receiver != &keypair.verifying_key() {
return Err(InvalidCapability);
}
let signature = keypair.sign(&handover);
let delegation = Delegation {
area: new_area,
user: new_receiver,
signature,
};
self.inner.inner.delegations.push(delegation);
Ok(())
}
pub fn delegate<UserKeypair>(
&mut self,
keypair: &UserKeypair,
new_area: Area,
new_receiver: SubspaceId,
) where
UserKeypair: Signer<SubspaceSignature> + Keypair<VerifyingKey = SubspaceId>,
{
self.try_delegate(keypair, new_area, new_receiver).unwrap()
}
}
impl Encodable for ReadCapability {
async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
where
C: BulkConsumer<Item = u8> + ?Sized,
{
self.inner.encode(consumer).await
}
}
impl EncodableKnownLength for ReadCapability {
fn len_of_encoding(&self) -> usize {
self.inner.len_of_encoding()
}
}
impl Decodable for ReadCapability {
type ErrorReason = Blame;
async fn decode<P>(
producer: &mut P,
) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
where
P: BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
let decoded: PossiblyValidReadCapability = producer.produce_decoded().await?;
if decoded.is_valid() {
Ok(Self { inner: decoded })
} else {
Err(DecodeError::Other(Blame::TheirFault))
}
}
}
impl DecodableCanonic for ReadCapability {
type ErrorCanonic = Blame;
async fn decode_canonic<P>(
producer: &mut P,
) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
where
P: BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
let decoded: PossiblyValidReadCapability = producer.produce_decoded_canonic().await?;
if decoded.is_valid() {
Ok(Self { inner: decoded })
} else {
Err(DecodeError::Other(Blame::TheirFault))
}
}
}
#[cfg(feature = "dev")]
impl<'a> Arbitrary<'a> for ReadCapability {
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let inner_cap: PossiblyValidReadCapability = Arbitrary::arbitrary(u)?;
if inner_cap.is_valid() {
Ok(Self { inner: inner_cap })
} else {
Err(arbitrary::Error::IncorrectFormat)
}
}
}