From 8522b55a0fd1e95528593796f57a9d1c16ee483f Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Fri, 23 Feb 2024 22:59:56 -0800 Subject: [PATCH 1/2] In theory, that's fully updated --- src/ability/arguments.rs | 32 +- src/ability/crud.rs | 198 ++++++------- src/ability/crud/create.rs | 102 +++---- src/ability/crud/destroy.rs | 102 +++---- src/ability/crud/read.rs | 78 ++--- src/ability/crud/update.rs | 129 ++++---- src/ability/dynamic.rs | 44 +-- src/ability/msg.rs | 141 +-------- src/ability/msg/receive.rs | 64 ++-- src/ability/msg/send.rs | 213 +++----------- src/ability/preset.rs | 143 ++------- src/ability/ucan/revoke.rs | 144 ++++----- src/ability/wasm/run.rs | 105 +------ src/delegation.rs | 106 +++---- src/delegation/agent.rs | 55 ++-- src/delegation/delegable.rs | 102 +++---- src/delegation/payload.rs | 421 ++------------------------- src/delegation/store/memory.rs | 64 ++-- src/delegation/store/traits.rs | 27 +- src/invocation.rs | 2 +- src/invocation/agent.rs | 110 ++++--- src/invocation/payload.rs | 117 +++++--- src/invocation/promise/resolvable.rs | 65 +---- src/lib.rs | 2 +- src/proof.rs | 16 +- src/url.rs | 24 +- 26 files changed, 883 insertions(+), 1723 deletions(-) diff --git a/src/ability/arguments.rs b/src/ability/arguments.rs index 0e96c6ef..6137a358 100644 --- a/src/ability/arguments.rs +++ b/src/ability/arguments.rs @@ -9,19 +9,19 @@ use libipld_core::ipld::Ipld; use std::collections::BTreeMap; // FIXME move under invoc::promise? -pub type Promised = Resolves>; - -impl Promised { - pub fn try_resolve_option(self) -> Option> { - match self.try_resolve() { - Err(_) => None, - Ok(named_promises) => named_promises - .iter() - .try_fold(BTreeMap::new(), |mut map, (k, v)| { - map.insert(k.clone(), Ipld::try_from(v.clone()).ok()?); - Some(map) - }) - .map(Named), - } - } -} +// pub type Promised = Resolves>; +// +// impl Promised { +// pub fn try_resolve_option(self) -> Option> { +// match self.try_resolve() { +// Err(_) => None, +// Ok(named_promises) => named_promises +// .iter() +// .try_fold(BTreeMap::new(), |mut map, (k, v)| { +// map.insert(k.clone(), Ipld::try_from(v.clone()).ok()?); +// Some(map) +// }) +// .map(Named), +// } +// } +// } diff --git a/src/ability/crud.rs b/src/ability/crud.rs index 1e1ab5df..57df163c 100644 --- a/src/ability/crud.rs +++ b/src/ability/crud.rs @@ -37,19 +37,19 @@ //! [CRUD]: https://en.wikipedia.org/wiki/Create,_read,_update_and_delete //! [`Did`]: crate::did::Did -mod any; -mod mutate; -mod parents; +// mod any; +// mod mutate; +// mod parents; pub mod create; pub mod destroy; -pub mod error; +// pub mod error; pub mod read; pub mod update; -pub use any::Any; -pub use mutate::Mutate; -pub use parents::*; +// pub use any::Any; +// pub use mutate::Mutate; +// pub use parents::*; use crate::{ ability::{ @@ -57,10 +57,8 @@ use crate::{ command::ToCommand, parse::{ParseAbility, ParseAbilityError, ParsePromised}, }, - delegation::Delegable, invocation::promise::Resolvable, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; @@ -75,14 +73,6 @@ pub enum Ready { Destroy(destroy::Ready), } -#[derive(Debug, Clone, PartialEq)] -pub enum Builder { - Create(create::Ready), - Read(read::Ready), - Update(update::Builder), - Destroy(destroy::Ready), -} - #[derive(Debug, Clone, PartialEq)] pub enum Promised { Create(create::Promised), @@ -134,11 +124,7 @@ impl ParsePromised for Promised { } } -impl Delegable for Ready { - type Builder = Builder; -} - -impl ParseAbility for Builder { +impl ParseAbility for Ready { type ArgsErr = (); fn try_parse( @@ -146,7 +132,7 @@ impl ParseAbility for Builder { args: arguments::Named, ) -> Result> { match create::Ready::try_parse(cmd, args.clone()) { - Ok(create) => return Ok(Builder::Create(create)), + Ok(create) => return Ok(Ready::Create(create)), Err(ParseAbilityError::InvalidArgs(_)) => { return Err(ParseAbilityError::InvalidArgs(())); } @@ -154,15 +140,15 @@ impl ParseAbility for Builder { } match read::Ready::try_parse(cmd, args.clone()) { - Ok(read) => return Ok(Builder::Read(read)), + Ok(read) => return Ok(Ready::Read(read)), Err(ParseAbilityError::InvalidArgs(_)) => { return Err(ParseAbilityError::InvalidArgs(())); } Err(ParseAbilityError::UnknownCommand(_)) => (), } - match update::Builder::try_parse(cmd, args.clone()) { - Ok(update) => return Ok(Builder::Update(update)), + match update::Ready::try_parse(cmd, args.clone()) { + Ok(update) => return Ok(Ready::Update(update)), Err(ParseAbilityError::InvalidArgs(_)) => { return Err(ParseAbilityError::InvalidArgs(())); } @@ -170,7 +156,7 @@ impl ParseAbility for Builder { } match destroy::Ready::try_parse(cmd, args) { - Ok(destroy) => return Ok(Builder::Destroy(destroy)), + Ok(destroy) => return Ok(Ready::Destroy(destroy)), Err(ParseAbilityError::InvalidArgs(_)) => { return Err(ParseAbilityError::InvalidArgs(())); } @@ -180,10 +166,10 @@ impl ParseAbility for Builder { Err(ParseAbilityError::UnknownCommand(cmd.into())) } } - -impl Checkable for Builder { - type Hierarchy = Parentful; -} +// +// impl Checkable for Builder { +// type Hierarchy = Parentful; +// } impl ToCommand for Ready { fn to_command(&self) -> String { @@ -207,44 +193,44 @@ impl ToCommand for Promised { } } -impl ToCommand for Builder { - fn to_command(&self) -> String { - match self { - Builder::Create(create) => create.to_command(), - Builder::Read(read) => read.to_command(), - Builder::Update(update) => update.to_command(), - Builder::Destroy(destroy) => destroy.to_command(), - } - } -} - -impl CheckParents for Builder { - type Parents = MutableParents; - type ParentError = (); // FIXME - - fn check_parent(&self, parents: &MutableParents) -> Result<(), Self::ParentError> { - match self { - Builder::Create(create) => create.check_parent(parents.into()).map_err(|_| ()), - Builder::Update(update) => update.check_parent(parents.into()).map_err(|_| ()), - Builder::Destroy(destroy) => destroy.check_parent(parents.into()).map_err(|_| ()), - Builder::Read(read) => match parents { - MutableParents::Any(crud_any) => read.check_parent(crud_any).map_err(|_| ()), - _ => Err(()), - }, - } - } -} - -impl From for arguments::Named { - fn from(builder: Builder) -> Self { - match builder { - Builder::Create(create) => create.into(), - Builder::Read(read) => read.into(), - Builder::Update(update) => update.into(), - Builder::Destroy(destroy) => destroy.into(), - } - } -} +// impl ToCommand for Builder { +// fn to_command(&self) -> String { +// match self { +// Builder::Create(create) => create.to_command(), +// Builder::Read(read) => read.to_command(), +// Builder::Update(update) => update.to_command(), +// Builder::Destroy(destroy) => destroy.to_command(), +// } +// } +// } +// +// impl CheckParents for Builder { +// type Parents = MutableParents; +// type ParentError = (); // FIXME +// +// fn check_parent(&self, parents: &MutableParents) -> Result<(), Self::ParentError> { +// match self { +// Builder::Create(create) => create.check_parent(parents.into()).map_err(|_| ()), +// Builder::Update(update) => update.check_parent(parents.into()).map_err(|_| ()), +// Builder::Destroy(destroy) => destroy.check_parent(parents.into()).map_err(|_| ()), +// Builder::Read(read) => match parents { +// MutableParents::Any(crud_any) => read.check_parent(crud_any).map_err(|_| ()), +// _ => Err(()), +// }, +// } +// } +// } +// +// impl From for arguments::Named { +// fn from(builder: Builder) -> Self { +// match builder { +// Builder::Create(create) => create.into(), +// Builder::Read(read) => read.into(), +// Builder::Update(update) => update.into(), +// Builder::Destroy(destroy) => destroy.into(), +// } +// } +// } // impl From for arguments::Named { // fn from(promised: Promised) -> Self { @@ -257,43 +243,43 @@ impl From for arguments::Named { // } // } -impl From for Builder { - fn from(ready: Ready) -> Self { - match ready { - Ready::Create(create) => Builder::Create(create.into()), - Ready::Read(read) => Builder::Read(read.into()), - Ready::Update(update) => Builder::Update(update.into()), - Ready::Destroy(destroy) => Builder::Destroy(destroy.into()), - } - } -} - -impl TryFrom for Ready { - type Error = (); // FIXME - - fn try_from(builder: Builder) -> Result { - match builder { - Builder::Create(create) => create.try_into().map(Ready::Create).map_err(|_| ()), - Builder::Read(read) => read.try_into().map(Ready::Read).map_err(|_| ()), - Builder::Update(update) => update.try_into().map(Ready::Update).map_err(|_| ()), - Builder::Destroy(destroy) => destroy.try_into().map(Ready::Destroy).map_err(|_| ()), - } - } -} - -impl CheckSame for Builder { - type Error = (); - - fn check_same(&self, other: &Self) -> Result<(), Self::Error> { - match (self, other) { - (Builder::Create(a), Builder::Create(b)) => a.check_same(b), - (Builder::Read(a), Builder::Read(b)) => a.check_same(b), - (Builder::Update(a), Builder::Update(b)) => a.check_same(b), - (Builder::Destroy(a), Builder::Destroy(b)) => a.check_same(b), - _ => Err(()), - } - } -} +// impl From for Builder { +// fn from(ready: Ready) -> Self { +// match ready { +// Ready::Create(create) => Builder::Create(create.into()), +// Ready::Read(read) => Builder::Read(read.into()), +// Ready::Update(update) => Builder::Update(update.into()), +// Ready::Destroy(destroy) => Builder::Destroy(destroy.into()), +// } +// } +// } +// +// impl TryFrom for Ready { +// type Error = (); // FIXME +// +// fn try_from(builder: Builder) -> Result { +// match builder { +// Builder::Create(create) => create.try_into().map(Ready::Create).map_err(|_| ()), +// Builder::Read(read) => read.try_into().map(Ready::Read).map_err(|_| ()), +// Builder::Update(update) => update.try_into().map(Ready::Update).map_err(|_| ()), +// Builder::Destroy(destroy) => destroy.try_into().map(Ready::Destroy).map_err(|_| ()), +// } +// } +// } +// +// impl CheckSame for Builder { +// type Error = (); +// +// fn check_same(&self, other: &Self) -> Result<(), Self::Error> { +// match (self, other) { +// (Builder::Create(a), Builder::Create(b)) => a.check_same(b), +// (Builder::Read(a), Builder::Read(b)) => a.check_same(b), +// (Builder::Update(a), Builder::Update(b)) => a.check_same(b), +// (Builder::Destroy(a), Builder::Destroy(b)) => a.check_same(b), +// _ => Err(()), +// } +// } +// } impl Resolvable for Ready { type Promised = Promised; diff --git a/src/ability/crud/create.rs b/src/ability/crud/create.rs index ae8a5b64..baa417cc 100644 --- a/src/ability/crud/create.rs +++ b/src/ability/crud/create.rs @@ -1,11 +1,11 @@ //! Create new resources. -use super::parents::MutableParents; +// use super::parents::MutableParents; use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::{promise, promise::Resolves}, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + // proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; use serde::Serialize; @@ -202,55 +202,55 @@ impl TryFrom> for Ready { } } -impl Delegable for Ready { - type Builder = Ready; -} - -impl Checkable for Ready { - type Hierarchy = Parentful; -} - -impl CheckSame for Ready { - type Error = (); // FIXME better error - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if self.path == proof.path { - Ok(()) - } else { - Err(()) - } - } -} - -impl CheckParents for Ready { - type Parents = MutableParents; - type ParentError = (); // FIXME - - fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { - if let Some(self_path) = &self.path { - match other { - MutableParents::Any(any) => { - // FIXME check the args, too! - if let Some(proof_path) = &any.path { - if self_path != proof_path { - return Err(()); - } - } - } - MutableParents::Mutate(mutate) => { - // FIXME check the args, too! - if let Some(proof_path) = &mutate.path { - if self_path != proof_path { - return Err(()); - } - } - } - } - } +// impl Delegable for Ready { +// type Builder = Ready; +// } - Ok(()) - } -} +// impl Checkable for Ready { +// type Hierarchy = Parentful; +// } +// +// impl CheckSame for Ready { +// type Error = (); // FIXME better error +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// if self.path == proof.path { +// Ok(()) +// } else { +// Err(()) +// } +// } +// } +// +// impl CheckParents for Ready { +// type Parents = MutableParents; +// type ParentError = (); // FIXME +// +// fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { +// if let Some(self_path) = &self.path { +// match other { +// MutableParents::Any(any) => { +// // FIXME check the args, too! +// if let Some(proof_path) = &any.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// MutableParents::Mutate(mutate) => { +// // FIXME check the args, too! +// if let Some(proof_path) = &mutate.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// } +// } +// +// Ok(()) +// } +// } // impl From for arguments::Named { // fn from(promised: Promised) -> Self { diff --git a/src/ability/crud/destroy.rs b/src/ability/crud/destroy.rs index a5d48571..e43123cb 100644 --- a/src/ability/crud/destroy.rs +++ b/src/ability/crud/destroy.rs @@ -1,12 +1,12 @@ //! Destroy a resource. -use super::parents::MutableParents; +// use super::parents::MutableParents; use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::promise, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + // proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; use serde::Serialize; @@ -143,9 +143,9 @@ impl Command for Promised { const COMMAND: &'static str = COMMAND; } -impl Delegable for Ready { - type Builder = Ready; -} +// impl Delegable for Ready { +// type Builder = Ready; +// } impl TryFrom> for Ready { type Error = (); // FIXME @@ -168,49 +168,49 @@ impl TryFrom> for Ready { } } -impl Checkable for Ready { - type Hierarchy = Parentful; -} - -impl CheckSame for Ready { - type Error = (); // FIXME better error - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if self.path == proof.path { - Ok(()) - } else { - Err(()) - } - } -} - -impl CheckParents for Ready { - type Parents = MutableParents; - type ParentError = (); // FIXME - - fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { - if let Some(self_path) = &self.path { - match other { - MutableParents::Any(any) => { - if let Some(proof_path) = &any.path { - if self_path != proof_path { - return Err(()); - } - } - } - MutableParents::Mutate(mutate) => { - if let Some(proof_path) = &mutate.path { - if self_path != proof_path { - return Err(()); - } - } - } - } - } - - Ok(()) - } -} +// impl Checkable for Ready { +// type Hierarchy = Parentful; +// } +// +// impl CheckSame for Ready { +// type Error = (); // FIXME better error +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// if self.path == proof.path { +// Ok(()) +// } else { +// Err(()) +// } +// } +// } +// +// impl CheckParents for Ready { +// type Parents = MutableParents; +// type ParentError = (); // FIXME +// +// fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { +// if let Some(self_path) = &self.path { +// match other { +// MutableParents::Any(any) => { +// if let Some(proof_path) = &any.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// MutableParents::Mutate(mutate) => { +// if let Some(proof_path) = &mutate.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// } +// } +// +// Ok(()) +// } +// } impl From for arguments::Named { fn from(promised: Promised) -> Self { @@ -265,10 +265,10 @@ impl From for Ready { } impl From for arguments::Named { - fn from(builder: Ready) -> Self { + fn from(ready: Ready) -> Self { let mut named = arguments::Named::new(); - if let Some(path) = builder.path { + if let Some(path) = ready.path { named.insert( "path".to_string(), path.into_os_string() diff --git a/src/ability/crud/read.rs b/src/ability/crud/read.rs index 57001d8c..b9201b26 100644 --- a/src/ability/crud/read.rs +++ b/src/ability/crud/read.rs @@ -1,12 +1,12 @@ //! Read from a resource. -use super::any as crud; +// use super::any as crud; use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::promise, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + // proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::{error::SerdeError, ipld::Ipld, serde as ipld_serde}; use serde::{Deserialize, Serialize}; @@ -157,9 +157,9 @@ impl Command for Promised { const COMMAND: &'static str = COMMAND; } -impl Delegable for Ready { - type Builder = Ready; -} +// impl Delegable for Ready { +// type Builder = Ready; +// } // FIXME resolves vs resolvable is confusing @@ -220,39 +220,39 @@ impl TryFrom> for Ready { } } -impl Checkable for Ready { - type Hierarchy = Parentful; -} - -impl CheckSame for Ready { - type Error = (); // FIXME better error - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if self.path == proof.path { - Ok(()) - } else { - Err(()) - } - } -} - -impl CheckParents for Ready { - type Parents = crud::Any; - type ParentError = (); // FIXME - - fn check_parent(&self, other: &crud::Any) -> Result<(), Self::ParentError> { - if let Some(self_path) = &self.path { - // FIXME check the args, too! - if let Some(proof_path) = &other.path { - if self_path != proof_path { - return Err(()); - } - } - } - - Ok(()) - } -} +// impl Checkable for Ready { +// type Hierarchy = Parentful; +// } +// +// impl CheckSame for Ready { +// type Error = (); // FIXME better error +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// if self.path == proof.path { +// Ok(()) +// } else { +// Err(()) +// } +// } +// } +// +// impl CheckParents for Ready { +// type Parents = crud::Any; +// type ParentError = (); // FIXME +// +// fn check_parent(&self, other: &crud::Any) -> Result<(), Self::ParentError> { +// if let Some(self_path) = &self.path { +// // FIXME check the args, too! +// if let Some(proof_path) = &other.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// +// Ok(()) +// } +// } impl promise::Resolvable for Ready { type Promised = Promised; diff --git a/src/ability/crud/update.rs b/src/ability/crud/update.rs index 305855e6..54863a76 100644 --- a/src/ability/crud/update.rs +++ b/src/ability/crud/update.rs @@ -1,11 +1,11 @@ //! Update existing resources. -use super::parents::MutableParents; +// use super::parents::MutableParents; use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::{promise, promise::Resolves}, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + // proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; use serde::Serialize; @@ -200,15 +200,38 @@ impl TryFrom> for Promised { } } -impl Delegable for Ready { - type Builder = Builder; -} +// impl Delegable for Ready { +// type Builder = Builder; +// } impl TryFrom> for Ready { type Error = (); fn try_from(named: arguments::Named) -> Result { - Self::try_from_named(named).map_err(|_| ()) + let mut path = None; + let mut args = None; + + for (key, ipld) in named { + match key.as_str() { + "path" => { + if let Ipld::String(s) = ipld { + path = Some(PathBuf::from(s)); + } else { + return Err(()); + } + } + "args" => { + if let Ipld::Map(map) = ipld { + args = Some(arguments::Named(map)); + } else { + return Err(()); + } + } + _ => return Err(()), + } + } + + Ok(Ready { path, args }) } } @@ -293,51 +316,51 @@ impl TryFrom for Ready { } } -impl Checkable for Builder { - type Hierarchy = Parentful; -} - -impl CheckSame for Builder { - type Error = (); // FIXME better error - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if self.path == proof.path { - Ok(()) - } else { - Err(()) - } - } -} - -impl CheckParents for Builder { - type Parents = MutableParents; - type ParentError = (); // FIXME - - fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { - if let Some(self_path) = &self.path { - match other { - MutableParents::Any(any) => { - // FIXME check the args, too! - if let Some(proof_path) = &any.path { - if self_path != proof_path { - return Err(()); - } - } - } - MutableParents::Mutate(mutate) => { - // FIXME check the args, too! - if let Some(proof_path) = &mutate.path { - if self_path != proof_path { - return Err(()); - } - } - } - } - } - - Ok(()) - } -} +// impl Checkable for Builder { +// type Hierarchy = Parentful; +// } +// +// impl CheckSame for Builder { +// type Error = (); // FIXME better error +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// if self.path == proof.path { +// Ok(()) +// } else { +// Err(()) +// } +// } +// } +// +// impl CheckParents for Builder { +// type Parents = MutableParents; +// type ParentError = (); // FIXME +// +// fn check_parent(&self, other: &Self::Parents) -> Result<(), Self::ParentError> { +// if let Some(self_path) = &self.path { +// match other { +// MutableParents::Any(any) => { +// // FIXME check the args, too! +// if let Some(proof_path) = &any.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// MutableParents::Mutate(mutate) => { +// // FIXME check the args, too! +// if let Some(proof_path) = &mutate.path { +// if self_path != proof_path { +// return Err(()); +// } +// } +// } +// } +// } +// +// Ok(()) +// } +// } impl From for arguments::Named { fn from(promised: Promised) -> Self { @@ -390,7 +413,7 @@ impl From for Builder { fn from(promised: Promised) -> Self { Builder { path: promised.path.and_then(|p| p.try_resolve().ok()), - args: promised.args.and_then(|a| a.try_resolve_option()), + args: todo!(), // promised.args.and_then(|a| a.try_resolve_option()), } } } diff --git a/src/ability/dynamic.rs b/src/ability/dynamic.rs index a665a7aa..441c1565 100644 --- a/src/ability/dynamic.rs +++ b/src/ability/dynamic.rs @@ -5,7 +5,7 @@ use super::{ command::ToCommand, parse::{ParseAbility, ParseAbilityError}, }; -use crate::proof::same::CheckSame; +// use crate::proof::same::CheckSame; use libipld_core::{error::SerdeError, ipld::Ipld, serde as ipld_serde}; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -118,27 +118,27 @@ impl TryFrom for Dynamic { } } -impl CheckSame for Dynamic { - type Error = String; // FIXME better err - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if self.cmd != proof.cmd { - return Err("Command mismatch".into()); - } - - self.args.0.iter().try_for_each(|(k, v)| { - if let Some(proof_v) = proof.args.get(k) { - if v != proof_v { - return Err("arguments::Named mismatch".into()); - } - } else { - return Err("arguments::Named mismatch".into()); - } - - Ok(()) - }) - } -} +// impl CheckSame for Dynamic { +// type Error = String; // FIXME better err +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// if self.cmd != proof.cmd { +// return Err("Command mismatch".into()); +// } +// +// self.args.0.iter().try_for_each(|(k, v)| { +// if let Some(proof_v) = proof.args.get(k) { +// if v != proof_v { +// return Err("arguments::Named mismatch".into()); +// } +// } else { +// return Err("arguments::Named mismatch".into()); +// } +// +// Ok(()) +// }) +// } +// } impl From for Ipld { fn from(dynamic: Dynamic) -> Self { diff --git a/src/ability/msg.rs b/src/ability/msg.rs index 4fa01bed..e1d90481 100644 --- a/src/ability/msg.rs +++ b/src/ability/msg.rs @@ -1,22 +1,16 @@ //! Message abilities -mod any; - pub mod receive; pub mod send; -pub use any::Any; - use crate::{ ability::{ arguments, command::ToCommand, parse::{ParseAbility, ParseAbilityError, ParsePromised}, }, - delegation::Delegable, invocation::promise::Resolvable, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; @@ -27,22 +21,12 @@ pub enum Ready { Receive(receive::Receive), } -#[derive(Debug, Clone, PartialEq)] -pub enum Builder { - Send(send::Builder), - Receive(receive::Receive), -} - #[derive(Debug, Clone, PartialEq)] pub enum Promised { Send(send::Promised), Receive(receive::Promised), } -impl Delegable for Ready { - type Builder = Builder; -} - impl ToCommand for Ready { fn to_command(&self) -> String { match self { @@ -52,15 +36,6 @@ impl ToCommand for Ready { } } -impl ToCommand for Builder { - fn to_command(&self) -> String { - match self { - Builder::Send(send) => send.to_command(), - Builder::Receive(receive) => receive.to_command(), - } - } -} - impl ToCommand for Promised { fn to_command(&self) -> String { match self { @@ -89,72 +64,6 @@ impl ParsePromised for Promised { } } -// impl ParseAbility for Ready { -// type ArgsErr = (); -// -// fn try_parse( -// cmd: &str, -// args: arguments::Named, -// ) -> Result> { -// match send::Ready::try_parse(cmd, args.clone()) { -// Ok(send) => return Ok(Ready::Send(send)), -// Err(ParseAbilityError::InvalidArgs(args)) => { -// return Err(ParseAbilityError::InvalidArgs(())) -// } -// Err(ParseAbilityError::UnknownCommand(_)) => {} -// } -// -// match receive::Receive::try_parse(cmd, args) { -// Ok(receive) => return Ok(Ready::Receive(receive)), -// Err(ParseAbilityError::InvalidArgs(args)) => { -// return Err(ParseAbilityError::InvalidArgs(())) -// } -// Err(ParseAbilityError::UnknownCommand(cmd)) => {} -// } -// -// Err(ParseAbilityError::UnknownCommand(cmd.to_string())) -// } -// } - -impl ParseAbility for Builder { - type ArgsErr = (); - - fn try_parse( - cmd: &str, - args: arguments::Named, - ) -> Result> { - if let Ok(send) = send::Builder::try_parse(cmd, args.clone()) { - return Ok(Builder::Send(send)); - } - - if let Ok(receive) = receive::Receive::try_parse(cmd, args) { - return Ok(Builder::Receive(receive)); - } - - Err(ParseAbilityError::UnknownCommand(cmd.to_string())) - } -} - -impl TryFrom for Ready { - type Error = (); - - fn try_from(builder: Builder) -> Result { - match builder { - Builder::Send(send) => send.try_into().map(Ready::Send).map_err(|_| ()), - Builder::Receive(receive) => Ok(Ready::Receive(receive)), - } - } -} - -impl From for Builder { - fn from(ready: Ready) -> Self { - match ready { - Ready::Send(send) => Builder::Send(send.into()), - Ready::Receive(receive) => Builder::Receive(receive.into()), - } - } -} - impl From for arguments::Named { fn from(promised: Promised) -> Self { match promised { @@ -168,48 +77,30 @@ impl Resolvable for Ready { type Promised = Promised; } -impl CheckSame for Builder { - type Error = (); // FIXME - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - match (self, proof) { - (Builder::Send(this), Builder::Send(that)) => this.check_same(that), - (Builder::Receive(this), Builder::Receive(that)) => this.check_same(that), - _ => Err(()), +impl From for arguments::Named { + fn from(promised: Promised) -> Self { + match promised { + Promised::Send(send) => send.into(), + Promised::Receive(receive) => receive.into(), } } } -impl CheckParents for Builder { - type Parents = Any; - type ParentError = (); +impl ParseAbility for Ready { + type ArgsErr = (); - fn check_parent(&self, proof: &Any) -> Result<(), Self::ParentError> { - match (self, proof) { - (Builder::Send(this), any) => this.check_parent(&any), - (Builder::Receive(this), any) => this.check_parent(&any), + fn try_parse( + cmd: &str, + args: arguments::Named, + ) -> Result> { + if let Ok(send) = send::Ready::try_parse(cmd, args.clone()) { + return Ok(Ready::Send(send)); } - } -} - -impl Checkable for Builder { - type Hierarchy = Parentful; -} -impl From for arguments::Named { - fn from(builder: Builder) -> Self { - match builder { - Builder::Send(send) => send.into(), - Builder::Receive(receive) => receive.into(), + if let Ok(receive) = receive::Receive::try_parse(cmd, args) { + return Ok(Ready::Receive(receive)); } - } -} -impl From for arguments::Named { - fn from(promised: Promised) -> Self { - match promised { - Promised::Send(send) => send.into(), - Promised::Receive(receive) => receive.into(), - } + Err(ParseAbilityError::UnknownCommand(cmd.to_string())) } } diff --git a/src/ability/msg/receive.rs b/src/ability/msg/receive.rs index 19373830..1b0e817b 100644 --- a/src/ability/msg/receive.rs +++ b/src/ability/msg/receive.rs @@ -2,10 +2,10 @@ use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::promise, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + // proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, url, }; use libipld_core::{error::SerdeError, ipld::Ipld, serde as ipld_serde}; @@ -59,9 +59,9 @@ impl Command for Promised { const COMMAND: &'static str = COMMAND; } -impl Delegable for Receive { - type Builder = Receive; -} +// impl Delegable for Receive { +// type Builder = Receive; +// } impl TryFrom> for Receive { type Error = (); @@ -94,33 +94,33 @@ impl From for arguments::Named { } } -impl Checkable for Receive { - type Hierarchy = Parentful; -} - -impl CheckSame for Receive { - type Error = (); // FIXME better error - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - self.from.check_same(&proof.from).map_err(|_| ()) - } -} - -impl CheckParents for Receive { - type Parents = super::Any; - type ParentError = ::Error; - - fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { - if let Some(from) = &self.from { - if let Some(proof_from) = &proof.from { - if &from != &proof_from { - return Err(()); - } - } - } - - Ok(()) - } -} +// impl Checkable for Receive { +// type Hierarchy = Parentful; +// } +// +// impl CheckSame for Receive { +// type Error = (); // FIXME better error +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// self.from.check_same(&proof.from).map_err(|_| ()) +// } +// } +// +// impl CheckParents for Receive { +// type Parents = super::Any; +// type ParentError = ::Error; +// +// fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { +// if let Some(from) = &self.from { +// if let Some(proof_from) = &proof.from { +// if &from != &proof_from { +// return Err(()); +// } +// } +// } +// +// Ok(()) +// } +// } impl From for Ipld { fn from(receive: Receive) -> Self { diff --git a/src/ability/msg/send.rs b/src/ability/msg/send.rs index fc8a2f2c..c65869d5 100644 --- a/src/ability/msg/send.rs +++ b/src/ability/msg/send.rs @@ -2,16 +2,11 @@ use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, invocation::promise, - ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, + ipld, url, }; -use libipld_core::ipld::Ipld; +use libipld_core::{error::SerdeError, ipld::Ipld}; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -// use url::Url; -use crate::url; #[cfg_attr(doc, aquamarine::aquamarine)] /// The executable/dispatchable variant of the `msg/send` ability. @@ -56,48 +51,6 @@ pub struct Ready { pub message: String, } -#[cfg_attr(doc, aquamarine::aquamarine)] -/// The delegatable variant of the `msg/send` ability. -/// -/// # Delegation Hierarchy -/// -/// The hierarchy of message abilities is as follows: -/// -/// ```mermaid -/// flowchart LR -/// top("*") -/// -/// subgraph Message Abilities -/// any("msg/*") -/// -/// subgraph Invokable -/// send("msg/send") -/// end -/// end -/// -/// sendrun{{"invoke"}} -/// -/// top --> any -/// any --> send -.-> sendrun -/// -/// style send stroke:orange; -/// ``` -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Builder { - /// The recipient of the message - pub to: Option, - - /// The sender address of the message - /// - /// This *may* be a URL (such as an email address). - /// If provided, the `subject` must have the right to send from this address. - pub from: Option, - - /// The main body of the message - pub message: Option, -} - #[cfg_attr(doc, aquamarine::aquamarine)] /// The invoked variant of the `msg/send` ability /// @@ -143,14 +96,52 @@ pub struct Promised { pub message: promise::Resolves, } -impl Delegable for Ready { - type Builder = Builder; -} +// impl Delegable for Ready { +// type Builder = Builder; +// } impl promise::Resolvable for Ready { type Promised = Promised; } +impl TryFrom> for Ready { + type Error = (); + + fn try_from(named: arguments::Named) -> Result { + let mut to = None; + let mut from = None; + let mut message = None; + + for (key, value) in named.0 { + match key.as_str() { + "to" => match Ipld::try_from(value) { + Ok(Ipld::String(s)) => { + to = Some(url::Newtype::parse(s.as_str()).map_err(|_| ())?) + } + _ => return Err(()), + }, + "from" => match Ipld::try_from(value) { + Ok(Ipld::String(s)) => { + from = Some(url::Newtype::parse(s.as_str()).map_err(|_| ())?) + } + _ => return Err(()), + }, + "message" => match Ipld::try_from(value) { + Ok(Ipld::String(s)) => message = Some(s), + _ => return Err(()), + }, + _ => return Err(()), + } + } + + Ok(Ready { + to: to.ok_or(())?, + from: from.ok_or(())?, + message: message.ok_or(())?, + }) + } +} + impl TryFrom> for Promised { type Error = (); @@ -196,19 +187,6 @@ impl TryFrom> for Promised { } } -impl From for arguments::Named { - fn from(b: Builder) -> Self { - let mut btree = BTreeMap::new(); - b.to.map(|to| btree.insert("to".into(), to.to_string().into())); - b.from - .map(|from| btree.insert("from".into(), from.to_string().into())); - b.message - .map(|msg| btree.insert("message".into(), msg.into())); - - arguments::Named(btree) - } -} - impl From for arguments::Named { fn from(p: Promised) -> Self { arguments::Named::from_iter([ @@ -219,103 +197,16 @@ impl From for arguments::Named { } } -impl From for Builder { - fn from(p: Promised) -> Self { - Builder { - to: p.to.into(), - from: p.from.into(), - message: p.message.into(), - } - } -} - const COMMAND: &'static str = "msg/send"; impl Command for Ready { const COMMAND: &'static str = COMMAND; } -impl Command for Builder { - const COMMAND: &'static str = COMMAND; -} - impl Command for Promised { const COMMAND: &'static str = COMMAND; } -impl Checkable for Builder { - type Hierarchy = Parentful; -} - -impl CheckSame for Builder { - type Error = (); // FIXME better error - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - self.to.check_same(&proof.to).map_err(|_| ())?; - self.from.check_same(&proof.from).map_err(|_| ())?; - self.message.check_same(&proof.message).map_err(|_| ()) - } -} - -impl CheckParents for Builder { - type Parents = super::Any; - type ParentError = ::Error; - - fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { - self.from.check_same(&proof.from).map_err(|_| ()) - } -} - -impl TryFrom> for Builder { - type Error = (); - - fn try_from(args: arguments::Named) -> Result { - let mut to = None; - let mut from = None; - let mut message = None; - - for (key, ipld) in args.0 { - match key.as_str() { - "to" => { - // FIXME extract this common pattern - if let Ipld::String(s) = ipld { - to = Some(url::Newtype::parse(s.as_str()).map_err(|_| ())?); - } else { - return Err(()); - } - } - "from" => { - if let Ipld::String(s) = ipld { - from = Some(url::Newtype::parse(s.as_str()).map_err(|_| ())?); - } else { - return Err(()); - } - } - "message" => { - if let Ipld::String(s) = ipld { - message = Some(s); - } else { - return Err(()); - } - } - _ => return Err(()), - } - } - - Ok(Builder { to, from, message }) - } -} - -impl From for Builder { - fn from(resolved: Ready) -> Self { - Builder { - to: resolved.to.into(), - from: resolved.from.into(), - message: resolved.message.into(), - } - } -} - impl From for Promised { fn from(r: Ready) -> Self { Promised { @@ -337,24 +228,6 @@ impl TryFrom for Ready { } } -impl TryFrom for Ready { - type Error = Builder; - - fn try_from(b: Builder) -> Result { - // Entirely by refernce - if b.to.is_none() || b.from.is_none() || b.message.is_none() { - return Err(b); - } - - // Moves, and unwrap because we checked above instead of 2 clones per line - Ok(Ready { - to: b.to.unwrap(), - from: b.from.unwrap(), - message: b.message.unwrap(), - }) - } -} - impl From for arguments::Named { fn from(p: Promised) -> Self { arguments::Named::from_iter([ diff --git a/src/ability/preset.rs b/src/ability/preset.rs index 2443e26a..29e0510f 100644 --- a/src/ability/preset.rs +++ b/src/ability/preset.rs @@ -5,10 +5,8 @@ use crate::{ command::ToCommand, parse::{ParseAbility, ParseAbilityError, ParsePromised}, }, - delegation::Delegable, invocation::promise::Resolvable, ipld, - proof::{checkable::Checkable, parentful::Parentful, parents::CheckParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; @@ -20,37 +18,6 @@ pub enum Ready { Wasm(wasm::run::Ready), } -#[derive(Debug, Clone, PartialEq)] //, Serialize, Deserialize)] -pub enum Builder { - Crud(crud::Builder), - Msg(msg::Builder), - Wasm(wasm::run::Builder), -} - -#[derive(Debug, Clone, PartialEq)] //, Serialize, Deserialize)] -pub enum Parents { - Crud(crud::MutableParents), - Msg(msg::Any), -} // NOTE WasmRun has no parents - -impl CheckSame for Parents { - type Error = (); // FIXME - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - match (self, proof) { - (Parents::Msg(self_), Parents::Msg(proof_)) => self_.check_same(proof_).map_err(|_| ()), - (Parents::Crud(self_), Parents::Crud(proof_)) => { - self_.check_same(proof_).map_err(|_| ()) - } - _ => Err(()), - } - } -} - -impl Delegable for Ready { - type Builder = Builder; -} - impl ToCommand for Ready { fn to_command(&self) -> String { match self { @@ -60,66 +27,6 @@ impl ToCommand for Ready { } } } - -impl ToCommand for Builder { - fn to_command(&self) -> String { - match self { - Builder::Crud(builder) => builder.to_command(), - Builder::Msg(builder) => builder.to_command(), - Builder::Wasm(builder) => builder.to_command(), - } - } -} - -impl CheckSame for Builder { - type Error = (); // FIXME - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - match (self, proof) { - (Builder::Wasm(builder), Builder::Wasm(proof)) => builder.check_same(proof), - _ => Err(()), - } - } -} - -impl CheckParents for Builder { - type Parents = Parents; - type ParentError = (); // FIXME - - fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { - match (self, proof) { - (Builder::Msg(builder), Parents::Msg(proof)) => builder.check_parent(proof), - _ => Err(()), - } - } -} - -impl Checkable for Builder { - type Hierarchy = Parentful; -} - -impl From for Builder { - fn from(ready: Ready) -> Self { - match ready { - Ready::Crud(ready) => Builder::Crud(ready.into()), - Ready::Msg(ready) => Builder::Msg(ready.into()), - Ready::Wasm(ready) => Builder::Wasm(ready.into()), - } - } -} - -impl TryFrom for Ready { - type Error = (); // FIXME - - fn try_from(builder: Builder) -> Result { - match builder { - Builder::Crud(builder) => builder.try_into().map(Ready::Crud).map_err(|_| ()), - Builder::Msg(builder) => builder.try_into().map(Ready::Msg).map_err(|_| ()), - Builder::Wasm(builder) => builder.try_into().map(Ready::Wasm).map_err(|_| ()), - } - } -} - #[derive(Debug, Clone, PartialEq)] //, Serialize, Deserialize)] pub enum Promised { Crud(crud::Promised), @@ -170,27 +77,27 @@ impl ParsePromised for Promised { } } -impl ParseAbility for Builder { +impl ParseAbility for Ready { type ArgsErr = (); fn try_parse( cmd: &str, args: arguments::Named, ) -> Result> { - match msg::Builder::try_parse(cmd, args.clone()) { - Ok(builder) => return Ok(Builder::Msg(builder)), + match msg::Ready::try_parse(cmd, args.clone()) { + Ok(builder) => return Ok(Ready::Msg(builder)), Err(err) => return Err(err), Err(ParseAbilityError::UnknownCommand(_)) => (), } - match crud::Builder::try_parse(cmd, args.clone()) { - Ok(builder) => return Ok(Builder::Crud(builder)), + match crud::Ready::try_parse(cmd, args.clone()) { + Ok(builder) => return Ok(Ready::Crud(builder)), Err(err) => return Err(err), Err(ParseAbilityError::UnknownCommand(_)) => (), } - match wasm::run::Builder::try_parse(cmd, args) { - Ok(builder) => return Ok(Builder::Wasm(builder)), + match wasm::run::Ready::try_parse(cmd, args) { + Ok(builder) => return Ok(Ready::Wasm(builder)), Err(err) => return Err(err), Err(ParseAbilityError::UnknownCommand(_)) => (), } @@ -199,24 +106,24 @@ impl ParseAbility for Builder { } } -impl From for arguments::Named { - fn from(builder: Builder) -> Self { - match builder { - Builder::Crud(builder) => builder.into(), - Builder::Msg(builder) => builder.into(), - Builder::Wasm(builder) => builder.into(), - } - } -} - -impl From for arguments::Named { - fn from(parents: Parents) -> Self { - match parents { - Parents::Crud(parents) => parents.into(), - Parents::Msg(parents) => parents.into(), - } - } -} +// impl From for arguments::Named { +// fn from(builder: Builder) -> Self { +// match builder { +// Builder::Crud(builder) => builder.into(), +// Builder::Msg(builder) => builder.into(), +// Builder::Wasm(builder) => builder.into(), +// } +// } +// } +// +// impl From for arguments::Named { +// fn from(parents: Parents) -> Self { +// match parents { +// Parents::Crud(parents) => parents.into(), +// Parents::Msg(parents) => parents.into(), +// } +// } +// } impl From for arguments::Named { fn from(promised: Promised) -> Self { diff --git a/src/ability/ucan/revoke.rs b/src/ability/ucan/revoke.rs index fd2b29cf..dcb7aec5 100644 --- a/src/ability/ucan/revoke.rs +++ b/src/ability/ucan/revoke.rs @@ -4,14 +4,14 @@ use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::promise, ipld, - proof::{error::OptionalFieldError, parentless::NoParents, same::CheckSame}, + // proof::{error::OptionalFieldError, parentless::NoParents, same::CheckSame}, }; use libipld_core::{cid::Cid, ipld::Ipld}; use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, fmt::Debug}; +use std::fmt::Debug; /// The fully resolved variant: ready to execute. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -26,17 +26,17 @@ impl Command for Ready { const COMMAND: &'static str = COMMAND; } -impl Command for Builder { - const COMMAND: &'static str = COMMAND; -} +// impl Command for Builder { +// const COMMAND: &'static str = COMMAND; +// } impl Command for Promised { const COMMAND: &'static str = COMMAND; } -impl Delegable for Ready { - type Builder = Builder; -} +// impl Delegable for Ready { +// type Builder = Builder; +// } impl TryFrom> for Ready { type Error = (); @@ -49,26 +49,26 @@ impl TryFrom> for Ready { } } -impl TryFrom> for Builder { - type Error = (); - - fn try_from(arguments: arguments::Named) -> Result { - if let Some(ipld) = arguments.get("ucan") { - let nt: ipld::cid::Newtype = ipld.try_into().map_err(|_| ())?; - Ok(Builder { ucan: Some(nt.cid) }) - } else { - Ok(Builder { ucan: None }) - } - } -} - -impl From for Builder { - fn from(promised: Promised) -> Self { - Builder { - ucan: promised.ucan.try_resolve().ok(), - } - } -} +// impl TryFrom> for Builder { +// type Error = (); +// +// fn try_from(arguments: arguments::Named) -> Result { +// if let Some(ipld) = arguments.get("ucan") { +// let nt: ipld::cid::Newtype = ipld.try_into().map_err(|_| ())?; +// Ok(Builder { ucan: Some(nt.cid) }) +// } else { +// Ok(Builder { ucan: None }) +// } +// } +// } + +// impl From for Builder { +// fn from(promised: Promised) -> Self { +// Builder { +// ucan: promised.ucan.try_resolve().ok(), +// } +// } +// } impl promise::Resolvable for Ready { type Promised = Promised; @@ -80,49 +80,49 @@ impl From for arguments::Named { } } -/// A variant with some fields waiting to be set. -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -pub struct Builder { - pub ucan: Option, -} - -impl NoParents for Builder {} - -impl CheckSame for Builder { - type Error = OptionalFieldError; - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - self.ucan.check_same(&proof.ucan) - } -} - -impl From for Builder { - fn from(resolved: Ready) -> Builder { - Builder { - ucan: Some(resolved.ucan), - } - } -} - -impl TryFrom for Ready { - type Error = (); - - fn try_from(b: Builder) -> Result { - Ok(Ready { - ucan: b.ucan.ok_or(())?, - }) - } -} - -impl From for arguments::Named { - fn from(b: Builder) -> arguments::Named { - let mut btree = BTreeMap::new(); - if let Some(cid) = b.ucan { - btree.insert("ucan".into(), cid.into()); - } - arguments::Named(btree) - } -} +// /// A variant with some fields waiting to be set. +// #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] +// pub struct Builder { +// pub ucan: Option, +// } +// +// impl NoParents for Builder {} +// +// impl CheckSame for Builder { +// type Error = OptionalFieldError; +// +// fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { +// self.ucan.check_same(&proof.ucan) +// } +// } + +// impl From for Builder { +// fn from(resolved: Ready) -> Builder { +// Builder { +// ucan: Some(resolved.ucan), +// } +// } +// } + +// impl TryFrom for Ready { +// type Error = (); +// +// fn try_from(b: Builder) -> Result { +// Ok(Ready { +// ucan: b.ucan.ok_or(())?, +// }) +// } +// } +// +// impl From for arguments::Named { +// fn from(b: Builder) -> arguments::Named { +// let mut btree = BTreeMap::new(); +// if let Some(cid) = b.ucan { +// btree.insert("ucan".into(), cid.into()); +// } +// arguments::Named(btree) +// } +// } /// A variant where arguments may be [`Promise`][crate::invocation::promise]s. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/ability/wasm/run.rs b/src/ability/wasm/run.rs index e9301a91..0c7f8cfa 100644 --- a/src/ability/wasm/run.rs +++ b/src/ability/wasm/run.rs @@ -3,14 +3,13 @@ use super::module::Module; use crate::{ ability::{arguments, command::Command}, - delegation::Delegable, + // delegation::Delegable, invocation::promise, ipld, - proof::{parentless::NoParents, same::CheckSame}, + // proof::{parentless::NoParents, same::CheckSame}, }; use libipld_core::ipld::Ipld; use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; const COMMAND: &'static str = "wasm/run"; @@ -18,10 +17,6 @@ impl Command for Ready { const COMMAND: &'static str = COMMAND; } -impl Command for Builder { - const COMMAND: &'static str = COMMAND; -} - impl Command for Promised { const COMMAND: &'static str = COMMAND; } @@ -39,11 +34,7 @@ pub struct Ready { pub args: Vec, } -impl Delegable for Ready { - type Builder = Builder; -} - -impl TryFrom> for Builder { +impl TryFrom> for Ready { type Error = (); fn try_from(named: arguments::Named) -> Result { @@ -74,10 +65,10 @@ impl TryFrom> for Builder { } } - Ok(Builder { - module, - function, - args, + Ok(Ready { + module: module.ok_or(())?, + function: function.ok_or(())?, + args: args.ok_or(())?, }) } } @@ -86,88 +77,6 @@ impl promise::Resolvable for Ready { type Promised = Promised; } -/// A variant meant for delegation, where fields may be omitted -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Builder { - /// The Wasm module to run - pub module: Option, - - /// The function from the module to run - pub function: Option, - - /// Arguments to pass to the function - pub args: Option>, -} - -impl NoParents for Builder {} - -impl From for arguments::Named { - fn from(builder: Builder) -> Self { - let mut btree = BTreeMap::new(); - if let Some(module) = builder.module { - btree.insert("module".into(), Ipld::from(module)); - } - - if let Some(function) = builder.function { - btree.insert("function".into(), Ipld::String(function)); - } - - if let Some(args) = builder.args { - btree.insert("args".into(), Ipld::List(args)); - } - - arguments::Named(btree) - } -} - -impl From for Builder { - fn from(ready: Ready) -> Builder { - Builder { - module: Some(ready.module), - function: Some(ready.function), - args: Some(ready.args), - } - } -} - -impl TryFrom for Ready { - type Error = (); // FIXME - - fn try_from(b: Builder) -> Result { - Ok(Ready { - module: b.module.ok_or(())?, - function: b.function.ok_or(())?, - args: b.args.ok_or(())?, - }) - } -} - -impl CheckSame for Builder { - type Error = (); // FIXME - - fn check_same(&self, proof: &Self) -> Result<(), Self::Error> { - if let Some(module) = &self.module { - if module != proof.module.as_ref().unwrap() { - return Err(()); - } - } - - if let Some(function) = &self.function { - if function != proof.function.as_ref().unwrap() { - return Err(()); - } - } - - if let Some(args) = &self.args { - if args != proof.args.as_ref().unwrap() { - return Err(()); - } - } - - Ok(()) - } -} - /// A variant meant for linking together invocations with promises #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Promised { diff --git a/src/delegation.rs b/src/delegation.rs index 5d81718e..e4c077db 100644 --- a/src/delegation.rs +++ b/src/delegation.rs @@ -16,18 +16,18 @@ pub mod condition; pub mod store; mod agent; -mod delegable; +// mod delegable; mod payload; pub use agent::Agent; -pub use delegable::Delegable; -pub use payload::{Payload, ValidationError}; +// pub use delegable::Delegable; +pub use payload::*; use crate::{ - ability, + // ability, crypto::{signature, varsig, Nonce}, did::{self, Did}, - proof::{parents::CheckParents, same::CheckSame}, + // proof::{parents::CheckParents, same::CheckSame}, time::{TimeBoundError, Timestamp}, }; use condition::Condition; @@ -47,16 +47,14 @@ use web_time::SystemTime; /// FIXME #[derive(Clone, Debug, PartialEq)] pub struct Delegation< - D, C: Condition, DID: Did, V: varsig::Header, Enc: Codec + TryFrom + Into, ->(pub signature::Envelope, DID, V, Enc>); +>(pub signature::Envelope, DID, V, Enc>); /// A variant of [`Delegation`] that has the abilties and DIDs from this library pre-filled. pub type Preset = Delegation< - ability::preset::Builder, condition::Preset, did::preset::Verifier, varsig::header::Preset, @@ -65,8 +63,8 @@ pub type Preset = Delegation< // FIXME checkable -> provable? -impl, Enc: Codec + Into + TryFrom> - Delegation +impl, Enc: Codec + Into + TryFrom> + Delegation { /// Retrive the `issuer` of a [`Delegation`] pub fn issuer(&self) -> &DID { @@ -74,7 +72,7 @@ impl, Enc: Codec + Into + } /// Retrive the `subject` of a [`Delegation`] - pub fn subject(&self) -> &DID { + pub fn subject(&self) -> &Option { &self.0.payload.subject } @@ -83,22 +81,6 @@ impl, Enc: Codec + Into + &self.0.payload.audience } - /// Retrive the `ability_builder` of a [`Delegation`] - pub fn ability_builder(&self) -> &B { - &self.0.payload.ability_builder - } - - pub fn map_ability_builder(self, f: F) -> Delegation - where - F: FnOnce(B) -> T, - { - Delegation(signature::Envelope::new( - self.0.varsig_header, - self.0.signature, - self.0.payload.map_ability(f), - )) - } - /// Retrive the `condition` of a [`Delegation`] pub fn conditions(&self) -> &[C] { &self.0.payload.conditions @@ -128,7 +110,7 @@ impl, Enc: Codec + Into + self.0.payload.check_time(now) } - pub fn payload(&self) -> &Payload { + pub fn payload(&self) -> &Payload { &self.0.payload } @@ -146,7 +128,7 @@ impl, Enc: Codec + Into + pub fn cid(&self) -> Result where - signature::Envelope, DID, V, Enc>: Clone + Encode, + signature::Envelope, DID, V, Enc>: Clone + Encode, Ipld: Encode, { self.0.cid() @@ -154,7 +136,7 @@ impl, Enc: Codec + Into + pub fn validate_signature(&self) -> Result<(), signature::ValidateError> where - Payload: Clone, + Payload: Clone, Ipld: Encode, { self.0.validate_signature() @@ -163,43 +145,43 @@ impl, Enc: Codec + Into + pub fn try_sign( signer: &DID::Signer, varsig_header: V, - payload: Payload, + payload: Payload, ) -> Result where Ipld: Encode, - Payload: Clone, + Payload: Clone, { signature::Envelope::try_sign(signer, varsig_header, payload).map(Delegation) } } -impl< - B: CheckSame, - C: Condition, - DID: Did, - V: varsig::Header, - Enc: Codec + TryFrom + Into, - > CheckSame for Delegation -{ - type Error = ::Error; - - fn check_same(&self, proof: &Delegation) -> Result<(), Self::Error> { - self.0.payload.check_same(&proof.payload()) - } -} - -impl< - T: CheckParents, - C: Condition, - DID: Did, - V: varsig::Header, - Enc: Codec + TryFrom + Into, - > CheckParents for Delegation -{ - type Parents = Delegation; - type ParentError = ::ParentError; - - fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { - self.payload().check_parent(&proof.payload()) - } -} +// impl< +// B: CheckSame, +// C: Condition, +// DID: Did, +// V: varsig::Header, +// Enc: Codec + TryFrom + Into, +// > CheckSame for Delegation +// { +// type Error = ::Error; +// +// fn check_same(&self, proof: &Delegation) -> Result<(), Self::Error> { +// self.0.payload.check_same(&proof.payload()) +// } +// } +// +// impl< +// T: CheckParents, +// C: Condition, +// DID: Did, +// V: varsig::Header, +// Enc: Codec + TryFrom + Into, +// > CheckParents for Delegation +// { +// type Parents = Delegation; +// type ParentError = ::ParentError; +// +// fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { +// self.payload().check_parent(&proof.payload()) +// } +// } diff --git a/src/delegation/agent.rs b/src/delegation/agent.rs index 389de622..42745c80 100644 --- a/src/delegation/agent.rs +++ b/src/delegation/agent.rs @@ -2,7 +2,7 @@ use super::{condition::Condition, payload::Payload, store::Store, Delegation}; use crate::{ crypto::{varsig, Nonce}, did::Did, - proof::checkable::Checkable, + // proof::checkable::Checkable, time::Timestamp, }; use libipld_core::{ @@ -20,10 +20,9 @@ use web_time::SystemTime; #[derive(Debug)] pub struct Agent< 'a, - B: Checkable, C: Condition, DID: Did, - S: Store, + S: Store, V: varsig::Header, Enc: Codec + TryFrom + Into, > { @@ -34,18 +33,17 @@ pub struct Agent< pub store: &'a mut S, signer: &'a ::Signer, - _marker: PhantomData<(B, C, V, Enc)>, + _marker: PhantomData<(C, V, Enc)>, } impl< 'a, - B: Checkable + Clone, C: Condition + Clone, DID: Did + ToString + Clone, - S: Store + Clone, + S: Store + Clone, V: varsig::Header, Enc: Codec + TryFrom + Into, - > Agent<'a, B, C, DID, S, V, Enc> + > Agent<'a, C, DID, S, V, Enc> where Ipld: Encode, { @@ -61,37 +59,39 @@ where pub fn delegate( &self, audience: DID, - subject: DID, - ability_builder: B, + subject: Option, new_conditions: Vec, metadata: BTreeMap, expiration: Timestamp, not_before: Option, now: SystemTime, varsig_header: V, - ) -> Result, DelegateError> { + ) -> Result, DelegateError> { let mut salt = self.did.clone().to_string().into_bytes(); let nonce = Nonce::generate_12(&mut salt); - if subject == *self.did { - let payload: Payload = Payload { - issuer: self.did.clone(), - audience, - subject, - ability_builder, - metadata, - nonce, - expiration: expiration.into(), - not_before: not_before.map(Into::into), - conditions: new_conditions, - }; - - return Ok(Delegation::try_sign(self.signer, varsig_header, payload).expect("FIXME")); + if let Some(ref sub) = subject { + if sub == self.did { + let payload: Payload = Payload { + issuer: self.did.clone(), + audience, + subject, + metadata, + nonce, + expiration: expiration.into(), + not_before: not_before.map(Into::into), + conditions: new_conditions, + }; + + return Ok( + Delegation::try_sign(self.signer, varsig_header, payload).expect("FIXME") + ); + } } let to_delegate = &self .store - .get_chain(&self.did, &subject, &ability_builder, vec![], now) + .get_chain(&self.did, &subject, vec![], now) .map_err(DelegateError::StoreError)? .ok_or(DelegateError::ProofsNotFound)? .first() @@ -101,11 +101,10 @@ where let mut conditions = to_delegate.conditions.clone(); conditions.append(&mut new_conditions.clone()); - let payload: Payload = Payload { + let payload: Payload = Payload { issuer: self.did.clone(), audience, subject, - ability_builder, conditions, metadata, nonce, @@ -119,7 +118,7 @@ where pub fn receive( &mut self, cid: Cid, // FIXME remove and generate from the capsule header? - delegation: Delegation, + delegation: Delegation, ) -> Result<(), ReceiveError> { if self.store.get(&cid).is_ok() { return Ok(()); diff --git a/src/delegation/delegable.rs b/src/delegation/delegable.rs index a8929ab1..9ab7e613 100644 --- a/src/delegation/delegable.rs +++ b/src/delegation/delegable.rs @@ -1,51 +1,51 @@ -use crate::{ - ability::{ - arguments, - command::ToCommand, - parse::{ParseAbility, ParseAbilityError}, - }, - proof::checkable::Checkable, -}; -use libipld_core::ipld::Ipld; - -/// A trait for types that can be delegated. -/// -/// Since [`Delegation`]s may omit fields (until [`Invocation`]), -/// this trait helps associate the delegatable variant to the invocable one. -/// -/// [`Delegation`]: crate::delegation::Delegation -/// [`Invocation`]: crate::invocation::Invocation -// FIXME NOTE: don't need parse ability, because parse -> builder -> self -// FIXME NOTE: don't need ToCommand ability, because parse -> builder -> self, or .. -> promieed -> .. -pub trait Delegable: Sized { - /// A delegation with some arguments filled. - type Builder: TryInto - + From - + Checkable - + ParseAbility - + ToCommand - + Into>; - - fn into_command(self) -> String { - Self::Builder::from(self).to_command() - } - - fn into_named_args(self) -> arguments::Named { - Self::Builder::from(self).into() - } - - fn try_parse_to_ready( - command: &str, - named: arguments::Named, - ) -> Result::ArgsErr>> { - let builder = Self::Builder::try_parse(command, named)?; - builder.try_into().map_err(|err| todo!()) - } - - fn try_from_named( - named: arguments::Named, - ) -> Result::ArgsErr>> { - let builder = Self::Builder::try_parse("", named)?; - builder.try_into().map_err(|err| todo!()) - } -} +// use crate::{ +// ability::{ +// arguments, +// command::ToCommand, +// parse::{ParseAbility, ParseAbilityError}, +// }, +// proof::checkable::Checkable, +// }; +// use libipld_core::ipld::Ipld; +// +// /// A trait for types that can be delegated. +// /// +// /// Since [`Delegation`]s may omit fields (until [`Invocation`]), +// /// this trait helps associate the delegatable variant to the invocable one. +// /// +// /// [`Delegation`]: crate::delegation::Delegation +// /// [`Invocation`]: crate::invocation::Invocation +// // FIXME NOTE: don't need parse ability, because parse -> builder -> self +// // FIXME NOTE: don't need ToCommand ability, because parse -> builder -> self, or .. -> promieed -> .. +// pub trait Delegable: Sized { +// /// A delegation with some arguments filled. +// type Builder: TryInto +// + From +// + Checkable +// + ParseAbility +// + ToCommand +// + Into>; +// +// fn into_command(self) -> String { +// Self::Builder::from(self).to_command() +// } +// +// fn into_named_args(self) -> arguments::Named { +// Self::Builder::from(self).into() +// } +// +// fn try_parse_to_ready( +// command: &str, +// named: arguments::Named, +// ) -> Result::ArgsErr>> { +// let builder = Self::Builder::try_parse(command, named)?; +// builder.try_into().map_err(|err| todo!()) +// } +// +// fn try_from_named( +// named: arguments::Named, +// ) -> Result::ArgsErr>> { +// let builder = Self::Builder::try_parse("", named)?; +// builder.try_into().map_err(|err| todo!()) +// } +// } diff --git a/src/delegation/payload.rs b/src/delegation/payload.rs index bd557979..bbde3e99 100644 --- a/src/delegation/payload.rs +++ b/src/delegation/payload.rs @@ -1,29 +1,13 @@ use super::condition::Condition; use crate::{ - ability::{ - arguments, - command::{Command, ToCommand}, - parse::ParseAbility, - }, capsule::Capsule, crypto::Nonce, did::{Did, Verifiable}, - proof::{ - checkable::Checkable, - parents::CheckParents, - prove::{Prove, Success}, - same::CheckSame, - }, time::{TimeBoundError, Timestamp}, }; use libipld_core::{error::SerdeError, ipld::Ipld, serde as ipld_serde}; -use serde::{ - de::{self, MapAccess, Visitor}, - ser::SerializeStruct, - Deserialize, Serialize, Serializer, -}; -use std::{collections::BTreeMap, fmt, fmt::Debug}; -use thiserror::Error; +use serde::{Deserialize, Serialize}; +use std::{collections::BTreeMap, fmt::Debug}; use web_time::SystemTime; #[cfg(feature = "test_utils")] @@ -36,8 +20,8 @@ use crate::ipld; /// /// This contains the semantic information about the delegation, including the /// issuer, subject, audience, the delegated ability, time bounds, and so on. -#[derive(Debug, Clone, PartialEq)] -pub struct Payload { +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Payload { /// The subject of the [`Delegation`]. /// /// This role *must* have issued the earlier (root) @@ -48,7 +32,7 @@ pub struct Payload { /// by the subject. /// /// [`Delegation`]: super::Delegation - pub subject: DID, + pub subject: Option, /// The issuer of the [`Delegation`]. /// @@ -61,11 +45,6 @@ pub struct Payload { /// The agent being delegated to. pub audience: DID, - /// A delegatable ability chain. - /// - /// Note that this should be is some [Proof::Hierarchy] - pub ability_builder: D, - /// Any [`Condition`]s on the `ability_builder`. pub conditions: Vec, @@ -91,35 +70,7 @@ pub struct Payload { pub not_before: Option, } -impl Payload { - pub fn map_ability(self, f: impl FnOnce(D) -> T) -> Payload { - Payload { - issuer: self.issuer, - subject: self.subject, - audience: self.audience, - ability_builder: f(self.ability_builder), - conditions: self.conditions, - metadata: self.metadata, - nonce: self.nonce, - expiration: self.expiration, - not_before: self.not_before, - } - } - - pub fn map_conditon(self, f: impl FnMut(C) -> T) -> Payload { - Payload { - issuer: self.issuer, - subject: self.subject, - audience: self.audience, - ability_builder: self.ability_builder, - conditions: self.conditions.into_iter().map(f).collect(), - metadata: self.metadata, - nonce: self.nonce, - expiration: self.expiration, - not_before: self.not_before, - } - } - +impl Payload { pub fn check_time(&self, now: SystemTime) -> Result<(), TimeBoundError> { let ts_now = &Timestamp::postel(now); @@ -137,227 +88,18 @@ impl Payload { } } -impl Capsule for Payload { - const TAG: &'static str = "ucan/d/1.0.0-rc.1"; +impl Capsule for Payload { + const TAG: &'static str = "ucan/d/1.0"; } -impl Verifiable for Payload { +impl Verifiable for Payload { fn verifier(&self) -> &DID { &self.issuer } } -impl CheckSame for Payload { - type Error = ::Error; - - fn check_same(&self, proof: &Payload) -> Result<(), Self::Error> { - self.ability_builder.check_same(&proof.ability_builder) - } -} - -impl CheckParents for Payload { - type Parents = Payload; - type ParentError = ::ParentError; - - fn check_parent(&self, proof: &Self::Parents) -> Result<(), Self::ParentError> { - self.ability_builder.check_parent(&proof.ability_builder) - } -} - -impl Serialize - for Payload -where - Ipld: From, - arguments::Named: From, -{ - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - let count_nbf = self.not_before.is_some() as usize; - let mut state = serializer.serialize_struct("delegation::Payload", 8 + count_nbf)?; - - state.serialize_field("iss", &self.issuer.clone().into().to_string())?; - state.serialize_field("sub", &self.subject.clone().into().to_string())?; - state.serialize_field("aud", &self.audience.clone().into().to_string())?; - state.serialize_field("meta", &self.metadata)?; - state.serialize_field("nonce", &self.nonce)?; - state.serialize_field("exp", &self.expiration)?; - - state.serialize_field("cmd", &self.ability_builder.to_command())?; - - state.serialize_field( - "args", - &arguments::Named::from(self.ability_builder.clone()), - )?; - - state.serialize_field( - "cond", - &self - .conditions - .iter() - .map(|c| Ipld::from(c.clone())) - .collect::>(), - )?; - - if let Some(nbf) = self.not_before { - state.serialize_field("nbf", &nbf)?; - } - - state.end() - } -} - -impl< - 'de, - T: ParseAbility + Deserialize<'de> + ToCommand, - C: Condition + Deserialize<'de>, - DID: Did + Deserialize<'de>, - > Deserialize<'de> for Payload -{ - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - struct DelegationPayloadVisitor( - std::marker::PhantomData<(T, C, DID)>, - ); - - const FIELDS: &'static [&'static str] = &[ - "iss", "sub", "aud", "cmd", "args", "cond", "meta", "nonce", "exp", "nbf", - ]; - - impl< - 'de, - T: ParseAbility + Deserialize<'de>, - C: Condition + Deserialize<'de>, - DID: Did + Deserialize<'de>, - > Visitor<'de> for DelegationPayloadVisitor - { - type Value = Payload; - - fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { - formatter.write_str("struct delegation::Payload") - } - - fn visit_map>(self, mut map: M) -> Result { - let mut issuer = None; - let mut subject = None; - let mut audience = None; - let mut command = None; - let mut arguments = None; - let mut conditions = None; - let mut metadata = None; - let mut nonce = None; - let mut expiration = None; - let mut not_before = None; - - while let Some(key) = map.next_key()? { - match key { - "iss" => { - if issuer.is_some() { - return Err(de::Error::duplicate_field("iss")); - } - issuer = Some(map.next_value()?); - } - "sub" => { - if subject.is_some() { - return Err(de::Error::duplicate_field("sub")); - } - subject = Some(map.next_value()?); - } - "aud" => { - if audience.is_some() { - return Err(de::Error::duplicate_field("aud")); - } - audience = Some(map.next_value()?); - } - "cmd" => { - if command.is_some() { - return Err(de::Error::duplicate_field("cmd")); - } - command = Some(map.next_value()?); - } - "args" => { - if arguments.is_some() { - return Err(de::Error::duplicate_field("args")); - } - arguments = Some(map.next_value()?); - } - "cond" => { - if conditions.is_some() { - return Err(de::Error::duplicate_field("cond")); - } - conditions = Some(map.next_value()?); - } - "meta" => { - if metadata.is_some() { - return Err(de::Error::duplicate_field("meta")); - } - metadata = Some(map.next_value()?); - } - "nonce" => { - if nonce.is_some() { - return Err(de::Error::duplicate_field("nonce")); - } - nonce = Some(map.next_value()?); - } - "exp" => { - if expiration.is_some() { - return Err(de::Error::duplicate_field("exp")); - } - expiration = Some(map.next_value()?); - } - "nbf" => { - if not_before.is_some() { - return Err(de::Error::duplicate_field("nbf")); - } - not_before = Some(map.next_value()?); - } - other => { - return Err(de::Error::unknown_field(other, FIELDS)); - } - } - } - - let cmd: String = command.ok_or(de::Error::missing_field("cmd"))?; - let args = arguments.ok_or(de::Error::missing_field("args"))?; - - let ability_builder = - ::try_parse(cmd.as_str(), args).map_err(|e| { - de::Error::custom(format!( - "Unable to parse ability field for {:?} because {:?}", - cmd, e - )) - })?; - - Ok(Payload { - issuer: issuer.ok_or(de::Error::missing_field("iss"))?, - subject: subject.ok_or(de::Error::missing_field("sub"))?, - audience: audience.ok_or(de::Error::missing_field("aud"))?, - conditions: conditions.ok_or(de::Error::missing_field("cond"))?, - metadata: metadata.ok_or(de::Error::missing_field("meta"))?, - nonce: nonce.ok_or(de::Error::missing_field("nonce"))?, - expiration: expiration.ok_or(de::Error::missing_field("exp"))?, - ability_builder, - not_before, - }) - } - } - - deserializer.deserialize_struct( - "DelegationPayload", - FIELDS, - DelegationPayloadVisitor(Default::default()), - ) - } -} - -impl< - T: ParseAbility + Command + for<'de> Deserialize<'de>, - C: Condition + for<'de> Deserialize<'de>, - DID: Did + for<'de> Deserialize<'de>, - > TryFrom for Payload +impl Deserialize<'de>, DID: Did + for<'de> Deserialize<'de>> TryFrom + for Payload { type Error = SerdeError; @@ -366,150 +108,25 @@ impl< } } -impl From> for Ipld { - fn from(payload: Payload) -> Self { +impl From> for Ipld { + fn from(payload: Payload) -> Self { payload.into() } } -impl>, C: Condition, DID: Did> Payload { - pub fn check( - &self, - proofs: Vec<&Payload>, - now: &SystemTime, - ) -> Result<(), ValidationError<::Error, C>> - where - T: Clone, - C: Clone, - DID: Clone, - T::Hierarchy: Clone + Into>, - { - let start: Acc = Acc { - issuer: self.issuer.clone(), - subject: self.subject.clone(), - hierarchy: T::Hierarchy::from(self.ability_builder.clone()), - }; - - let args: arguments::Named = self.ability_builder.clone().into(); - - proofs.into_iter().fold(Ok(start), |prev, proof| { - if let Ok(prev_) = prev { - prev_.step(&proof, &args, now).map(move |success| { - match success { - Success::ProvenByAny => Acc { - issuer: proof.issuer.clone(), - subject: proof.subject.clone(), - hierarchy: prev_.hierarchy, - }, - Success::Proven => Acc { - issuer: proof.issuer.clone(), - subject: proof.subject.clone(), - hierarchy: proof.ability_builder.clone(), // FIXME double check - }, - } - }) - } else { - prev - } - })?; - - Ok(()) - } -} - -#[derive(Debug, Clone)] -struct Acc { - issuer: DID, - subject: DID, - hierarchy: H, -} - -impl Acc { - // FIXME this should move to Delegable? - fn step<'a, C: Condition>( - &self, - proof: &Payload, - args: &arguments::Named, - now: &SystemTime, - ) -> Result::Error, C>> - where - C: Clone, - H: Prove + Clone + Into>, - { - if self.issuer != proof.audience { - return Err(ValidationError::InvalidSubject.into()); - } - - if self.subject != proof.subject { - return Err(ValidationError::MisalignedIssAud.into()); - } - - if SystemTime::from(proof.expiration.clone()) > *now { - return Err(ValidationError::Expired.into()); - } - - if let Some(nbf) = proof.not_before.clone() { - if SystemTime::from(nbf) > *now { - return Err(ValidationError::NotYetValid.into()); - } - } - - // This could be more efficient (dedup) with sets, but floats don't Ord :( - for c in proof.conditions.iter() { - // Validate both current & proof integrity. - // This should have the same semantic guarantees as looking at subsets, - // but for all known conditions will run much faster on average. - // Plz let me know if I got this wrong. - // —@expede - if !c.validate(&args) || !c.validate(&self.hierarchy.clone().into()) { - return Err(ValidationError::FailedCondition(c.clone())); - } - } - - self.hierarchy - .check(&proof.ability_builder.clone()) - .map_err(ValidationError::AbilityError) - } -} - -/// Delegation validation errors. -#[derive(Debug, Clone, PartialEq, Eq, Error)] -pub enum ValidationError { - #[error("The subject of the delegation is invalid")] - InvalidSubject, - - #[error("The issuer and audience of the delegation are misaligned")] - MisalignedIssAud, - - #[error("The delegation has expired")] - Expired, - - #[error("The delegation is not yet valid")] - NotYetValid, - - #[error("The delegation failed a condition: {0:?}")] - FailedCondition(C), - - #[error(transparent)] - AbilityError(AbilityError), -} - #[cfg(feature = "test_utils")] -impl Arbitrary - for Payload +impl Arbitrary for Payload where - T::Strategy: 'static, C::Strategy: 'static, DID::Parameters: Clone, C::Parameters: Clone, { - type Parameters = (T::Parameters, DID::Parameters, C::Parameters); + type Parameters = (DID::Parameters, C::Parameters); type Strategy = BoxedStrategy; - fn arbitrary_with((t_args, did_args, c_args): Self::Parameters) -> Self::Strategy { + fn arbitrary_with((did_args, c_args): Self::Parameters) -> Self::Strategy { ( - T::arbitrary_with(t_args), - DID::arbitrary_with(did_args.clone()), + Option::::arbitrary(), DID::arbitrary_with(did_args.clone()), DID::arbitrary_with(did_args), Nonce::arbitrary(), @@ -524,10 +141,9 @@ where ) .prop_map( |( - ability_builder, + subject, issuer, audience, - subject, nonce, expiration, not_before, @@ -538,7 +154,6 @@ where issuer, subject, audience, - ability_builder, conditions, metadata, nonce, diff --git a/src/delegation/store/memory.rs b/src/delegation/store/memory.rs index e87399af..e87bfc5d 100644 --- a/src/delegation/store/memory.rs +++ b/src/delegation/store/memory.rs @@ -1,12 +1,12 @@ use super::Store; use crate::{ - ability::arguments, + // ability::arguments, crypto::varsig, delegation::{condition::Condition, Delegation}, did::Did, - proof::{checkable::Checkable, prove::Prove}, + // proof::{checkable::Checkable, prove::Prove}, }; -use libipld_core::{cid::Cid, codec::Codec, ipld::Ipld}; +use libipld_core::{cid::Cid, codec::Codec}; use nonempty::NonEmpty; use std::{ collections::{BTreeMap, BTreeSet}, @@ -72,41 +72,34 @@ use web_time::SystemTime; /// ``` #[derive(Debug, Clone, PartialEq)] pub struct MemoryStore< - H, C: Condition, DID: Did + Ord, V: varsig::Header, Enc: Codec + TryFrom + Into, > { - ucans: BTreeMap>, - index: BTreeMap>>, + ucans: BTreeMap>, + index: BTreeMap, BTreeMap>>, revocations: BTreeSet, } // FIXME check that UCAN is valid impl< - B: Checkable + Clone, C: Condition + PartialEq, DID: Did + Ord + Clone, V: varsig::Header, Enc: Codec + TryFrom + Into, - > Store for MemoryStore -where - B::Hierarchy: Into> + Clone, + > Store for MemoryStore { type DelegationStoreError = (); // FIXME misisng - fn get( - &self, - cid: &Cid, - ) -> Result<&Delegation, Self::DelegationStoreError> { + fn get(&self, cid: &Cid) -> Result<&Delegation, Self::DelegationStoreError> { self.ucans.get(cid).ok_or(()) } fn insert( &mut self, cid: Cid, - delegation: Delegation, + delegation: Delegation, ) -> Result<(), Self::DelegationStoreError> { self.index .entry(delegation.subject().clone()) @@ -115,10 +108,7 @@ where .or_default() .insert(cid); - let hierarchy: Delegation = - delegation.map_ability_builder(Into::into); - - self.ucans.insert(cid.clone(), hierarchy); + self.ucans.insert(cid.clone(), delegation); Ok(()) } @@ -130,15 +120,16 @@ where fn get_chain( &self, aud: &DID, - subject: &DID, - builder: &B, + subject: &Option, conditions: Vec, now: SystemTime, - ) -> Result< - Option)>>, - Self::DelegationStoreError, - > { - match self.index.get(subject).and_then(|aud_map| aud_map.get(aud)) { + ) -> Result)>>, Self::DelegationStoreError> + { + match self + .index + .get(subject) // FIXME probably need to rework this after last minbute chanegs + .and_then(|aud_map| aud_map.get(aud)) + { None => Ok(None), Some(delegation_subtree) => { #[derive(PartialEq)] @@ -150,7 +141,6 @@ where let mut status = Status::Looking; let mut target_aud = aud; - let mut args = &B::Hierarchy::from(builder.clone()); let mut chain = vec![]; while status == Status::Looking { @@ -166,24 +156,14 @@ where target_aud = &d.audience(); - if args.check(&d.ability_builder()).is_ok() { - args = &d.ability_builder(); - } else { - return ControlFlow::Continue(()); - } - - for condition in &conditions { - if !condition.validate(&d.ability_builder().clone().into()) { - return ControlFlow::Continue(()); - } - } - chain.push((*cid, d)); - if d.issuer() == subject { - status = Status::Complete; + if let Some(ref subject) = subject { + if d.issuer() == subject { + status = Status::Complete; + } } else { - target_aud = &d.issuer(); + status = Status::Complete; } ControlFlow::Break(()) diff --git a/src/delegation/store/traits.rs b/src/delegation/store/traits.rs index 93c6d525..44b032dd 100644 --- a/src/delegation/store/traits.rs +++ b/src/delegation/store/traits.rs @@ -2,7 +2,7 @@ use crate::{ crypto::varsig, delegation::{condition::Condition, Delegation}, did::Did, - proof::checkable::Checkable, + // proof::checkable::Checkable, }; use libipld_core::{cid::Cid, codec::Codec}; use nonempty::NonEmpty; @@ -11,7 +11,6 @@ use web_time::SystemTime; // NOTE the T here is the builder... FIXME add one layer up and call T::Builder? May be confusing? pub trait Store< - B: Checkable, C: Condition, DID: Did, V: varsig::Header, @@ -20,10 +19,7 @@ pub trait Store< { type DelegationStoreError: Debug; - fn get( - &self, - cid: &Cid, - ) -> Result<&Delegation, Self::DelegationStoreError>; + fn get(&self, cid: &Cid) -> Result<&Delegation, Self::DelegationStoreError>; // FIXME add a variant that calculated the CID from the capsulre header? // FIXME that means changing the name to insert_by_cid or similar @@ -31,7 +27,7 @@ pub trait Store< fn insert( &mut self, cid: Cid, - delegation: Delegation, + delegation: Delegation, ) -> Result<(), Self::DelegationStoreError>; // FIXME validate invocation @@ -42,33 +38,28 @@ pub trait Store< fn get_chain( &self, audience: &DID, - subject: &DID, - builder: &B, + subject: &Option, conditions: Vec, now: SystemTime, - ) -> Result< - Option)>>, - Self::DelegationStoreError, - >; + ) -> Result)>>, Self::DelegationStoreError>; fn can_delegate( &self, - issuer: &DID, + issuer: DID, audience: &DID, - builder: &B, conditions: Vec, now: SystemTime, ) -> Result { - self.get_chain(audience, issuer, builder, conditions, now) + self.get_chain(audience, &Some(issuer), conditions, now) .map(|chain| chain.is_some()) } fn get_many( &self, cids: &[Cid], - ) -> Result>, Self::DelegationStoreError> { + ) -> Result>, Self::DelegationStoreError> { cids.iter().try_fold(vec![], |mut acc, cid| { - let d: &Delegation = self.get(cid)?; + let d: &Delegation = self.get(cid)?; acc.push(d); Ok(acc) }) diff --git a/src/invocation.rs b/src/invocation.rs index 2aa36b8e..7e66670e 100644 --- a/src/invocation.rs +++ b/src/invocation.rs @@ -19,7 +19,7 @@ pub mod promise; pub mod store; pub use agent::Agent; -pub use payload::{Payload, Promised}; +pub use payload::*; use crate::{ ability, diff --git a/src/invocation/agent.rs b/src/invocation/agent.rs index 9bc24aab..5e728646 100644 --- a/src/invocation/agent.rs +++ b/src/invocation/agent.rs @@ -1,15 +1,20 @@ -use super::{payload::Payload, promise::Resolvable, store::Store, Invocation}; +use super::{ + payload::{Payload, ValidationError}, + promise::Resolvable, + store::Store, + Invocation, +}; use crate::{ ability::{ + arguments, parse::{ParseAbility, ParseAbilityError, ParsePromised}, ucan, }, crypto::{signature, varsig, Nonce}, - delegation, - delegation::{condition::Condition, Delegable}, + delegation::{self, condition::Condition}, did::Did, invocation::promise, - proof::{checkable::Checkable, prove::Prove}, + // proof::prove::Prove, time::Timestamp, }; use libipld_core::{ @@ -28,12 +33,12 @@ use web_time::SystemTime; #[derive(Debug)] pub struct Agent< 'a, - T: Resolvable + Delegable, + T: Resolvable, C: Condition, DID: Did, S: Store, P: promise::Store, - D: delegation::store::Store, + D: delegation::store::Store, V: varsig::Header, Enc: Codec + Into + TryFrom, > { @@ -51,13 +56,13 @@ impl<'a, T, C, DID, S, P, D, V, Enc> Agent<'a, T, C, DID, S, P, D, V, Enc> where T::Promised: Clone, Ipld: Encode, - delegation::Payload<::Hierarchy, C, DID>: Clone, - T: Resolvable + Delegable + Clone, + delegation::Payload: Clone, + T: Resolvable + Clone, C: Condition, DID: Did + Clone, S: Store, P: promise::Store, - D: delegation::store::Store, + D: delegation::store::Store, V: varsig::Header, Enc: Codec + Into + TryFrom, { @@ -80,8 +85,8 @@ where pub fn invoke( &mut self, - audience: Option<&DID>, - subject: &DID, + audience: Option, + subject: DID, ability: T, metadata: BTreeMap, cause: Option, @@ -90,32 +95,42 @@ where now: SystemTime, varsig_header: V, ) -> Result< - Invocation, + Invocation, InvokeError< D::DelegationStoreError, - ParseAbilityError<<::Builder as ParseAbility>::ArgsErr>, + ParseAbilityError<()>, // FIXME argserror >, - > - where - <::Promised as ParsePromised>::PromisedArgsError: fmt::Debug, - { - self.invoke_promise( - audience, + > { + let proofs = self + .delegation_store + .get_chain(self.did, &Some(subject.clone()), vec![], now) + .map_err(InvokeError::DelegationStoreError)? + .map(|chain| chain.map(|(cid, _)| cid).into()) + .unwrap_or(vec![]); + + let mut seed = vec![]; + + let payload = Payload { + issuer: self.did.clone(), subject, - Resolvable::into_promised(ability), + audience, + ability, + proofs, metadata, + nonce: Nonce::generate_12(&mut seed), cause, expiration, issued_at, - now, - varsig_header, - ) + }; + + Ok(Invocation::try_sign(self.signer, varsig_header, payload) + .map_err(InvokeError::SignError)?) } pub fn invoke_promise( &mut self, audience: Option<&DID>, - subject: &DID, + subject: DID, ability: T::Promised, metadata: BTreeMap, cause: Option, @@ -127,19 +142,12 @@ where Invocation, InvokeError< D::DelegationStoreError, - ParseAbilityError<<::Builder as ParseAbility>::ArgsErr>, + ParseAbilityError<()>, // FIXME errs >, > { let proofs = self .delegation_store - .get_chain( - self.did, - subject, - &::try_to_builder(ability.clone()) - .map_err(InvokeError::PromiseResolveError)?, - vec![], - now, - ) + .get_chain(self.did, &Some(subject.clone()), vec![], now) .map_err(InvokeError::DelegationStoreError)? .map(|chain| chain.map(|(cid, _)| cid).into()) .unwrap_or(vec![]); @@ -148,7 +156,7 @@ where let payload = Payload { issuer: self.did.clone(), - subject: subject.clone(), + subject, audience: audience.cloned(), ability, proofs, @@ -172,12 +180,10 @@ where ReceiveError, > where - Enc: From + Into, - T::Builder: Clone + Encode, C: Clone, - ::Hierarchy: Clone, + Enc: From + Into, + arguments::Named: From, Invocation: Clone, - <<::Builder as Checkable>::Hierarchy as Prove>::Error: fmt::Debug,

>::PromiseStoreError: fmt::Debug, signature::Envelope, DID, V, Enc>: Clone, ::Promised, DID, V, Enc>>::InvocationStoreError: fmt::Debug, @@ -217,9 +223,9 @@ where let resolved_payload = promised.payload().clone().map_ability(|_| resolved_ability); - delegation::Payload::::from(resolved_payload.clone()) + let _ = &resolved_payload .check(proof_payloads, now) - .map_err(ReceiveError::DelegationValidationError)?; + .map_err(ReceiveError::ValidationError)?; if promised.audience() != &Some(self.did.clone()) { return Ok(Recipient::Other(resolved_payload)); @@ -230,7 +236,7 @@ where pub fn revoke( &mut self, - subject: &DID, + subject: DID, cause: Option, cid: Cid, now: Timestamp, @@ -241,17 +247,11 @@ where T: From, { let ability: T = ucan::revoke::Ready { ucan: cid.clone() }.into(); - let proofs = if subject == self.did { + let proofs = if &subject == self.did { vec![] } else { self.delegation_store - .get_chain( - subject, - self.did, - &ability.clone().into(), - vec![], - now.into(), - ) + .get_chain(&subject, &Some(self.did.clone()), vec![], now.into()) .map_err(|_| ())? .map(|chain| chain.map(|(index_cid, _)| index_cid).into()) .unwrap_or(vec![]) @@ -297,10 +297,6 @@ pub enum ReceiveError< V: varsig::Header, Enc: Codec + From + Into, > where - delegation::ValidationError< - <<::Builder as Checkable>::Hierarchy as Prove>::Error, - C, - >: fmt::Debug,

>::PromiseStoreError: fmt::Debug, ::Promised, DID, V, Enc>>::InvocationStoreError: fmt::Debug, { @@ -322,13 +318,7 @@ pub enum ReceiveError< DelegationStoreError(#[source] D), #[error("delegation validation error: {0}")] - DelegationValidationError( - #[source] - delegation::ValidationError< - <<::Builder as Checkable>::Hierarchy as Prove>::Error, - C, - >, - ), + ValidationError(#[source] ValidationError), } #[derive(Debug, Error)] diff --git a/src/invocation/payload.rs b/src/invocation/payload.rs index fa0e9aea..0350aa98 100644 --- a/src/invocation/payload.rs +++ b/src/invocation/payload.rs @@ -3,9 +3,8 @@ use crate::{ ability::{arguments, command::ToCommand, parse::ParseAbility}, capsule::Capsule, crypto::Nonce, - delegation::{self, condition::Condition, Delegable, ValidationError}, + delegation::{self, condition::Condition}, //, ValidationError}, did::{Did, Verifiable}, - proof::{checkable::Checkable, prove::Prove}, time::{Expired, Timestamp}, }; use libipld_core::{cid::Cid, ipld::Ipld}; @@ -14,7 +13,8 @@ use serde::{ ser::SerializeStruct, Deserialize, Serialize, Serializer, }; -use std::{collections::BTreeMap, fmt::Debug}; +use std::{collections::BTreeMap, fmt}; +use thiserror::Error; use web_time::SystemTime; #[cfg(feature = "test_utils")] @@ -132,48 +132,95 @@ impl Payload { Ok(()) } - pub fn check( - self, - proofs: Vec<&delegation::Payload<::Hierarchy, C, DID>>, + pub fn check( + &self, + proofs: Vec<&delegation::Payload>, now: &SystemTime, - ) -> Result<(), ValidationError<<::Hierarchy as Prove>::Error, C>> + ) -> Result<(), ValidationError> where - A: Delegable, - A::Builder: Clone + Into>, - ::Hierarchy: Clone + Into>, + A: Clone, DID: Clone, + arguments::Named: From, { - let builder_payload: delegation::Payload = self.into(); - builder_payload.check(proofs, now) + let args: arguments::Named = self.ability.clone().into(); + + proofs.into_iter().try_fold(&self.issuer, |iss, proof| { + // FIXME extract step function? + if *iss != proof.audience { + return Err(ValidationError::InvalidSubject.into()); + } + + if let Some(proof_subject) = &proof.subject { + if self.subject != *proof_subject { + return Err(ValidationError::MisalignedIssAud.into()); + } + } + + if SystemTime::from(proof.expiration.clone()) > *now { + return Err(ValidationError::Expired.into()); + } + + if let Some(nbf) = proof.not_before.clone() { + if SystemTime::from(nbf) > *now { + return Err(ValidationError::NotYetValid.into()); + } + } + + for predicate in proof.conditions.iter() { + if !predicate.validate(&args) { + return Err(ValidationError::FailedCondition(predicate.clone())); + } + } + + Ok(&proof.issuer) + })?; + + Ok(()) } } +/// Delegation validation errors. +#[derive(Debug, Clone, PartialEq, Eq, Error)] +pub enum ValidationError { + #[error("The subject of the delegation is invalid")] + InvalidSubject, + + #[error("The issuer and audience of the delegation are misaligned")] + MisalignedIssAud, + + #[error("The delegation has expired")] + Expired, + + #[error("The delegation is not yet valid")] + NotYetValid, + + #[error("The delegation failed a condition: {0:?}")] + FailedCondition(C), +} + impl Capsule for Payload { const TAG: &'static str = "ucan/i/1.0.0-rc.1"; } -impl From> - for delegation::Payload -{ - fn from(inv_payload: Payload) -> Self { - delegation::Payload { - issuer: inv_payload.issuer, - subject: inv_payload.subject.clone(), - audience: inv_payload.audience.unwrap_or(inv_payload.subject), - - ability_builder: A::Builder::from(inv_payload.ability), - conditions: vec![], - - metadata: inv_payload.metadata, - nonce: inv_payload.nonce, - - not_before: None, - expiration: inv_payload - .expiration - .unwrap_or(Timestamp::postel(SystemTime::now())), - } - } -} +// impl From> for delegation::Payload { +// fn from(inv_payload: Payload) -> Self { +// delegation::Payload { +// issuer: inv_payload.issuer, +// subject: Some(inv_payload.subject.clone()), +// audience: inv_payload.audience.unwrap_or(inv_payload.subject), +// +// conditions: vec![], +// +// metadata: inv_payload.metadata, +// nonce: inv_payload.nonce, +// +// not_before: None, +// expiration: inv_payload +// .expiration +// .unwrap_or(Timestamp::postel(SystemTime::now())), +// } +// } +// } impl, DID: Did> From> for arguments::Named { fn from(payload: Payload) -> Self { @@ -408,7 +455,7 @@ impl From> for Ipld { } #[cfg(feature = "test_utils")] -impl Arbitrary for Payload +impl Arbitrary for Payload where T::Strategy: 'static, DID::Parameters: Clone, diff --git a/src/invocation/promise/resolvable.rs b/src/invocation/promise/resolvable.rs index 17c9cd0d..e9b351ad 100644 --- a/src/invocation/promise/resolvable.rs +++ b/src/invocation/promise/resolvable.rs @@ -4,7 +4,6 @@ use crate::{ command::ToCommand, parse::{ParseAbility, ParseAbilityError, ParsePromised}, }, - delegation::Delegable, invocation::promise::Pending, ipld, }; @@ -18,7 +17,7 @@ use thiserror::Error; /// A trait for [`Delegable`]s that can be deferred (by promises). /// /// FIXME exmaples -pub trait Resolvable: Delegable { +pub trait Resolvable: Sized + ParseAbility + ToCommand { /// The promise type that resolves to `Self`. /// /// Note that this may be a more complex type than the promise selector @@ -30,18 +29,17 @@ pub trait Resolvable: Delegable { + ParsePromised // TryFrom> + Into>; - fn into_promised(self) -> Self::Promised - where - ::PromisedArgsError: fmt::Debug, - { - // FIXME In no way efficient... override where possible, or just cut the impl - let builder = Self::Builder::from(self); - let cmd = &builder.to_command(); - let named_ipld: arguments::Named = builder.into(); - let promised_ipld: arguments::Named = named_ipld.into(); - ::Promised::try_parse_promised(cmd, promised_ipld) - .expect("promise to always be possible from a ready ability") - } + // fn into_promised(self) -> Self::Promised + // where + // ::PromisedArgsError: fmt::Debug, + // { + // // FIXME In no way efficient... override where possible, or just cut the impl + // let cmd = &builder.to_command(); + // let named_ipld: arguments::Named = builder.into(); + // let promised_ipld: arguments::Named = named_ipld.into(); + // ::Promised::try_parse_promised(cmd, promised_ipld) + // .expect("promise to always be possible from a ready ability") + // } /// Attempt to resolve the [`Self::Promised`]. fn try_resolve(promised: Self::Promised) -> Result> @@ -55,15 +53,11 @@ pub trait Resolvable: Delegable { reason: ResolveError::StillWaiting(pending), }), Ok(named) => { - let builder = Self::Builder::try_parse(promised.to_command().as_str(), named) - .map_err(|_reason| CantResolve { - promised: promised.clone(), + ParseAbility::try_parse(&promised.to_command(), named).map_err(|_reason| { + CantResolve { + promised, reason: ResolveError::ConversionError, - })?; - - builder.try_into().map_err(|_reason| CantResolve { - promised, - reason: ResolveError::ConversionError, + } }) } } @@ -82,32 +76,6 @@ pub trait Resolvable: Delegable { set }) } - - fn try_to_builder( - promised: Self::Promised, - ) -> Result< - Self::Builder, - ParseAbilityError<<::Builder as ParseAbility>::ArgsErr>, - > { - let cmd = promised.to_command(); - let ipld_promise: arguments::Named = promised.into(); - - let named: arguments::Named = - ipld_promise - .into_iter() - .fold(arguments::Named::new(), |mut acc, (k, v)| { - match v.try_into() { - Err(_) => (), - Ok(ipld) => { - acc.insert(k, ipld); // i.e. forget any promises - } - } - - acc - }); - - Self::Builder::try_parse(&cmd, named) - } } #[derive(Error, Clone)] @@ -119,7 +87,6 @@ pub struct CantResolve { impl fmt::Debug for CantResolve where S::Promised: fmt::Debug, - <::Builder as ParseAbility>::ArgsErr: fmt::Debug, Pending: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/lib.rs b/src/lib.rs index 694c91aa..32a40fdc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ pub mod delegation; pub mod did; pub mod invocation; pub mod ipld; -pub mod proof; +//pub mod proof; pub mod reader; pub mod receipt; pub mod task; diff --git a/src/proof.rs b/src/proof.rs index 82092cb5..de58a8ff 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -1,12 +1,12 @@ //! Proof chains, checking, and utilities. -pub mod checkable; -pub mod error; -pub mod parentful; -pub mod parentless; -pub mod parents; -pub mod prove; -pub mod same; +// pub mod checkable; +// pub mod error; +// pub mod parentful; +// pub mod parentless; +// pub mod parents; +// pub mod prove; +// pub mod same; // NOTE must remain *un*exported! -pub(super) mod internal; +// pub(super) mod internal; diff --git a/src/url.rs b/src/url.rs index efa2f68f..d23b8efb 100644 --- a/src/url.rs +++ b/src/url.rs @@ -1,6 +1,6 @@ //! URL utilities. -use crate::proof::same::CheckSame; +// use crate::proof::same::CheckSame; use libipld_core::ipld::Ipld; use serde::{Deserialize, Serialize}; use std::fmt; @@ -50,17 +50,17 @@ impl fmt::Display for Newtype { } } -impl CheckSame for Newtype { - type Error = (); - - fn check_same(&self, other: &Self) -> Result<(), Self::Error> { - if self == other { - Ok(()) - } else { - Err(()) - } - } -} +// impl CheckSame for Newtype { +// type Error = (); +// +// fn check_same(&self, other: &Self) -> Result<(), Self::Error> { +// if self == other { +// Ok(()) +// } else { +// Err(()) +// } +// } +// } impl From for Ipld { fn from(newtype: Newtype) -> Self { From 56668999bcb5becbeefa0eb3898c1c349ae03488 Mon Sep 17 00:00:00 2001 From: Brooklyn Zelenka Date: Tue, 27 Feb 2024 12:26:32 -0800 Subject: [PATCH 2/2] Working on policy DSL --- src/delegation.rs | 1 + src/delegation/condition.rs | 1 + src/delegation/policy.rs | 2 + src/delegation/policy/frontend.rs | 62 +++++ src/delegation/policy/ir.rs | 379 ++++++++++++++++++++++++++++++ 5 files changed, 445 insertions(+) create mode 100644 src/delegation/policy.rs create mode 100644 src/delegation/policy/frontend.rs create mode 100644 src/delegation/policy/ir.rs diff --git a/src/delegation.rs b/src/delegation.rs index e4c077db..543ce82b 100644 --- a/src/delegation.rs +++ b/src/delegation.rs @@ -13,6 +13,7 @@ //! - [`store`] is an interface for caching [`Delegation`]s. pub mod condition; +pub mod policy; pub mod store; mod agent; diff --git a/src/delegation/condition.rs b/src/delegation/condition.rs index f9594bbc..868f90b9 100644 --- a/src/delegation/condition.rs +++ b/src/delegation/condition.rs @@ -27,6 +27,7 @@ pub use traits::Condition; use crate::ability::arguments; use libipld_core::{error::SerdeError, ipld::Ipld, serde as ipld_serde}; use serde_derive::{Deserialize, Serialize}; +use std::collections::BTreeMap; /// The union of the common [`Condition`]s that ship directly with this library. #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/src/delegation/policy.rs b/src/delegation/policy.rs new file mode 100644 index 00000000..6f111432 --- /dev/null +++ b/src/delegation/policy.rs @@ -0,0 +1,2 @@ +pub mod frontend; +pub mod ir; diff --git a/src/delegation/policy/frontend.rs b/src/delegation/policy/frontend.rs new file mode 100644 index 00000000..4ac89bb9 --- /dev/null +++ b/src/delegation/policy/frontend.rs @@ -0,0 +1,62 @@ +use super::ir; +use libipld_core::ipld::Ipld; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Term { + // Leaves + Args, // $ + Literal(Ipld), + Variable(Variable), + + Selector(Selector), + + // Connectives + Not(Box), + And(Vec), + Or(Vec), + + // Comparison + Equal(Value, Value), + GreaterThan(Value, Value), + GreaterOrEqual(Value, Value), + LessThan(Value, Value), + LessOrEqual(Value, Value), + + // String Matcher + Glob(Value, String), + + // Existential Quantification + Exists(Variable, Collection), // ∃x ∈ xs +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Variable(String); // ?x + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Collection { + Array(Vec), + Map(BTreeMap), + Variable(Variable), + Selector(Selector), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Selector(Vec); // .foo.bar[].baz + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Index { + This, + // RecDesend, // .. + FlattenAll, // .[] + Index(usize), // .[2] + Key(String), // .key +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Value { + Literal(Ipld), + Variable(Variable), + ImplicitBind(Selector), +} diff --git a/src/delegation/policy/ir.rs b/src/delegation/policy/ir.rs new file mode 100644 index 00000000..fe1ce03b --- /dev/null +++ b/src/delegation/policy/ir.rs @@ -0,0 +1,379 @@ +use libipld_core::ipld::Ipld; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Term { + // Leaves + Args, // $ + Literal(Ipld), + Stream(Stream), + + Selector(Selector), + + // Connectives + Not(Box), + And(Vec), + Or(Vec), + + // Comparison + Equal(Value, Value), + GreaterThan(Value, Value), + GreaterOrEqual(Value, Value), + LessThan(Value, Value), + LessOrEqual(Value, Value), + + // String Matcher + Glob(Value, String), + + // Existential Quantification + Exists(Variable, Collection), // ∃x ∈ xs -> convert every -> some +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Variable(String); // ?x + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Collection { + Array(Vec), + Map(BTreeMap), + Variable(Variable), + Selector(Selector), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Selector(Vec); // .foo.bar[].baz + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum PathSegment { + This, // . + // RecDesend, // .. + FlattenAll, // .[] --> creates an Every stream + Index(usize), // .[2] + Key(String), // .key +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Value { + Literal(Ipld), + Variable(Variable), +} + +// #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +// pub Struct EveryStream(Vec); +// +// #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +// pub struct SomeStream(Vec); + +pub fn glob(input: String, pattern: String) -> bool { + let mut input = input.chars(); + let mut pattern = pattern.chars(); + + loop { + match (input.next(), pattern.next()) { + (Some(i), Some(p)) => { + if p == '*' { + return true; + } else if i != p { + return false; + } + } + (Some(_), None) => { + return false; // FIXME correct? + } + (None, Some(p)) => { + if p == '*' { + return true; + } + } + (None, None) => { + return true; + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Stream { + Every(Vec), // "All or nothing" + Some(Vec), +} + +pub struct EveryStream(Vec); +pub struct SomeStream(Vec); + +pub trait Apply { + fn apply(&self, other: &T, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool; +} + +impl Apply for Ipld { + fn apply(&self, other: &Ipld, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + if f(self, other) { + ( + Stream::Every(vec![self.clone()]), + Stream::Every(vec![other.clone()]), + ) + } else { + (Stream::Every(vec![]), Stream::Every(vec![])) + } + } +} + +impl Apply for Ipld { + fn apply(&self, other: &EveryStream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut y_results = vec![]; + + for y in other.0.iter() { + if f(self, y) { + y_results.push(y.clone()); + } else { + y_results = vec![]; + break; + } + } + + if y_results.is_empty() { + (Stream::Every(vec![]), Stream::Every(vec![])) + } else { + (Stream::Every(vec![self.clone()]), Stream::Every(y_results)) + } + } +} + +impl Apply for EveryStream { + fn apply(&self, other: &Ipld, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut x_results = vec![]; + + for x in self.0.iter() { + if f(x, other) { + x_results.push(x.clone()); + } else { + x_results = vec![]; + break; + } + } + + if x_results.is_empty() { + (Stream::Every(vec![]), Stream::Every(vec![])) + } else { + (Stream::Every(x_results), Stream::Every(vec![other.clone()])) + } + } +} + +impl Apply for EveryStream { + fn apply(&self, other: &EveryStream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut x_results = vec![]; + let mut y_results = vec![]; + + for x in self.0.iter() { + for y in other.0.iter() { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } else { + x_results = vec![]; + y_results = vec![]; + break; + } + } + } + + (Stream::Every(x_results), Stream::Every(y_results)) + } +} + +impl Apply for EveryStream { + fn apply(&self, other: &SomeStream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut x_results = vec![]; + let mut y_results = vec![]; + + for x in self.0.iter() { + for y in other.0.iter() { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } else { + x_results = vec![]; + y_results.push(y.clone()); + break; + } + } + } + + (Stream::Every(x_results), Stream::Some(y_results)) + } +} + +impl Apply for SomeStream { + fn apply(&self, other: &EveryStream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut x_results = vec![]; + let mut y_results = vec![]; + + for x in self.0.iter() { + for y in other.0.iter() { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } else { + x_results = vec![]; + y_results.push(y.clone()); + break; + } + } + } + + (Stream::Some(x_results), Stream::Every(y_results)) + } +} + +impl Apply for SomeStream { + fn apply(&self, other: &SomeStream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + let mut x_results = vec![]; + let mut y_results = vec![]; + + for x in self.0.iter() { + for y in other.0.iter() { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } + } + } + + (Stream::Some(x_results), Stream::Some(y_results)) + } +} + +impl Apply for Stream { + fn apply(&self, other: &Stream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + match self { + Stream::Every(xs) => match other { + Stream::Every(ys) => EveryStream(xs.clone()).apply(&EveryStream(ys.clone()), f), + Stream::Some(ys) => EveryStream(xs.clone()).apply(&EveryStream(ys.clone()), f), + }, + + Stream::Some(xs) => match other { + Stream::Every(ys) => SomeStream(xs.clone()).apply(&EveryStream(ys.clone()), f), + Stream::Some(ys) => SomeStream(xs.clone()).apply(&SomeStream(ys.clone()), f), + }, + } + } +} + +impl Stream { + /// Call like stream.apply(other_stream, |x, y| x == y) + pub fn apply(&self, other: &Stream, f: F) -> (Stream, Stream) + where + F: Fn(&Ipld, &Ipld) -> bool, + { + match self { + Stream::Every(xs) => match other { + Stream::Every(ys) => { + let mut x_results = Vec::new(); + let mut y_results = Vec::new(); + + for x in xs { + for y in ys { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } else { + x_results = vec![]; + y_results = vec![]; + break; + } + } + } + + (Stream::Every(x_results), Stream::Every(y_results)) + } + Stream::Some(ys) => { + let mut x_results = Vec::new(); + let mut y_results = Vec::new(); + + for x in xs { + for y in ys { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } else { + x_results = vec![]; + break; + } + } + } + + if &Stream::Every(x_results.clone()) == self { + (Stream::Every(x_results), Stream::Some(y_results)) + } else { + (Stream::Every(vec![]), Stream::Some(y_results)) + } + } + }, + + Stream::Some(xs) => match other { + Stream::Every(ys) => { + let mut x_results = Vec::new(); + let mut y_results = Vec::new(); + + for x in xs { + for y in ys { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(x.clone()); + } else { + x_results.push(x.clone()); + y_results = vec![]; + break; + } + } + } + + (Stream::Some(x_results), Stream::Every(y_results)) + } + Stream::Some(ys) => { + let mut x_results = Vec::new(); + let mut y_results = Vec::new(); + + for x in xs { + for y in ys { + if f(x, y) { + x_results.push(x.clone()); + y_results.push(y.clone()); + } + } + } + + (Stream::Some(x_results), Stream::Some(y_results)) + } + }, + } + } +}