refactor api to clean up internals
This commit is contained in:
@@ -10,6 +10,7 @@ mod routing_domains;
|
||||
mod routing_table_inner;
|
||||
mod stats_accounting;
|
||||
mod tasks;
|
||||
mod types;
|
||||
|
||||
use crate::*;
|
||||
|
||||
@@ -17,9 +18,10 @@ use crate::crypto::*;
|
||||
use crate::network_manager::*;
|
||||
use crate::rpc_processor::*;
|
||||
use bucket::*;
|
||||
use hashlink::LruCache;
|
||||
|
||||
pub use bucket_entry::*;
|
||||
pub use debug::*;
|
||||
use hashlink::LruCache;
|
||||
pub use node_ref::*;
|
||||
pub use node_ref_filter::*;
|
||||
pub use privacy::*;
|
||||
@@ -28,6 +30,7 @@ pub use routing_domain_editor::*;
|
||||
pub use routing_domains::*;
|
||||
pub use routing_table_inner::*;
|
||||
pub use stats_accounting::*;
|
||||
pub use types::*;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
43
veilid-core/src/routing_table/types/dial_info_detail.rs
Normal file
43
veilid-core/src/routing_table/types/dial_info_detail.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use super::*;
|
||||
|
||||
// Keep member order appropriate for sorting < preference
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
PartialEq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Eq,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct DialInfoDetail {
|
||||
pub class: DialInfoClass,
|
||||
pub dial_info: DialInfo,
|
||||
}
|
||||
|
||||
impl MatchesDialInfoFilter for DialInfoDetail {
|
||||
fn matches_filter(&self, filter: &DialInfoFilter) -> bool {
|
||||
self.dial_info.matches_filter(filter)
|
||||
}
|
||||
}
|
||||
|
||||
impl DialInfoDetail {
|
||||
pub fn ordered_sequencing_sort(a: &DialInfoDetail, b: &DialInfoDetail) -> core::cmp::Ordering {
|
||||
if a.class < b.class {
|
||||
return core::cmp::Ordering::Less;
|
||||
}
|
||||
if a.class > b.class {
|
||||
return core::cmp::Ordering::Greater;
|
||||
}
|
||||
DialInfo::ordered_sequencing_sort(&a.dial_info, &b.dial_info)
|
||||
}
|
||||
pub const NO_SORT: std::option::Option<
|
||||
for<'r, 's> fn(&'r DialInfoDetail, &'s DialInfoDetail) -> std::cmp::Ordering,
|
||||
> = None::<fn(&DialInfoDetail, &DialInfoDetail) -> core::cmp::Ordering>;
|
||||
}
|
22
veilid-core/src/routing_table/types/direction.rs
Normal file
22
veilid-core/src/routing_table/types/direction.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
use super::*;
|
||||
|
||||
#[allow(clippy::derive_hash_xor_eq)]
|
||||
#[derive(
|
||||
Debug,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
EnumSetType,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[enumset(repr = "u8")]
|
||||
#[archive_attr(repr(u8), derive(CheckBytes))]
|
||||
pub enum Direction {
|
||||
Inbound,
|
||||
Outbound,
|
||||
}
|
||||
pub type DirectionSet = EnumSet<Direction>;
|
25
veilid-core/src/routing_table/types/mod.rs
Normal file
25
veilid-core/src/routing_table/types/mod.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
mod dial_info_detail;
|
||||
mod direction;
|
||||
mod node_info;
|
||||
mod node_status;
|
||||
mod peer_info;
|
||||
mod routing_domain;
|
||||
mod signed_direct_node_info;
|
||||
mod signed_node_info;
|
||||
mod signed_relayed_node_info;
|
||||
|
||||
use super::*;
|
||||
|
||||
pub use dial_info_detail::*;
|
||||
pub use direction::*;
|
||||
pub use node_info::*;
|
||||
pub use node_status::*;
|
||||
pub use peer_info::*;
|
||||
pub use routing_domain::*;
|
||||
pub use signed_direct_node_info::*;
|
||||
pub use signed_node_info::*;
|
||||
pub use signed_relayed_node_info::*;
|
||||
|
||||
use enumset::*;
|
||||
use rkyv::{Archive as RkyvArchive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
|
||||
use serde::*;
|
125
veilid-core/src/routing_table/types/node_info.rs
Normal file
125
veilid-core/src/routing_table/types/node_info.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct NodeInfo {
|
||||
pub network_class: NetworkClass,
|
||||
#[with(RkyvEnumSet)]
|
||||
pub 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>,
|
||||
}
|
||||
|
||||
impl NodeInfo {
|
||||
pub fn first_filtered_dial_info_detail<S, F>(
|
||||
&self,
|
||||
sort: Option<S>,
|
||||
filter: F,
|
||||
) -> Option<DialInfoDetail>
|
||||
where
|
||||
S: Fn(&DialInfoDetail, &DialInfoDetail) -> std::cmp::Ordering,
|
||||
F: Fn(&DialInfoDetail) -> bool,
|
||||
{
|
||||
if let Some(sort) = sort {
|
||||
let mut dids = self.dial_info_detail_list.clone();
|
||||
dids.sort_by(sort);
|
||||
for did in dids {
|
||||
if filter(&did) {
|
||||
return Some(did);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for did in &self.dial_info_detail_list {
|
||||
if filter(did) {
|
||||
return Some(did.clone());
|
||||
}
|
||||
}
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
pub fn all_filtered_dial_info_details<S, F>(
|
||||
&self,
|
||||
sort: Option<S>,
|
||||
filter: F,
|
||||
) -> Vec<DialInfoDetail>
|
||||
where
|
||||
S: Fn(&DialInfoDetail, &DialInfoDetail) -> std::cmp::Ordering,
|
||||
F: Fn(&DialInfoDetail) -> bool,
|
||||
{
|
||||
let mut dial_info_detail_list = Vec::new();
|
||||
|
||||
if let Some(sort) = sort {
|
||||
let mut dids = self.dial_info_detail_list.clone();
|
||||
dids.sort_by(sort);
|
||||
for did in dids {
|
||||
if filter(&did) {
|
||||
dial_info_detail_list.push(did);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for did in &self.dial_info_detail_list {
|
||||
if filter(did) {
|
||||
dial_info_detail_list.push(did.clone());
|
||||
}
|
||||
}
|
||||
};
|
||||
dial_info_detail_list
|
||||
}
|
||||
|
||||
/// Does this node has some dial info
|
||||
pub fn has_dial_info(&self) -> bool {
|
||||
!self.dial_info_detail_list.is_empty()
|
||||
}
|
||||
|
||||
/// Is some relay required either for signal or inbound relay or outbound relay?
|
||||
pub fn requires_relay(&self) -> bool {
|
||||
match self.network_class {
|
||||
NetworkClass::InboundCapable => {
|
||||
for did in &self.dial_info_detail_list {
|
||||
if did.class.requires_relay() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
NetworkClass::OutboundOnly => {
|
||||
return true;
|
||||
}
|
||||
NetworkClass::WebApp => {
|
||||
return true;
|
||||
}
|
||||
NetworkClass::Invalid => {}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Can this node assist with signalling? Yes but only if it doesn't require signalling, itself.
|
||||
pub fn can_signal(&self) -> bool {
|
||||
// Must be inbound capable
|
||||
if !matches!(self.network_class, NetworkClass::InboundCapable) {
|
||||
return false;
|
||||
}
|
||||
// Do any of our dial info require signalling? if so, we can't offer signalling
|
||||
for did in &self.dial_info_detail_list {
|
||||
if did.class.requires_signal() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Can this node relay be an inbound relay?
|
||||
pub fn can_inbound_relay(&self) -> bool {
|
||||
// For now this is the same
|
||||
self.can_signal()
|
||||
}
|
||||
|
||||
/// Is this node capable of validating dial info
|
||||
pub fn can_validate_dial_info(&self) -> bool {
|
||||
// For now this is the same
|
||||
self.can_signal()
|
||||
}
|
||||
}
|
66
veilid-core/src/routing_table/types/node_status.rs
Normal file
66
veilid-core/src/routing_table/types/node_status.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use super::*;
|
||||
|
||||
/// RoutingDomain-specific status for each node
|
||||
/// is returned by the StatusA call
|
||||
|
||||
/// PublicInternet RoutingDomain Status
|
||||
#[derive(
|
||||
Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct PublicInternetNodeStatus {
|
||||
pub will_route: bool,
|
||||
pub will_tunnel: bool,
|
||||
pub will_signal: bool,
|
||||
pub will_relay: bool,
|
||||
pub will_validate_dial_info: bool,
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Clone, Debug, Default, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize,
|
||||
)]
|
||||
#[archive_attr(repr(C), derive(CheckBytes))]
|
||||
pub struct LocalNetworkNodeStatus {
|
||||
pub will_relay: bool,
|
||||
pub will_validate_dial_info: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(u8), derive(CheckBytes))]
|
||||
pub enum NodeStatus {
|
||||
PublicInternet(PublicInternetNodeStatus),
|
||||
LocalNetwork(LocalNetworkNodeStatus),
|
||||
}
|
||||
|
||||
impl NodeStatus {
|
||||
pub fn will_route(&self) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.will_route,
|
||||
NodeStatus::LocalNetwork(_) => false,
|
||||
}
|
||||
}
|
||||
pub fn will_tunnel(&self) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.will_tunnel,
|
||||
NodeStatus::LocalNetwork(_) => false,
|
||||
}
|
||||
}
|
||||
pub fn will_signal(&self) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.will_signal,
|
||||
NodeStatus::LocalNetwork(_) => false,
|
||||
}
|
||||
}
|
||||
pub fn will_relay(&self) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.will_relay,
|
||||
NodeStatus::LocalNetwork(ln) => ln.will_relay,
|
||||
}
|
||||
}
|
||||
pub fn will_validate_dial_info(&self) -> bool {
|
||||
match self {
|
||||
NodeStatus::PublicInternet(pi) => pi.will_validate_dial_info,
|
||||
NodeStatus::LocalNetwork(ln) => ln.will_validate_dial_info,
|
||||
}
|
||||
}
|
||||
}
|
18
veilid-core/src/routing_table/types/peer_info.rs
Normal file
18
veilid-core/src/routing_table/types/peer_info.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
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,
|
||||
}
|
||||
|
||||
impl PeerInfo {
|
||||
pub fn new(node_ids: TypedKeySet, signed_node_info: SignedNodeInfo) -> Self {
|
||||
assert!(node_ids.len() > 0 && node_ids.len() <= MAX_CRYPTO_KINDS);
|
||||
Self {
|
||||
node_ids,
|
||||
signed_node_info,
|
||||
}
|
||||
}
|
||||
}
|
32
veilid-core/src/routing_table/types/routing_domain.rs
Normal file
32
veilid-core/src/routing_table/types/routing_domain.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use super::*;
|
||||
|
||||
// Routing domain here is listed in order of preference, keep in order
|
||||
#[allow(clippy::derive_hash_xor_eq)]
|
||||
#[derive(
|
||||
Debug,
|
||||
Ord,
|
||||
PartialOrd,
|
||||
Hash,
|
||||
EnumSetType,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
RkyvArchive,
|
||||
RkyvSerialize,
|
||||
RkyvDeserialize,
|
||||
)]
|
||||
#[enumset(repr = "u8")]
|
||||
#[archive_attr(repr(u8), derive(CheckBytes))]
|
||||
pub enum RoutingDomain {
|
||||
LocalNetwork = 0,
|
||||
PublicInternet = 1,
|
||||
}
|
||||
impl RoutingDomain {
|
||||
pub const fn count() -> usize {
|
||||
2
|
||||
}
|
||||
pub const fn all() -> [RoutingDomain; RoutingDomain::count()] {
|
||||
// Routing domain here is listed in order of preference, keep in order
|
||||
[RoutingDomain::LocalNetwork, RoutingDomain::PublicInternet]
|
||||
}
|
||||
}
|
||||
pub type RoutingDomainSet = EnumSet<RoutingDomain>;
|
@@ -0,0 +1,86 @@
|
||||
use super::*;
|
||||
|
||||
/// Signed NodeInfo that can be passed around amongst peers and verifiable
|
||||
#[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>,
|
||||
}
|
||||
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(
|
||||
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)?;
|
||||
|
||||
// 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 {
|
||||
apibail_generic!("no valid node ids in direct node info");
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
node_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_signatures(
|
||||
crypto: Crypto,
|
||||
typed_key_pairs: Vec<TypedKeyPair>,
|
||||
node_info: NodeInfo,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let timestamp = get_aligned_timestamp();
|
||||
let node_info_bytes = Self::make_signature_bytes(&node_info, timestamp)?;
|
||||
let typed_signatures =
|
||||
crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| {
|
||||
TypedSignature::new(kp.kind, s)
|
||||
})?;
|
||||
Ok(Self {
|
||||
node_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
}
|
||||
|
||||
fn make_signature_bytes(
|
||||
node_info: &NodeInfo,
|
||||
timestamp: Timestamp,
|
||||
) -> Result<Vec<u8>, VeilidAPIError> {
|
||||
let mut node_info_bytes = Vec::new();
|
||||
|
||||
// Add nodeinfo to signature
|
||||
let mut ni_msg = ::capnp::message::Builder::new_default();
|
||||
let mut ni_builder = ni_msg.init_root::<veilid_capnp::node_info::Builder>();
|
||||
encode_node_info(node_info, &mut ni_builder).map_err(VeilidAPIError::internal)?;
|
||||
node_info_bytes.append(&mut builder_to_vec(ni_msg).map_err(VeilidAPIError::internal)?);
|
||||
|
||||
// Add timestamp to signature
|
||||
node_info_bytes.append(&mut timestamp.as_u64().to_le_bytes().to_vec());
|
||||
|
||||
Ok(node_info_bytes)
|
||||
}
|
||||
|
||||
pub fn with_no_signature(node_info: NodeInfo) -> Self {
|
||||
Self {
|
||||
node_info,
|
||||
timestamp: get_aligned_timestamp(),
|
||||
signatures: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
!self.signatures.is_empty()
|
||||
}
|
||||
}
|
89
veilid-core/src/routing_table/types/signed_node_info.rs
Normal file
89
veilid-core/src/routing_table/types/signed_node_info.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use super::*;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, RkyvArchive, RkyvSerialize, RkyvDeserialize)]
|
||||
#[archive_attr(repr(u8), derive(CheckBytes))]
|
||||
pub enum SignedNodeInfo {
|
||||
Direct(SignedDirectNodeInfo),
|
||||
Relayed(SignedRelayedNodeInfo),
|
||||
}
|
||||
|
||||
impl SignedNodeInfo {
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(d) => d.has_any_signature(),
|
||||
SignedNodeInfo::Relayed(r) => r.has_any_signature(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timestamp(&self) -> Timestamp {
|
||||
match self {
|
||||
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,
|
||||
}
|
||||
}
|
||||
pub fn relay_ids(&self) -> TypedKeySet {
|
||||
match self {
|
||||
SignedNodeInfo::Direct(_) => TypedKeySet::new(),
|
||||
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),
|
||||
}
|
||||
}
|
||||
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()),
|
||||
)),
|
||||
}
|
||||
}
|
||||
pub fn has_any_dial_info(&self) -> bool {
|
||||
self.node_info().has_dial_info()
|
||||
|| self
|
||||
.relay_info()
|
||||
.map(|relay_ni| relay_ni.has_dial_info())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
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 {
|
||||
match sequencing {
|
||||
Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
|
||||
Sequencing::EnsureOrdered => {
|
||||
if did.dial_info.protocol_type().is_connection_oriented() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check our relay if we have one
|
||||
return self
|
||||
.relay_info()
|
||||
.map(|relay_ni| {
|
||||
for did in &relay_ni.dial_info_detail_list {
|
||||
match sequencing {
|
||||
Sequencing::NoPreference | Sequencing::PreferOrdered => return true,
|
||||
Sequencing::EnsureOrdered => {
|
||||
if did.dial_info.protocol_type().is_connection_oriented() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
})
|
||||
.unwrap_or_default();
|
||||
}
|
||||
}
|
106
veilid-core/src/routing_table/types/signed_relayed_node_info.rs
Normal file
106
veilid-core/src/routing_table/types/signed_relayed_node_info.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use super::*;
|
||||
|
||||
/// Signed NodeInfo with a relay that can be passed around amongst peers and verifiable
|
||||
#[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>,
|
||||
}
|
||||
|
||||
impl SignedRelayedNodeInfo {
|
||||
/// Returns a new SignedRelayedNodeInfo 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(
|
||||
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 {
|
||||
node_info,
|
||||
relay_ids,
|
||||
relay_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn make_signatures(
|
||||
crypto: Crypto,
|
||||
typed_key_pairs: Vec<TypedKeyPair>,
|
||||
node_info: NodeInfo,
|
||||
relay_ids: TypedKeySet,
|
||||
relay_info: SignedDirectNodeInfo,
|
||||
) -> Result<Self, VeilidAPIError> {
|
||||
let timestamp = get_aligned_timestamp();
|
||||
let node_info_bytes =
|
||||
Self::make_signature_bytes(&node_info, &relay_ids, &relay_info, timestamp)?;
|
||||
let typed_signatures =
|
||||
crypto.generate_signatures(&node_info_bytes, &typed_key_pairs, |kp, s| {
|
||||
TypedSignature::new(kp.kind, s)
|
||||
})?;
|
||||
Ok(Self {
|
||||
node_info,
|
||||
relay_ids,
|
||||
relay_info,
|
||||
timestamp,
|
||||
signatures: typed_signatures,
|
||||
})
|
||||
}
|
||||
|
||||
fn make_signature_bytes(
|
||||
node_info: &NodeInfo,
|
||||
relay_ids: &[TypedKey],
|
||||
relay_info: &SignedDirectNodeInfo,
|
||||
timestamp: Timestamp,
|
||||
) -> Result<Vec<u8>, VeilidAPIError> {
|
||||
let mut sig_bytes = Vec::new();
|
||||
|
||||
// Add nodeinfo to signature
|
||||
let mut ni_msg = ::capnp::message::Builder::new_default();
|
||||
let mut ni_builder = ni_msg.init_root::<veilid_capnp::node_info::Builder>();
|
||||
encode_node_info(node_info, &mut ni_builder).map_err(VeilidAPIError::internal)?;
|
||||
sig_bytes.append(&mut builder_to_vec(ni_msg).map_err(VeilidAPIError::internal)?);
|
||||
|
||||
// Add relay ids to signature
|
||||
for relay_id in relay_ids {
|
||||
let mut rid_msg = ::capnp::message::Builder::new_default();
|
||||
let mut rid_builder = rid_msg.init_root::<veilid_capnp::typed_key::Builder>();
|
||||
encode_typed_key(relay_id, &mut rid_builder);
|
||||
sig_bytes.append(&mut builder_to_vec(rid_msg).map_err(VeilidAPIError::internal)?);
|
||||
}
|
||||
|
||||
// Add relay info to signature
|
||||
let mut ri_msg = ::capnp::message::Builder::new_default();
|
||||
let mut ri_builder = ri_msg.init_root::<veilid_capnp::signed_direct_node_info::Builder>();
|
||||
encode_signed_direct_node_info(relay_info, &mut ri_builder)
|
||||
.map_err(VeilidAPIError::internal)?;
|
||||
sig_bytes.append(&mut builder_to_vec(ri_msg).map_err(VeilidAPIError::internal)?);
|
||||
|
||||
// Add timestamp to signature
|
||||
sig_bytes.append(&mut timestamp.as_u64().to_le_bytes().to_vec());
|
||||
|
||||
Ok(sig_bytes)
|
||||
}
|
||||
|
||||
pub fn has_any_signature(&self) -> bool {
|
||||
!self.signatures.is_empty()
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user