chore: move authenticator into gateway crate (#5982)
* removed unused bits of authenticator config * moved authenticator into gateway * cleaned up imports * clippy
This commit is contained in:
committed by
GitHub
parent
0a48fa6172
commit
724420f97c
@@ -0,0 +1,86 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_network_defaults::{
|
||||
WG_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6, WG_TUN_DEVICE_NETMASK_V4,
|
||||
WG_TUN_DEVICE_NETMASK_V6,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
|
||||
pub use nym_client_core::config::Config as BaseClientConfig;
|
||||
pub use persistence::AuthenticatorPaths;
|
||||
|
||||
pub mod persistence;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseClientConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub authenticator: Authenticator,
|
||||
|
||||
pub storage_paths: AuthenticatorPaths,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.base.validate()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Authenticator {
|
||||
/// Socket address this node will use for binding its wireguard interface.
|
||||
/// default: `0.0.0.0:51822`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// Private IP address of the wireguard gateway.
|
||||
/// default: `10.1.0.1`
|
||||
pub private_ipv4: Ipv4Addr,
|
||||
|
||||
/// Private IP address of the wireguard gateway.
|
||||
/// default: `fc01::1`
|
||||
pub private_ipv6: Ipv6Addr,
|
||||
|
||||
/// Port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_port: u16,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
/// The maximum value for IPv4 is 32
|
||||
pub private_network_prefix_v4: u8,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
|
||||
/// The maximum value for IPv6 is 128
|
||||
pub private_network_prefix_v6: u8,
|
||||
}
|
||||
|
||||
impl Default for Authenticator {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_PORT),
|
||||
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
announced_port: WG_PORT,
|
||||
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
|
||||
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Authenticator> for nym_wireguard_types::Config {
|
||||
fn from(value: Authenticator) -> Self {
|
||||
nym_wireguard_types::Config {
|
||||
bind_address: value.bind_address,
|
||||
private_ipv4: value.private_ipv4,
|
||||
private_ipv6: value.private_ipv6,
|
||||
announced_port: value.announced_port,
|
||||
private_network_prefix_v4: value.private_network_prefix_v4,
|
||||
private_network_prefix_v6: value.private_network_prefix_v6,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_client_core::config::disk_persistence::CommonClientPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
|
||||
pub struct AuthenticatorPaths {
|
||||
#[serde(flatten)]
|
||||
pub common_paths: CommonClientPaths,
|
||||
}
|
||||
|
||||
impl AuthenticatorPaths {
|
||||
pub fn new_base<P: AsRef<Path>>(base_data_directory: P) -> Self {
|
||||
let base_dir = base_data_directory.as_ref();
|
||||
|
||||
Self {
|
||||
common_paths: CommonClientPaths::new_base(base_dir),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use ipnetwork::IpNetworkError;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
use nym_id::NymIdError;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum AuthenticatorError {
|
||||
#[error("client-core error: {0}")]
|
||||
ClientCoreError(#[from] ClientCoreError),
|
||||
|
||||
// TODO: add more details here
|
||||
#[error("failed to validate the loaded config")]
|
||||
ConfigValidationFailure,
|
||||
|
||||
#[error("{0}")]
|
||||
CredentialVerificationError(#[from] nym_credential_verification::Error),
|
||||
|
||||
#[error("invalid credential type")]
|
||||
InvalidCredentialType,
|
||||
|
||||
#[error("the entity wrapping the network requester has disconnected")]
|
||||
DisconnectedParent,
|
||||
|
||||
#[error("received too short packet")]
|
||||
ShortPacket,
|
||||
|
||||
#[error("failed to connect to mixnet: {source}")]
|
||||
FailedToConnectToMixnet { source: Box<nym_sdk::Error> },
|
||||
|
||||
#[error("failed to deserialize tagged packet: {source}")]
|
||||
FailedToDeserializeTaggedPacket { source: bincode::Error },
|
||||
|
||||
#[error("failed to load configuration file: {0}")]
|
||||
FailedToLoadConfig(String),
|
||||
|
||||
#[error("failed to send packet to mixnet: {source}")]
|
||||
FailedToSendPacketToMixnet { source: Box<nym_sdk::Error> },
|
||||
|
||||
#[error("failed to serialize response packet: {source}")]
|
||||
FailedToSerializeResponsePacket { source: Box<bincode::ErrorKind> },
|
||||
|
||||
#[error("failed to setup mixnet client: {source}")]
|
||||
FailedToSetupMixnetClient { source: Box<nym_sdk::Error> },
|
||||
|
||||
#[error("{0}")]
|
||||
GatewayStorageError(#[from] nym_gateway_storage::error::GatewayStorageError),
|
||||
|
||||
#[error("internal error: {0}")]
|
||||
InternalError(String),
|
||||
|
||||
#[error("received packet has an invalid type: {0}")]
|
||||
InvalidPacketType(u8),
|
||||
|
||||
#[error("received packet has an invalid version: {0}")]
|
||||
InvalidPacketVersion(u8),
|
||||
|
||||
#[error("I/O error: {0}")]
|
||||
IoError(#[from] std::io::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
IpNetworkError(#[from] IpNetworkError),
|
||||
|
||||
#[error("mac does not verify")]
|
||||
MacVerificationFailure,
|
||||
|
||||
#[error("no more space in the network")]
|
||||
NoFreeIp,
|
||||
|
||||
#[error(transparent)]
|
||||
NymIdError(#[from] NymIdError),
|
||||
|
||||
#[error("registration is not in progress for the given key")]
|
||||
RegistrationNotInProgress,
|
||||
|
||||
#[error("internal data corruption: {0}")]
|
||||
InternalDataCorruption(String),
|
||||
|
||||
#[error("peers can't be interacted with anymore")]
|
||||
PeerInteractionStopped,
|
||||
|
||||
#[error("unknown version number")]
|
||||
UnknownVersion,
|
||||
|
||||
#[error("missing reply_to for old client")]
|
||||
MissingReplyToForOldClient,
|
||||
|
||||
#[error("{0}")]
|
||||
PublicKey(#[from] nym_wireguard_types::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
IpAddr(#[from] std::net::AddrParseError),
|
||||
|
||||
#[error("{0}")]
|
||||
AuthenticatorRequests(#[from] nym_authenticator_requests::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
RecipientFormatting(#[from] nym_sdk::mixnet::RecipientFormattingError),
|
||||
|
||||
#[error("no credential received")]
|
||||
NoCredentialReceived,
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_client_core::{config::disk_persistence::CommonClientPaths, TopologyProvider};
|
||||
use nym_sdk::{GatewayTransceiver, NymNetworkDetails};
|
||||
use nym_task::TaskClient;
|
||||
|
||||
use crate::node::internal_service_providers::authenticator::{
|
||||
config::BaseClientConfig, error::AuthenticatorError,
|
||||
};
|
||||
|
||||
// Helper function to create the mixnet client.
|
||||
// This is NOT in the SDK since we don't want to expose any of the client-core config types.
|
||||
// We could however consider moving it to a crate in common in the future.
|
||||
// TODO: refactor this function and its arguments
|
||||
pub async fn create_mixnet_client(
|
||||
config: &BaseClientConfig,
|
||||
shutdown: TaskClient,
|
||||
custom_transceiver: Option<Box<dyn GatewayTransceiver + Send + Sync>>,
|
||||
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
||||
wait_for_gateway: bool,
|
||||
paths: &CommonClientPaths,
|
||||
) -> Result<nym_sdk::mixnet::MixnetClient, AuthenticatorError> {
|
||||
let debug_config = config.debug;
|
||||
|
||||
let storage_paths = nym_sdk::mixnet::StoragePaths::from(paths.clone());
|
||||
|
||||
let mut client_builder =
|
||||
nym_sdk::mixnet::MixnetClientBuilder::new_with_default_storage(storage_paths)
|
||||
.await
|
||||
.map_err(|err| AuthenticatorError::FailedToSetupMixnetClient {
|
||||
source: Box::new(err),
|
||||
})?
|
||||
.network_details(NymNetworkDetails::new_from_env())
|
||||
.debug_config(debug_config)
|
||||
.custom_shutdown(shutdown)
|
||||
.with_wait_for_gateway(wait_for_gateway);
|
||||
if !config.get_disabled_credentials_mode() {
|
||||
client_builder = client_builder.enable_credentials_mode();
|
||||
}
|
||||
if let Some(gateway_transceiver) = custom_transceiver {
|
||||
client_builder = client_builder.custom_gateway_transceiver(gateway_transceiver);
|
||||
}
|
||||
if let Some(topology_provider) = custom_topology_provider {
|
||||
client_builder = client_builder.custom_topology_provider(topology_provider);
|
||||
}
|
||||
|
||||
let mixnet_client =
|
||||
client_builder
|
||||
.build()
|
||||
.map_err(|err| AuthenticatorError::FailedToSetupMixnetClient {
|
||||
source: Box::new(err),
|
||||
})?;
|
||||
|
||||
mixnet_client.connect_to_mixnet().await.map_err(|err| {
|
||||
AuthenticatorError::FailedToConnectToMixnet {
|
||||
source: Box::new(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,988 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::{
|
||||
net::IpAddr,
|
||||
sync::Arc,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
|
||||
use crate::node::internal_service_providers::authenticator::{
|
||||
config::Config, error::AuthenticatorError, peer_manager::PeerManager,
|
||||
seen_credential_cache::SeenCredentialCache,
|
||||
};
|
||||
use defguard_wireguard_rs::net::IpAddrMask;
|
||||
use defguard_wireguard_rs::{host::Peer, key::Key};
|
||||
use futures::StreamExt;
|
||||
use nym_authenticator_requests::{
|
||||
latest::registration::RegistrationData, v4::registration::IpPair,
|
||||
};
|
||||
use nym_authenticator_requests::{
|
||||
latest::registration::{GatewayClient, PendingRegistrations, PrivateIPs},
|
||||
traits::{
|
||||
AuthenticatorRequest, AuthenticatorVersion, FinalMessage, InitMessage,
|
||||
QueryBandwidthMessage, TopUpMessage,
|
||||
},
|
||||
v1, v2, v3, v4, v5, CURRENT_VERSION,
|
||||
};
|
||||
use nym_credential_verification::ecash::traits::EcashManager;
|
||||
use nym_credential_verification::{
|
||||
bandwidth_storage_manager::BandwidthStorageManager, BandwidthFlushingBehaviourConfig,
|
||||
ClientBandwidth, CredentialVerifier,
|
||||
};
|
||||
use nym_credentials_interface::{CredentialSpendingData, TicketType};
|
||||
use nym_crypto::asymmetric::x25519::KeyPair;
|
||||
use nym_gateway_requests::models::CredentialSpendingRequest;
|
||||
use nym_gateway_storage::models::PersistedBandwidth;
|
||||
use nym_sdk::mixnet::{
|
||||
AnonymousSenderTag, InputMessage, MixnetMessageSender, Recipient, TransmissionLane,
|
||||
};
|
||||
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||
use nym_sphinx::receiver::ReconstructedMessage;
|
||||
use nym_task::TaskHandle;
|
||||
use nym_wireguard::WireguardGatewayData;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
use rand::{prelude::IteratorRandom, thread_rng};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio_stream::wrappers::IntervalStream;
|
||||
|
||||
type AuthenticatorHandleResult = Result<(Vec<u8>, Option<Recipient>), AuthenticatorError>;
|
||||
const DEFAULT_REGISTRATION_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
|
||||
|
||||
pub(crate) struct RegistredAndFree {
|
||||
registration_in_progres: PendingRegistrations,
|
||||
free_private_network_ips: PrivateIPs,
|
||||
}
|
||||
|
||||
impl RegistredAndFree {
|
||||
pub(crate) fn new(free_private_network_ips: PrivateIPs) -> Self {
|
||||
RegistredAndFree {
|
||||
registration_in_progres: Default::default(),
|
||||
free_private_network_ips,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MixnetListener {
|
||||
// The configuration for the mixnet listener
|
||||
pub(crate) config: Config,
|
||||
|
||||
// The mixnet client that we use to send and receive packets from the mixnet
|
||||
pub(crate) mixnet_client: nym_sdk::mixnet::MixnetClient,
|
||||
|
||||
// The task handle for the main loop
|
||||
pub(crate) task_handle: TaskHandle,
|
||||
|
||||
// Registrations awaiting confirmation
|
||||
pub(crate) registred_and_free: RwLock<RegistredAndFree>,
|
||||
|
||||
pub(crate) peer_manager: PeerManager,
|
||||
|
||||
pub(crate) ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
|
||||
pub(crate) timeout_check_interval: IntervalStream,
|
||||
|
||||
pub(crate) seen_credential_cache: SeenCredentialCache,
|
||||
}
|
||||
|
||||
impl MixnetListener {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
free_private_network_ips: PrivateIPs,
|
||||
wireguard_gateway_data: WireguardGatewayData,
|
||||
mixnet_client: nym_sdk::mixnet::MixnetClient,
|
||||
task_handle: TaskHandle,
|
||||
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
) -> Self {
|
||||
let timeout_check_interval =
|
||||
IntervalStream::new(tokio::time::interval(DEFAULT_REGISTRATION_TIMEOUT_CHECK));
|
||||
MixnetListener {
|
||||
config,
|
||||
mixnet_client,
|
||||
task_handle,
|
||||
registred_and_free: RwLock::new(RegistredAndFree::new(free_private_network_ips)),
|
||||
peer_manager: PeerManager::new(wireguard_gateway_data),
|
||||
ecash_verifier,
|
||||
timeout_check_interval,
|
||||
seen_credential_cache: SeenCredentialCache::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn keypair(&self) -> &Arc<KeyPair> {
|
||||
self.peer_manager.wireguard_gateway_data.keypair()
|
||||
}
|
||||
|
||||
async fn remove_stale_registrations(&self) -> Result<(), AuthenticatorError> {
|
||||
let mut registred_and_free = self.registred_and_free.write().await;
|
||||
let registred_values: Vec<_> = registred_and_free
|
||||
.registration_in_progres
|
||||
.values()
|
||||
.cloned()
|
||||
.collect();
|
||||
for reg in registred_values {
|
||||
let ip = registred_and_free
|
||||
.free_private_network_ips
|
||||
.get_mut(®.gateway_data.private_ips)
|
||||
.ok_or(AuthenticatorError::InternalDataCorruption(format!(
|
||||
"IPs {} should be present",
|
||||
reg.gateway_data.private_ips
|
||||
)))?;
|
||||
|
||||
let Some(timestamp) = ip else {
|
||||
registred_and_free
|
||||
.registration_in_progres
|
||||
.remove(®.gateway_data.pub_key());
|
||||
tracing::debug!(
|
||||
"Removed stale registration of {}",
|
||||
reg.gateway_data.pub_key()
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let duration = SystemTime::now().duration_since(*timestamp).map_err(|_| {
|
||||
AuthenticatorError::InternalDataCorruption(
|
||||
"set timestamp shouldn't have been set in the future".to_string(),
|
||||
)
|
||||
})?;
|
||||
if duration > DEFAULT_REGISTRATION_TIMEOUT_CHECK {
|
||||
*ip = None;
|
||||
registred_and_free
|
||||
.registration_in_progres
|
||||
.remove(®.gateway_data.pub_key());
|
||||
tracing::debug!(
|
||||
"Removed stale registration of {}",
|
||||
reg.gateway_data.pub_key()
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn on_initial_request(
|
||||
&mut self,
|
||||
init_message: Box<dyn InitMessage + Send + Sync + 'static>,
|
||||
protocol: Protocol,
|
||||
request_id: u64,
|
||||
reply_to: Option<Recipient>,
|
||||
) -> AuthenticatorHandleResult {
|
||||
let remote_public = init_message.pub_key();
|
||||
let nonce: u64 = fastrand::u64(..);
|
||||
let mut registred_and_free = self.registred_and_free.write().await;
|
||||
if let Some(registration_data) = registred_and_free
|
||||
.registration_in_progres
|
||||
.get(&remote_public)
|
||||
{
|
||||
let gateway_data = registration_data.gateway_data.clone();
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V1 => {
|
||||
v1::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v1::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v1::GatewayClient {
|
||||
pub_key: gateway_data.pub_key,
|
||||
private_ip: gateway_data.private_ips.ipv4.into(),
|
||||
mac: v1::ClientMac::new(gateway_data.mac.to_vec()),
|
||||
},
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V2 => {
|
||||
v2::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v2::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v2::registration::GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
registration_data.gateway_data.private_ips.ipv4.into(),
|
||||
registration_data.nonce,
|
||||
),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V3 => {
|
||||
v3::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v3::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v3::registration::GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
registration_data.gateway_data.private_ips.ipv4.into(),
|
||||
registration_data.nonce,
|
||||
),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V4 => {
|
||||
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v4::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: registration_data.gateway_data.clone().into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V5 => {
|
||||
v5::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v5::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: registration_data.gateway_data.clone(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::UNKNOWN => return Err(AuthenticatorError::UnknownVersion),
|
||||
};
|
||||
return Ok((bytes, reply_to));
|
||||
}
|
||||
|
||||
let peer = self.peer_manager.query_peer(remote_public).await?;
|
||||
if let Some(peer) = peer {
|
||||
let allowed_ipv4 = peer
|
||||
.allowed_ips
|
||||
.iter()
|
||||
.find_map(|ip_mask| match ip_mask.ip {
|
||||
std::net::IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
|
||||
_ => None,
|
||||
})
|
||||
.ok_or(AuthenticatorError::InternalError(
|
||||
"there should be one private IPv4 in the list".to_string(),
|
||||
))?;
|
||||
let allowed_ipv6 = peer
|
||||
.allowed_ips
|
||||
.iter()
|
||||
.find_map(|ip_mask| match ip_mask.ip {
|
||||
std::net::IpAddr::V6(ipv6_addr) => Some(ipv6_addr),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or(IpPair::from(IpAddr::from(allowed_ipv4)).ipv6);
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V1 => v1::response::AuthenticatorResponse::new_registered(
|
||||
v1::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?,
|
||||
AuthenticatorVersion::V2 => v2::response::AuthenticatorResponse::new_registered(
|
||||
v2::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?,
|
||||
AuthenticatorVersion::V3 => v3::response::AuthenticatorResponse::new_registered(
|
||||
v3::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?,
|
||||
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_registered(
|
||||
v4::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?,
|
||||
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_registered(
|
||||
v5::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?,
|
||||
AuthenticatorVersion::UNKNOWN => return Err(AuthenticatorError::UnknownVersion),
|
||||
};
|
||||
return Ok((bytes, reply_to));
|
||||
}
|
||||
|
||||
let private_ip_ref = registred_and_free
|
||||
.free_private_network_ips
|
||||
.iter_mut()
|
||||
.filter(|r| r.1.is_none())
|
||||
.choose(&mut thread_rng())
|
||||
.ok_or(AuthenticatorError::NoFreeIp)?;
|
||||
let private_ips = *private_ip_ref.0;
|
||||
// mark it as used, even though it's not final
|
||||
*private_ip_ref.1 = Some(SystemTime::now());
|
||||
let gateway_data = GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
*private_ip_ref.0,
|
||||
nonce,
|
||||
);
|
||||
let registration_data = RegistrationData {
|
||||
nonce,
|
||||
gateway_data: gateway_data.clone(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
};
|
||||
registred_and_free
|
||||
.registration_in_progres
|
||||
.insert(remote_public, registration_data.clone());
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V1 => {
|
||||
v1::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v1::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v1::registration::GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
private_ips.ipv4.into(),
|
||||
nonce,
|
||||
),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V2 => {
|
||||
v2::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v2::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v2::registration::GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
private_ips.ipv4.into(),
|
||||
nonce,
|
||||
),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V3 => {
|
||||
v3::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v3::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: v3::registration::GatewayClient::new(
|
||||
self.keypair().private_key(),
|
||||
remote_public.inner(),
|
||||
private_ips.ipv4.into(),
|
||||
nonce,
|
||||
),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V4 => {
|
||||
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v4::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: registration_data.gateway_data.into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V5 => {
|
||||
v5::response::AuthenticatorResponse::new_pending_registration_success(
|
||||
v5::registration::RegistrationData {
|
||||
nonce: registration_data.nonce,
|
||||
gateway_data: registration_data.gateway_data,
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::UNKNOWN => return Err(AuthenticatorError::UnknownVersion),
|
||||
};
|
||||
|
||||
Ok((bytes, reply_to))
|
||||
}
|
||||
|
||||
async fn on_final_request(
|
||||
&mut self,
|
||||
final_message: Box<dyn FinalMessage + Send + Sync + 'static>,
|
||||
protocol: Protocol,
|
||||
request_id: u64,
|
||||
reply_to: Option<Recipient>,
|
||||
) -> AuthenticatorHandleResult {
|
||||
let mut registred_and_free = self.registred_and_free.write().await;
|
||||
let registration_data = registred_and_free
|
||||
.registration_in_progres
|
||||
.get(&final_message.pub_key())
|
||||
.ok_or(AuthenticatorError::RegistrationNotInProgress)?
|
||||
.clone();
|
||||
|
||||
if final_message
|
||||
.verify(self.keypair().private_key(), registration_data.nonce)
|
||||
.is_err()
|
||||
{
|
||||
return Err(AuthenticatorError::MacVerificationFailure);
|
||||
}
|
||||
|
||||
let mut peer = Peer::new(Key::new(final_message.pub_key().to_bytes()));
|
||||
peer.allowed_ips
|
||||
.push(IpAddrMask::new(final_message.private_ips().ipv4.into(), 32));
|
||||
peer.allowed_ips.push(IpAddrMask::new(
|
||||
final_message.private_ips().ipv6.into(),
|
||||
128,
|
||||
));
|
||||
|
||||
let Some(credential) = final_message.credential() else {
|
||||
return Err(AuthenticatorError::NoCredentialReceived);
|
||||
};
|
||||
let client_id = self
|
||||
.ecash_verifier
|
||||
.storage()
|
||||
.insert_wireguard_peer(
|
||||
&peer,
|
||||
TicketType::try_from_encoded(credential.payment.t_type)
|
||||
.map_err(|_| AuthenticatorError::InvalidCredentialType)?
|
||||
.into(),
|
||||
)
|
||||
.await?;
|
||||
if let Err(e) =
|
||||
credential_verification(self.ecash_verifier.clone(), credential, client_id).await
|
||||
{
|
||||
self.ecash_verifier
|
||||
.storage()
|
||||
.remove_wireguard_peer(&peer.public_key.to_string())
|
||||
.await?;
|
||||
return Err(e);
|
||||
}
|
||||
let public_key = peer.public_key.to_string();
|
||||
if let Err(e) = self.peer_manager.add_peer(peer).await {
|
||||
self.ecash_verifier
|
||||
.storage()
|
||||
.remove_wireguard_peer(&public_key)
|
||||
.await?;
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
registred_and_free
|
||||
.registration_in_progres
|
||||
.remove(&final_message.pub_key());
|
||||
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V1 => v1::response::AuthenticatorResponse::new_registered(
|
||||
v1::registration::RegistredData {
|
||||
pub_key: registration_data.gateway_data.pub_key,
|
||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V2 => v2::response::AuthenticatorResponse::new_registered(
|
||||
v2::registration::RegistredData {
|
||||
pub_key: registration_data.gateway_data.pub_key,
|
||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V3 => v3::response::AuthenticatorResponse::new_registered(
|
||||
v3::registration::RegistredData {
|
||||
pub_key: registration_data.gateway_data.pub_key,
|
||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_registered(
|
||||
v4::registration::RegistredData {
|
||||
pub_key: registration_data.gateway_data.pub_key,
|
||||
private_ips: registration_data.gateway_data.private_ips.into(),
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_registered(
|
||||
v5::registration::RegistredData {
|
||||
pub_key: registration_data.gateway_data.pub_key,
|
||||
private_ips: registration_data.gateway_data.private_ips,
|
||||
wg_port: registration_data.wg_port,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::UNKNOWN => return Err(AuthenticatorError::UnknownVersion),
|
||||
};
|
||||
Ok((bytes, reply_to))
|
||||
}
|
||||
|
||||
async fn on_query_bandwidth_request(
|
||||
&mut self,
|
||||
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
||||
protocol: Protocol,
|
||||
request_id: u64,
|
||||
reply_to: Option<Recipient>,
|
||||
) -> AuthenticatorHandleResult {
|
||||
let available_bandwidth = self.peer_manager.query_bandwidth(msg.pub_key()).await?;
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V1 => {
|
||||
v1::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
Some(v1::registration::RemainingBandwidthData {
|
||||
available_bandwidth: available_bandwidth as u64,
|
||||
suspended: false,
|
||||
}),
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V2 => {
|
||||
v2::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
Some(v2::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
}),
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V3 => {
|
||||
v3::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
Some(v3::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
}),
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V4 => {
|
||||
v4::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
Some(v4::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
}),
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::V5 => {
|
||||
v5::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||
Some(v5::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
}),
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||
})?
|
||||
}
|
||||
AuthenticatorVersion::UNKNOWN => return Err(AuthenticatorError::UnknownVersion),
|
||||
};
|
||||
Ok((bytes, reply_to))
|
||||
}
|
||||
|
||||
async fn on_topup_bandwidth_request(
|
||||
&mut self,
|
||||
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
||||
protocol: Protocol,
|
||||
request_id: u64,
|
||||
reply_to: Option<Recipient>,
|
||||
) -> AuthenticatorHandleResult {
|
||||
let available_bandwidth = if self.received_retry(msg.as_ref()) {
|
||||
// don't process the credential and just return the current bandwidth
|
||||
self.peer_manager.query_bandwidth(msg.pub_key()).await?
|
||||
} else {
|
||||
let mut verifier = self
|
||||
.peer_manager
|
||||
.query_verifier(msg.pub_key(), msg.credential())
|
||||
.await?;
|
||||
let available_bandwidth = verifier.verify().await?;
|
||||
self.seen_credential_cache
|
||||
.insert_credential(msg.credential(), msg.pub_key());
|
||||
available_bandwidth
|
||||
};
|
||||
|
||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||
v5::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||
v4::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V3 => v3::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||
v3::registration::RemainingBandwidthData {
|
||||
available_bandwidth,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
)
|
||||
.to_bytes()
|
||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||
AuthenticatorVersion::V1 | AuthenticatorVersion::V2 | AuthenticatorVersion::UNKNOWN => {
|
||||
return Err(AuthenticatorError::UnknownVersion)
|
||||
}
|
||||
};
|
||||
|
||||
Ok((bytes, reply_to))
|
||||
}
|
||||
|
||||
fn received_retry(&self, msg: &(dyn TopUpMessage + Send + Sync + 'static)) -> bool {
|
||||
if let Some(peer_pub_key) = self
|
||||
.seen_credential_cache
|
||||
.get_peer_pub_key(&msg.credential())
|
||||
{
|
||||
// check if the same peer sent the same credential twice, probably because of a retry
|
||||
peer_pub_key == msg.pub_key()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
async fn on_reconstructed_message(
|
||||
&mut self,
|
||||
reconstructed: ReconstructedMessage,
|
||||
) -> AuthenticatorHandleResult {
|
||||
tracing::debug!(
|
||||
"Received message with sender_tag: {:?}",
|
||||
reconstructed.sender_tag
|
||||
);
|
||||
|
||||
let request = deserialize_request(&reconstructed)?;
|
||||
|
||||
match request {
|
||||
AuthenticatorRequest::Initial {
|
||||
msg,
|
||||
reply_to,
|
||||
request_id,
|
||||
protocol,
|
||||
} => {
|
||||
self.on_initial_request(msg, protocol, request_id, reply_to)
|
||||
.await
|
||||
}
|
||||
AuthenticatorRequest::Final {
|
||||
msg,
|
||||
reply_to,
|
||||
request_id,
|
||||
protocol,
|
||||
} => {
|
||||
self.on_final_request(msg, protocol, request_id, reply_to)
|
||||
.await
|
||||
}
|
||||
AuthenticatorRequest::QueryBandwidth {
|
||||
msg,
|
||||
reply_to,
|
||||
request_id,
|
||||
protocol,
|
||||
} => {
|
||||
self.on_query_bandwidth_request(msg, protocol, request_id, reply_to)
|
||||
.await
|
||||
}
|
||||
AuthenticatorRequest::TopUpBandwidth {
|
||||
msg,
|
||||
reply_to,
|
||||
request_id,
|
||||
protocol,
|
||||
} => {
|
||||
self.on_topup_bandwidth_request(msg, protocol, request_id, reply_to)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When an incoming mixnet message triggers a response that we send back.
|
||||
async fn handle_response(
|
||||
&self,
|
||||
response: Vec<u8>,
|
||||
recipient: Option<Recipient>,
|
||||
sender_tag: Option<AnonymousSenderTag>,
|
||||
) -> Result<(), AuthenticatorError> {
|
||||
let input_message = create_input_message(recipient, sender_tag, response)?;
|
||||
self.mixnet_client.send(input_message).await.map_err(|err| {
|
||||
AuthenticatorError::FailedToSendPacketToMixnet {
|
||||
source: Box::new(err),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn run(mut self) -> Result<(), AuthenticatorError> {
|
||||
tracing::info!("Using authenticator version {CURRENT_VERSION}");
|
||||
let mut task_client = self.task_handle.fork("main_loop");
|
||||
|
||||
while !task_client.is_shutdown() {
|
||||
tokio::select! {
|
||||
_ = task_client.recv() => {
|
||||
tracing::debug!("Authenticator [main loop]: received shutdown");
|
||||
},
|
||||
_ = self.timeout_check_interval.next() => {
|
||||
if let Err(e) = self.remove_stale_registrations().await {
|
||||
tracing::error!("Could not clear stale registrations. The registration process might get jammed soon - {e:?}");
|
||||
}
|
||||
self.seen_credential_cache.remove_stale();
|
||||
}
|
||||
msg = self.mixnet_client.next() => {
|
||||
if let Some(msg) = msg {
|
||||
let sender_tag = msg.sender_tag;
|
||||
match self.on_reconstructed_message(msg).await {
|
||||
Ok((response, recipient)) => {
|
||||
if let Err(err) = self.handle_response(response, recipient, sender_tag).await {
|
||||
tracing::error!("Mixnet listener failed to handle response: {err}");
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("Error handling reconstructed mixnet message: {err}");
|
||||
}
|
||||
|
||||
};
|
||||
} else {
|
||||
tracing::trace!("Authenticator [main loop]: stopping since channel closed");
|
||||
break;
|
||||
};
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
tracing::debug!("Authenticator: stopping");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn credential_storage_preparation(
|
||||
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
client_id: i64,
|
||||
) -> Result<PersistedBandwidth, AuthenticatorError> {
|
||||
ecash_verifier
|
||||
.storage()
|
||||
.create_bandwidth_entry(client_id)
|
||||
.await?;
|
||||
let bandwidth = ecash_verifier
|
||||
.storage()
|
||||
.get_available_bandwidth(client_id)
|
||||
.await?
|
||||
.ok_or(AuthenticatorError::InternalError(
|
||||
"bandwidth entry should have just been created".to_string(),
|
||||
))?;
|
||||
Ok(bandwidth)
|
||||
}
|
||||
|
||||
async fn credential_verification(
|
||||
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
credential: CredentialSpendingData,
|
||||
client_id: i64,
|
||||
) -> Result<i64, AuthenticatorError> {
|
||||
let bandwidth = credential_storage_preparation(ecash_verifier.clone(), client_id).await?;
|
||||
let client_bandwidth = ClientBandwidth::new(bandwidth.into());
|
||||
let mut verifier = CredentialVerifier::new(
|
||||
CredentialSpendingRequest::new(credential),
|
||||
ecash_verifier.clone(),
|
||||
BandwidthStorageManager::new(
|
||||
ecash_verifier.storage(),
|
||||
client_bandwidth,
|
||||
client_id,
|
||||
BandwidthFlushingBehaviourConfig::default(),
|
||||
true,
|
||||
),
|
||||
);
|
||||
Ok(verifier.verify().await?)
|
||||
}
|
||||
|
||||
fn deserialize_request(
|
||||
reconstructed: &ReconstructedMessage,
|
||||
) -> Result<AuthenticatorRequest, AuthenticatorError> {
|
||||
let request_version = *reconstructed
|
||||
.message
|
||||
.first_chunk::<2>()
|
||||
.ok_or(AuthenticatorError::ShortPacket)?;
|
||||
|
||||
// Check version of the request and convert to the latest version if necessary
|
||||
match request_version {
|
||||
[1, _] => v1::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket { source: err })
|
||||
.map(Into::into),
|
||||
[2, request_type] => {
|
||||
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||
v2::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||
source: err,
|
||||
})
|
||||
.map(Into::<v3::request::AuthenticatorRequest>::into)
|
||||
.map(Into::into)
|
||||
} else {
|
||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||
}
|
||||
}
|
||||
[3, request_type] => {
|
||||
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||
v3::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||
source: err,
|
||||
})
|
||||
.map(Into::into)
|
||||
} else {
|
||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||
}
|
||||
}
|
||||
[4, request_type] => {
|
||||
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||
v4::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||
source: err,
|
||||
})
|
||||
.map(Into::into)
|
||||
} else {
|
||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||
}
|
||||
}
|
||||
[5, request_type] => {
|
||||
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||
v5::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||
source: err,
|
||||
})
|
||||
.map(Into::into)
|
||||
} else {
|
||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||
}
|
||||
}
|
||||
[version, _] => {
|
||||
tracing::info!("Received packet with invalid version: v{version}");
|
||||
Err(AuthenticatorError::InvalidPacketVersion(version))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_input_message(
|
||||
nym_address: Option<Recipient>,
|
||||
reply_to_tag: Option<AnonymousSenderTag>,
|
||||
response_packet: Vec<u8>,
|
||||
) -> Result<InputMessage, AuthenticatorError> {
|
||||
let lane = TransmissionLane::General;
|
||||
let packet_type = None;
|
||||
if let Some(reply_to_tag) = reply_to_tag {
|
||||
tracing::debug!("Creating message using SURB");
|
||||
Ok(InputMessage::new_reply(
|
||||
reply_to_tag,
|
||||
response_packet,
|
||||
lane,
|
||||
packet_type,
|
||||
))
|
||||
} else if let Some(nym_address) = nym_address {
|
||||
tracing::debug!("Creating message using nym_address");
|
||||
Ok(InputMessage::new_regular(
|
||||
nym_address,
|
||||
response_packet,
|
||||
lane,
|
||||
packet_type,
|
||||
))
|
||||
} else {
|
||||
tracing::error!("No nym-address or sender tag provided");
|
||||
Err(AuthenticatorError::MissingReplyToForOldClient)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
|
||||
use futures::channel::oneshot;
|
||||
use ipnetwork::IpNetwork;
|
||||
use nym_client_core::{HardcodedTopologyProvider, TopologyProvider};
|
||||
use nym_credential_verification::ecash::EcashManager;
|
||||
use nym_sdk::{mixnet::Recipient, GatewayTransceiver};
|
||||
use nym_task::{TaskClient, TaskHandle};
|
||||
use nym_wireguard::WireguardGatewayData;
|
||||
use std::{net::IpAddr, path::Path, sync::Arc, time::SystemTime};
|
||||
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod mixnet_client;
|
||||
pub mod mixnet_listener;
|
||||
mod peer_manager;
|
||||
mod seen_credential_cache;
|
||||
|
||||
pub use config::Config;
|
||||
|
||||
pub struct OnStartData {
|
||||
// to add more fields as required
|
||||
pub address: Recipient,
|
||||
}
|
||||
|
||||
impl OnStartData {
|
||||
pub fn new(address: Recipient) -> Self {
|
||||
Self { address }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Authenticator {
|
||||
#[allow(unused)]
|
||||
config: crate::node::internal_service_providers::authenticator::Config,
|
||||
wait_for_gateway: bool,
|
||||
custom_topology_provider: Option<Box<dyn TopologyProvider + Send + Sync>>,
|
||||
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send + Sync>>,
|
||||
wireguard_gateway_data: WireguardGatewayData,
|
||||
ecash_verifier: Arc<EcashManager>,
|
||||
used_private_network_ips: Vec<IpAddr>,
|
||||
shutdown: Option<TaskClient>,
|
||||
on_start: Option<oneshot::Sender<OnStartData>>,
|
||||
}
|
||||
|
||||
impl Authenticator {
|
||||
pub fn new(
|
||||
config: crate::node::internal_service_providers::authenticator::Config,
|
||||
wireguard_gateway_data: WireguardGatewayData,
|
||||
used_private_network_ips: Vec<IpAddr>,
|
||||
ecash_verifier: Arc<EcashManager>,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
wait_for_gateway: false,
|
||||
custom_topology_provider: None,
|
||||
custom_gateway_transceiver: None,
|
||||
ecash_verifier,
|
||||
wireguard_gateway_data,
|
||||
used_private_network_ips,
|
||||
shutdown: None,
|
||||
on_start: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn with_shutdown(mut self, shutdown: TaskClient) -> Self {
|
||||
self.shutdown = Some(shutdown);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn with_wait_for_gateway(mut self, wait_for_gateway: bool) -> Self {
|
||||
self.wait_for_gateway = wait_for_gateway;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_minimum_gateway_performance(mut self, minimum_gateway_performance: u8) -> Self {
|
||||
self.config.base.debug.topology.minimum_gateway_performance = minimum_gateway_performance;
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn with_on_start(mut self, on_start: oneshot::Sender<OnStartData>) -> Self {
|
||||
self.on_start = Some(on_start);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn with_custom_gateway_transceiver(
|
||||
mut self,
|
||||
gateway_transceiver: Box<dyn GatewayTransceiver + Send + Sync>,
|
||||
) -> Self {
|
||||
self.custom_gateway_transceiver = Some(gateway_transceiver);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[allow(unused)]
|
||||
pub fn with_custom_topology_provider(
|
||||
mut self,
|
||||
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
|
||||
) -> Self {
|
||||
self.custom_topology_provider = Some(topology_provider);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_stored_topology<P: AsRef<Path>>(
|
||||
mut self,
|
||||
file: P,
|
||||
) -> Result<Self, AuthenticatorError> {
|
||||
self.custom_topology_provider =
|
||||
Some(Box::new(HardcodedTopologyProvider::new_from_file(file)?));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub async fn run_service_provider(self) -> Result<(), AuthenticatorError> {
|
||||
// Used to notify tasks to shutdown. Not all tasks fully supports this (yet).
|
||||
|
||||
let task_handle: TaskHandle = self.shutdown.map(Into::into).unwrap_or_default();
|
||||
|
||||
// Connect to the mixnet
|
||||
let mixnet_client = crate::node::internal_service_providers::authenticator::mixnet_client::create_mixnet_client(
|
||||
&self.config.base,
|
||||
task_handle
|
||||
.get_handle()
|
||||
.named("nym_sdk::MixnetClient[AUTH]"),
|
||||
self.custom_gateway_transceiver,
|
||||
self.custom_topology_provider,
|
||||
self.wait_for_gateway,
|
||||
&self.config.storage_paths.common_paths,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let self_address = *mixnet_client.nym_address();
|
||||
|
||||
let used_private_network_ips =
|
||||
std::collections::BTreeSet::from_iter(self.used_private_network_ips.iter());
|
||||
let private_ip_network = IpNetwork::new(
|
||||
self.config.authenticator.private_ipv4.into(),
|
||||
self.config.authenticator.private_network_prefix_v4,
|
||||
)?;
|
||||
let now = SystemTime::now();
|
||||
let free_private_network_ips = private_ip_network
|
||||
.iter()
|
||||
.map(|ip: IpAddr| {
|
||||
if used_private_network_ips.contains(&ip) {
|
||||
(ip.into(), Some(now))
|
||||
} else {
|
||||
(ip.into(), None)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let mixnet_listener = crate::node::internal_service_providers::authenticator::mixnet_listener::MixnetListener::new(
|
||||
self.config,
|
||||
free_private_network_ips,
|
||||
self.wireguard_gateway_data,
|
||||
mixnet_client,
|
||||
task_handle,
|
||||
self.ecash_verifier,
|
||||
);
|
||||
|
||||
tracing::info!("The address of this client is: {self_address}");
|
||||
tracing::info!("All systems go. Press CTRL-C to stop the server.");
|
||||
|
||||
if let Some(on_start) = self.on_start {
|
||||
if on_start.send(OnStartData::new(self_address)).is_err() {
|
||||
// the parent has dropped the channel before receiving the response
|
||||
return Err(AuthenticatorError::DisconnectedParent);
|
||||
}
|
||||
}
|
||||
|
||||
mixnet_listener.run().await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,469 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
|
||||
use defguard_wireguard_rs::{host::Peer, key::Key};
|
||||
use futures::channel::oneshot;
|
||||
use nym_credential_verification::{ClientBandwidth, CredentialVerifier};
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_wireguard::{peer_controller::PeerControlRequest, WireguardGatewayData};
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
|
||||
pub struct PeerManager {
|
||||
pub(crate) wireguard_gateway_data: WireguardGatewayData,
|
||||
}
|
||||
|
||||
impl PeerManager {
|
||||
pub fn new(wireguard_gateway_data: WireguardGatewayData) -> Self {
|
||||
PeerManager {
|
||||
wireguard_gateway_data,
|
||||
}
|
||||
}
|
||||
pub async fn add_peer(&mut self, peer: Peer) -> Result<(), AuthenticatorError> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::AddPeer { peer, response_tx };
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::InternalError("no response for add peer".to_string()))?
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::InternalError(format!(
|
||||
"adding peer could not be performed: {err:?}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn _remove_peer(&mut self, pub_key: PeerPublicKey) -> Result<(), AuthenticatorError> {
|
||||
let key = Key::new(pub_key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::RemovePeer { key, response_tx };
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| {
|
||||
AuthenticatorError::InternalError("no response for remove peer".to_string())
|
||||
})?
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::InternalError(format!(
|
||||
"removing peer could not be performed: {err:?}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn query_peer(
|
||||
&mut self,
|
||||
public_key: PeerPublicKey,
|
||||
) -> Result<Option<Peer>, AuthenticatorError> {
|
||||
let key = Key::new(public_key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::QueryPeer { key, response_tx };
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| {
|
||||
AuthenticatorError::InternalError("no response for query peer".to_string())
|
||||
})?
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::InternalError(format!(
|
||||
"querying peer could not be performed: {err:?}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn query_bandwidth(
|
||||
&mut self,
|
||||
public_key: PeerPublicKey,
|
||||
) -> Result<i64, AuthenticatorError> {
|
||||
let client_bandwidth = self.query_client_bandwidth(public_key).await?;
|
||||
Ok(client_bandwidth.available().await)
|
||||
}
|
||||
|
||||
pub async fn query_client_bandwidth(
|
||||
&mut self,
|
||||
key: PeerPublicKey,
|
||||
) -> Result<ClientBandwidth, AuthenticatorError> {
|
||||
let key = Key::new(key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetClientBandwidth { key, response_tx };
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| {
|
||||
AuthenticatorError::InternalError(
|
||||
"no response for query client bandwidth".to_string(),
|
||||
)
|
||||
})?
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::InternalError(format!(
|
||||
"querying client bandwidth could not be performed: {err:?}"
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn query_verifier(
|
||||
&mut self,
|
||||
key: PeerPublicKey,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<CredentialVerifier, AuthenticatorError> {
|
||||
let key = Key::new(key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetVerifier {
|
||||
key,
|
||||
credential: Box::new(credential),
|
||||
response_tx,
|
||||
};
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| AuthenticatorError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| {
|
||||
AuthenticatorError::InternalError("no response for query verifier".to_string())
|
||||
})?
|
||||
.map_err(|err| {
|
||||
AuthenticatorError::InternalError(format!(
|
||||
"querying verifier could not be performed: {err:?}"
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{str::FromStr, sync::Arc};
|
||||
|
||||
use nym_credential_verification::{
|
||||
bandwidth_storage_manager::BandwidthStorageManager, ecash::MockEcashManager,
|
||||
};
|
||||
use nym_credentials_interface::Bandwidth;
|
||||
use nym_crypto::asymmetric::x25519::KeyPair;
|
||||
use nym_gateway_storage::traits::{mock::MockGatewayStorage, BandwidthGatewayStorage};
|
||||
use nym_wireguard::peer_controller::{start_controller, stop_controller};
|
||||
use rand::rngs::OsRng;
|
||||
use time::{Duration, OffsetDateTime};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::nym_authenticator::{
|
||||
config::Authenticator, mixnet_listener::credential_storage_preparation,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
|
||||
const CREDENTIAL_BYTES: [u8; 1245] = [
|
||||
0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254,
|
||||
16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139,
|
||||
154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123,
|
||||
35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1,
|
||||
151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43,
|
||||
90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193,
|
||||
39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81,
|
||||
184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195,
|
||||
196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48,
|
||||
92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48,
|
||||
166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186,
|
||||
19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38,
|
||||
228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85,
|
||||
88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241,
|
||||
85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112,
|
||||
48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31,
|
||||
97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203,
|
||||
71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107,
|
||||
213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180,
|
||||
178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1,
|
||||
96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166,
|
||||
30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212,
|
||||
207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71,
|
||||
223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22,
|
||||
119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131,
|
||||
59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119,
|
||||
240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202,
|
||||
58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144,
|
||||
189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33,
|
||||
30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150,
|
||||
74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6,
|
||||
227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85,
|
||||
15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38,
|
||||
161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20,
|
||||
47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48,
|
||||
135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170,
|
||||
150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109,
|
||||
55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249,
|
||||
87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144,
|
||||
178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32,
|
||||
203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184,
|
||||
96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169,
|
||||
24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61,
|
||||
130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82,
|
||||
108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1,
|
||||
32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234,
|
||||
150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241,
|
||||
203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217,
|
||||
160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52,
|
||||
147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81,
|
||||
70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233,
|
||||
178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98,
|
||||
110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69,
|
||||
131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251,
|
||||
197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233,
|
||||
162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106,
|
||||
83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145,
|
||||
192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124,
|
||||
55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0,
|
||||
0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
|
||||
#[tokio::test]
|
||||
async fn add_peer() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
let peer = Peer::default();
|
||||
let ecash_manager = MockEcashManager::new(Box::new(storage.clone()));
|
||||
|
||||
assert!(peer_manager.add_peer(peer.clone()).await.is_err());
|
||||
|
||||
let client_id = storage
|
||||
.insert_wireguard_peer(&peer, FromStr::from_str("entry_wireguard").unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(peer_manager.add_peer(peer.clone()).await.is_err());
|
||||
|
||||
credential_storage_preparation(Arc::new(ecash_manager), client_id)
|
||||
.await
|
||||
.unwrap();
|
||||
peer_manager.add_peer(peer.clone()).await.unwrap();
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
async fn helper_add_peer(
|
||||
storage: &Arc<RwLock<MockGatewayStorage>>,
|
||||
peer_manager: &mut PeerManager,
|
||||
) -> i64 {
|
||||
let peer = Peer::default();
|
||||
let ecash_manager = MockEcashManager::new(Box::new(storage.clone()));
|
||||
let client_id = storage
|
||||
.insert_wireguard_peer(&peer, FromStr::from_str("entry_wireguard").unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
credential_storage_preparation(Arc::new(ecash_manager), client_id)
|
||||
.await
|
||||
.unwrap();
|
||||
peer_manager.add_peer(peer.clone()).await.unwrap();
|
||||
|
||||
client_id
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remove_peer() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
peer_manager._remove_peer(public_key).await.unwrap();
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn query_peer() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
|
||||
assert!(peer_manager.query_peer(public_key).await.unwrap().is_none());
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
let peer = peer_manager.query_peer(public_key).await.unwrap().unwrap();
|
||||
assert_eq!(peer.public_key, key);
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn query_bandwidth() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
|
||||
assert!(peer_manager.query_bandwidth(public_key).await.is_err());
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
let available_bandwidth = peer_manager.query_bandwidth(public_key).await.unwrap();
|
||||
assert_eq!(available_bandwidth, 0);
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn query_client_bandwidth() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
|
||||
assert!(peer_manager
|
||||
.query_client_bandwidth(public_key)
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
let available_bandwidth = peer_manager
|
||||
.query_client_bandwidth(public_key)
|
||||
.await
|
||||
.unwrap()
|
||||
.available()
|
||||
.await;
|
||||
assert_eq!(available_bandwidth, 0);
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn query_verifier() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
|
||||
assert!(peer_manager
|
||||
.query_verifier(public_key, credential.clone())
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
peer_manager
|
||||
.query_verifier(public_key, credential)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn increase_decrease_bandwidth() {
|
||||
let (wireguard_data, request_rx) = WireguardGatewayData::new(
|
||||
Authenticator::default().into(),
|
||||
Arc::new(KeyPair::new(&mut OsRng)),
|
||||
);
|
||||
let mut peer_manager = PeerManager::new(wireguard_data);
|
||||
let key = Key::default();
|
||||
let public_key = PeerPublicKey::from_str(&key.to_string()).unwrap();
|
||||
let top_up = 42;
|
||||
let consume = 4;
|
||||
let (storage, task_manager) = start_controller(
|
||||
peer_manager.wireguard_gateway_data.peer_tx().clone(),
|
||||
request_rx,
|
||||
);
|
||||
|
||||
let client_id = helper_add_peer(&storage, &mut peer_manager).await;
|
||||
let client_bandwidth = peer_manager
|
||||
.query_client_bandwidth(public_key)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut bw_manager = BandwidthStorageManager::new(
|
||||
Box::new(storage),
|
||||
client_bandwidth.clone(),
|
||||
client_id,
|
||||
Default::default(),
|
||||
true,
|
||||
);
|
||||
bw_manager
|
||||
.increase_bandwidth(
|
||||
Bandwidth::new_unchecked(top_up as u64),
|
||||
OffsetDateTime::now_utc()
|
||||
.checked_add(Duration::minutes(1))
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(client_bandwidth.available().await, top_up);
|
||||
assert_eq!(
|
||||
peer_manager.query_bandwidth(public_key).await.unwrap(),
|
||||
top_up
|
||||
);
|
||||
|
||||
bw_manager.try_use_bandwidth(consume).await.unwrap();
|
||||
let remaining = top_up - consume;
|
||||
assert_eq!(client_bandwidth.available().await, remaining);
|
||||
assert_eq!(
|
||||
peer_manager.query_bandwidth(public_key).await.unwrap(),
|
||||
remaining
|
||||
);
|
||||
|
||||
stop_controller(task_manager).await;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(test)]
|
||||
use mock_instant::thread_local::SystemTime;
|
||||
#[cfg(not(test))]
|
||||
use std::time::SystemTime;
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
|
||||
const SEEN_CREDENTIAL_CACHE_TIME: Duration = Duration::from_secs(60 * 60); // 1 hour
|
||||
|
||||
#[derive(Eq, Hash, PartialEq)]
|
||||
struct TimestampedPeerPubKey {
|
||||
peer_pub_key: PeerPublicKey,
|
||||
timestamp: SystemTime,
|
||||
}
|
||||
|
||||
pub(crate) struct SeenCredentialCache {
|
||||
cached_credentials: HashMap<String, TimestampedPeerPubKey>,
|
||||
}
|
||||
|
||||
impl SeenCredentialCache {
|
||||
pub(crate) fn new() -> Self {
|
||||
SeenCredentialCache {
|
||||
cached_credentials: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn insert_credential(
|
||||
&mut self,
|
||||
credential: CredentialSpendingData,
|
||||
peer_pub_key: PeerPublicKey,
|
||||
) {
|
||||
let value = TimestampedPeerPubKey {
|
||||
peer_pub_key,
|
||||
timestamp: SystemTime::now(),
|
||||
};
|
||||
self.cached_credentials
|
||||
.insert(credential.serial_number_b58(), value);
|
||||
}
|
||||
|
||||
pub(crate) fn get_peer_pub_key(
|
||||
&self,
|
||||
credential: &CredentialSpendingData,
|
||||
) -> Option<PeerPublicKey> {
|
||||
self.cached_credentials
|
||||
.get(&credential.serial_number_b58())
|
||||
.map(|value| value.peer_pub_key)
|
||||
}
|
||||
|
||||
pub(crate) fn remove_stale(&mut self) {
|
||||
let now = SystemTime::now();
|
||||
self.cached_credentials.retain(|_, value| {
|
||||
let Ok(cache_time) = now.duration_since(value.timestamp) else {
|
||||
tracing::warn!("Got decreasing consecutive system timestamps");
|
||||
return false;
|
||||
};
|
||||
cache_time < SEEN_CREDENTIAL_CACHE_TIME
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use mock_instant::thread_local::MockClock;
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
|
||||
const CREDENTIAL_BYTES: [u8; 1245] = [
|
||||
0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254,
|
||||
16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139,
|
||||
154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123,
|
||||
35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1,
|
||||
151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43,
|
||||
90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193,
|
||||
39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81,
|
||||
184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195,
|
||||
196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48,
|
||||
92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48,
|
||||
166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186,
|
||||
19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38,
|
||||
228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85,
|
||||
88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241,
|
||||
85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112,
|
||||
48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31,
|
||||
97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203,
|
||||
71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107,
|
||||
213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180,
|
||||
178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1,
|
||||
96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166,
|
||||
30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212,
|
||||
207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71,
|
||||
223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22,
|
||||
119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131,
|
||||
59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119,
|
||||
240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202,
|
||||
58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144,
|
||||
189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33,
|
||||
30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150,
|
||||
74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6,
|
||||
227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85,
|
||||
15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38,
|
||||
161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20,
|
||||
47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48,
|
||||
135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170,
|
||||
150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109,
|
||||
55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249,
|
||||
87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144,
|
||||
178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32,
|
||||
203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184,
|
||||
96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169,
|
||||
24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61,
|
||||
130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82,
|
||||
108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1,
|
||||
32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234,
|
||||
150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241,
|
||||
203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217,
|
||||
160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52,
|
||||
147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81,
|
||||
70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233,
|
||||
178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98,
|
||||
110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69,
|
||||
131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251,
|
||||
197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233,
|
||||
162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106,
|
||||
83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145,
|
||||
192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124,
|
||||
55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0,
|
||||
0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
const PUB_KEY: &str = "yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=";
|
||||
|
||||
#[test]
|
||||
fn insertion() {
|
||||
let mut cache = SeenCredentialCache::new();
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
let peer_pub_key = PeerPublicKey::from_str(PUB_KEY).unwrap();
|
||||
|
||||
assert!(cache.get_peer_pub_key(&credential).is_none());
|
||||
|
||||
cache.insert_credential(credential.clone(), peer_pub_key);
|
||||
let cached_peer_pub_key = cache.get_peer_pub_key(&credential).unwrap();
|
||||
assert_eq!(cached_peer_pub_key, peer_pub_key);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn staleness() {
|
||||
let mut cache = SeenCredentialCache::new();
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
let peer_pub_key = PeerPublicKey::from_str(PUB_KEY).unwrap();
|
||||
|
||||
cache.insert_credential(credential.clone(), peer_pub_key);
|
||||
cache.remove_stale();
|
||||
assert!(cache.get_peer_pub_key(&credential).is_some());
|
||||
|
||||
MockClock::advance_system_time(SEEN_CREDENTIAL_CACHE_TIME * 2);
|
||||
|
||||
cache.remove_stale();
|
||||
assert!(cache.get_peer_pub_key(&credential).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_time() {
|
||||
assert!(MockClock::is_thread_local());
|
||||
assert!(SystemTime::now().is_thread_local());
|
||||
|
||||
let mut cache = SeenCredentialCache::new();
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
let peer_pub_key = PeerPublicKey::from_str(PUB_KEY).unwrap();
|
||||
|
||||
// set some value for time
|
||||
MockClock::set_system_time(Duration::from_secs(10));
|
||||
cache.insert_credential(credential.clone(), peer_pub_key);
|
||||
|
||||
// then set the time in the past
|
||||
MockClock::set_system_time(Duration::ZERO);
|
||||
cache.remove_stale();
|
||||
|
||||
// invalid time should remove the credential, just in case
|
||||
assert!(cache.get_peer_pub_key(&credential).is_none());
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -5,10 +5,10 @@ use crate::node::client_handling::embedded_clients::{LocalEmbeddedClientHandle,
|
||||
use crate::node::client_handling::websocket::message_receiver::{
|
||||
MixMessageReceiver, MixMessageSender,
|
||||
};
|
||||
use crate::node::internal_service_providers::authenticator::Authenticator;
|
||||
use crate::GatewayError;
|
||||
use async_trait::async_trait;
|
||||
use futures::channel::{mpsc, oneshot};
|
||||
use nym_authenticator::Authenticator;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_ip_packet_router::error::IpPacketRouterError;
|
||||
use nym_ip_packet_router::IpPacketRouter;
|
||||
@@ -22,6 +22,8 @@ use std::fmt::Display;
|
||||
use tokio::task::JoinHandle;
|
||||
use tracing::error;
|
||||
|
||||
pub mod authenticator;
|
||||
|
||||
pub trait LocalRecipient {
|
||||
fn address(&self) -> Recipient;
|
||||
}
|
||||
@@ -38,7 +40,7 @@ impl LocalRecipient for nym_ip_packet_router::OnStartData {
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalRecipient for nym_authenticator::OnStartData {
|
||||
impl LocalRecipient for authenticator::OnStartData {
|
||||
fn address(&self) -> Recipient {
|
||||
self.address
|
||||
}
|
||||
@@ -78,8 +80,8 @@ impl RunnableServiceProvider for IpPacketRouter {
|
||||
#[async_trait]
|
||||
impl RunnableServiceProvider for Authenticator {
|
||||
const NAME: &'static str = "authenticator";
|
||||
type OnStartData = nym_authenticator::OnStartData;
|
||||
type Error = nym_authenticator::error::AuthenticatorError;
|
||||
type OnStartData = authenticator::OnStartData;
|
||||
type Error = authenticator::error::AuthenticatorError;
|
||||
|
||||
async fn run_service_provider(self) -> Result<(), Self::Error> {
|
||||
self.run_service_provider().await
|
||||
@@ -5,10 +5,10 @@ use crate::config::Config;
|
||||
use crate::error::GatewayError;
|
||||
use crate::node::client_handling::websocket;
|
||||
use crate::node::internal_service_providers::{
|
||||
ExitServiceProviders, ServiceProviderBeingBuilt, SpMessageRouterBuilder,
|
||||
authenticator, ExitServiceProviders, ServiceProviderBeingBuilt, SpMessageRouterBuilder,
|
||||
};
|
||||
use crate::node::stale_data_cleaner::StaleMessagesCleaner;
|
||||
use futures::channel::oneshot;
|
||||
use nym_authenticator::Authenticator;
|
||||
use nym_credential_verification::ecash::{
|
||||
credential_sender::CredentialHandlerConfig, EcashManager,
|
||||
};
|
||||
@@ -18,6 +18,7 @@ use nym_mixnet_client::forwarder::MixForwardingSender;
|
||||
use nym_network_defaults::NymNetworkDetails;
|
||||
use nym_network_requester::NRServiceProviderBuilder;
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_task::TaskClient;
|
||||
use nym_topology::TopologyProvider;
|
||||
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||
@@ -31,10 +32,10 @@ use tracing::*;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
pub(crate) mod client_handling;
|
||||
mod internal_service_providers;
|
||||
pub(crate) mod internal_service_providers;
|
||||
mod stale_data_cleaner;
|
||||
|
||||
use crate::node::stale_data_cleaner::StaleMessagesCleaner;
|
||||
use crate::node::internal_service_providers::authenticator::Authenticator;
|
||||
pub use client_handling::active_clients::ActiveClientsStore;
|
||||
pub use nym_gateway_stats_storage::PersistentStatsStorage;
|
||||
pub use nym_gateway_storage::{
|
||||
@@ -42,7 +43,6 @@ pub use nym_gateway_storage::{
|
||||
traits::{BandwidthGatewayStorage, InboxGatewayStorage},
|
||||
GatewayStorage,
|
||||
};
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
pub use nym_sdk::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgent};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -61,7 +61,7 @@ pub struct LocalIpPacketRouterOpts {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LocalAuthenticatorOpts {
|
||||
pub config: nym_authenticator::Config,
|
||||
pub config: authenticator::Config,
|
||||
|
||||
pub custom_mixnet_path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user