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:
Jędrzej Stuczyński
2025-08-27 09:05:02 +01:00
committed by GitHub
parent 0a48fa6172
commit 724420f97c
24 changed files with 196 additions and 603 deletions
Generated
+8 -48
View File
@@ -4951,51 +4951,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "nym-authenticator"
version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"bs58",
"bytes",
"clap",
"defguard_wireguard_rs",
"fastrand 2.3.0",
"futures",
"ipnetwork",
"log",
"mock_instant",
"nym-authenticator-requests",
"nym-bin-common",
"nym-client-core",
"nym-config",
"nym-credential-verification",
"nym-credentials-interface",
"nym-crypto",
"nym-gateway-requests",
"nym-gateway-storage",
"nym-id",
"nym-network-defaults",
"nym-sdk",
"nym-service-provider-requests-common",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
"serde_json",
"thiserror 2.0.12",
"time",
"tokio",
"tokio-stream",
"tokio-util",
"url",
]
[[package]]
name = "nym-authenticator-requests"
version = "0.1.0"
@@ -5728,14 +5683,18 @@ version = "1.1.36"
dependencies = [
"anyhow",
"async-trait",
"bincode",
"bip39",
"bs58",
"dashmap",
"defguard_wireguard_rs",
"fastrand 2.3.0",
"futures",
"ipnetwork",
"mock_instant",
"nym-api-requests",
"nym-authenticator",
"nym-authenticator-requests",
"nym-client-core",
"nym-credential-verification",
"nym-credentials",
"nym-credentials-interface",
@@ -5743,6 +5702,7 @@ dependencies = [
"nym-gateway-requests",
"nym-gateway-stats-storage",
"nym-gateway-storage",
"nym-id",
"nym-ip-packet-router",
"nym-mixnet-client",
"nym-mixnode-common",
@@ -5750,6 +5710,7 @@ dependencies = [
"nym-network-requester",
"nym-node-metrics",
"nym-sdk",
"nym-service-provider-requests-common",
"nym-sphinx",
"nym-statistics-common",
"nym-task",
@@ -5759,8 +5720,8 @@ dependencies = [
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
"sha2 0.10.9",
"sqlx",
"thiserror 2.0.12",
"time",
"tokio",
@@ -6276,7 +6237,6 @@ dependencies = [
"indicatif 0.17.11",
"ipnetwork",
"lioness",
"nym-authenticator",
"nym-bin-common",
"nym-client-core-config-types",
"nym-config",
-2
View File
@@ -127,7 +127,6 @@ members = [
"sdk/ffi/go",
"sdk/ffi/shared",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
@@ -165,7 +164,6 @@ default-members = [
"nym-statistics-api",
"nym-validator-rewarder",
"nyx-chain-watcher",
"service-providers/authenticator",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"tools/nymvisor",
+16 -10
View File
@@ -11,7 +11,7 @@ authors = [
]
description = "Implementation of the Nym Mixnet Gateway"
edition = "2021"
rust-version = "1.76"
rust-version = "1.77"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -20,13 +20,16 @@ path = "src/lib.rs"
[dependencies]
anyhow = { workspace = true }
bincode = { workspace = true }
async-trait = { workspace = true }
bip39 = { workspace = true }
bs58 = { workspace = true }
dashmap = { workspace = true }
fastrand = { workspace = true }
futures = { workspace = true }
ipnetwork = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
sha2 = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true }
@@ -44,8 +47,8 @@ tracing = { workspace = true }
url = { workspace = true, features = ["serde"] }
zeroize = { workspace = true }
# internal
nym-authenticator = { path = "../service-providers/authenticator" }
nym-api-requests = { path = "../nym-api/nym-api-requests" }
nym-credentials = { path = "../common/credentials" }
nym-credentials-interface = { path = "../common/credentials-interface" }
@@ -71,13 +74,16 @@ nym-node-metrics = { path = "../nym-node/nym-node-metrics" }
nym-wireguard = { path = "../common/wireguard" }
nym-wireguard-types = { path = "../common/wireguard-types", default-features = false }
nym-authenticator-requests = { path = "../common/authenticator-requests" }
nym-client-core = { path = "../common/client-core", features = ["cli"] }
nym-id = { path = "../common/nym-id" }
nym-service-provider-requests-common = { path = "../common/service-provider-requests-common" }
defguard_wireguard_rs = { workspace = true }
[build-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
sqlx = { workspace = true, features = [
"runtime-tokio-rustls",
"sqlite",
"macros",
"migrate",
] }
[dev-dependencies]
nym-gateway-storage = { path = "../common/gateway-storage", features = ["mock"] }
nym-wireguard = { path = "../common/wireguard", features = ["mock"] }
mock_instant = "0.5.3"
time = { workspace = true }
+1 -1
View File
@@ -1,7 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_authenticator::error::AuthenticatorError;
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
use nym_gateway_stats_storage::error::StatsStorageError;
use nym_gateway_storage::error::GatewayStorageError;
use nym_ip_packet_router::error::IpPacketRouterError;
+2
View File
@@ -10,3 +10,5 @@ pub mod node;
pub use error::GatewayError;
pub use node::GatewayTasksBuilder;
pub use node::internal_service_providers::authenticator as nym_authenticator;
@@ -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,
}
}
}
@@ -101,5 +101,3 @@ pub enum AuthenticatorError {
#[error("no credential received")]
NoCredentialReceived,
}
pub type Result<T> = std::result::Result<T, AuthenticatorError>;
@@ -5,7 +5,9 @@ use nym_client_core::{config::disk_persistence::CommonClientPaths, TopologyProvi
use nym_sdk::{GatewayTransceiver, NymNetworkDetails};
use nym_task::TaskClient;
use crate::{config::BaseClientConfig, error::AuthenticatorError};
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.
@@ -7,8 +7,10 @@ use std::{
time::{Duration, SystemTime},
};
use crate::{config::Config, error::*, seen_credential_cache::SeenCredentialCache};
use crate::{error::AuthenticatorError, peer_manager::PeerManager};
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;
@@ -44,7 +46,7 @@ use rand::{prelude::IteratorRandom, thread_rng};
use tokio::sync::RwLock;
use tokio_stream::wrappers::IntervalStream;
type AuthenticatorHandleResult = Result<(Vec<u8>, Option<Recipient>)>;
type AuthenticatorHandleResult = Result<(Vec<u8>, Option<Recipient>), AuthenticatorError>;
const DEFAULT_REGISTRATION_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
pub(crate) struct RegistredAndFree {
@@ -110,7 +112,7 @@ impl MixnetListener {
self.peer_manager.wireguard_gateway_data.keypair()
}
async fn remove_stale_registrations(&self) -> Result<()> {
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
@@ -130,7 +132,7 @@ impl MixnetListener {
registred_and_free
.registration_in_progres
.remove(&reg.gateway_data.pub_key());
log::debug!(
tracing::debug!(
"Removed stale registration of {}",
reg.gateway_data.pub_key()
);
@@ -146,7 +148,7 @@ impl MixnetListener {
registred_and_free
.registration_in_progres
.remove(&reg.gateway_data.pub_key());
log::debug!(
tracing::debug!(
"Removed stale registration of {}",
reg.gateway_data.pub_key()
);
@@ -748,7 +750,7 @@ impl MixnetListener {
&mut self,
reconstructed: ReconstructedMessage,
) -> AuthenticatorHandleResult {
log::debug!(
tracing::debug!(
"Received message with sender_tag: {:?}",
reconstructed.sender_tag
);
@@ -801,7 +803,7 @@ impl MixnetListener {
response: Vec<u8>,
recipient: Option<Recipient>,
sender_tag: Option<AnonymousSenderTag>,
) -> Result<()> {
) -> Result<(), AuthenticatorError> {
let input_message = create_input_message(recipient, sender_tag, response)?;
self.mixnet_client.send(input_message).await.map_err(|err| {
AuthenticatorError::FailedToSendPacketToMixnet {
@@ -810,18 +812,18 @@ impl MixnetListener {
})
}
pub(crate) async fn run(mut self) -> Result<()> {
log::info!("Using authenticator version {CURRENT_VERSION}");
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() => {
log::debug!("Authenticator [main loop]: received shutdown");
tracing::debug!("Authenticator [main loop]: received shutdown");
},
_ = self.timeout_check_interval.next() => {
if let Err(e) = self.remove_stale_registrations().await {
log::error!("Could not clear stale registrations. The registration process might get jammed soon - {e:?}");
tracing::error!("Could not clear stale registrations. The registration process might get jammed soon - {e:?}");
}
self.seen_credential_cache.remove_stale();
}
@@ -831,23 +833,23 @@ impl MixnetListener {
match self.on_reconstructed_message(msg).await {
Ok((response, recipient)) => {
if let Err(err) = self.handle_response(response, recipient, sender_tag).await {
log::error!("Mixnet listener failed to handle response: {err}");
tracing::error!("Mixnet listener failed to handle response: {err}");
}
}
Err(err) => {
log::error!("Error handling reconstructed mixnet message: {err}");
tracing::error!("Error handling reconstructed mixnet message: {err}");
}
};
} else {
log::trace!("Authenticator [main loop]: stopping since channel closed");
tracing::trace!("Authenticator [main loop]: stopping since channel closed");
break;
};
},
}
}
log::debug!("Authenticator: stopping");
tracing::debug!("Authenticator: stopping");
Ok(())
}
}
@@ -855,7 +857,7 @@ impl MixnetListener {
pub async fn credential_storage_preparation(
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
client_id: i64,
) -> Result<PersistedBandwidth> {
) -> Result<PersistedBandwidth, AuthenticatorError> {
ecash_verifier
.storage()
.create_bandwidth_entry(client_id)
@@ -874,7 +876,7 @@ async fn credential_verification(
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
credential: CredentialSpendingData,
client_id: i64,
) -> Result<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(
@@ -891,7 +893,9 @@ async fn credential_verification(
Ok(verifier.verify().await?)
}
fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<AuthenticatorRequest> {
fn deserialize_request(
reconstructed: &ReconstructedMessage,
) -> Result<AuthenticatorRequest, AuthenticatorError> {
let request_version = *reconstructed
.message
.first_chunk::<2>()
@@ -948,7 +952,7 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
}
}
[version, _] => {
log::info!("Received packet with invalid version: v{version}");
tracing::info!("Received packet with invalid version: v{version}");
Err(AuthenticatorError::InvalidPacketVersion(version))
}
}
@@ -958,11 +962,11 @@ fn create_input_message(
nym_address: Option<Recipient>,
reply_to_tag: Option<AnonymousSenderTag>,
response_packet: Vec<u8>,
) -> Result<InputMessage> {
) -> Result<InputMessage, AuthenticatorError> {
let lane = TransmissionLane::General;
let packet_type = None;
if let Some(reply_to_tag) = reply_to_tag {
log::debug!("Creating message using SURB");
tracing::debug!("Creating message using SURB");
Ok(InputMessage::new_reply(
reply_to_tag,
response_packet,
@@ -970,7 +974,7 @@ fn create_input_message(
packet_type,
))
} else if let Some(nym_address) = nym_address {
log::debug!("Creating message using nym_address");
tracing::debug!("Creating message using nym_address");
Ok(InputMessage::new_regular(
nym_address,
response_packet,
@@ -978,7 +982,7 @@ fn create_input_message(
packet_type,
))
} else {
log::error!("No nym-address or sender tag provided");
tracing::error!("No nym-address or sender tag provided");
Err(AuthenticatorError::MissingReplyToForOldClient)
}
}
@@ -1,8 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::{net::IpAddr, path::Path, sync::Arc, time::SystemTime};
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
use futures::channel::oneshot;
use ipnetwork::IpNetwork;
use nym_client_core::{HardcodedTopologyProvider, TopologyProvider};
@@ -10,8 +9,16 @@ 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};
use crate::{config::Config, error::AuthenticatorError};
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
@@ -26,7 +33,7 @@ impl OnStartData {
pub struct Authenticator {
#[allow(unused)]
config: Config,
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>>,
@@ -39,7 +46,7 @@ pub struct Authenticator {
impl Authenticator {
pub fn new(
config: Config,
config: crate::node::internal_service_providers::authenticator::Config,
wireguard_gateway_data: WireguardGatewayData,
used_private_network_ips: Vec<IpAddr>,
ecash_verifier: Arc<EcashManager>,
@@ -119,7 +126,7 @@ impl Authenticator {
let task_handle: TaskHandle = self.shutdown.map(Into::into).unwrap_or_default();
// Connect to the mixnet
let mixnet_client = crate::mixnet_client::create_mixnet_client(
let mixnet_client = crate::node::internal_service_providers::authenticator::mixnet_client::create_mixnet_client(
&self.config.base,
task_handle
.get_handle()
@@ -129,7 +136,7 @@ impl Authenticator {
self.wait_for_gateway,
&self.config.storage_paths.common_paths,
)
.await?;
.await?;
let self_address = *mixnet_client.nym_address();
@@ -150,7 +157,7 @@ impl Authenticator {
}
})
.collect();
let mixnet_listener = crate::mixnet_listener::MixnetListener::new(
let mixnet_listener = crate::node::internal_service_providers::authenticator::mixnet_listener::MixnetListener::new(
self.config,
free_private_network_ips,
self.wireguard_gateway_data,
@@ -159,8 +166,8 @@ impl Authenticator {
self.ecash_verifier,
);
log::info!("The address of this client is: {self_address}");
log::info!("All systems go. Press CTRL-C to stop the server.");
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() {
@@ -1,7 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::*;
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};
@@ -19,7 +19,7 @@ impl PeerManager {
wireguard_gateway_data,
}
}
pub async fn add_peer(&mut self, peer: Peer) -> Result<()> {
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
@@ -38,7 +38,7 @@ impl PeerManager {
})
}
pub async fn _remove_peer(&mut self, pub_key: PeerPublicKey) -> Result<()> {
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 };
@@ -60,7 +60,10 @@ impl PeerManager {
})
}
pub async fn query_peer(&mut self, public_key: PeerPublicKey) -> Result<Option<Peer>> {
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 };
@@ -82,12 +85,18 @@ impl PeerManager {
})
}
pub async fn query_bandwidth(&mut self, public_key: PeerPublicKey) -> Result<i64> {
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> {
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 };
@@ -115,7 +124,7 @@ impl PeerManager {
&mut self,
key: PeerPublicKey,
credential: CredentialSpendingData,
) -> Result<CredentialVerifier> {
) -> Result<CredentialVerifier, AuthenticatorError> {
let key = Key::new(key.to_bytes());
let (response_tx, response_rx) = oneshot::channel();
let msg = PeerControlRequest::GetVerifier {
@@ -157,7 +166,9 @@ mod tests {
use time::{Duration, OffsetDateTime};
use tokio::sync::RwLock;
use crate::{config::Authenticator, mixnet_listener::credential_storage_preparation};
use crate::nym_authenticator::{
config::Authenticator, mixnet_listener::credential_storage_preparation,
};
use super::*;
@@ -55,7 +55,7 @@ impl SeenCredentialCache {
let now = SystemTime::now();
self.cached_credentials.retain(|_, value| {
let Ok(cache_time) = now.duration_since(value.timestamp) else {
log::warn!("Got decreasing consecutive system timestamps");
tracing::warn!("Got decreasing consecutive system timestamps");
return false;
};
cache_time < SEEN_CREDENTIAL_CACHE_TIME
@@ -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
+6 -6
View File
@@ -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>,
}
-1
View File
@@ -102,7 +102,6 @@ nym-node-metrics = { path = "nym-node-metrics" }
# nodes:
nym-gateway = { path = "../gateway" }
nym-authenticator = { path = "../service-providers/authenticator" }
nym-network-requester = { path = "../service-providers/network-requester" }
nym-ip-packet-router = { path = "../service-providers/ip-packet-router" }
+1 -1
View File
@@ -7,6 +7,7 @@ use clap::crate_version;
use nym_gateway::node::{
LocalAuthenticatorOpts, LocalIpPacketRouterOpts, LocalNetworkRequesterOpts,
};
use nym_gateway::nym_authenticator;
// a temporary solution until further refactoring is made
fn ephemeral_gateway_config(config: &Config) -> nym_gateway::config::Config {
@@ -182,7 +183,6 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig {
.authenticator
.to_common_client_paths(),
},
logging: config.logging,
},
custom_mixnet_path: None,
};
+1
View File
@@ -21,6 +21,7 @@ use nym_config::{
must_get_home, parse_urls, read_config_from_toml_file, save_formatted_config_to_file,
NymConfigTemplate, DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use nym_gateway::nym_authenticator;
use serde::{Deserialize, Serialize};
use std::env;
use std::fmt::{Display, Formatter};
@@ -1,59 +0,0 @@
[package]
name = "nym-authenticator"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
anyhow = { workspace = true }
bincode = { workspace = true }
bs58 = { workspace = true }
bytes = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"] }
defguard_wireguard_rs = { workspace = true }
fastrand = { workspace = true }
futures = { workspace = true }
ipnetwork = { workspace = true }
log = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net"] }
tokio-stream = { workspace = true }
tokio-util = { workspace = true, features = ["codec"] }
url = { workspace = true }
nym-authenticator-requests = { path = "../../common/authenticator-requests" }
nym-bin-common = { path = "../../common/bin-common", features = [
"clap",
"output_format",
"basic_tracing",
] }
nym-client-core = { path = "../../common/client-core", features = ["cli"] }
nym-config = { path = "../../common/config" }
nym-credentials-interface = { path = "../../common/credentials-interface" }
nym-credential-verification = { path = "../../common/credential-verification" }
nym-crypto = { path = "../../common/crypto" }
nym-gateway-requests = { path = "../../common/gateway-requests" }
nym-gateway-storage = { path = "../../common/gateway-storage" }
nym-id = { path = "../../common/nym-id" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
nym-service-providers-common = { path = "../common" }
nym-service-provider-requests-common = { path = "../../common/service-provider-requests-common" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-task = { path = "../../common/task" }
nym-types = { path = "../../common/types" }
nym-wireguard = { path = "../../common/wireguard" }
nym-wireguard-types = { path = "../../common/wireguard-types" }
[dev-dependencies]
mock_instant = "0.5.3"
time = { workspace = true }
nym-wireguard = { path = "../../common/wireguard", features = ["mock"] }
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use log::{info, trace};
use std::path::Path;
use crate::{config::old_config_v1_1_54::ConfigV1_1_54, error::AuthenticatorError};
async fn try_upgrade_v1_1_54_config<P: AsRef<Path>>(id: P) -> Result<bool, AuthenticatorError> {
// explicitly load it as v1.1.54 (which is incompatible with the current one, i.e. +1.1.55)
let Ok(old_config) = ConfigV1_1_54::read_from_default_path(id) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.54 config template.");
info!("It is going to get updated to the current specification.");
let updated = old_config.try_upgrade()?;
updated.save_to_default_location()?;
Ok(true)
}
pub async fn try_upgrade_config<P: AsRef<Path>>(id: P) -> Result<(), AuthenticatorError> {
trace!("Attempting to upgrade config");
if try_upgrade_v1_1_54_config(id).await? {
return Ok(());
}
Ok(())
}
@@ -1,242 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_bin_common::logging::LoggingSettings;
pub use nym_client_core::config::Config as BaseClientConfig;
use nym_client_core::{cli_helpers::CliClientConfig, config::disk_persistence::CommonClientPaths};
use nym_config::{
must_get_home, save_formatted_config_to_file, NymConfigTemplate, OptionalSet,
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
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 nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
pub use persistence::AuthenticatorPaths;
use serde::{Deserialize, Serialize};
use std::{
io,
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
path::{Path, PathBuf},
str::FromStr,
};
use template::CONFIG_TEMPLATE;
pub mod helpers;
pub mod old_config_v1_1_54;
pub mod persistence;
pub mod template;
const DEFAULT_AUTHENTICATOR_DIR: &str = "authenticator";
/// Derive default path to authenticator's config directory.
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/config`
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_SERVICE_PROVIDERS_DIR)
.join(DEFAULT_AUTHENTICATOR_DIR)
.join(id)
.join(DEFAULT_CONFIG_DIR)
}
/// Derive default path to authenticator's config file.
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/config/config.toml`
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
}
/// Derive default path to authenticator's data directory where files, such as keys, are stored.
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/data`
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
must_get_home()
.join(NYM_DIR)
.join(DEFAULT_SERVICE_PROVIDERS_DIR)
.join(DEFAULT_AUTHENTICATOR_DIR)
.join(id)
.join(DEFAULT_DATA_DIR)
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
#[serde(flatten)]
pub base: BaseClientConfig,
#[serde(default)]
pub authenticator: Authenticator,
pub storage_paths: AuthenticatorPaths,
pub logging: LoggingSettings,
}
impl NymConfigTemplate for Config {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
impl CliClientConfig for Config {
fn common_paths(&self) -> &CommonClientPaths {
&self.storage_paths.common_paths
}
fn core_config(&self) -> &BaseClientConfig {
&self.base
}
fn default_store_location(&self) -> PathBuf {
self.default_location()
}
fn save_to<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
save_formatted_config_to_file(self, path)
}
}
impl Config {
pub fn new<S: AsRef<str>>(id: S) -> Self {
Config {
base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")),
authenticator: Default::default(),
storage_paths: AuthenticatorPaths::new_base(default_data_directory(id.as_ref())),
logging: Default::default(),
}
}
#[allow(unused)]
pub fn with_data_directory<P: AsRef<Path>>(mut self, data_directory: P) -> Self {
self.storage_paths = AuthenticatorPaths::new_base(data_directory);
self
}
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
nym_config::read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
pub fn default_location(&self) -> PathBuf {
default_config_filepath(&self.base.client.id)
}
#[allow(unused)]
pub fn save_to_default_location(&self) -> io::Result<()> {
let config_save_location: PathBuf = self.default_location();
save_formatted_config_to_file(self, config_save_location)
}
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.base.validate()
}
#[doc(hidden)]
pub fn set_no_poisson_process(&mut self) {
self.base.set_no_poisson_process()
}
// poor man's 'builder' method
#[allow(unused)]
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
{
self.base = f(self.base, val);
self
}
// helper methods to use `OptionalSet` trait. Those are defined due to very... ehm. 'specific' structure of this config
// (plz, lets refactor it)
pub fn with_optional_base<F, T>(mut self, f: F, val: Option<T>) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
{
self.base = self.base.with_optional(f, val);
self
}
#[allow(unused)]
pub fn with_optional_base_env<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
T: FromStr,
<T as FromStr>::Err: std::fmt::Debug,
{
self.base = self.base.with_optional_env(f, val, env_var);
self
}
pub fn with_optional_base_custom_env<F, T, G>(
mut self,
f: F,
val: Option<T>,
env_var: &str,
parser: G,
) -> Self
where
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
G: Fn(&str) -> T,
{
self.base = self.base.with_optional_custom_env(f, val, env_var, parser);
self
}
}
#[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,
}
}
}
@@ -1,43 +0,0 @@
use std::{io, path::Path};
use nym_bin_common::logging::LoggingSettings;
pub use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54;
use nym_config::read_config_from_toml_file;
use serde::{Deserialize, Serialize};
use crate::{config::Config, error::AuthenticatorError};
use super::{default_config_filepath, Authenticator, AuthenticatorPaths};
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1_1_54 {
#[serde(flatten)]
pub base: BaseConfigV1_1_54,
#[serde(default)]
pub authenticator: Authenticator,
pub storage_paths: AuthenticatorPaths,
pub logging: LoggingSettings,
}
impl ConfigV1_1_54 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
read_config_from_toml_file(path)
}
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
Self::read_from_toml_file(default_config_filepath(id))
}
pub fn try_upgrade(self) -> Result<Config, AuthenticatorError> {
Ok(Config {
base: self.base.into(),
authenticator: self.authenticator,
storage_paths: self.storage_paths,
logging: self.logging,
})
}
}
@@ -1,94 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub(crate) const CONFIG_TEMPLATE: &str =
// While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields.
// Note: any changes to the template must be reflected in the appropriate structs.
r#"
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base client config options #####
[client]
# Version of the client for which this configuration was created.
version = '{{ client.version }}'
# Human readable ID of this particular client.
id = '{{ client.id }}'
# Indicates whether this client is running in a disabled credentials mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
disabled_credentials_mode = {{ client.disabled_credentials_mode }}
# Addresses to nyxd validators via which the client can communicate with the chain.
nyxd_urls = [
{{#each client.nyxd_urls }}
'{{this}}',
{{/each}}
]
# Addresses to APIs running on validator from which the client gets the view of the network.
nym_api_urls = [
{{#each client.nym_api_urls }}
'{{this}}',
{{/each}}
]
[storage_paths]
# Path to file containing private identity key.
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
# Path to file containing public identity key.
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
# Path to file containing private encryption key.
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
# Path to file containing public encryption key.
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
# Path to file containing key used for encrypting and decrypting the content of an
# acknowledgement so that nobody besides the client knows which packet it refers to.
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
# Path to the database containing bandwidth credentials
credentials_database = '{{ storage_paths.credentials_database }}'
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
# Path to the file containing information about gateways used by this client,
# i.e. details such as their public keys, owner addresses or the network information.
gateway_registrations = '{{ storage_paths.gateway_registrations }}'
# Location of the file containing our allow.list
allowed_list_location = '{{ storage_paths.allowed_list_location }}'
# Location of the file containing our unknown.list
unknown_list_location = '{{ storage_paths.unknown_list_location }}'
##### logging configuration options #####
[logging]
# TODO
##### debug configuration options #####
# The following options should not be modified unless you know EXACTLY what you are doing
# as if set incorrectly, they may impact your anonymity.
[debug]
[debug.acknowledgements]
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
[debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
"#;
@@ -1,13 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use authenticator::{Authenticator, OnStartData};
pub use config::Config;
pub mod authenticator;
pub mod config;
pub mod error;
pub mod mixnet_client;
pub mod mixnet_listener;
mod peer_manager;
mod seen_credential_cache;