More updates to gatekeeper protocol

This commit is contained in:
Tony Garnock-Jones 2023-02-09 00:17:12 +01:00
parent 45406c75ac
commit 4dca1b1615
11 changed files with 131 additions and 93 deletions

View File

@ -1,3 +1,3 @@
let ?root_ds = dataspace let ?root_ds = dataspace
<require-service <relay-listener <tcp "0.0.0.0" 9001> $gatekeeper>> <require-service <relay-listener <tcp "0.0.0.0" 9001> $gatekeeper>>
<bind <ref "syndicate" #x""> $root_ds #f> <bind <ref { oid: "syndicate" key: #x"" }> $root_ds #f>

View File

@ -15,7 +15,7 @@ use core::time::Duration;
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, StructOpt)]
pub struct Config { pub struct Config {
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -26,7 +26,7 @@ mod dirty;
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, StructOpt)]
pub struct Config { pub struct Config {
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -25,7 +25,7 @@ pub struct Config {
#[structopt(short = "b", default_value = "0")] #[structopt(short = "b", default_value = "0")]
bytes_padding: usize, bytes_padding: usize,
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -43,7 +43,7 @@ pub struct Config {
#[structopt(subcommand)] #[structopt(subcommand)]
mode: PingPongMode, mode: PingPongMode,
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -16,7 +16,7 @@ pub struct Config {
#[structopt(short = "b", default_value = "0")] #[structopt(short = "b", default_value = "0")]
bytes_padding: usize, bytes_padding: usize,
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -15,7 +15,7 @@ use core::time::Duration;
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, StructOpt)]
pub struct Config { pub struct Config {
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -10,7 +10,7 @@ use tokio::net::TcpStream;
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, StructOpt)]
pub struct Config { pub struct Config {
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")] #[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String, dataspace: String,
} }

View File

@ -27,38 +27,44 @@ use crate::language::language;
use syndicate_macros::during; use syndicate_macros::during;
use syndicate_macros::pattern; use syndicate_macros::pattern;
pub fn handle_binds(t: &mut Activation, ds: &Arc<Cap>) -> ActorResult { fn sturdy_step_type() -> String {
Ok(during!(t, ds, language(), <bind $description $target $observer>, |t: &mut Activation| { language().unparse(&sturdy::SturdyStepType).value().to_symbol().unwrap().clone()
t.spawn_link(None, move |t| { handle_bind(t, description, target, observer) });
Ok(())
}))
} }
fn handle_bind( fn noise_step_type() -> String {
t: &mut Activation, language().unparse(&noise::NoiseStepType).value().to_symbol().unwrap().clone()
description: AnyValue, }
target: AnyValue,
observer: AnyValue,
) -> ActorResult {
let _target = target.value().to_embedded()?;
let observer = language().parse::<gatekeeper::BindObserver>(&observer)?;
if let Ok(s) = language().parse::<sturdy::SturdyService>(&description) { pub fn handle_binds(t: &mut Activation, ds: &Arc<Cap>) -> ActorResult {
let sr = sturdy::SturdyRef::mint(s.oid, &s.key); during!(t, ds, language(), <bind <ref $desc> $target $observer>, |t: &mut Activation| {
t.spawn_link(None, move |t| {
target.value().to_embedded()?;
let observer = language().parse::<gatekeeper::BindObserver>(&observer)?;
let desc = language().parse::<sturdy::SturdyDescriptionDetail>(&desc)?;
let sr = sturdy::SturdyRef::mint(desc.oid, &desc.key);
if let gatekeeper::BindObserver::Present(o) = observer { if let gatekeeper::BindObserver::Present(o) = observer {
o.assert(t, language(), &gatekeeper::Bound::Bound { o.assert(t, language(), &gatekeeper::Bound::Bound {
step: language().unparse(&sr), path_step: Box::new(gatekeeper::PathStep {
step_type: sturdy_step_type(),
detail: language().unparse(&sr.parameters),
}),
}); });
} }
return Ok(()); Ok(())
} });
Ok(())
if let Ok(s) = language().parse::<noise::NoiseService<AnyValue>>(&description) { });
match validate_noise_spec(s.spec) { during!(t, ds, language(), <bind <noise $desc> $target $observer>, |t: &mut Activation| {
t.spawn_link(None, move |t| {
target.value().to_embedded()?;
let observer = language().parse::<gatekeeper::BindObserver>(&observer)?;
let spec = language().parse::<noise::NoiseDescriptionDetail<AnyValue>>(&desc)?.0;
match validate_noise_spec(spec) {
Ok(spec) => if let gatekeeper::BindObserver::Present(o) = observer { Ok(spec) => if let gatekeeper::BindObserver::Present(o) = observer {
o.assert(t, language(), &gatekeeper::Bound::Bound { o.assert(t, language(), &gatekeeper::Bound::Bound {
step: language().unparse(&noise::NoiseRouteStep { path_step: Box::new(gatekeeper::PathStep {
spec: noise::NoiseSpec { step_type: noise_step_type(),
detail: language().unparse(&noise::NoisePathStepDetail(noise::NoiseSpec {
key: spec.public_key, key: spec.public_key,
service: noise::ServiceSelector(spec.service), service: noise::ServiceSelector(spec.service),
protocol: if spec.protocol == default_noise_protocol() { protocol: if spec.protocol == default_noise_protocol() {
@ -75,7 +81,7 @@ fn handle_bind(
pre_shared_keys: spec.psks, pre_shared_keys: spec.psks,
} }
}, },
}, })),
}), }),
}); });
}, },
@ -89,15 +95,10 @@ fn handle_bind(
tracing::error!("Invalid noise bind description: {}", e); tracing::error!("Invalid noise bind description: {}", e);
} }
} }
return Ok(()); Ok(())
} });
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(())
} }
@ -114,15 +115,24 @@ pub fn handle_resolves(
t: &mut Activation, t: &mut Activation,
a: gatekeeper::Resolve, a: gatekeeper::Resolve,
) -> DuringResult<Arc<Cap>> { ) -> DuringResult<Arc<Cap>> {
let step = language().unparse(&a.step); let mut detail: &'static str = "unsupported";
if let Ok(s) = language().parse::<sturdy::SturdyStep>(&step) {
return handle_resolve_sturdyref(ds, t, s.0, a.observer); if a.step.step_type == sturdy_step_type() {
detail = "invalid";
if let Ok(s) = language().parse::<sturdy::SturdyStepDetail>(&a.step.detail) {
return handle_resolve_sturdyref(ds, t, sturdy::SturdyRef { parameters: s.0 }, a.observer);
} }
if let Ok(s) = language().parse::<noise::NoiseStep<AnyValue>>(&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::<noise::NoiseStepDetail<AnyValue>>(&a.step.detail) {
return handle_resolve_noise(ds, t, s.0.0, a.observer);
}
}
eventually_retract(ds.assert(t, language(), &gatekeeper::Rejected { 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, sturdyref: sturdy::SturdyRef,
observer: Arc<Cap>, observer: Arc<Cap>,
) -> DuringResult<Arc<Cap>> { ) -> DuringResult<Arc<Cap>> {
let queried_oid = sturdyref.oid.clone(); let queried_oid = sturdyref.parameters.oid.clone();
let handler = syndicate::entity(observer) let handler = syndicate::entity(observer)
.on_asserted(move |observer, t, a: AnyValue| { .on_asserted(move |observer, t, a: AnyValue| {
let bindings = a.value().to_sequence()?; let bindings = a.value().to_sequence()?;
@ -160,7 +170,7 @@ fn handle_resolve_sturdyref(
.create_cap(t); .create_cap(t);
eventually_retract(ds.assert(t, language(), &dataspace::Observe { eventually_retract(ds.assert(t, language(), &dataspace::Observe {
// TODO: codegen plugin to generate pattern constructors // TODO: codegen plugin to generate pattern constructors
pattern: pattern!{<bind <ref #(&queried_oid) $> $ _>}, pattern: pattern!{<bind <ref { oid: #(&queried_oid), key: $ }> $ _>},
observer: handler, observer: handler,
})) }))
} }

View File

@ -195,14 +195,16 @@ pub fn connect_stream<I, O, Step, E, F>(
let i = Input::Bytes(Box::pin(i)); let i = Input::Bytes(Box::pin(i));
let o = Output::Bytes(Box::pin(o)); let o = Output::Bytes(Box::pin(o));
let gatekeeper = TunnelRelay::run(t, i, o, None, Some(sturdy::Oid(0.into())), output_text).unwrap(); 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 main_entity = t.create(during::entity(initial_state).on_asserted(move |state, t, a: gatekeeper::Resolved| {
let denotation = a.value().to_embedded()?; match a {
f(state, t, Arc::clone(denotation)) gatekeeper::Resolved::Accepted { responder_session } => f(state, t, responder_session),
gatekeeper::Resolved::Rejected(r) => Err(error("Resolve rejected", r.detail))?,
}
})); }));
let step = language().parse::<gatekeeper::Step>(&language().unparse(&step))?; let step = language().parse::<gatekeeper::Step>(&language().unparse(&step))?;
gatekeeper.assert(t, language(), &gatekeeper::Resolve::<AnyValue> { gatekeeper.assert(t, language(), &gatekeeper::Resolve::<AnyValue> {
step, step,
observer: Cap::new(&main_entity), observer: Cap::guard(Language::arc(), main_entity),
}); });
Ok(()) Ok(())
} }

View File

@ -21,6 +21,7 @@ pub use super::schemas::sturdy::*;
pub enum ValidationError { pub enum ValidationError {
SignatureError, SignatureError,
AttenuationError(CaveatError), AttenuationError(CaveatError),
BadCaveatsField,
} }
impl std::fmt::Display for ValidationError { impl std::fmt::Display for ValidationError {
@ -30,6 +31,8 @@ impl std::fmt::Display for ValidationError {
write!(f, "Invalid SturdyRef signature"), write!(f, "Invalid SturdyRef signature"),
ValidationError::AttenuationError(e) => ValidationError::AttenuationError(e) =>
write!(f, "Invalid SturdyRef attenuation: {:?}", e), write!(f, "Invalid SturdyRef attenuation: {:?}", e),
ValidationError::BadCaveatsField =>
write!(f, "Invalid caveats field in SturdyRef parameters"),
} }
} }
} }
@ -71,7 +74,21 @@ pub fn decode<N: NestedValue>(bs: &[u8]) -> io::Result<N> {
impl SturdyRef { impl SturdyRef {
pub fn mint(oid: _Any, key: &[u8]) -> Self { pub fn mint(oid: _Any, key: &[u8]) -> Self {
let sig = signature(key, &encode(&oid)); 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<Caveat>, sig: Vec<u8>) -> Self {
SturdyRef {
parameters: Parameters {
oid,
sig,
caveats: if caveats.is_empty() {
CaveatsField::Absent
} else {
CaveatsField::Present { caveats }
}
}
}
} }
pub fn from_hex(s: &str) -> Result<Self, Error> { pub fn from_hex(s: &str) -> Result<Self, Error> {
@ -83,6 +100,14 @@ impl SturdyRef {
HexFormatter::Packed.encode(&encode(&language().unparse(self))) 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( pub fn validate_and_attenuate(
&self, &self,
key: &[u8], key: &[u8],
@ -90,14 +115,15 @@ impl SturdyRef {
) -> Result<_Ptr, ValidationError> { ) -> Result<_Ptr, ValidationError> {
self.validate(key).map_err(|_| ValidationError::SignatureError)?; self.validate(key).map_err(|_| ValidationError::SignatureError)?;
let target = unattenuated_target let target = unattenuated_target
.attenuate(&self.caveat_chain) .attenuate(self.caveat_chain()?)
.map_err(ValidationError::AttenuationError)?; .map_err(ValidationError::AttenuationError)?;
Ok(target) Ok(target)
} }
pub fn validate(&self, key: &[u8]) -> Result<(), ()> { pub fn validate(&self, key: &[u8]) -> Result<(), ()> {
let SturdyRef { oid, caveat_chain, sig } = self; let SturdyRef { parameters: Parameters { oid, sig, .. } } = self;
let key = chain_signature(&signature(&key, &encode(oid)), caveat_chain); let key = chain_signature(&signature(&key, &encode(oid)),
self.caveat_chain().map_err(|_| ())?);
if &key == sig { if &key == sig {
Ok(()) Ok(())
} else { } else {
@ -105,13 +131,13 @@ impl SturdyRef {
} }
} }
pub fn attenuate(&self, attenuation: &[Caveat]) -> Result<Self, CaveatError> { pub fn attenuate(&self, attenuation: &[Caveat]) -> Result<Self, ValidationError> {
Caveat::validate_many(attenuation)?; Caveat::validate_many(attenuation).map_err(ValidationError::AttenuationError)?;
let SturdyRef { oid, caveat_chain, sig } = self; let SturdyRef { parameters: Parameters { oid, sig, .. } } = self;
let oid = oid.clone(); 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()); caveat_chain.extend(attenuation.iter().cloned());
let sig = chain_signature(&sig, attenuation); let sig = chain_signature(&sig, attenuation);
Ok(SturdyRef { oid, caveat_chain, sig }) Ok(SturdyRef::from_parts(oid, caveat_chain, sig))
} }
} }