More updates to gatekeeper protocol
This commit is contained in:
parent
45406c75ac
commit
4dca1b1615
|
@ -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>
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue