mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-24 23:09:25 -05:00
refactor rpc validation
This commit is contained in:
parent
b4a071170d
commit
7f909a06b9
@ -367,7 +367,7 @@ struct OperationSetValueQ @0xbac06191ff8bdbc5 {
|
||||
struct OperationSetValueA @0x9378d0732dc95be2 {
|
||||
union {
|
||||
schemaError @0 :Void; # Either the schema is not available at the node, or the data does not match the schema that is there
|
||||
value @1 :ValueDetail; # the new value if successful, may be a different value than what was set if the seq number was lower or equal
|
||||
value @1 :ValueDetail; # the new value if successful, may be a different value than what was set if the seq number was lower or equal
|
||||
peers @2 :List(PeerInfo); # returned 'closer peer' information if this node is refusing to store the key
|
||||
}
|
||||
}
|
||||
|
@ -282,6 +282,28 @@ where
|
||||
tks
|
||||
}
|
||||
}
|
||||
impl<K> From<&[CryptoTyped<K>]> for CryptoTypedSet<K>
|
||||
where
|
||||
K: Clone
|
||||
+ Copy
|
||||
+ fmt::Debug
|
||||
+ fmt::Display
|
||||
+ FromStr
|
||||
+ PartialEq
|
||||
+ Eq
|
||||
+ PartialOrd
|
||||
+ Ord
|
||||
+ Hash
|
||||
+ RkyvArchive
|
||||
+ Encodable,
|
||||
<K as RkyvArchive>::Archived: Hash + PartialEq + Eq,
|
||||
{
|
||||
fn from(x: &[CryptoTyped<K>]) -> Self {
|
||||
let mut tks = CryptoTypedSet::<K>::with_capacity(x.len());
|
||||
tks.add_all(x);
|
||||
tks
|
||||
}
|
||||
}
|
||||
impl<K> Into<Vec<CryptoTyped<K>>> for CryptoTypedSet<K>
|
||||
where
|
||||
K: Clone
|
||||
|
@ -58,3 +58,5 @@ pub type TypedSignature = CryptoTyped<Signature>;
|
||||
|
||||
pub type TypedKeySet = CryptoTypedSet<PublicKey>;
|
||||
pub type TypedSecretSet = CryptoTypedSet<SecretKey>;
|
||||
pub type TypedKeyPairSet = CryptoTypedSet<KeyPair>;
|
||||
pub type TypedSignatureSet = CryptoTypedSet<Signature>;
|
||||
|
@ -463,7 +463,7 @@ impl NetworkManager {
|
||||
will_validate_dial_info: false,
|
||||
};
|
||||
};
|
||||
let own_node_info = own_peer_info.signed_node_info.node_info();
|
||||
let own_node_info = own_peer_info.signed_node_info().node_info();
|
||||
|
||||
let will_route = own_node_info.can_inbound_relay(); // xxx: eventually this may have more criteria added
|
||||
let will_tunnel = own_node_info.can_inbound_relay(); // xxx: we may want to restrict by battery life and network bandwidth at some point
|
||||
@ -490,7 +490,7 @@ impl NetworkManager {
|
||||
};
|
||||
};
|
||||
|
||||
let own_node_info = own_peer_info.signed_node_info.node_info();
|
||||
let own_node_info = own_peer_info.signed_node_info().node_info();
|
||||
|
||||
let will_relay = own_node_info.can_inbound_relay();
|
||||
let will_validate_dial_info = own_node_info.can_validate_dial_info();
|
||||
|
@ -34,50 +34,39 @@ pub async fn test_signed_node_info() {
|
||||
node_info.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut tks: TypedKeySet = TypedKey::new(ck, keypair.key).into();
|
||||
let tks: TypedKeySet = TypedKey::new(ck, keypair.key).into();
|
||||
let oldtkslen = tks.len();
|
||||
let _ = SignedDirectNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tks,
|
||||
let sdni = SignedDirectNodeInfo::new(
|
||||
node_info.clone(),
|
||||
sni.timestamp,
|
||||
sni.signatures.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(tks.len(), oldtkslen);
|
||||
assert_eq!(tks.len(), sni.signatures.len());
|
||||
sni.timestamp(),
|
||||
sni.signatures().to_vec(),
|
||||
);
|
||||
let tks_validated = sdni.validate(&tks, crypto.clone()).unwrap();
|
||||
assert_eq!(tks_validated.len(), oldtkslen);
|
||||
assert_eq!(tks_validated.len(), sni.signatures().len());
|
||||
|
||||
// Test incorrect validation
|
||||
let keypair1 = vcrypto.generate_keypair();
|
||||
let mut tks1: TypedKeySet = TypedKey::new(ck, keypair1.key).into();
|
||||
let tks1: TypedKeySet = TypedKey::new(ck, keypair1.key).into();
|
||||
let oldtks1len = tks1.len();
|
||||
let _ = SignedDirectNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tks1,
|
||||
let sdni = SignedDirectNodeInfo::new(
|
||||
node_info.clone(),
|
||||
sni.timestamp,
|
||||
sni.signatures.clone(),
|
||||
)
|
||||
.unwrap_err();
|
||||
assert_eq!(tks1.len(), oldtks1len);
|
||||
assert_eq!(tks1.len(), sni.signatures.len());
|
||||
sni.timestamp(),
|
||||
sni.signatures().to_vec(),
|
||||
);
|
||||
sdni.validate(&tks1, crypto.clone()).unwrap_err();
|
||||
|
||||
// Test unsupported cryptosystem validation
|
||||
let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]);
|
||||
let mut tksfake: TypedKeySet = TypedKey::new(fake_crypto_kind, PublicKey::default()).into();
|
||||
let mut sigsfake = sni.signatures.clone();
|
||||
let mut sigsfake = sni.signatures().to_vec();
|
||||
sigsfake.push(TypedSignature::new(fake_crypto_kind, Signature::default()));
|
||||
tksfake.add(TypedKey::new(ck, keypair.key));
|
||||
let sdnifake = SignedDirectNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tksfake,
|
||||
node_info.clone(),
|
||||
sni.timestamp,
|
||||
sigsfake.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(tksfake.len(), 1);
|
||||
assert_eq!(sdnifake.signatures.len(), sigsfake.len());
|
||||
let sdnifake =
|
||||
SignedDirectNodeInfo::new(node_info.clone(), sni.timestamp(), sigsfake.clone());
|
||||
let tksfake_validated = sdnifake.validate(&tksfake, crypto.clone()).unwrap();
|
||||
assert_eq!(tksfake_validated.len(), 1);
|
||||
assert_eq!(sdnifake.signatures().len(), sigsfake.len());
|
||||
|
||||
// Test relayed
|
||||
let node_info2 = NodeInfo {
|
||||
@ -94,7 +83,7 @@ pub async fn test_signed_node_info() {
|
||||
|
||||
// Test correct validation
|
||||
let keypair2 = vcrypto.generate_keypair();
|
||||
let mut tks2: TypedKeySet = TypedKey::new(ck, keypair2.key).into();
|
||||
let tks2: TypedKeySet = TypedKey::new(ck, keypair2.key).into();
|
||||
let oldtks2len = tks2.len();
|
||||
|
||||
let sni2 = SignedRelayedNodeInfo::make_signatures(
|
||||
@ -105,58 +94,49 @@ pub async fn test_signed_node_info() {
|
||||
sni.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let _ = SignedRelayedNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tks2,
|
||||
let srni = SignedRelayedNodeInfo::new(
|
||||
node_info2.clone(),
|
||||
tks.clone(),
|
||||
sni.clone(),
|
||||
sni2.timestamp,
|
||||
sni2.signatures.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
sni2.timestamp(),
|
||||
sni2.signatures().to_vec(),
|
||||
);
|
||||
let tks2_validated = srni.validate(&tks2, crypto.clone()).unwrap();
|
||||
|
||||
assert_eq!(tks2.len(), oldtks2len);
|
||||
assert_eq!(tks2.len(), sni2.signatures.len());
|
||||
assert_eq!(tks2_validated.len(), oldtks2len);
|
||||
assert_eq!(tks2_validated.len(), sni2.signatures().len());
|
||||
|
||||
// Test incorrect validation
|
||||
let keypair3 = vcrypto.generate_keypair();
|
||||
let mut tks3: TypedKeySet = TypedKey::new(ck, keypair3.key).into();
|
||||
let tks3: TypedKeySet = TypedKey::new(ck, keypair3.key).into();
|
||||
let oldtks3len = tks3.len();
|
||||
|
||||
let _ = SignedRelayedNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tks3,
|
||||
let srni = SignedRelayedNodeInfo::new(
|
||||
node_info2.clone(),
|
||||
tks.clone(),
|
||||
sni.clone(),
|
||||
sni2.timestamp,
|
||||
sni2.signatures.clone(),
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(tks3.len(), oldtks3len);
|
||||
assert_eq!(tks3.len(), sni2.signatures.len());
|
||||
sni2.timestamp(),
|
||||
sni2.signatures().to_vec(),
|
||||
);
|
||||
srni.validate(&tks3, crypto.clone()).unwrap_err();
|
||||
|
||||
// Test unsupported cryptosystem validation
|
||||
let fake_crypto_kind: CryptoKind = FourCC::from([0, 1, 2, 3]);
|
||||
let mut tksfake3: TypedKeySet =
|
||||
TypedKey::new(fake_crypto_kind, PublicKey::default()).into();
|
||||
let mut sigsfake3 = sni2.signatures.clone();
|
||||
let mut sigsfake3 = sni2.signatures().to_vec();
|
||||
sigsfake3.push(TypedSignature::new(fake_crypto_kind, Signature::default()));
|
||||
tksfake3.add(TypedKey::new(ck, keypair2.key));
|
||||
let srnifake = SignedRelayedNodeInfo::new(
|
||||
crypto.clone(),
|
||||
&mut tksfake3,
|
||||
node_info2.clone(),
|
||||
tks.clone(),
|
||||
sni.clone(),
|
||||
sni2.timestamp,
|
||||
sni2.timestamp(),
|
||||
sigsfake3.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(tksfake3.len(), 1);
|
||||
assert_eq!(srnifake.signatures.len(), sigsfake3.len());
|
||||
);
|
||||
let tksfake3_validated = srnifake.validate(&tksfake3, crypto.clone()).unwrap();
|
||||
assert_eq!(tksfake3_validated.len(), 1);
|
||||
assert_eq!(srnifake.signatures().len(), sigsfake3.len());
|
||||
}
|
||||
|
||||
api.shutdown().await;
|
||||
|
@ -73,7 +73,9 @@ pub struct BucketEntryLocalNetwork {
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct BucketEntryInner {
|
||||
/// The node ids matching this bucket entry, with the cryptography versions supported by this node as the 'kind' field
|
||||
node_ids: TypedKeySet,
|
||||
validated_node_ids: TypedKeySet,
|
||||
/// The node ids claimed by the remote node that use cryptography versions we do not support
|
||||
unsupported_node_ids: TypedKeySet,
|
||||
/// The set of envelope versions supported by the node inclusive of the requirements of any relay the node may be using
|
||||
envelope_support: Vec<u8>,
|
||||
/// If this node has updated it's SignedNodeInfo since our network
|
||||
@ -122,9 +124,11 @@ impl BucketEntryInner {
|
||||
self.node_ref_tracks.remove(&track_id);
|
||||
}
|
||||
|
||||
/// Get node ids
|
||||
/// Get all node ids
|
||||
pub fn node_ids(&self) -> TypedKeySet {
|
||||
self.node_ids.clone()
|
||||
let mut node_ids = self.validated_node_ids.clone();
|
||||
node_ids.add_all(&self.unsupported_node_ids);
|
||||
node_ids
|
||||
}
|
||||
|
||||
/// Add a node id for a particular crypto kind.
|
||||
@ -132,33 +136,39 @@ impl BucketEntryInner {
|
||||
/// Returns Ok(None) if no previous existing node id was associated with that crypto kind
|
||||
/// Results Err() if this operation would add more crypto kinds than we support
|
||||
pub fn add_node_id(&mut self, node_id: TypedKey) -> EyreResult<Option<TypedKey>> {
|
||||
if let Some(old_node_id) = self.node_ids.get(node_id.kind) {
|
||||
let node_ids = if VALID_CRYPTO_KINDS.contains(&node_id.kind) {
|
||||
&mut self.validated_node_ids
|
||||
} else {
|
||||
&mut self.unsupported_node_ids
|
||||
};
|
||||
|
||||
if let Some(old_node_id) = node_ids.get(node_id.kind) {
|
||||
// If this was already there we do nothing
|
||||
if old_node_id == node_id {
|
||||
return Ok(None);
|
||||
}
|
||||
// Won't change number of crypto kinds
|
||||
self.node_ids.add(node_id);
|
||||
node_ids.add(node_id);
|
||||
return Ok(Some(old_node_id));
|
||||
}
|
||||
// Check to ensure we aren't adding more crypto kinds than we support
|
||||
if self.node_ids.len() == MAX_CRYPTO_KINDS {
|
||||
if self.validated_node_ids.len() + self.unsupported_node_ids.len() == MAX_CRYPTO_KINDS {
|
||||
bail!("too many crypto kinds for this node");
|
||||
}
|
||||
self.node_ids.add(node_id);
|
||||
node_ids.add(node_id);
|
||||
Ok(None)
|
||||
}
|
||||
pub fn best_node_id(&self) -> TypedKey {
|
||||
self.node_ids.best().unwrap()
|
||||
self.validated_node_ids.best().unwrap()
|
||||
}
|
||||
|
||||
/// Get crypto kinds
|
||||
pub fn crypto_kinds(&self) -> Vec<CryptoKind> {
|
||||
self.node_ids.kinds()
|
||||
self.validated_node_ids.kinds()
|
||||
}
|
||||
/// Compare sets of crypto kinds
|
||||
pub fn common_crypto_kinds(&self, other: &[CryptoKind]) -> Vec<CryptoKind> {
|
||||
common_crypto_kinds(&self.node_ids.kinds(), other)
|
||||
common_crypto_kinds(&self.validated_node_ids.kinds(), other)
|
||||
}
|
||||
|
||||
|
||||
@ -270,7 +280,7 @@ impl BucketEntryInner {
|
||||
}
|
||||
|
||||
// Update the envelope version support we have to use
|
||||
let envelope_support = signed_node_info.node_info().envelope_support.clone();
|
||||
let envelope_support = signed_node_info.node_info().envelope_support().to_vec();
|
||||
|
||||
// Update the signed node info
|
||||
*opt_current_sni = Some(Box::new(signed_node_info));
|
||||
@ -333,8 +343,10 @@ impl BucketEntryInner {
|
||||
RoutingDomain::LocalNetwork => &self.local_network.signed_node_info,
|
||||
RoutingDomain::PublicInternet => &self.public_internet.signed_node_info,
|
||||
};
|
||||
// Peer info includes all node ids, even unvalidated ones
|
||||
let node_ids = self.node_ids();
|
||||
opt_current_sni.as_ref().map(|s| PeerInfo {
|
||||
node_ids: self.node_ids.clone(),
|
||||
node_ids,
|
||||
signed_node_info: *s.clone(),
|
||||
})
|
||||
}
|
||||
@ -781,11 +793,13 @@ pub struct BucketEntry {
|
||||
impl BucketEntry {
|
||||
pub(super) fn new(first_node_id: TypedKey) -> Self {
|
||||
let now = get_aligned_timestamp();
|
||||
let mut node_ids = TypedKeySet::new();
|
||||
node_ids.add(first_node_id);
|
||||
let mut validated_node_ids = TypedKeySet::new();
|
||||
let mut unsupported_node_ids = TypedKeySet::new();
|
||||
validated_node_ids.add(first_node_id);
|
||||
|
||||
let inner = BucketEntryInner {
|
||||
node_ids,
|
||||
validated_node_ids,
|
||||
unsupported_node_ids,
|
||||
envelope_support: Vec::new(),
|
||||
updated_since_last_network_change: false,
|
||||
last_connections: BTreeMap::new(),
|
||||
|
@ -792,8 +792,8 @@ impl RoutingTable {
|
||||
e.with(rti, |_rti, e| {
|
||||
if let Some(ni) = e.node_info(routing_domain) {
|
||||
let dif = DialInfoFilter::all()
|
||||
.with_protocol_type_set(ni.outbound_protocols)
|
||||
.with_address_type_set(ni.address_types);
|
||||
.with_protocol_type_set(ni.outbound_protocols())
|
||||
.with_address_type_set(ni.address_types());
|
||||
if dial_info.matches_filter(&dif) {
|
||||
return true;
|
||||
}
|
||||
@ -851,7 +851,7 @@ impl RoutingTable {
|
||||
// does it have some dial info we need?
|
||||
let filter = |n: &NodeInfo| {
|
||||
let mut keep = false;
|
||||
for did in &n.dial_info_detail_list {
|
||||
for did in n.dial_info_detail_list() {
|
||||
if matches!(did.dial_info.address_type(), AddressType::IPV4) {
|
||||
for (n, protocol_type) in protocol_types.iter().enumerate() {
|
||||
if nodes_proto_v4[n] < max_per_type
|
||||
@ -974,12 +974,12 @@ impl RoutingTable {
|
||||
let mut out = Vec::<NodeRef>::with_capacity(peers.len());
|
||||
for p in peers {
|
||||
// Ensure we're getting back nodes we asked for
|
||||
if !p.node_ids.kinds().contains(&crypto_kind) {
|
||||
if !p.node_ids().kinds().contains(&crypto_kind) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't register our own node
|
||||
if self.matches_own_node_id(&p.node_ids) {
|
||||
if self.matches_own_node_id(p.node_ids()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -174,13 +174,13 @@ pub trait NodeRefBase: Sized {
|
||||
self.operate_mut(|_rti, e| e.set_our_node_info_ts(routing_domain, seen_ts));
|
||||
}
|
||||
fn network_class(&self, routing_domain: RoutingDomain) -> Option<NetworkClass> {
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class))
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.network_class()))
|
||||
}
|
||||
fn outbound_protocols(&self, routing_domain: RoutingDomain) -> Option<ProtocolTypeSet> {
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.outbound_protocols))
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.outbound_protocols()))
|
||||
}
|
||||
fn address_types(&self, routing_domain: RoutingDomain) -> Option<AddressTypeSet> {
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.address_types))
|
||||
self.operate(|_rt, e| e.node_info(routing_domain).map(|n| n.address_types()))
|
||||
}
|
||||
fn node_info_outbound_filter(&self, routing_domain: RoutingDomain) -> DialInfoFilter {
|
||||
let mut dif = DialInfoFilter::all();
|
||||
@ -199,7 +199,7 @@ pub trait NodeRefBase: Sized {
|
||||
.and_then(|rpi| {
|
||||
// If relay is ourselves, then return None, because we can't relay through ourselves
|
||||
// and to contact this node we should have had an existing inbound connection
|
||||
if rti.unlocked_inner.matches_own_node_id(&rpi.node_ids) {
|
||||
if rti.unlocked_inner.matches_own_node_id(rpi.node_ids()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,19 @@ pub enum RouteNode {
|
||||
}
|
||||
|
||||
impl RouteNode {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> {
|
||||
match self {
|
||||
RouteNode::NodeId(_) => Ok(()),
|
||||
RouteNode::PeerInfo(pi) => {
|
||||
let validated_node_ids = pi.validate(crypto)?;
|
||||
if validated_node_ids.is_empty() {
|
||||
apibail_generic!("no validated node ids for route node");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn node_ref(
|
||||
&self,
|
||||
routing_table: RoutingTable,
|
||||
@ -48,10 +61,10 @@ impl RouteNode {
|
||||
RouteNode::NodeId(id) => {
|
||||
format!("{}", TypedKey::new(crypto_kind, *id))
|
||||
}
|
||||
RouteNode::PeerInfo(pi) => match pi.node_ids.get(crypto_kind) {
|
||||
RouteNode::PeerInfo(pi) => match pi.node_ids().get(crypto_kind) {
|
||||
Some(id) => format!("{}", id),
|
||||
None => {
|
||||
format!("({})?{}", crypto_kind, pi.node_ids)
|
||||
format!("({})?{}", crypto_kind, pi.node_ids())
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -66,6 +79,11 @@ pub struct RouteHop {
|
||||
/// The encrypted blob to pass to the next hop as its data (None for stubs)
|
||||
pub next_hop: Option<RouteHopData>,
|
||||
}
|
||||
impl RouteHop {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> {
|
||||
self.node.validate(crypto)
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of hops a private route can have
|
||||
#[derive(Clone, Debug)]
|
||||
@ -78,6 +96,15 @@ pub enum PrivateRouteHops {
|
||||
Empty,
|
||||
}
|
||||
|
||||
impl PrivateRouteHops {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> {
|
||||
match self {
|
||||
PrivateRouteHops::FirstHop(rh) => rh.validate(crypto),
|
||||
PrivateRouteHops::Data(_) => Ok(()),
|
||||
PrivateRouteHops::Empty => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
/// A private route for receiver privacy
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PrivateRoute {
|
||||
@ -108,6 +135,10 @@ impl PrivateRoute {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), VeilidAPIError> {
|
||||
self.hops.validate(crypto)
|
||||
}
|
||||
|
||||
/// Check if this is a stub route
|
||||
pub fn is_stub(&self) -> bool {
|
||||
if let PrivateRouteHops::FirstHop(first_hop) = &self.hops {
|
||||
@ -155,7 +186,7 @@ impl PrivateRoute {
|
||||
// Get the safety route to use from the spec
|
||||
Some(match &pr_first_hop.node {
|
||||
RouteNode::NodeId(n) => TypedKey::new(self.public_key.kind, *n),
|
||||
RouteNode::PeerInfo(p) => p.node_ids.get(self.public_key.kind).unwrap(),
|
||||
RouteNode::PeerInfo(p) => p.node_ids().get(self.public_key.kind).unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1550,7 +1550,9 @@ impl RouteSpecStore {
|
||||
.get_root::<veilid_capnp::private_route::Reader>()
|
||||
.map_err(RPCError::internal)
|
||||
.wrap_err("failed to make reader for private_route")?;
|
||||
let private_route = decode_private_route(&pr_reader, crypto.clone()).wrap_err("failed to decode private route")?;
|
||||
let private_route = decode_private_route(&pr_reader).wrap_err("failed to decode private route")?;
|
||||
private_route.validate(crypto.clone()).wrap_err("failed to validate private route")?;
|
||||
|
||||
out.push(private_route);
|
||||
}
|
||||
|
||||
|
@ -102,14 +102,14 @@ impl RoutingDomainDetailCommon {
|
||||
}
|
||||
|
||||
fn make_peer_info(&self, rti: &RoutingTableInner) -> PeerInfo {
|
||||
let node_info = NodeInfo {
|
||||
network_class: self.network_class.unwrap_or(NetworkClass::Invalid),
|
||||
outbound_protocols: self.outbound_protocols,
|
||||
address_types: self.address_types,
|
||||
envelope_support: VALID_ENVELOPE_VERSIONS.to_vec(),
|
||||
crypto_support: VALID_CRYPTO_KINDS.to_vec(),
|
||||
dial_info_detail_list: self.dial_info_details.clone(),
|
||||
};
|
||||
let node_info = NodeInfo::new(
|
||||
self.network_class.unwrap_or(NetworkClass::Invalid),
|
||||
self.outbound_protocols,
|
||||
self.address_types,
|
||||
VALID_ENVELOPE_VERSIONS.to_vec(),
|
||||
VALID_CRYPTO_KINDS.to_vec(),
|
||||
self.dial_info_details.clone()
|
||||
);
|
||||
|
||||
let relay_info = self
|
||||
.relay_node
|
||||
@ -117,8 +117,9 @@ impl RoutingDomainDetailCommon {
|
||||
.and_then(|rn| {
|
||||
let opt_relay_pi = rn.locked(rti).make_peer_info(self.routing_domain);
|
||||
if let Some(relay_pi) = opt_relay_pi {
|
||||
match relay_pi.signed_node_info {
|
||||
SignedNodeInfo::Direct(d) => Some((relay_pi.node_ids, d)),
|
||||
let (relay_ids, relay_sni) = relay_pi.into_fields();
|
||||
match relay_sni {
|
||||
SignedNodeInfo::Direct(d) => Some((relay_ids, d)),
|
||||
SignedNodeInfo::Relayed(_) => {
|
||||
warn!("relay node should not have a relay itself! if this happens, a relay updated its signed node info and became a relay, which should cause the relay to be dropped");
|
||||
None
|
||||
@ -230,8 +231,8 @@ fn first_filtered_dial_info_detail(
|
||||
) -> Option<DialInfoDetail> {
|
||||
let dial_info_filter = dial_info_filter.clone().filtered(
|
||||
&DialInfoFilter::all()
|
||||
.with_address_type_set(from_node.address_types)
|
||||
.with_protocol_type_set(from_node.outbound_protocols),
|
||||
.with_address_type_set(from_node.address_types())
|
||||
.with_protocol_type_set(from_node.outbound_protocols()),
|
||||
);
|
||||
|
||||
// Get first filtered dialinfo
|
||||
@ -278,18 +279,18 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
|
||||
sequencing: Sequencing,
|
||||
) -> ContactMethod {
|
||||
// Get the nodeinfos for convenience
|
||||
let node_a = peer_a.signed_node_info.node_info();
|
||||
let node_b = peer_b.signed_node_info.node_info();
|
||||
let node_a = peer_a.signed_node_info().node_info();
|
||||
let node_b = peer_b.signed_node_info().node_info();
|
||||
|
||||
// Get the node ids that would be used between these peers
|
||||
let cck = common_crypto_kinds(&peer_a.node_ids.kinds(), &peer_b.node_ids.kinds());
|
||||
let cck = common_crypto_kinds(&peer_a.node_ids().kinds(), &peer_b.node_ids().kinds());
|
||||
let Some(best_ck) = cck.first().copied() else {
|
||||
// No common crypto kinds between these nodes, can't contact
|
||||
return ContactMethod::Unreachable;
|
||||
};
|
||||
|
||||
//let node_a_id = peer_a.node_ids.get(best_ck).unwrap();
|
||||
let node_b_id = peer_b.node_ids.get(best_ck).unwrap();
|
||||
//let node_a_id = peer_a.node_ids().get(best_ck).unwrap();
|
||||
let node_b_id = peer_b.node_ids().get(best_ck).unwrap();
|
||||
|
||||
// Get the best match dial info for node B if we have it
|
||||
if let Some(target_did) =
|
||||
@ -302,17 +303,17 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
|
||||
}
|
||||
|
||||
// Get the target's inbound relay, it must have one or it is not reachable
|
||||
if let Some(node_b_relay) = peer_b.signed_node_info.relay_info() {
|
||||
if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() {
|
||||
|
||||
// Note that relay_peer_info could be node_a, in which case a connection already exists
|
||||
// and we only get here if the connection had dropped, in which case node_a is unreachable until
|
||||
// it gets a new relay connection up
|
||||
if peer_b.signed_node_info.relay_ids().contains_any(&peer_a.node_ids) {
|
||||
if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) {
|
||||
return ContactMethod::Existing;
|
||||
}
|
||||
|
||||
// Get best node id to contact relay with
|
||||
let Some(node_b_relay_id) = peer_b.signed_node_info.relay_ids().get(best_ck) else {
|
||||
let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else {
|
||||
// No best relay id
|
||||
return ContactMethod::Unreachable;
|
||||
};
|
||||
@ -327,7 +328,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
|
||||
.is_some()
|
||||
{
|
||||
// Can node A receive anything inbound ever?
|
||||
if matches!(node_a.network_class, NetworkClass::InboundCapable) {
|
||||
if matches!(node_a.network_class(), NetworkClass::InboundCapable) {
|
||||
///////// Reverse connection
|
||||
|
||||
// Get the best match dial info for an reverse inbound connection from node B to node A
|
||||
@ -390,17 +391,17 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
|
||||
}
|
||||
}
|
||||
// If the node B has no direct dial info, it needs to have an inbound relay
|
||||
else if let Some(node_b_relay) = peer_b.signed_node_info.relay_info() {
|
||||
else if let Some(node_b_relay) = peer_b.signed_node_info().relay_info() {
|
||||
|
||||
// Note that relay_peer_info could be node_a, in which case a connection already exists
|
||||
// and we only get here if the connection had dropped, in which case node_a is unreachable until
|
||||
// it gets a new relay connection up
|
||||
if peer_b.signed_node_info.relay_ids().contains_any(&peer_a.node_ids) {
|
||||
if peer_b.signed_node_info().relay_ids().contains_any(peer_a.node_ids()) {
|
||||
return ContactMethod::Existing;
|
||||
}
|
||||
|
||||
// Get best node id to contact relay with
|
||||
let Some(node_b_relay_id) = peer_b.signed_node_info.relay_ids().get(best_ck) else {
|
||||
let Some(node_b_relay_id) = peer_b.signed_node_info().relay_ids().get(best_ck) else {
|
||||
// No best relay id
|
||||
return ContactMethod::Unreachable;
|
||||
};
|
||||
@ -419,7 +420,7 @@ impl RoutingDomainDetail for PublicInternetRoutingDomainDetail {
|
||||
}
|
||||
|
||||
// If node A can't reach the node by other means, it may need to use its own relay
|
||||
if let Some(node_a_relay_id) = peer_a.signed_node_info.relay_ids().get(best_ck) {
|
||||
if let Some(node_a_relay_id) = peer_a.signed_node_info().relay_ids().get(best_ck) {
|
||||
return ContactMethod::OutboundRelay(node_a_relay_id);
|
||||
}
|
||||
|
||||
@ -484,8 +485,8 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail {
|
||||
// Scope the filter down to protocols node A can do outbound
|
||||
let dial_info_filter = dial_info_filter.filtered(
|
||||
&DialInfoFilter::all()
|
||||
.with_address_type_set(peer_a.signed_node_info.node_info().address_types)
|
||||
.with_protocol_type_set(peer_a.signed_node_info.node_info().outbound_protocols),
|
||||
.with_address_type_set(peer_a.signed_node_info().node_info().address_types())
|
||||
.with_protocol_type_set(peer_a.signed_node_info().node_info().outbound_protocols()),
|
||||
);
|
||||
|
||||
// Get first filtered dialinfo
|
||||
@ -509,7 +510,7 @@ impl RoutingDomainDetail for LocalNetworkRoutingDomainDetail {
|
||||
|
||||
let filter = |did: &DialInfoDetail| did.matches_filter(&dial_info_filter);
|
||||
|
||||
let opt_target_did = peer_b.signed_node_info.node_info().first_filtered_dial_info_detail(sort, filter);
|
||||
let opt_target_did = peer_b.signed_node_info().node_info().first_filtered_dial_info_detail(sort, filter);
|
||||
if let Some(target_did) = opt_target_did {
|
||||
return ContactMethod::Direct(target_did.dial_info);
|
||||
}
|
||||
|
@ -171,11 +171,11 @@ impl RoutingTableInner {
|
||||
node_info: &NodeInfo,
|
||||
) -> bool {
|
||||
// Should not be passing around nodeinfo with an invalid network class
|
||||
if matches!(node_info.network_class, NetworkClass::Invalid) {
|
||||
if matches!(node_info.network_class(), NetworkClass::Invalid) {
|
||||
return false;
|
||||
}
|
||||
// Ensure all of the dial info works in this routing domain
|
||||
for did in &node_info.dial_info_detail_list {
|
||||
for did in node_info.dial_info_detail_list() {
|
||||
if !self.ensure_dial_info_is_valid(routing_domain, &did.dial_info) {
|
||||
return false;
|
||||
}
|
||||
@ -258,7 +258,7 @@ impl RoutingTableInner {
|
||||
} else {
|
||||
Some(
|
||||
rdd.common()
|
||||
.with_peer_info(self, |pi| pi.signed_node_info.timestamp()),
|
||||
.with_peer_info(self, |pi| pi.signed_node_info().timestamp()),
|
||||
)
|
||||
}
|
||||
})
|
||||
@ -804,13 +804,16 @@ impl RoutingTableInner {
|
||||
allow_invalid: bool,
|
||||
) -> Option<NodeRef> {
|
||||
// if our own node if is in the list then ignore it, as we don't add ourselves to our own routing table
|
||||
if self.unlocked_inner.matches_own_node_id(&peer_info.node_ids) {
|
||||
if self
|
||||
.unlocked_inner
|
||||
.matches_own_node_id(peer_info.node_ids())
|
||||
{
|
||||
log_rtab!(debug "can't register own node id in routing table");
|
||||
return None;
|
||||
}
|
||||
|
||||
// node can not be its own relay
|
||||
let rids = peer_info.signed_node_info.relay_ids();
|
||||
let rids = peer_info.signed_node_info().relay_ids();
|
||||
if self.unlocked_inner.matches_own_node_id(&rids) {
|
||||
log_rtab!(debug "node can not be its own relay");
|
||||
return None;
|
||||
@ -818,22 +821,22 @@ impl RoutingTableInner {
|
||||
|
||||
if !allow_invalid {
|
||||
// verify signature
|
||||
if !peer_info.signed_node_info.has_any_signature() {
|
||||
log_rtab!(debug "signed node info for {:?} has invalid signature", &peer_info.node_ids);
|
||||
if !peer_info.signed_node_info().has_any_signature() {
|
||||
log_rtab!(debug "signed node info for {:?} has no valid signature", peer_info.node_ids());
|
||||
return None;
|
||||
}
|
||||
// verify signed node info is valid in this routing domain
|
||||
if !self.signed_node_info_is_valid_in_routing_domain(
|
||||
routing_domain,
|
||||
&peer_info.signed_node_info,
|
||||
peer_info.signed_node_info(),
|
||||
) {
|
||||
log_rtab!(debug "signed node info for {:?} not valid in the {:?} routing domain", peer_info.node_ids, routing_domain);
|
||||
log_rtab!(debug "signed node info for {:?} not valid in the {:?} routing domain", peer_info.node_ids(), routing_domain);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
self.create_node_ref(outer_self, &peer_info.node_ids, |_rti, e| {
|
||||
e.update_signed_node_info(routing_domain, peer_info.signed_node_info);
|
||||
self.create_node_ref(outer_self, peer_info.node_ids(), |_rti, e| {
|
||||
e.update_signed_node_info(routing_domain, peer_info.into_signed_node_info());
|
||||
})
|
||||
.map(|mut nr| {
|
||||
nr.set_filter(Some(
|
||||
|
@ -13,8 +13,8 @@ impl RoutingTable {
|
||||
let Some(own_peer_info) = self.get_own_peer_info(RoutingDomain::PublicInternet) else {
|
||||
return Ok(());
|
||||
};
|
||||
let own_node_info = own_peer_info.signed_node_info.node_info();
|
||||
let network_class = own_node_info.network_class;
|
||||
let own_node_info = own_peer_info.signed_node_info().node_info();
|
||||
let network_class = own_node_info.network_class();
|
||||
|
||||
// Get routing domain editor
|
||||
let mut editor = self.edit_routing_domain(RoutingDomain::PublicInternet);
|
||||
|
@ -1,19 +1,58 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[derive(
|
||||
Clone, Default, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct NodeInfo {
|
||||
pub network_class: NetworkClass,
|
||||
network_class: NetworkClass,
|
||||
#[with(RkyvEnumSet)]
|
||||
pub outbound_protocols: ProtocolTypeSet,
|
||||
outbound_protocols: ProtocolTypeSet,
|
||||
#[with(RkyvEnumSet)]
|
||||
pub address_types: AddressTypeSet,
|
||||
pub envelope_support: Vec<u8>,
|
||||
pub crypto_support: Vec<CryptoKind>,
|
||||
pub dial_info_detail_list: Vec<DialInfoDetail>,
|
||||
address_types: AddressTypeSet,
|
||||
envelope_support: Vec<u8>,
|
||||
crypto_support: Vec<CryptoKind>,
|
||||
dial_info_detail_list: Vec<DialInfoDetail>,
|
||||
}
|
||||
|
||||
impl NodeInfo {
|
||||
pub fn new(
|
||||
network_class: NetworkClass,
|
||||
outbound_protocols: ProtocolTypeSet,
|
||||
address_types: AddressTypeSet,
|
||||
envelope_support: Vec<u8>,
|
||||
crypto_support: Vec<CryptoKind>,
|
||||
dial_info_detail_list: Vec<DialInfoDetail>,
|
||||
) -> Self {
|
||||
Self {
|
||||
network_class,
|
||||
outbound_protocols,
|
||||
address_types,
|
||||
envelope_support,
|
||||
crypto_support,
|
||||
dial_info_detail_list,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn network_class(&self) -> NetworkClass {
|
||||
self.network_class
|
||||
}
|
||||
pub fn outbound_protocols(&self) -> ProtocolTypeSet {
|
||||
self.outbound_protocols
|
||||
}
|
||||
pub fn address_types(&self) -> AddressTypeSet {
|
||||
self.address_types
|
||||
}
|
||||
pub fn envelope_support(&self) -> &[u8] {
|
||||
&self.envelope_support
|
||||
}
|
||||
pub fn crypto_support(&self) -> &[CryptoKind] {
|
||||
&self.crypto_support
|
||||
}
|
||||
pub fn dial_info_detail_list(&self) -> &[DialInfoDetail] {
|
||||
&self.dial_info_detail_list
|
||||
}
|
||||
|
||||
pub fn first_filtered_dial_info_detail<S, F>(
|
||||
&self,
|
||||
sort: Option<S>,
|
||||
|
@ -3,8 +3,8 @@ use super::*;
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct PeerInfo {
|
||||
pub node_ids: TypedKeySet,
|
||||
pub signed_node_info: SignedNodeInfo,
|
||||
node_ids: TypedKeySet,
|
||||
signed_node_info: SignedNodeInfo,
|
||||
}
|
||||
|
||||
impl PeerInfo {
|
||||
@ -15,4 +15,21 @@ impl PeerInfo {
|
||||
signed_node_info,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<TypedKeySet, VeilidAPIError> {
|
||||
self.signed_node_info.validate(&self.node_ids, crypto)
|
||||
}
|
||||
|
||||
pub fn node_ids(&self) -> &TypedKeySet {
|
||||
&self.node_ids
|
||||
}
|
||||
pub fn signed_node_info(&self) -> &SignedNodeInfo {
|
||||
&self.signed_node_info
|
||||
}
|
||||
pub fn into_signed_node_info(self) -> SignedNodeInfo {
|
||||
self.signed_node_info
|
||||
}
|
||||
pub fn into_fields(self) -> (TypedKeySet, SignedNodeInfo) {
|
||||
(self.node_ids, self.signed_node_info)
|
||||
}
|
||||
}
|
||||
|
@ -4,36 +4,37 @@ use super::*;
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct SignedDirectNodeInfo {
|
||||
pub node_info: NodeInfo,
|
||||
pub timestamp: Timestamp,
|
||||
pub signatures: Vec<TypedSignature>,
|
||||
node_info: NodeInfo,
|
||||
timestamp: Timestamp,
|
||||
signatures: Vec<TypedSignature>,
|
||||
}
|
||||
impl SignedDirectNodeInfo {
|
||||
/// Returns a new SignedDirectNodeInfo that has its signatures validated.
|
||||
/// On success, this will modify the node_ids set to only include node_ids whose signatures validate.
|
||||
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
|
||||
pub fn new(
|
||||
pub fn new(node_info: NodeInfo, timestamp: Timestamp, signatures: Vec<TypedSignature>) -> Self {
|
||||
Self {
|
||||
node_info,
|
||||
timestamp,
|
||||
signatures,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(
|
||||
&self,
|
||||
node_ids: &TypedKeySet,
|
||||
crypto: Crypto,
|
||||
node_ids: &mut TypedKeySet,
|
||||
node_info: NodeInfo,
|
||||
timestamp: Timestamp,
|
||||
typed_signatures: Vec<TypedSignature>,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?;
|
||||
) -> Result<TypedKeySet, VeilidAPIError> {
|
||||
let node_info_bytes = Self::make_signature_bytes(&self.node_info, self.timestamp)?;
|
||||
|
||||
// Verify the signatures that we can
|
||||
let validated_node_ids =
|
||||
crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?;
|
||||
*node_ids = validated_node_ids;
|
||||
if node_ids.len() == 0 {
|
||||
crypto.verify_signatures(node_ids, &node_info_bytes, &self.signatures)?;
|
||||
if validated_node_ids.len() == 0 {
|
||||
apibail_generic!("no valid node ids in direct node info");
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
node_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
Ok(validated_node_ids)
|
||||
}
|
||||
|
||||
pub fn make_signatures(
|
||||
@ -83,4 +84,14 @@ impl SignedDirectNodeInfo {
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
!self.signatures.is_empty()
|
||||
}
|
||||
|
||||
pub fn node_info(&self) -> &NodeInfo {
|
||||
&self.node_info
|
||||
}
|
||||
pub fn timestamp(&self) -> Timestamp {
|
||||
self.timestamp
|
||||
}
|
||||
pub fn signatures(&self) -> &[TypedSignature] {
|
||||
&self.signatures
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,17 @@ pub enum SignedNodeInfo {
|
||||
}
|
||||
|
||||
impl SignedNodeInfo {
|
||||
pub fn validate(
|
||||
&self,
|
||||
node_ids: &TypedKeySet,
|
||||
crypto: Crypto,
|
||||
) -> Result<TypedKeySet, VeilidAPIError> {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(d) => d.validate(node_ids, crypto),
|
||||
SignedNodeInfo::Relayed(r) => r.validate(node_ids, crypto),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(d) => d.has_any_signature(),
|
||||
@ -17,34 +28,34 @@ impl SignedNodeInfo {
|
||||
|
||||
pub fn timestamp(&self) -> Timestamp {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(d) => d.timestamp,
|
||||
SignedNodeInfo::Relayed(r) => r.timestamp,
|
||||
SignedNodeInfo::Direct(d) => d.timestamp(),
|
||||
SignedNodeInfo::Relayed(r) => r.timestamp(),
|
||||
}
|
||||
}
|
||||
pub fn node_info(&self) -> &NodeInfo {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(d) => &d.node_info,
|
||||
SignedNodeInfo::Relayed(r) => &r.node_info,
|
||||
SignedNodeInfo::Direct(d) => &d.node_info(),
|
||||
SignedNodeInfo::Relayed(r) => &r.node_info(),
|
||||
}
|
||||
}
|
||||
pub fn relay_ids(&self) -> TypedKeySet {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(_) => TypedKeySet::new(),
|
||||
SignedNodeInfo::Relayed(r) => r.relay_ids.clone(),
|
||||
SignedNodeInfo::Relayed(r) => r.relay_ids().clone(),
|
||||
}
|
||||
}
|
||||
pub fn relay_info(&self) -> Option<&NodeInfo> {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(_) => None,
|
||||
SignedNodeInfo::Relayed(r) => Some(&r.relay_info.node_info),
|
||||
SignedNodeInfo::Relayed(r) => Some(r.relay_info().node_info()),
|
||||
}
|
||||
}
|
||||
pub fn relay_peer_info(&self) -> Option<PeerInfo> {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(_) => None,
|
||||
SignedNodeInfo::Relayed(r) => Some(PeerInfo::new(
|
||||
r.relay_ids.clone(),
|
||||
SignedNodeInfo::Direct(r.relay_info.clone()),
|
||||
r.relay_ids().clone(),
|
||||
SignedNodeInfo::Direct(r.relay_info().clone()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
@ -58,7 +69,7 @@ impl SignedNodeInfo {
|
||||
|
||||
pub fn has_sequencing_matched_dial_info(&self, sequencing: Sequencing) -> bool {
|
||||
// Check our dial info
|
||||
for did in &self.node_info().dial_info_detail_list {
|
||||
for did in self.node_info().dial_info_detail_list() {
|
||||
match sequencing {
|
||||
Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
|
||||
Sequencing::EnsureOrdered => {
|
||||
@ -72,7 +83,7 @@ impl SignedNodeInfo {
|
||||
return self
|
||||
.relay_info()
|
||||
.map(|relay_ni| {
|
||||
for did in &relay_ni.dial_info_detail_list {
|
||||
for did in relay_ni.dial_info_detail_list() {
|
||||
match sequencing {
|
||||
Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
|
||||
Sequencing::EnsureOrdered => {
|
||||
|
@ -4,11 +4,11 @@ use super::*;
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct SignedRelayedNodeInfo {
|
||||
pub node_info: NodeInfo,
|
||||
pub relay_ids: TypedKeySet,
|
||||
pub relay_info: SignedDirectNodeInfo,
|
||||
pub timestamp: Timestamp,
|
||||
pub signatures: Vec<TypedSignature>,
|
||||
node_info: NodeInfo,
|
||||
relay_ids: TypedKeySet,
|
||||
relay_info: SignedDirectNodeInfo,
|
||||
timestamp: Timestamp,
|
||||
signatures: Vec<TypedSignature>,
|
||||
}
|
||||
|
||||
impl SignedRelayedNodeInfo {
|
||||
@ -16,30 +16,50 @@ impl SignedRelayedNodeInfo {
|
||||
/// On success, this will modify the node_ids set to only include node_ids whose signatures validate.
|
||||
/// All signatures are stored however, as this can be passed to other nodes that may be able to validate those signatures.
|
||||
pub fn new(
|
||||
crypto: Crypto,
|
||||
node_ids: &mut TypedKeySet,
|
||||
node_info: NodeInfo,
|
||||
relay_ids: TypedKeySet,
|
||||
relay_info: SignedDirectNodeInfo,
|
||||
timestamp: Timestamp,
|
||||
typed_signatures: Vec<TypedSignature>,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let node_info_bytes =
|
||||
Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?;
|
||||
let validated_node_ids =
|
||||
crypto.verify_signatures(node_ids, &node_info_bytes, &typed_signatures)?;
|
||||
*node_ids = validated_node_ids;
|
||||
if node_ids.len() == 0 {
|
||||
apibail_generic!("no valid node ids in relayed node info");
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
signatures: Vec<TypedSignature>,
|
||||
) -> Self {
|
||||
Self {
|
||||
node_info,
|
||||
relay_ids,
|
||||
relay_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
signatures,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(
|
||||
&self,
|
||||
node_ids: &TypedKeySet,
|
||||
crypto: Crypto,
|
||||
) -> Result<TypedKeySet, VeilidAPIError> {
|
||||
// Ensure the relay info for the node has a superset of the crypto kinds of the node it is relaying
|
||||
if common_crypto_kinds(
|
||||
self.node_info.crypto_support(),
|
||||
self.relay_info.node_info().crypto_support(),
|
||||
)
|
||||
.len()
|
||||
!= self.node_info.crypto_support().len()
|
||||
{
|
||||
apibail_generic!("relay should have superset of node crypto kinds");
|
||||
}
|
||||
|
||||
// Verify signatures
|
||||
let node_info_bytes = Self::make_signature_bytes(
|
||||
&self.node_info,
|
||||
&self.relay_ids,
|
||||
&self.relay_info,
|
||||
self.timestamp,
|
||||
)?;
|
||||
let validated_node_ids =
|
||||
crypto.verify_signatures(node_ids, &node_info_bytes, &self.signatures)?;
|
||||
if validated_node_ids.len() == 0 {
|
||||
apibail_generic!("no valid node ids in relayed node info");
|
||||
}
|
||||
Ok(validated_node_ids)
|
||||
}
|
||||
|
||||
pub fn make_signatures(
|
||||
@ -103,4 +123,20 @@ impl SignedRelayedNodeInfo {
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
!self.signatures.is_empty()
|
||||
}
|
||||
|
||||
pub fn node_info(&self) -> &NodeInfo {
|
||||
&self.node_info
|
||||
}
|
||||
pub fn timestamp(&self) -> Timestamp {
|
||||
self.timestamp
|
||||
}
|
||||
pub fn relay_ids(&self) -> &TypedKeySet {
|
||||
&self.relay_ids
|
||||
}
|
||||
pub fn relay_info(&self) -> &SignedDirectNodeInfo {
|
||||
&self.relay_info
|
||||
}
|
||||
pub fn signatures(&self) -> &[TypedSignature] {
|
||||
&self.signatures
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,27 @@ pub fn encode_node_info(
|
||||
node_info: &NodeInfo,
|
||||
builder: &mut veilid_capnp::node_info::Builder,
|
||||
) -> Result<(), RPCError> {
|
||||
builder.set_network_class(encode_network_class(node_info.network_class));
|
||||
builder.set_network_class(encode_network_class(node_info.network_class()));
|
||||
|
||||
let mut ps_builder = builder.reborrow().init_outbound_protocols();
|
||||
encode_protocol_type_set(&node_info.outbound_protocols, &mut ps_builder)?;
|
||||
encode_protocol_type_set(&node_info.outbound_protocols(), &mut ps_builder)?;
|
||||
|
||||
let mut ats_builder = builder.reborrow().init_address_types();
|
||||
encode_address_type_set(&node_info.address_types, &mut ats_builder)?;
|
||||
encode_address_type_set(&node_info.address_types(), &mut ats_builder)?;
|
||||
|
||||
let mut es_builder = builder
|
||||
.reborrow()
|
||||
.init_envelope_support(node_info.envelope_support.len() as u32);
|
||||
.init_envelope_support(node_info.envelope_support().len() as u32);
|
||||
if let Some(s) = es_builder.as_slice() {
|
||||
s.clone_from_slice(&node_info.envelope_support);
|
||||
s.clone_from_slice(&node_info.envelope_support());
|
||||
}
|
||||
|
||||
let mut cs_builder = builder
|
||||
.reborrow()
|
||||
.init_crypto_support(node_info.crypto_support.len() as u32);
|
||||
.init_crypto_support(node_info.crypto_support().len() as u32);
|
||||
if let Some(s) = cs_builder.as_slice() {
|
||||
let csvec: Vec<u32> = node_info
|
||||
.crypto_support
|
||||
.crypto_support()
|
||||
.iter()
|
||||
.map(|x| u32::from_be_bytes(x.0))
|
||||
.collect();
|
||||
@ -33,7 +33,7 @@ pub fn encode_node_info(
|
||||
|
||||
let mut didl_builder = builder.reborrow().init_dial_info_detail_list(
|
||||
node_info
|
||||
.dial_info_detail_list
|
||||
.dial_info_detail_list()
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(RPCError::map_protocol(
|
||||
@ -41,9 +41,9 @@ pub fn encode_node_info(
|
||||
))?,
|
||||
);
|
||||
|
||||
for idx in 0..node_info.dial_info_detail_list.len() {
|
||||
for idx in 0..node_info.dial_info_detail_list().len() {
|
||||
let mut did_builder = didl_builder.reborrow().get(idx as u32);
|
||||
encode_dial_info_detail(&node_info.dial_info_detail_list[idx], &mut did_builder)?;
|
||||
encode_dial_info_detail(&node_info.dial_info_detail_list()[idx], &mut did_builder)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -131,12 +131,12 @@ pub fn decode_node_info(reader: &veilid_capnp::node_info::Reader) -> Result<Node
|
||||
dial_info_detail_list.push(decode_dial_info_detail(&did)?)
|
||||
}
|
||||
|
||||
Ok(NodeInfo {
|
||||
Ok(NodeInfo::new(
|
||||
network_class,
|
||||
outbound_protocols,
|
||||
address_types,
|
||||
envelope_support,
|
||||
crypto_support,
|
||||
dial_info_detail_list,
|
||||
})
|
||||
))
|
||||
}
|
||||
|
@ -9,18 +9,18 @@ impl RPCAnswer {
|
||||
pub fn new(detail: RPCAnswerDetail) -> Self {
|
||||
Self { detail }
|
||||
}
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
self.detail.validate(crypto)
|
||||
}
|
||||
pub fn into_detail(self) -> RPCAnswerDetail {
|
||||
self.detail
|
||||
}
|
||||
pub fn desc(&self) -> &'static str {
|
||||
self.detail.desc()
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::answer::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCAnswer, RPCError> {
|
||||
pub fn decode(reader: &veilid_capnp::answer::Reader) -> Result<RPCAnswer, RPCError> {
|
||||
let d_reader = reader.get_detail();
|
||||
let detail = RPCAnswerDetail::decode(&d_reader, crypto)?;
|
||||
let detail = RPCAnswerDetail::decode(&d_reader)?;
|
||||
Ok(RPCAnswer { detail })
|
||||
}
|
||||
pub fn encode(&self, builder: &mut veilid_capnp::answer::Builder) -> Result<(), RPCError> {
|
||||
@ -60,10 +60,23 @@ impl RPCAnswerDetail {
|
||||
RPCAnswerDetail::CancelTunnelA(_) => "CancelTunnelA",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
match self {
|
||||
RPCAnswerDetail::StatusA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::FindNodeA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::AppCallA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::GetValueA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::SetValueA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::WatchValueA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::SupplyBlockA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::FindBlockA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::StartTunnelA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::CompleteTunnelA(r) => r.validate(crypto),
|
||||
RPCAnswerDetail::CancelTunnelA(r) => r.validate(crypto),
|
||||
}
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::answer::detail::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCAnswerDetail, RPCError> {
|
||||
let which_reader = reader.which().map_err(RPCError::protocol)?;
|
||||
let out = match which_reader {
|
||||
@ -74,7 +87,7 @@ impl RPCAnswerDetail {
|
||||
}
|
||||
veilid_capnp::answer::detail::FindNodeA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationFindNodeA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationFindNodeA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::FindNodeA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::AppCallA(r) => {
|
||||
@ -84,27 +97,27 @@ impl RPCAnswerDetail {
|
||||
}
|
||||
veilid_capnp::answer::detail::GetValueA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationGetValueA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationGetValueA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::GetValueA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::SetValueA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationSetValueA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationSetValueA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::SetValueA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::WatchValueA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationWatchValueA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationWatchValueA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::WatchValueA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::SupplyBlockA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationSupplyBlockA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationSupplyBlockA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::SupplyBlockA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::FindBlockA(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationFindBlockA::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationFindBlockA::decode(&op_reader)?;
|
||||
RPCAnswerDetail::FindBlockA(out)
|
||||
}
|
||||
veilid_capnp::answer::detail::StartTunnelA(r) => {
|
||||
|
@ -16,25 +16,30 @@ impl RPCOperationKind {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
kind_reader: &veilid_capnp::operation::kind::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<Self, RPCError> {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
match self {
|
||||
RPCOperationKind::Question(r) => r.validate(crypto),
|
||||
RPCOperationKind::Statement(r) => r.validate(crypto),
|
||||
RPCOperationKind::Answer(r) => r.validate(crypto),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(kind_reader: &veilid_capnp::operation::kind::Reader) -> Result<Self, RPCError> {
|
||||
let which_reader = kind_reader.which().map_err(RPCError::protocol)?;
|
||||
let out = match which_reader {
|
||||
veilid_capnp::operation::kind::Which::Question(r) => {
|
||||
let q_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCQuestion::decode(&q_reader, crypto)?;
|
||||
let out = RPCQuestion::decode(&q_reader)?;
|
||||
RPCOperationKind::Question(out)
|
||||
}
|
||||
veilid_capnp::operation::kind::Which::Statement(r) => {
|
||||
let q_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCStatement::decode(&q_reader, crypto)?;
|
||||
let out = RPCStatement::decode(&q_reader)?;
|
||||
RPCOperationKind::Statement(out)
|
||||
}
|
||||
veilid_capnp::operation::kind::Which::Answer(r) => {
|
||||
let q_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCAnswer::decode(&q_reader, crypto)?;
|
||||
let out = RPCAnswer::decode(&q_reader)?;
|
||||
RPCOperationKind::Answer(out)
|
||||
}
|
||||
};
|
||||
@ -93,6 +98,15 @@ impl RPCOperation {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
// Validate sender peer info
|
||||
if let Some(sender_peer_info) = &self.opt_sender_peer_info {
|
||||
sender_peer_info.validate(crypto.clone())?;
|
||||
}
|
||||
// Validate operation kind
|
||||
self.kind.validate(crypto)
|
||||
}
|
||||
|
||||
pub fn op_id(&self) -> OperationId {
|
||||
self.op_id
|
||||
}
|
||||
@ -112,17 +126,14 @@ impl RPCOperation {
|
||||
self.kind
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
operation_reader: &veilid_capnp::operation::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<Self, RPCError> {
|
||||
pub fn decode(operation_reader: &veilid_capnp::operation::Reader) -> Result<Self, RPCError> {
|
||||
let op_id = OperationId::new(operation_reader.get_op_id());
|
||||
|
||||
let sender_peer_info = if operation_reader.has_sender_peer_info() {
|
||||
let pi_reader = operation_reader
|
||||
.get_sender_peer_info()
|
||||
.map_err(RPCError::protocol)?;
|
||||
let pi = decode_peer_info(&pi_reader, crypto.clone())?;
|
||||
let pi = decode_peer_info(&pi_reader)?;
|
||||
Some(pi)
|
||||
} else {
|
||||
None
|
||||
@ -131,7 +142,7 @@ impl RPCOperation {
|
||||
let target_node_info_ts = Timestamp::new(operation_reader.get_target_node_info_ts());
|
||||
|
||||
let kind_reader = operation_reader.get_kind();
|
||||
let kind = RPCOperationKind::decode(&kind_reader, crypto)?;
|
||||
let kind = RPCOperationKind::decode(&kind_reader)?;
|
||||
|
||||
Ok(RPCOperation {
|
||||
op_id,
|
||||
|
@ -6,6 +6,10 @@ pub struct RPCOperationAppCallQ {
|
||||
}
|
||||
|
||||
impl RPCOperationAppCallQ {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
xxx length should be checked in decode verify this
|
||||
Ok(())
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_app_call_q::Reader,
|
||||
) -> Result<RPCOperationAppCallQ, RPCError> {
|
||||
|
@ -35,7 +35,6 @@ pub struct RPCOperationFindBlockA {
|
||||
impl RPCOperationFindBlockA {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_find_block_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationFindBlockA, RPCError> {
|
||||
let data = reader.get_data().map_err(RPCError::protocol)?.to_vec();
|
||||
|
||||
@ -47,7 +46,7 @@ impl RPCOperationFindBlockA {
|
||||
.map_err(RPCError::map_internal("too many suppliers"))?,
|
||||
);
|
||||
for s in suppliers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&s, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&s)?;
|
||||
suppliers.push(peer_info);
|
||||
}
|
||||
|
||||
@ -59,7 +58,7 @@ impl RPCOperationFindBlockA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,9 @@ pub struct RPCOperationFindNodeQ {
|
||||
}
|
||||
|
||||
impl RPCOperationFindNodeQ {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_find_node_q::Reader,
|
||||
) -> Result<RPCOperationFindNodeQ, RPCError> {
|
||||
@ -29,9 +32,14 @@ pub struct RPCOperationFindNodeA {
|
||||
}
|
||||
|
||||
impl RPCOperationFindNodeA {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
for pi in &self.peers {
|
||||
pi.validate(crypto.clone()).map_err(RPCError::protocol)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_find_node_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationFindNodeA, RPCError> {
|
||||
let peers_reader = reader.get_peers().map_err(RPCError::protocol)?;
|
||||
let mut peers = Vec::<PeerInfo>::with_capacity(
|
||||
@ -41,7 +49,7 @@ impl RPCOperationFindNodeA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -4,16 +4,22 @@ use super::*;
|
||||
pub struct RPCOperationGetValueQ {
|
||||
pub key: TypedKey,
|
||||
pub subkey: ValueSubkey,
|
||||
pub want_descriptor: bool,
|
||||
}
|
||||
|
||||
impl RPCOperationGetValueQ {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_get_value_q::Reader,
|
||||
) -> Result<RPCOperationGetValueQ, RPCError> {
|
||||
let k_reader = reader.get_key().map_err(RPCError::protocol)?;
|
||||
let k_reader = reader.reborrow().get_key().map_err(RPCError::protocol)?;
|
||||
let key = decode_typed_key(&k_reader)?;
|
||||
let subkey = reader.get_subkey();
|
||||
Ok(RPCOperationGetValueQ { key, subkey })
|
||||
let subkey = reader.reborrow().get_subkey();
|
||||
let want_descriptor = reader.reborrow().get_want_descriptor();
|
||||
Ok(RPCOperationGetValueQ {
|
||||
key,
|
||||
subkey,
|
||||
want_descriptor,
|
||||
})
|
||||
}
|
||||
pub fn encode(
|
||||
&self,
|
||||
@ -22,24 +28,24 @@ impl RPCOperationGetValueQ {
|
||||
let mut k_builder = builder.reborrow().init_key();
|
||||
encode_typed_key(&self.key, &mut k_builder);
|
||||
builder.set_subkey(self.subkey);
|
||||
builder.set_want_descriptor(self.want_descriptor);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RPCOperationGetValueA {
|
||||
Data(ValueData),
|
||||
Value(ValueDetail),
|
||||
Peers(Vec<PeerInfo>),
|
||||
}
|
||||
|
||||
impl RPCOperationGetValueA {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_get_value_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationGetValueA, RPCError> {
|
||||
match reader.which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::operation_get_value_a::Which::Data(r) => {
|
||||
let data = decode_value_data(&r.map_err(RPCError::protocol)?)?;
|
||||
veilid_capnp::operation_get_value_a::Which::Value(r) => {
|
||||
let value_detail = decode_value_detail(&r.map_err(RPCError::protocol)?)?;
|
||||
Ok(RPCOperationGetValueA::Data(data))
|
||||
}
|
||||
veilid_capnp::operation_get_value_a::Which::Peers(r) => {
|
||||
@ -51,7 +57,7 @@ impl RPCOperationGetValueA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -80,10 +80,9 @@ pub struct RPCOperationRoute {
|
||||
impl RPCOperationRoute {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_route::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationRoute, RPCError> {
|
||||
let sr_reader = reader.get_safety_route().map_err(RPCError::protocol)?;
|
||||
let safety_route = decode_safety_route(&sr_reader, crypto)?;
|
||||
let safety_route = decode_safety_route(&sr_reader)?;
|
||||
|
||||
let o_reader = reader.get_operation().map_err(RPCError::protocol)?;
|
||||
let operation = RoutedOperation::decode(&o_reader)?;
|
||||
|
@ -40,7 +40,6 @@ pub enum RPCOperationSetValueA {
|
||||
impl RPCOperationSetValueA {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_set_value_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationSetValueA, RPCError> {
|
||||
match reader.which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::operation_set_value_a::Which::Data(r) => {
|
||||
@ -56,7 +55,7 @@ impl RPCOperationSetValueA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -8,9 +8,8 @@ pub struct RPCOperationSignal {
|
||||
impl RPCOperationSignal {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_signal::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationSignal, RPCError> {
|
||||
let signal_info = decode_signal_info(reader, crypto)?;
|
||||
let signal_info = decode_signal_info(reader)?;
|
||||
Ok(RPCOperationSignal { signal_info })
|
||||
}
|
||||
pub fn encode(
|
||||
|
@ -6,6 +6,10 @@ pub struct RPCOperationStatusQ {
|
||||
}
|
||||
|
||||
impl RPCOperationStatusQ {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_status_q::Reader,
|
||||
) -> Result<RPCOperationStatusQ, RPCError> {
|
||||
@ -37,6 +41,9 @@ pub struct RPCOperationStatusA {
|
||||
}
|
||||
|
||||
impl RPCOperationStatusA {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
Ok(())
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_status_a::Reader,
|
||||
) -> Result<RPCOperationStatusA, RPCError> {
|
||||
|
@ -34,8 +34,7 @@ pub enum RPCOperationSupplyBlockA {
|
||||
impl RPCOperationSupplyBlockA {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_supply_block_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationSupplyBlockA, RPCError> {
|
||||
= ) -> Result<RPCOperationSupplyBlockA, RPCError> {
|
||||
match reader.which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::operation_supply_block_a::Which::Expiration(r) => {
|
||||
Ok(RPCOperationSupplyBlockA::Expiration(r))
|
||||
@ -49,7 +48,7 @@ impl RPCOperationSupplyBlockA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,6 @@ pub struct RPCOperationWatchValueA {
|
||||
impl RPCOperationWatchValueA {
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::operation_watch_value_a::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCOperationWatchValueA, RPCError> {
|
||||
let expiration = reader.get_expiration();
|
||||
let peers_reader = reader.get_peers().map_err(RPCError::protocol)?;
|
||||
@ -91,7 +90,7 @@ impl RPCOperationWatchValueA {
|
||||
.map_err(RPCError::map_internal("too many peers"))?,
|
||||
);
|
||||
for p in peers_reader.iter() {
|
||||
let peer_info = decode_peer_info(&p, crypto.clone())?;
|
||||
let peer_info = decode_peer_info(&p)?;
|
||||
peers.push(peer_info);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,10 @@ impl RPCQuestion {
|
||||
pub fn new(respond_to: RespondTo, detail: RPCQuestionDetail) -> Self {
|
||||
Self { respond_to, detail }
|
||||
}
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
self.respond_to.validate(crypto.clone())?;
|
||||
self.detail.validate(crypto)
|
||||
}
|
||||
pub fn respond_to(&self) -> &RespondTo {
|
||||
&self.respond_to
|
||||
}
|
||||
@ -19,12 +23,9 @@ impl RPCQuestion {
|
||||
pub fn desc(&self) -> &'static str {
|
||||
self.detail.desc()
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::question::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCQuestion, RPCError> {
|
||||
pub fn decode(reader: &veilid_capnp::question::Reader) -> Result<RPCQuestion, RPCError> {
|
||||
let rt_reader = reader.get_respond_to();
|
||||
let respond_to = RespondTo::decode(&rt_reader, crypto)?;
|
||||
let respond_to = RespondTo::decode(&rt_reader)?;
|
||||
let d_reader = reader.get_detail();
|
||||
let detail = RPCQuestionDetail::decode(&d_reader)?;
|
||||
Ok(RPCQuestion { respond_to, detail })
|
||||
@ -68,6 +69,21 @@ impl RPCQuestionDetail {
|
||||
RPCQuestionDetail::CancelTunnelQ(_) => "CancelTunnelQ",
|
||||
}
|
||||
}
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
match self {
|
||||
RPCQuestionDetail::StatusQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::FindNodeQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::AppCallQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::GetValueQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::SetValueQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::WatchValueQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::SupplyBlockQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::FindBlockQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::StartTunnelQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::CompleteTunnelQ(r) => r.validate(crypto),
|
||||
RPCQuestionDetail::CancelTunnelQ(r) => r.validate(crypto),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::question::detail::Reader,
|
||||
|
@ -7,6 +7,13 @@ pub enum RespondTo {
|
||||
}
|
||||
|
||||
impl RespondTo {
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
match self {
|
||||
RespondTo::Sender => Ok(()),
|
||||
RespondTo::PrivateRoute(pr) => pr.validate(crypto).map_err(RPCError::protocol),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode(
|
||||
&self,
|
||||
builder: &mut veilid_capnp::question::respond_to::Builder,
|
||||
@ -23,15 +30,12 @@ impl RespondTo {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::question::respond_to::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<Self, RPCError> {
|
||||
pub fn decode(reader: &veilid_capnp::question::respond_to::Reader) -> Result<Self, RPCError> {
|
||||
let respond_to = match reader.which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::question::respond_to::Sender(()) => RespondTo::Sender,
|
||||
veilid_capnp::question::respond_to::PrivateRoute(pr_reader) => {
|
||||
let pr_reader = pr_reader.map_err(RPCError::protocol)?;
|
||||
let pr = decode_private_route(&pr_reader, crypto)?;
|
||||
let pr = decode_private_route(&pr_reader)?;
|
||||
RespondTo::PrivateRoute(pr)
|
||||
}
|
||||
};
|
||||
|
@ -9,6 +9,9 @@ impl RPCStatement {
|
||||
pub fn new(detail: RPCStatementDetail) -> Self {
|
||||
Self { detail }
|
||||
}
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
self.detail.validate(crypto)
|
||||
}
|
||||
pub fn detail(&self) -> &RPCStatementDetail {
|
||||
&self.detail
|
||||
}
|
||||
@ -18,12 +21,9 @@ impl RPCStatement {
|
||||
pub fn desc(&self) -> &'static str {
|
||||
self.detail.desc()
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::statement::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCStatement, RPCError> {
|
||||
pub fn decode(reader: &veilid_capnp::statement::Reader) -> Result<RPCStatement, RPCError> {
|
||||
let d_reader = reader.get_detail();
|
||||
let detail = RPCStatementDetail::decode(&d_reader, crypto)?;
|
||||
let detail = RPCStatementDetail::decode(&d_reader)?;
|
||||
Ok(RPCStatement { detail })
|
||||
}
|
||||
pub fn encode(&self, builder: &mut veilid_capnp::statement::Builder) -> Result<(), RPCError> {
|
||||
@ -53,9 +53,18 @@ impl RPCStatementDetail {
|
||||
RPCStatementDetail::AppMessage(_) => "AppMessage",
|
||||
}
|
||||
}
|
||||
pub fn validate(&self, crypto: Crypto) -> Result<(), RPCError> {
|
||||
match self {
|
||||
RPCStatementDetail::ValidateDialInfo(r) => r.validate(crypto),
|
||||
RPCStatementDetail::Route(r) => r.validate(crypto),
|
||||
RPCStatementDetail::ValueChanged(r) => r.validate(crypto),
|
||||
RPCStatementDetail::Signal(r) => r.validate(crypto),
|
||||
RPCStatementDetail::ReturnReceipt(r) => r.validate(crypto),
|
||||
RPCStatementDetail::AppMessage(r) => r.validate(crypto),
|
||||
}
|
||||
}
|
||||
pub fn decode(
|
||||
reader: &veilid_capnp::statement::detail::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RPCStatementDetail, RPCError> {
|
||||
let which_reader = reader.which().map_err(RPCError::protocol)?;
|
||||
let out = match which_reader {
|
||||
@ -66,7 +75,7 @@ impl RPCStatementDetail {
|
||||
}
|
||||
veilid_capnp::statement::detail::Route(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationRoute::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationRoute::decode(&op_reader)?;
|
||||
RPCStatementDetail::Route(out)
|
||||
}
|
||||
veilid_capnp::statement::detail::ValueChanged(r) => {
|
||||
@ -76,7 +85,7 @@ impl RPCStatementDetail {
|
||||
}
|
||||
veilid_capnp::statement::detail::Signal(r) => {
|
||||
let op_reader = r.map_err(RPCError::protocol)?;
|
||||
let out = RPCOperationSignal::decode(&op_reader, crypto)?;
|
||||
let out = RPCOperationSignal::decode(&op_reader)?;
|
||||
RPCStatementDetail::Signal(out)
|
||||
}
|
||||
veilid_capnp::statement::detail::ReturnReceipt(r) => {
|
||||
|
@ -7,12 +7,12 @@ pub fn encode_peer_info(
|
||||
//
|
||||
let mut nids_builder = builder.reborrow().init_node_ids(
|
||||
peer_info
|
||||
.node_ids
|
||||
.node_ids()
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(RPCError::map_invalid_format("out of bound error"))?,
|
||||
);
|
||||
for (i, nid) in peer_info.node_ids.iter().enumerate() {
|
||||
for (i, nid) in peer_info.node_ids().iter().enumerate() {
|
||||
encode_typed_key(
|
||||
nid,
|
||||
&mut nids_builder.reborrow().get(
|
||||
@ -22,15 +22,12 @@ pub fn encode_peer_info(
|
||||
);
|
||||
}
|
||||
let mut sni_builder = builder.reborrow().init_signed_node_info();
|
||||
encode_signed_node_info(&peer_info.signed_node_info, &mut sni_builder)?;
|
||||
encode_signed_node_info(peer_info.signed_node_info(), &mut sni_builder)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_peer_info(
|
||||
reader: &veilid_capnp::peer_info::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<PeerInfo, RPCError> {
|
||||
pub fn decode_peer_info(reader: &veilid_capnp::peer_info::Reader) -> Result<PeerInfo, RPCError> {
|
||||
let nids_reader = reader
|
||||
.reborrow()
|
||||
.get_node_ids()
|
||||
@ -43,7 +40,7 @@ pub fn decode_peer_info(
|
||||
for nid_reader in nids_reader.iter() {
|
||||
node_ids.add(decode_typed_key(&nid_reader)?);
|
||||
}
|
||||
let signed_node_info = decode_signed_node_info(&sni_reader, crypto, &mut node_ids)?;
|
||||
let signed_node_info = decode_signed_node_info(&sni_reader)?;
|
||||
if node_ids.len() == 0 {
|
||||
return Err(RPCError::protocol("no verified node ids"));
|
||||
}
|
||||
|
@ -67,10 +67,7 @@ pub fn encode_route_hop(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_route_hop(
|
||||
reader: &veilid_capnp::route_hop::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<RouteHop, RPCError> {
|
||||
pub fn decode_route_hop(reader: &veilid_capnp::route_hop::Reader) -> Result<RouteHop, RPCError> {
|
||||
let n_reader = reader.reborrow().get_node();
|
||||
let node = match n_reader.which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::route_hop::node::Which::NodeId(ni) => {
|
||||
@ -80,7 +77,7 @@ pub fn decode_route_hop(
|
||||
veilid_capnp::route_hop::node::Which::PeerInfo(pi) => {
|
||||
let pi_reader = pi.map_err(RPCError::protocol)?;
|
||||
RouteNode::PeerInfo(
|
||||
decode_peer_info(&pi_reader, crypto)
|
||||
decode_peer_info(&pi_reader)
|
||||
.map_err(RPCError::map_protocol("invalid peer info in route hop"))?,
|
||||
)
|
||||
}
|
||||
@ -128,7 +125,6 @@ pub fn encode_private_route(
|
||||
|
||||
pub fn decode_private_route(
|
||||
reader: &veilid_capnp::private_route::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<PrivateRoute, RPCError> {
|
||||
let public_key = decode_typed_key(&reader.get_public_key().map_err(
|
||||
RPCError::map_protocol("invalid public key in private route"),
|
||||
@ -138,7 +134,7 @@ pub fn decode_private_route(
|
||||
let hops = match reader.get_hops().which().map_err(RPCError::protocol)? {
|
||||
veilid_capnp::private_route::hops::Which::FirstHop(rh_reader) => {
|
||||
let rh_reader = rh_reader.map_err(RPCError::protocol)?;
|
||||
PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader, crypto)?)
|
||||
PrivateRouteHops::FirstHop(decode_route_hop(&rh_reader)?)
|
||||
}
|
||||
veilid_capnp::private_route::hops::Which::Data(rhd_reader) => {
|
||||
let rhd_reader = rhd_reader.map_err(RPCError::protocol)?;
|
||||
@ -182,7 +178,6 @@ pub fn encode_safety_route(
|
||||
|
||||
pub fn decode_safety_route(
|
||||
reader: &veilid_capnp::safety_route::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<SafetyRoute, RPCError> {
|
||||
let public_key = decode_typed_key(
|
||||
&reader
|
||||
@ -197,7 +192,7 @@ pub fn decode_safety_route(
|
||||
}
|
||||
veilid_capnp::safety_route::hops::Which::Private(pr_reader) => {
|
||||
let pr_reader = pr_reader.map_err(RPCError::protocol)?;
|
||||
SafetyRouteHops::Private(decode_private_route(&pr_reader, crypto)?)
|
||||
SafetyRouteHops::Private(decode_private_route(&pr_reader)?)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -34,7 +34,6 @@ pub fn encode_signal_info(
|
||||
|
||||
pub fn decode_signal_info(
|
||||
reader: &veilid_capnp::operation_signal::Reader,
|
||||
crypto: Crypto,
|
||||
) -> Result<SignalInfo, RPCError> {
|
||||
Ok(
|
||||
match reader
|
||||
@ -53,7 +52,7 @@ pub fn decode_signal_info(
|
||||
let pi_reader = r.get_peer_info().map_err(RPCError::map_protocol(
|
||||
"invalid peer info in hole punch signal info",
|
||||
))?;
|
||||
let peer_info = decode_peer_info(&pi_reader, crypto)?;
|
||||
let peer_info = decode_peer_info(&pi_reader)?;
|
||||
|
||||
SignalInfo::HolePunch { receipt, peer_info }
|
||||
}
|
||||
@ -69,7 +68,7 @@ pub fn decode_signal_info(
|
||||
let pi_reader = r.get_peer_info().map_err(RPCError::map_protocol(
|
||||
"invalid peer info in reverse connect signal info",
|
||||
))?;
|
||||
let peer_info = decode_peer_info(&pi_reader, crypto)?;
|
||||
let peer_info = decode_peer_info(&pi_reader)?;
|
||||
|
||||
SignalInfo::ReverseConnect { receipt, peer_info }
|
||||
}
|
||||
|
@ -6,20 +6,20 @@ pub fn encode_signed_direct_node_info(
|
||||
) -> Result<(), RPCError> {
|
||||
//
|
||||
let mut ni_builder = builder.reborrow().init_node_info();
|
||||
encode_node_info(&signed_direct_node_info.node_info, &mut ni_builder)?;
|
||||
encode_node_info(signed_direct_node_info.node_info(), &mut ni_builder)?;
|
||||
|
||||
builder
|
||||
.reborrow()
|
||||
.set_timestamp(signed_direct_node_info.timestamp.into());
|
||||
.set_timestamp(signed_direct_node_info.timestamp().into());
|
||||
|
||||
let mut sigs_builder = builder.reborrow().init_signatures(
|
||||
signed_direct_node_info
|
||||
.signatures
|
||||
.signatures()
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(RPCError::map_invalid_format("out of bound error"))?,
|
||||
);
|
||||
for (i, typed_signature) in signed_direct_node_info.signatures.iter().enumerate() {
|
||||
for (i, typed_signature) in signed_direct_node_info.signatures().iter().enumerate() {
|
||||
encode_typed_signature(
|
||||
typed_signature,
|
||||
&mut sigs_builder.reborrow().get(
|
||||
@ -34,8 +34,6 @@ pub fn encode_signed_direct_node_info(
|
||||
|
||||
pub fn decode_signed_direct_node_info(
|
||||
reader: &veilid_capnp::signed_direct_node_info::Reader,
|
||||
crypto: Crypto,
|
||||
node_ids: &mut TypedKeySet,
|
||||
) -> Result<SignedDirectNodeInfo, RPCError> {
|
||||
let ni_reader = reader
|
||||
.reborrow()
|
||||
@ -61,6 +59,9 @@ pub fn decode_signed_direct_node_info(
|
||||
typed_signatures.push(typed_signature);
|
||||
}
|
||||
|
||||
SignedDirectNodeInfo::new(crypto, node_ids, node_info, timestamp, typed_signatures)
|
||||
.map_err(RPCError::protocol)
|
||||
Ok(SignedDirectNodeInfo::new(
|
||||
node_info,
|
||||
timestamp,
|
||||
typed_signatures,
|
||||
))
|
||||
}
|
||||
|
@ -20,8 +20,6 @@ pub fn encode_signed_node_info(
|
||||
|
||||
pub fn decode_signed_node_info(
|
||||
reader: &veilid_capnp::signed_node_info::Reader,
|
||||
crypto: Crypto,
|
||||
node_ids: &mut TypedKeySet,
|
||||
) -> Result<SignedNodeInfo, RPCError> {
|
||||
match reader
|
||||
.which()
|
||||
@ -29,12 +27,12 @@ pub fn decode_signed_node_info(
|
||||
{
|
||||
veilid_capnp::signed_node_info::Direct(d) => {
|
||||
let d_reader = d.map_err(RPCError::protocol)?;
|
||||
let sdni = decode_signed_direct_node_info(&d_reader, crypto, node_ids)?;
|
||||
let sdni = decode_signed_direct_node_info(&d_reader)?;
|
||||
Ok(SignedNodeInfo::Direct(sdni))
|
||||
}
|
||||
veilid_capnp::signed_node_info::Relayed(r) => {
|
||||
let r_reader = r.map_err(RPCError::protocol)?;
|
||||
let srni = decode_signed_relayed_node_info(&r_reader, crypto, node_ids)?;
|
||||
let srni = decode_signed_relayed_node_info(&r_reader)?;
|
||||
Ok(SignedNodeInfo::Relayed(srni))
|
||||
}
|
||||
}
|
||||
|
@ -6,16 +6,16 @@ pub fn encode_signed_relayed_node_info(
|
||||
) -> Result<(), RPCError> {
|
||||
//
|
||||
let mut ni_builder = builder.reborrow().init_node_info();
|
||||
encode_node_info(&signed_relayed_node_info.node_info, &mut ni_builder)?;
|
||||
encode_node_info(signed_relayed_node_info.node_info(), &mut ni_builder)?;
|
||||
|
||||
let mut rids_builder = builder.reborrow().init_relay_ids(
|
||||
signed_relayed_node_info
|
||||
.relay_ids
|
||||
.relay_ids()
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(RPCError::map_invalid_format("out of bound error"))?,
|
||||
);
|
||||
for (i, typed_key) in signed_relayed_node_info.relay_ids.iter().enumerate() {
|
||||
for (i, typed_key) in signed_relayed_node_info.relay_ids().iter().enumerate() {
|
||||
encode_typed_key(
|
||||
typed_key,
|
||||
&mut rids_builder.reborrow().get(
|
||||
@ -26,20 +26,20 @@ pub fn encode_signed_relayed_node_info(
|
||||
}
|
||||
|
||||
let mut ri_builder = builder.reborrow().init_relay_info();
|
||||
encode_signed_direct_node_info(&signed_relayed_node_info.relay_info, &mut ri_builder)?;
|
||||
encode_signed_direct_node_info(signed_relayed_node_info.relay_info(), &mut ri_builder)?;
|
||||
|
||||
builder
|
||||
.reborrow()
|
||||
.set_timestamp(signed_relayed_node_info.timestamp.into());
|
||||
.set_timestamp(signed_relayed_node_info.timestamp().into());
|
||||
|
||||
let mut sigs_builder = builder.reborrow().init_signatures(
|
||||
signed_relayed_node_info
|
||||
.signatures
|
||||
.signatures()
|
||||
.len()
|
||||
.try_into()
|
||||
.map_err(RPCError::map_invalid_format("out of bound error"))?,
|
||||
);
|
||||
for (i, typed_signature) in signed_relayed_node_info.signatures.iter().enumerate() {
|
||||
for (i, typed_signature) in signed_relayed_node_info.signatures().iter().enumerate() {
|
||||
encode_typed_signature(
|
||||
typed_signature,
|
||||
&mut sigs_builder.reborrow().get(
|
||||
@ -54,8 +54,6 @@ pub fn encode_signed_relayed_node_info(
|
||||
|
||||
pub fn decode_signed_relayed_node_info(
|
||||
reader: &veilid_capnp::signed_relayed_node_info::Reader,
|
||||
crypto: Crypto,
|
||||
node_ids: &mut TypedKeySet,
|
||||
) -> Result<SignedRelayedNodeInfo, RPCError> {
|
||||
let ni_reader = reader
|
||||
.reborrow()
|
||||
@ -81,20 +79,7 @@ pub fn decode_signed_relayed_node_info(
|
||||
.reborrow()
|
||||
.get_relay_info()
|
||||
.map_err(RPCError::protocol)?;
|
||||
let relay_info = decode_signed_direct_node_info(&ri_reader, crypto.clone(), &mut relay_ids)?;
|
||||
|
||||
// Ensure the relay info for the node has a superset of the crypto kinds of the node it is relaying
|
||||
if common_crypto_kinds(
|
||||
&node_info.crypto_support,
|
||||
&relay_info.node_info.crypto_support,
|
||||
)
|
||||
.len()
|
||||
!= node_info.crypto_support.len()
|
||||
{
|
||||
return Err(RPCError::protocol(
|
||||
"relay should have superset of node crypto kinds",
|
||||
));
|
||||
}
|
||||
let relay_info = decode_signed_direct_node_info(&ri_reader)?;
|
||||
|
||||
let timestamp = reader.reborrow().get_timestamp().into();
|
||||
|
||||
@ -113,14 +98,11 @@ pub fn decode_signed_relayed_node_info(
|
||||
let typed_signature = decode_typed_signature(&sig_reader)?;
|
||||
typed_signatures.push(typed_signature);
|
||||
}
|
||||
SignedRelayedNodeInfo::new(
|
||||
crypto,
|
||||
node_ids,
|
||||
Ok(SignedRelayedNodeInfo::new(
|
||||
node_info,
|
||||
relay_ids,
|
||||
relay_info,
|
||||
timestamp,
|
||||
typed_signatures,
|
||||
)
|
||||
.map_err(RPCError::protocol)
|
||||
))
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub fn encode_signed_value_data(
|
||||
|
||||
pub fn decode_signed_value_data(
|
||||
reader: &veilid_capnp::signed_value_data::Reader,
|
||||
) -> Result<ValueData, RPCError> {
|
||||
) -> Result<SignedValueData, RPCError> {
|
||||
let seq = reader.get_seq();
|
||||
let data = reader.get_data().map_err(RPCError::protocol)?.to_vec();
|
||||
let wr = reader.get_writer().map_err(RPCError::protocol)?;
|
||||
@ -24,8 +24,8 @@ pub fn decode_signed_value_data(
|
||||
let sr = reader.get_signature().map_err(RPCError::protocol)?;
|
||||
let signature = decode_signature512(&sr);
|
||||
|
||||
Ok(SignedValueData {
|
||||
value_data: ValueData { seq, data, writer },
|
||||
Ok(SignedValueData::new(
|
||||
ValueData::new_with_seq(seq, data, writer),
|
||||
signature,
|
||||
})
|
||||
))
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ pub fn encode_signed_value_descriptor(
|
||||
) -> Result<(), RPCError> {
|
||||
let mut ob = builder.reborrow().init_owner();
|
||||
encode_key256(signed_value_descriptor.owner(), &mut ob);
|
||||
builder.set_data(signed_value_descriptor.data());
|
||||
builder.set_schema_data(signed_value_descriptor.schema_data());
|
||||
let mut sb = builder.reborrow().init_signature();
|
||||
encode_signature512(signed_value_descriptor.signature(), &mut sb);
|
||||
Ok(())
|
||||
@ -15,12 +15,14 @@ pub fn encode_signed_value_descriptor(
|
||||
|
||||
pub fn decode_signed_value_descriptor(
|
||||
reader: &veilid_capnp::signed_value_descriptor::Reader,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) -> Result<SignedValueDescriptor, RPCError> {
|
||||
let or = reader.get_owner().map_err(RPCError::protocol)?;
|
||||
let owner = decode_key256(&or);
|
||||
let data = reader.get_data().map_err(RPCError::protocol)?.to_vec();
|
||||
let schema_data = reader
|
||||
.get_schema_data()
|
||||
.map_err(RPCError::protocol)?
|
||||
.to_vec();
|
||||
let sr = reader.get_signature().map_err(RPCError::protocol)?;
|
||||
let signature = decode_signature512(&sr);
|
||||
Ok(SignedValueDescriptor::new(owner, data, signature, vcrypto).map_err(RPCError::protocol)?)
|
||||
Ok(SignedValueDescriptor::new(owner, schema_data, signature))
|
||||
}
|
||||
|
@ -6,13 +6,31 @@ pub fn encode_value_detail(
|
||||
builder: &mut veilid_capnp::value_detail::Builder,
|
||||
) -> Result<(), RPCError> {
|
||||
let mut svdb = builder.reborrow().init_signed_value_data();
|
||||
|
||||
encode_signed_value_data(value_detail.signed_value_data(), &mut svdb)?;
|
||||
if let Some(descriptor) = value_detail.descriptor() {
|
||||
let mut db = builder.reborrow().init_descriptor();
|
||||
encode_signed_value_descriptor(descriptor, &mut db)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn decode_value_detail(
|
||||
reader: &veilid_capnp::value_detail::Reader,
|
||||
) -> Result<ValueDetail, RPCError> {
|
||||
let svdr = reader.get_signed_value_data().map_err(RPCError::protocol)?;
|
||||
let signed_value_data = decode_signed_value_data(&svdr)?;
|
||||
|
||||
let descriptor = if reader.has_descriptor() {
|
||||
let dr = reader
|
||||
.reborrow()
|
||||
.get_descriptor()
|
||||
.map_err(RPCError::protocol)?;
|
||||
let descriptor = decode_signed_value_descriptor(&dr)?;
|
||||
Some(descriptor)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Ok(ValueDetail {
|
||||
signed_value_data,
|
||||
descriptor,
|
||||
|
@ -753,7 +753,7 @@ impl RPCProcessor {
|
||||
};
|
||||
|
||||
// Get our node info timestamp
|
||||
let our_node_info_ts = own_peer_info.signed_node_info.timestamp();
|
||||
let our_node_info_ts = own_peer_info.signed_node_info().timestamp();
|
||||
|
||||
// If the target has seen our node info already don't send it again
|
||||
if target.has_seen_our_node_info_ts(routing_domain, our_node_info_ts) {
|
||||
@ -1214,16 +1214,19 @@ impl RPCProcessor {
|
||||
.get_root::<veilid_capnp::operation::Reader>()
|
||||
.map_err(RPCError::protocol)
|
||||
.map_err(logthru_rpc!())?;
|
||||
RPCOperation::decode(&op_reader, self.crypto.clone())?
|
||||
RPCOperation::decode(&op_reader)?
|
||||
};
|
||||
|
||||
// Validate the RPC operation
|
||||
operation.validate(self.crypto.clone())?;
|
||||
|
||||
// Get the sender noderef, incorporating sender's peer info
|
||||
let mut opt_sender_nr: Option<NodeRef> = None;
|
||||
if let Some(sender_peer_info) = operation.sender_peer_info() {
|
||||
// Ensure the sender peer info is for the actual sender specified in the envelope
|
||||
|
||||
// Sender PeerInfo was specified, update our routing table with it
|
||||
if !self.filter_node_info(routing_domain, &sender_peer_info.signed_node_info) {
|
||||
if !self.filter_node_info(routing_domain, sender_peer_info.signed_node_info()) {
|
||||
return Err(RPCError::invalid_format(
|
||||
"sender peerinfo has invalid peer scope",
|
||||
));
|
||||
@ -1261,9 +1264,12 @@ impl RPCProcessor {
|
||||
.get_root::<veilid_capnp::operation::Reader>()
|
||||
.map_err(RPCError::protocol)
|
||||
.map_err(logthru_rpc!())?;
|
||||
RPCOperation::decode(&op_reader, self.crypto.clone())?
|
||||
RPCOperation::decode(&op_reader)?
|
||||
};
|
||||
|
||||
// Validate the RPC operation
|
||||
operation.validate(self.crypto.clone())?;
|
||||
|
||||
// Make the RPC message
|
||||
RPCMessage {
|
||||
header: encoded_msg.header,
|
||||
|
@ -52,7 +52,7 @@ impl RPCProcessor {
|
||||
|
||||
// Verify peers are in the correct peer scope
|
||||
for peer_info in &find_node_a.peers {
|
||||
if !self.filter_node_info(RoutingDomain::PublicInternet, &peer_info.signed_node_info) {
|
||||
if !self.filter_node_info(RoutingDomain::PublicInternet, peer_info.signed_node_info()) {
|
||||
return Err(RPCError::invalid_format(
|
||||
"find_node response has invalid peer scope",
|
||||
));
|
||||
|
@ -341,8 +341,11 @@ impl RPCProcessor {
|
||||
let rh_reader = dec_blob_reader
|
||||
.get_root::<veilid_capnp::route_hop::Reader>()
|
||||
.map_err(RPCError::protocol)?;
|
||||
decode_route_hop(&rh_reader, self.crypto.clone())?
|
||||
decode_route_hop(&rh_reader)?
|
||||
};
|
||||
|
||||
// Validate the RouteHop
|
||||
route_hop.validate(self.crypto.clone()).map_err(RPCError::protocol)?;
|
||||
|
||||
// Sign the operation if this is not our last hop
|
||||
// as the last hop is already signed by the envelope
|
||||
@ -422,8 +425,11 @@ impl RPCProcessor {
|
||||
let pr_reader = dec_blob_reader
|
||||
.get_root::<veilid_capnp::private_route::Reader>()
|
||||
.map_err(RPCError::protocol)?;
|
||||
decode_private_route(&pr_reader, self.crypto.clone())?
|
||||
decode_private_route(&pr_reader)?
|
||||
};
|
||||
|
||||
// Validate the private route
|
||||
private_route.validate(self.crypto.clone()).map_err(RPCError::protocol)?;
|
||||
|
||||
// Switching from full safety route to private route first hop
|
||||
network_result_try!(
|
||||
@ -440,9 +446,12 @@ impl RPCProcessor {
|
||||
let rh_reader = dec_blob_reader
|
||||
.get_root::<veilid_capnp::route_hop::Reader>()
|
||||
.map_err(RPCError::protocol)?;
|
||||
decode_route_hop(&rh_reader, self.crypto.clone())?
|
||||
decode_route_hop(&rh_reader)?
|
||||
};
|
||||
|
||||
// Validate the route hop
|
||||
route_hop.validate(self.crypto.clone()).map_err(RPCError::protocol)?;
|
||||
|
||||
// Continue the full safety route with another hop
|
||||
network_result_try!(
|
||||
self.process_route_safety_route_hop(
|
||||
|
@ -3,9 +3,7 @@ mod record;
|
||||
mod record_data;
|
||||
mod record_store;
|
||||
mod record_store_limits;
|
||||
mod signed_value_data;
|
||||
mod signed_value_descriptor;
|
||||
mod value_detail;
|
||||
mod types;
|
||||
|
||||
use keys::*;
|
||||
use record::*;
|
||||
@ -13,9 +11,7 @@ use record_data::*;
|
||||
use record_store::*;
|
||||
use record_store_limits::*;
|
||||
|
||||
pub use signed_value_data::*;
|
||||
pub use signed_value_descriptor::*;
|
||||
pub use value_detail::*;
|
||||
pub use types::*;
|
||||
|
||||
use super::*;
|
||||
use crate::rpc_processor::*;
|
||||
@ -174,14 +170,15 @@ impl StorageManager {
|
||||
&self,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
record: Record,
|
||||
) -> Result<(), VeilidAPIError> {
|
||||
) -> Result<TypedKey, VeilidAPIError> {
|
||||
// add value record to record store
|
||||
let mut inner = self.inner.lock();
|
||||
let Some(local_record_store) = inner.local_record_store.as_mut() else {
|
||||
apibail_generic!("not initialized");
|
||||
};
|
||||
let key = self.get_key(vcrypto.clone(), &record);
|
||||
local_record_store.new_record(key, record).await
|
||||
local_record_store.new_record(key, record).await?;
|
||||
Ok(key)
|
||||
}
|
||||
|
||||
pub async fn create_record(
|
||||
@ -202,22 +199,27 @@ impl StorageManager {
|
||||
let owner = vcrypto.generate_keypair();
|
||||
|
||||
// Make a signed value descriptor for this dht value
|
||||
let signed_value_descriptor = SignedValueDescriptor::new(owner.key, )
|
||||
let signed_value_descriptor = SignedValueDescriptor::make_signature(
|
||||
owner.key,
|
||||
schema_data,
|
||||
vcrypto.clone(),
|
||||
owner.secret,
|
||||
)?;
|
||||
|
||||
// Add new local value record
|
||||
let cur_ts = get_aligned_timestamp();
|
||||
let record = Record::new(
|
||||
cur_ts,
|
||||
owner.key,
|
||||
signed_value_descriptor,
|
||||
Some(owner.secret),
|
||||
schema,
|
||||
safety_selection,
|
||||
);
|
||||
self.new_local_record(vcrypto.clone(), record)
|
||||
)?;
|
||||
let dht_key = self
|
||||
.new_local_record(vcrypto, record)
|
||||
.await
|
||||
.map_err(VeilidAPIError::internal)?;
|
||||
|
||||
Ok(key)
|
||||
Ok(dht_key)
|
||||
}
|
||||
|
||||
pub async fn open_record(
|
||||
|
9
veilid-core/src/storage_manager/types/mod.rs
Normal file
9
veilid-core/src/storage_manager/types/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
mod signed_value_data;
|
||||
mod signed_value_descriptor;
|
||||
mod value_detail;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub use signed_value_data::*;
|
||||
pub use signed_value_descriptor::*;
|
||||
pub use value_detail::*;
|
@ -24,31 +24,32 @@ pub struct SignedValueData {
|
||||
signature: Signature,
|
||||
}
|
||||
impl SignedValueData {
|
||||
pub fn new(
|
||||
value_data: ValueData,
|
||||
owner: PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
signature: Signature,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let node_info_bytes = Self::make_signature_bytes(&value_data, &owner, subkey)?;
|
||||
|
||||
// validate signature
|
||||
vcrypto.verify(&value_data.writer(), &node_info_bytes, &signature)?;
|
||||
Ok(Self {
|
||||
pub fn new(value_data: ValueData, signature: Signature) -> Self {
|
||||
Self {
|
||||
value_data,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(
|
||||
&self,
|
||||
owner: &PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) -> Result<(), VeilidAPIError> {
|
||||
let node_info_bytes = Self::make_signature_bytes(&self.value_data, owner, subkey)?;
|
||||
// validate signature
|
||||
vcrypto.verify(&self.value_data.writer(), &node_info_bytes, &self.signature)
|
||||
}
|
||||
|
||||
pub fn make_signature(
|
||||
value_data: ValueData,
|
||||
owner: PublicKey,
|
||||
owner: &PublicKey,
|
||||
subkey: ValueSubkey,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
writer_secret: SecretKey,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let node_info_bytes = Self::make_signature_bytes(&value_data, &owner, subkey)?;
|
||||
let node_info_bytes = Self::make_signature_bytes(&value_data, owner, subkey)?;
|
||||
|
||||
// create signature
|
||||
let signature = vcrypto.sign(&value_data.writer(), &writer_secret, &node_info_bytes)?;
|
@ -25,20 +25,17 @@ pub struct SignedValueDescriptor {
|
||||
signature: Signature,
|
||||
}
|
||||
impl SignedValueDescriptor {
|
||||
pub fn new(
|
||||
owner: PublicKey,
|
||||
schema_data: Vec<u8>,
|
||||
signature: Signature,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
// validate signature
|
||||
vcrypto.verify(&owner, &schema_data, &signature)?;
|
||||
|
||||
Ok(Self {
|
||||
pub fn new(owner: PublicKey, schema_data: Vec<u8>, signature: Signature) -> Self {
|
||||
Self {
|
||||
owner,
|
||||
schema_data,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(&self, vcrypto: CryptoSystemVersion) -> Result<(), VeilidAPIError> {
|
||||
// validate signature
|
||||
vcrypto.verify(&self.owner, &self.schema_data, &self.signature)
|
||||
}
|
||||
|
||||
pub fn owner(&self) -> &PublicKey {
|
||||
@ -75,4 +72,12 @@ impl SignedValueDescriptor {
|
||||
pub fn total_size(&self) -> usize {
|
||||
mem::size_of::<Self>() + self.schema_data.len()
|
||||
}
|
||||
|
||||
pub fn cmp_no_sig(&self, other: &Self) -> cmp::Ordering {
|
||||
let o = self.owner.cmp(&other.owner);
|
||||
if o != cmp::Ordering::Equal {
|
||||
return o;
|
||||
}
|
||||
self.schema_data.cmp(&other.schema_data)
|
||||
}
|
||||
}
|
77
veilid-core/src/storage_manager/types/value_detail.rs
Normal file
77
veilid-core/src/storage_manager/types/value_detail.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use super::*;
|
||||
use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
|
||||
use serde::*;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
PartialOrd,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct ValueDetail {
|
||||
signed_value_data: SignedValueData,
|
||||
descriptor: Option<SignedValueDescriptor>,
|
||||
}
|
||||
|
||||
impl ValueDetail {
|
||||
pub fn new(
|
||||
signed_value_data: SignedValueData,
|
||||
descriptor: Option<SignedValueDescriptor>,
|
||||
) -> Self {
|
||||
Self {
|
||||
signed_value_data,
|
||||
descriptor,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate(
|
||||
&self,
|
||||
last_descriptor: Option<&SignedValueDescriptor>,
|
||||
subkey: ValueSubkey,
|
||||
vcrypto: CryptoSystemVersion,
|
||||
) -> Result<(), VeilidAPIError> {
|
||||
// Get descriptor to validate with
|
||||
let descriptor = if let Some(descriptor) = &self.descriptor {
|
||||
if let Some(last_descriptor) = last_descriptor {
|
||||
if descriptor.cmp_no_sig(&last_descriptor) != cmp::Ordering::Equal {
|
||||
return Err(VeilidAPIError::generic(
|
||||
"value detail descriptor does not match last descriptor",
|
||||
));
|
||||
}
|
||||
}
|
||||
descriptor
|
||||
} else {
|
||||
let Some(descriptor) = last_descriptor else {
|
||||
return Err(VeilidAPIError::generic(
|
||||
"no last descriptor, requires a descriptor",
|
||||
));
|
||||
};
|
||||
descriptor
|
||||
};
|
||||
|
||||
// Ensure the descriptor itself validates
|
||||
descriptor.validate(vcrypto.clone())?;
|
||||
|
||||
// And the signed value data
|
||||
self.signed_value_data
|
||||
.validate(descriptor.owner(), subkey, vcrypto)
|
||||
}
|
||||
|
||||
pub fn signed_value_data(&self) -> &SignedValueData {
|
||||
&self.signed_value_data
|
||||
}
|
||||
pub fn descriptor(&self) -> Option<&SignedValueDescriptor> {
|
||||
self.descriptor.as_ref()
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
use super::*;
|
||||
use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
|
||||
use serde::*;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///
|
||||
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
PartialOrd,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Ord,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct ValueDetail {
|
||||
signed_value_data: SignedValueData,
|
||||
descriptor: Option<SignedValueDescriptor>,
|
||||
}
|
||||
|
||||
impl ValueDetail {
|
||||
pub fn new(
|
||||
signed_value_data: SignedValueData,
|
||||
descriptor: Option<SignedValueDescriptor>,
|
||||
) -> Self {
|
||||
Self {
|
||||
signed_value_data,
|
||||
descriptor,
|
||||
}
|
||||
}
|
||||
pub fn signed_value_data(&self) -> &SignedValueData {
|
||||
&self.signed_value_data
|
||||
}
|
||||
pub fn descriptor(&self) -> Option<&SignedValueDescriptor> {
|
||||
self.descriptor.as_ref()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user