From 4dca1b16157b31b31375b022bd0980deb92d6bb3 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Thu, 9 Feb 2023 00:17:12 +0100 Subject: [PATCH] More updates to gatekeeper protocol --- dev-scripts/benchmark-config.pr | 2 +- syndicate-server/examples/consumer.rs | 2 +- syndicate-server/examples/dirty-consumer.rs | 2 +- syndicate-server/examples/dirty-producer.rs | 2 +- syndicate-server/examples/pingpong.rs | 2 +- syndicate-server/examples/producer.rs | 2 +- syndicate-server/examples/state-consumer.rs | 2 +- syndicate-server/examples/state-producer.rs | 2 +- syndicate-server/src/gatekeeper.rs | 154 +++++++++++--------- syndicate/src/relay.rs | 10 +- syndicate/src/sturdy.rs | 44 ++++-- 11 files changed, 131 insertions(+), 93 deletions(-) diff --git a/dev-scripts/benchmark-config.pr b/dev-scripts/benchmark-config.pr index 51ff005..45562b3 100644 --- a/dev-scripts/benchmark-config.pr +++ b/dev-scripts/benchmark-config.pr @@ -1,3 +1,3 @@ let ?root_ds = dataspace $gatekeeper>> - $root_ds #f> + $root_ds #f> diff --git a/syndicate-server/examples/consumer.rs b/syndicate-server/examples/consumer.rs index bc4ad65..c231566 100644 --- a/syndicate-server/examples/consumer.rs +++ b/syndicate-server/examples/consumer.rs @@ -15,7 +15,7 @@ use core::time::Duration; #[derive(Clone, Debug, StructOpt)] pub struct Config { - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/dirty-consumer.rs b/syndicate-server/examples/dirty-consumer.rs index 6f38108..e578439 100644 --- a/syndicate-server/examples/dirty-consumer.rs +++ b/syndicate-server/examples/dirty-consumer.rs @@ -26,7 +26,7 @@ mod dirty; #[derive(Clone, Debug, StructOpt)] pub struct Config { - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/dirty-producer.rs b/syndicate-server/examples/dirty-producer.rs index 34bfc14..888d16e 100644 --- a/syndicate-server/examples/dirty-producer.rs +++ b/syndicate-server/examples/dirty-producer.rs @@ -25,7 +25,7 @@ pub struct Config { #[structopt(short = "b", default_value = "0")] bytes_padding: usize, - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/pingpong.rs b/syndicate-server/examples/pingpong.rs index 545abc7..a969043 100644 --- a/syndicate-server/examples/pingpong.rs +++ b/syndicate-server/examples/pingpong.rs @@ -43,7 +43,7 @@ pub struct Config { #[structopt(subcommand)] mode: PingPongMode, - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/producer.rs b/syndicate-server/examples/producer.rs index af7b1a1..61eacfc 100644 --- a/syndicate-server/examples/producer.rs +++ b/syndicate-server/examples/producer.rs @@ -16,7 +16,7 @@ pub struct Config { #[structopt(short = "b", default_value = "0")] bytes_padding: usize, - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/state-consumer.rs b/syndicate-server/examples/state-consumer.rs index 4168f66..72e5e56 100644 --- a/syndicate-server/examples/state-consumer.rs +++ b/syndicate-server/examples/state-consumer.rs @@ -15,7 +15,7 @@ use core::time::Duration; #[derive(Clone, Debug, StructOpt)] pub struct Config { - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/examples/state-producer.rs b/syndicate-server/examples/state-producer.rs index 0ad2c64..b1f5439 100644 --- a/syndicate-server/examples/state-producer.rs +++ b/syndicate-server/examples/state-producer.rs @@ -10,7 +10,7 @@ use tokio::net::TcpStream; #[derive(Clone, Debug, StructOpt)] pub struct Config { - #[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] + #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")] dataspace: String, } diff --git a/syndicate-server/src/gatekeeper.rs b/syndicate-server/src/gatekeeper.rs index a3ce185..699889c 100644 --- a/syndicate-server/src/gatekeeper.rs +++ b/syndicate-server/src/gatekeeper.rs @@ -27,77 +27,78 @@ use crate::language::language; use syndicate_macros::during; use syndicate_macros::pattern; -pub fn handle_binds(t: &mut Activation, ds: &Arc) -> ActorResult { - Ok(during!(t, ds, language(), , |t: &mut Activation| { - t.spawn_link(None, move |t| { handle_bind(t, description, target, observer) }); - Ok(()) - })) +fn sturdy_step_type() -> String { + language().unparse(&sturdy::SturdyStepType).value().to_symbol().unwrap().clone() } -fn handle_bind( - t: &mut Activation, - description: AnyValue, - target: AnyValue, - observer: AnyValue, -) -> ActorResult { - let _target = target.value().to_embedded()?; - let observer = language().parse::(&observer)?; +fn noise_step_type() -> String { + language().unparse(&noise::NoiseStepType).value().to_symbol().unwrap().clone() +} - if let Ok(s) = language().parse::(&description) { - let sr = sturdy::SturdyRef::mint(s.oid, &s.key); - if let gatekeeper::BindObserver::Present(o) = observer { - o.assert(t, language(), &gatekeeper::Bound::Bound { - step: language().unparse(&sr), - }); - } - return Ok(()); - } - - if let Ok(s) = language().parse::>(&description) { - match validate_noise_spec(s.spec) { - Ok(spec) => if let gatekeeper::BindObserver::Present(o) = observer { +pub fn handle_binds(t: &mut Activation, ds: &Arc) -> ActorResult { + during!(t, ds, language(), $target $observer>, |t: &mut Activation| { + t.spawn_link(None, move |t| { + target.value().to_embedded()?; + let observer = language().parse::(&observer)?; + let desc = language().parse::(&desc)?; + let sr = sturdy::SturdyRef::mint(desc.oid, &desc.key); + if let gatekeeper::BindObserver::Present(o) = observer { o.assert(t, language(), &gatekeeper::Bound::Bound { - step: language().unparse(&noise::NoiseRouteStep { - spec: noise::NoiseSpec { - key: spec.public_key, - service: noise::ServiceSelector(spec.service), - protocol: if spec.protocol == default_noise_protocol() { - noise::NoiseProtocol::Absent - } else { - noise::NoiseProtocol::Present { - protocol: spec.protocol, - } - }, - pre_shared_keys: if spec.psks.is_empty() { - noise::NoisePreSharedKeys::Absent - } else { - noise::NoisePreSharedKeys::Present { - pre_shared_keys: spec.psks, - } - }, - }, + path_step: Box::new(gatekeeper::PathStep { + step_type: sturdy_step_type(), + detail: language().unparse(&sr.parameters), }), }); - }, - Err(e) => { - if let gatekeeper::BindObserver::Present(o) = observer { - o.assert(t, language(), &gatekeeper::Bound::Rejected( - Box::new(gatekeeper::Rejected { - detail: AnyValue::new(format!("{}", &e)), - }))); - } - tracing::error!("Invalid noise bind description: {}", e); } - } - return Ok(()); - } - - if let gatekeeper::BindObserver::Present(o) = observer { - o.assert(t, language(), &gatekeeper::Bound::Rejected( - Box::new(gatekeeper::Rejected { - detail: AnyValue::symbol("unsupported"), - }))); - } + Ok(()) + }); + Ok(()) + }); + during!(t, ds, language(), $target $observer>, |t: &mut Activation| { + t.spawn_link(None, move |t| { + target.value().to_embedded()?; + let observer = language().parse::(&observer)?; + let spec = language().parse::>(&desc)?.0; + match validate_noise_spec(spec) { + Ok(spec) => if let gatekeeper::BindObserver::Present(o) = observer { + o.assert(t, language(), &gatekeeper::Bound::Bound { + path_step: Box::new(gatekeeper::PathStep { + step_type: noise_step_type(), + detail: language().unparse(&noise::NoisePathStepDetail(noise::NoiseSpec { + key: spec.public_key, + service: noise::ServiceSelector(spec.service), + protocol: if spec.protocol == default_noise_protocol() { + noise::NoiseProtocol::Absent + } else { + noise::NoiseProtocol::Present { + protocol: spec.protocol, + } + }, + pre_shared_keys: if spec.psks.is_empty() { + noise::NoisePreSharedKeys::Absent + } else { + noise::NoisePreSharedKeys::Present { + pre_shared_keys: spec.psks, + } + }, + })), + }), + }); + }, + Err(e) => { + if let gatekeeper::BindObserver::Present(o) = observer { + o.assert(t, language(), &gatekeeper::Bound::Rejected( + Box::new(gatekeeper::Rejected { + detail: AnyValue::new(format!("{}", &e)), + }))); + } + tracing::error!("Invalid noise bind description: {}", e); + } + } + Ok(()) + }); + Ok(()) + }); Ok(()) } @@ -114,15 +115,24 @@ pub fn handle_resolves( t: &mut Activation, a: gatekeeper::Resolve, ) -> DuringResult> { - let step = language().unparse(&a.step); - if let Ok(s) = language().parse::(&step) { - return handle_resolve_sturdyref(ds, t, s.0, a.observer); + let mut detail: &'static str = "unsupported"; + + if a.step.step_type == sturdy_step_type() { + detail = "invalid"; + if let Ok(s) = language().parse::(&a.step.detail) { + return handle_resolve_sturdyref(ds, t, sturdy::SturdyRef { parameters: s.0 }, a.observer); + } } - if let Ok(s) = language().parse::>(&step) { - return handle_resolve_noise(ds, t, s.service.0, a.observer); + + if a.step.step_type == noise_step_type() { + detail = "invalid"; + if let Ok(s) = language().parse::>(&a.step.detail) { + return handle_resolve_noise(ds, t, s.0.0, a.observer); + } } + eventually_retract(ds.assert(t, language(), &gatekeeper::Rejected { - detail: AnyValue::symbol("unsupported"), + detail: AnyValue::symbol(detail), })) } @@ -132,7 +142,7 @@ fn handle_resolve_sturdyref( sturdyref: sturdy::SturdyRef, observer: Arc, ) -> DuringResult> { - let queried_oid = sturdyref.oid.clone(); + let queried_oid = sturdyref.parameters.oid.clone(); let handler = syndicate::entity(observer) .on_asserted(move |observer, t, a: AnyValue| { let bindings = a.value().to_sequence()?; @@ -160,7 +170,7 @@ fn handle_resolve_sturdyref( .create_cap(t); eventually_retract(ds.assert(t, language(), &dataspace::Observe { // TODO: codegen plugin to generate pattern constructors - pattern: pattern!{ $ _>}, + pattern: pattern!{ $ _>}, observer: handler, })) } diff --git a/syndicate/src/relay.rs b/syndicate/src/relay.rs index 5fc1e13..7d0efd9 100644 --- a/syndicate/src/relay.rs +++ b/syndicate/src/relay.rs @@ -195,14 +195,16 @@ pub fn connect_stream( let i = Input::Bytes(Box::pin(i)); let o = Output::Bytes(Box::pin(o)); let gatekeeper = TunnelRelay::run(t, i, o, None, Some(sturdy::Oid(0.into())), output_text).unwrap(); - let main_entity = t.create(during::entity(initial_state).on_asserted(move |state, t, a: AnyValue| { - let denotation = a.value().to_embedded()?; - f(state, t, Arc::clone(denotation)) + let main_entity = t.create(during::entity(initial_state).on_asserted(move |state, t, a: gatekeeper::Resolved| { + match a { + gatekeeper::Resolved::Accepted { responder_session } => f(state, t, responder_session), + gatekeeper::Resolved::Rejected(r) => Err(error("Resolve rejected", r.detail))?, + } })); let step = language().parse::(&language().unparse(&step))?; gatekeeper.assert(t, language(), &gatekeeper::Resolve:: { step, - observer: Cap::new(&main_entity), + observer: Cap::guard(Language::arc(), main_entity), }); Ok(()) } diff --git a/syndicate/src/sturdy.rs b/syndicate/src/sturdy.rs index aae9207..740f6b3 100644 --- a/syndicate/src/sturdy.rs +++ b/syndicate/src/sturdy.rs @@ -21,6 +21,7 @@ pub use super::schemas::sturdy::*; pub enum ValidationError { SignatureError, AttenuationError(CaveatError), + BadCaveatsField, } impl std::fmt::Display for ValidationError { @@ -30,6 +31,8 @@ impl std::fmt::Display for ValidationError { write!(f, "Invalid SturdyRef signature"), ValidationError::AttenuationError(e) => write!(f, "Invalid SturdyRef attenuation: {:?}", e), + ValidationError::BadCaveatsField => + write!(f, "Invalid caveats field in SturdyRef parameters"), } } } @@ -71,7 +74,21 @@ pub fn decode(bs: &[u8]) -> io::Result { impl SturdyRef { pub fn mint(oid: _Any, key: &[u8]) -> Self { let sig = signature(key, &encode(&oid)); - SturdyRef { oid, caveat_chain: Vec::new(), sig } + SturdyRef::from_parts(oid, vec![], sig) + } + + pub fn from_parts(oid: _Any, caveats: Vec, sig: Vec) -> Self { + SturdyRef { + parameters: Parameters { + oid, + sig, + caveats: if caveats.is_empty() { + CaveatsField::Absent + } else { + CaveatsField::Present { caveats } + } + } + } } pub fn from_hex(s: &str) -> Result { @@ -83,6 +100,14 @@ impl SturdyRef { HexFormatter::Packed.encode(&encode(&language().unparse(self))) } + pub fn caveat_chain(&self) -> Result<&[Caveat], ValidationError> { + match &self.parameters.caveats { + CaveatsField::Absent => Ok(&[]), + CaveatsField::Invalid { .. } => Err(ValidationError::BadCaveatsField), + CaveatsField::Present { caveats } => Ok(caveats), + } + } + pub fn validate_and_attenuate( &self, key: &[u8], @@ -90,14 +115,15 @@ impl SturdyRef { ) -> Result<_Ptr, ValidationError> { self.validate(key).map_err(|_| ValidationError::SignatureError)?; let target = unattenuated_target - .attenuate(&self.caveat_chain) + .attenuate(self.caveat_chain()?) .map_err(ValidationError::AttenuationError)?; Ok(target) } pub fn validate(&self, key: &[u8]) -> Result<(), ()> { - let SturdyRef { oid, caveat_chain, sig } = self; - let key = chain_signature(&signature(&key, &encode(oid)), caveat_chain); + let SturdyRef { parameters: Parameters { oid, sig, .. } } = self; + let key = chain_signature(&signature(&key, &encode(oid)), + self.caveat_chain().map_err(|_| ())?); if &key == sig { Ok(()) } else { @@ -105,13 +131,13 @@ impl SturdyRef { } } - pub fn attenuate(&self, attenuation: &[Caveat]) -> Result { - Caveat::validate_many(attenuation)?; - let SturdyRef { oid, caveat_chain, sig } = self; + pub fn attenuate(&self, attenuation: &[Caveat]) -> Result { + Caveat::validate_many(attenuation).map_err(ValidationError::AttenuationError)?; + let SturdyRef { parameters: Parameters { oid, sig, .. } } = self; let oid = oid.clone(); - let mut caveat_chain = caveat_chain.clone(); + let mut caveat_chain = self.caveat_chain()?.to_vec(); caveat_chain.extend(attenuation.iter().cloned()); let sig = chain_signature(&sig, attenuation); - Ok(SturdyRef { oid, caveat_chain, sig }) + Ok(SturdyRef::from_parts(oid, caveat_chain, sig)) } }