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
<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)]
pub struct Config {
#[structopt(short = "d", default_value = "b4b303726566b10973796e646963617465b584b21069ca300c1dbfa08fba692102dd82311a84")]
#[structopt(short = "d", default_value = "b4b303726566b7b3036f6964b10973796e646963617465b303736967b21069ca300c1dbfa08fba692102dd82311a8484")]
dataspace: String,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -27,38 +27,44 @@ use crate::language::language;
use syndicate_macros::during;
use syndicate_macros::pattern;
pub fn handle_binds(t: &mut Activation, ds: &Arc<Cap>) -> ActorResult {
Ok(during!(t, ds, language(), <bind $description $target $observer>, |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::<gatekeeper::BindObserver>(&observer)?;
fn noise_step_type() -> String {
language().unparse(&noise::NoiseStepType).value().to_symbol().unwrap().clone()
}
if let Ok(s) = language().parse::<sturdy::SturdyService>(&description) {
let sr = sturdy::SturdyRef::mint(s.oid, &s.key);
pub fn handle_binds(t: &mut Activation, ds: &Arc<Cap>) -> ActorResult {
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 {
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(());
}
if let Ok(s) = language().parse::<noise::NoiseService<AnyValue>>(&description) {
match validate_noise_spec(s.spec) {
Ok(())
});
Ok(())
});
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 {
o.assert(t, language(), &gatekeeper::Bound::Bound {
step: language().unparse(&noise::NoiseRouteStep {
spec: noise::NoiseSpec {
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() {
@ -75,7 +81,7 @@ fn handle_bind(
pre_shared_keys: spec.psks,
}
},
},
})),
}),
});
},
@ -89,15 +95,10 @@ fn handle_bind(
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(())
});
Ok(())
}
@ -114,15 +115,24 @@ pub fn handle_resolves(
t: &mut Activation,
a: gatekeeper::Resolve,
) -> DuringResult<Arc<Cap>> {
let step = language().unparse(&a.step);
if let Ok(s) = language().parse::<sturdy::SturdyStep>(&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::<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 {
detail: AnyValue::symbol("unsupported"),
detail: AnyValue::symbol(detail),
}))
}
@ -132,7 +142,7 @@ fn handle_resolve_sturdyref(
sturdyref: sturdy::SturdyRef,
observer: Arc<Cap>,
) -> DuringResult<Arc<Cap>> {
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!{<bind <ref #(&queried_oid) $> $ _>},
pattern: pattern!{<bind <ref { oid: #(&queried_oid), key: $ }> $ _>},
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 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::<gatekeeper::Step>(&language().unparse(&step))?;
gatekeeper.assert(t, language(), &gatekeeper::Resolve::<AnyValue> {
step,
observer: Cap::new(&main_entity),
observer: Cap::guard(Language::arc(), main_entity),
});
Ok(())
}

View File

@ -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<N: NestedValue>(bs: &[u8]) -> io::Result<N> {
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<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> {
@ -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<Self, CaveatError> {
Caveat::validate_many(attenuation)?;
let SturdyRef { oid, caveat_chain, sig } = self;
pub fn attenuate(&self, attenuation: &[Caveat]) -> Result<Self, ValidationError> {
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))
}
}