refactor rpc validation

This commit is contained in:
John Smith 2023-04-20 11:47:54 -04:00
parent b4a071170d
commit 7f909a06b9
52 changed files with 729 additions and 430 deletions

View File

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

View File

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

View File

@ -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>;

View File

@ -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();

View File

@ -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;

View File

@ -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(),

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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(

View File

@ -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);

View File

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

View File

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

View File

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

View File

@ -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 => {

View File

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

View File

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

View File

@ -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) => {

View File

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

View File

@ -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> {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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)?;

View File

@ -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);
}

View File

@ -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(

View File

@ -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> {

View File

@ -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);
}

View File

@ -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);
}

View File

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

View File

@ -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)
}
};

View File

@ -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) => {

View File

@ -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"));
}

View File

@ -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)?)
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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",
));

View File

@ -341,9 +341,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 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
if route_hop.next_hop.is_some() {
@ -422,9 +425,12 @@ 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!(
self.process_private_route_first_hop(
@ -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(

View File

@ -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(

View 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::*;

View File

@ -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)?;

View File

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

View 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()
}
}

View File

@ -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()
}
}