Compare commits

..

1 Commits

Author SHA1 Message Date
Tommy Verrall 7644a48c23 Update ci-build-upload-binaries.yml 2024-07-04 09:54:12 +02:00
127 changed files with 1259 additions and 4622 deletions
-32
View File
@@ -4,38 +4,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2024.7-doubledecker] (2024-07-04)
- Add an early return in `parse_raw_str_logs` for empty raw log strings. ([#4686])
- Bump braces from 3.0.2 to 3.0.3 in /wasm/mix-fetch/internal-dev ([#4672])
- add expiry returned on import ([#4670])
- [bugfix] missing rustls feature ([#4666])
- Bump ws from 8.13.0 to 8.17.1 in /wasm/client/internal-dev-node ([#4665])
- Bump braces from 3.0.2 to 3.0.3 in /clients/native/examples/js-examples/websocket ([#4663])
- Bump ws from 8.14.2 to 8.17.1 in /sdk/typescript/packages/nodejs-client ([#4662])
- Update setup.md ([#4661])
- New clippy lints ([#4660])
- Bump braces from 3.0.2 to 3.0.3 in /nym-api/tests ([#4659])
- Bump braces from 3.0.2 to 3.0.3 in /docker/typescript_client/upload_contract ([#4658])
- Update vps-setup.md ([#4656])
- Update configuration.md ([#4655])
- Remove old PR template ([#4639])
[#4686]: https://github.com/nymtech/nym/pull/4686
[#4672]: https://github.com/nymtech/nym/pull/4672
[#4670]: https://github.com/nymtech/nym/pull/4670
[#4666]: https://github.com/nymtech/nym/pull/4666
[#4665]: https://github.com/nymtech/nym/pull/4665
[#4663]: https://github.com/nymtech/nym/pull/4663
[#4662]: https://github.com/nymtech/nym/pull/4662
[#4661]: https://github.com/nymtech/nym/pull/4661
[#4660]: https://github.com/nymtech/nym/pull/4660
[#4659]: https://github.com/nymtech/nym/pull/4659
[#4658]: https://github.com/nymtech/nym/pull/4658
[#4656]: https://github.com/nymtech/nym/pull/4656
[#4655]: https://github.com/nymtech/nym/pull/4655
[#4639]: https://github.com/nymtech/nym/pull/4639
## [2024.6-chomp] (2024-06-25)
- Remove additional code as part of Ephemera Purge and SP and contracts ([#4650])
Generated
+8 -75
View File
@@ -2093,7 +2093,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "explorer-api"
version = "1.1.36"
version = "1.1.35"
dependencies = [
"chrono",
"clap 4.5.4",
@@ -3849,7 +3849,7 @@ dependencies = [
[[package]]
name = "nym-api"
version = "1.1.40"
version = "1.1.39"
dependencies = [
"anyhow",
"async-trait",
@@ -3950,54 +3950,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "nym-authenticator"
version = "0.1.0"
dependencies = [
"anyhow",
"bincode",
"bs58 0.5.1",
"bytes",
"clap 4.5.4",
"fastrand 2.1.0",
"futures",
"ipnetwork 0.16.0",
"log",
"nym-authenticator-requests",
"nym-bin-common",
"nym-client-core",
"nym-config",
"nym-crypto",
"nym-id",
"nym-network-defaults",
"nym-sdk",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
"serde_json",
"thiserror",
"tokio",
"tokio-stream",
"tokio-util",
"url",
]
[[package]]
name = "nym-authenticator-requests"
version = "0.1.0"
dependencies = [
"bincode",
"nym-sphinx",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
]
[[package]]
name = "nym-bandwidth-controller"
version = "0.1.0"
@@ -4057,7 +4009,7 @@ dependencies = [
[[package]]
name = "nym-cli"
version = "1.1.38"
version = "1.1.37"
dependencies = [
"anyhow",
"base64 0.13.1",
@@ -4136,7 +4088,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.37"
version = "1.1.36"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -4562,7 +4514,6 @@ dependencies = [
"ipnetwork 0.16.0",
"log",
"nym-api-requests",
"nym-authenticator",
"nym-bin-common",
"nym-config",
"nym-credentials",
@@ -4950,7 +4901,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.38"
version = "1.1.37"
dependencies = [
"addr",
"anyhow",
@@ -4999,26 +4950,9 @@ dependencies = [
"zeroize",
]
[[package]]
name = "nym-network-statistics"
version = "1.1.34"
dependencies = [
"dirs 4.0.0",
"log",
"nym-bin-common",
"nym-statistics-common",
"nym-task",
"pretty_env_logger",
"rocket",
"serde",
"sqlx",
"thiserror",
"tokio",
]
[[package]]
name = "nym-node"
version = "1.1.4"
version = "1.1.3"
dependencies = [
"anyhow",
"bip39",
@@ -5030,7 +4964,6 @@ dependencies = [
"cupid",
"humantime-serde",
"ipnetwork 0.16.0",
"nym-authenticator",
"nym-bin-common",
"nym-client-core-config-types",
"nym-config",
@@ -5281,7 +5214,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.37"
version = "1.1.36"
dependencies = [
"bs58 0.5.1",
"clap 4.5.4",
@@ -5794,7 +5727,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.3"
version = "0.1.2"
dependencies = [
"anyhow",
"bytes",
-2
View File
@@ -20,7 +20,6 @@ members = [
"clients/native",
"clients/native/websocket-requests",
"clients/socks5",
"common/authenticator-requests",
"common/async-file-watcher",
"common/bandwidth-controller",
"common/bin-common",
@@ -96,7 +95,6 @@ members = [
"mixnode",
"sdk/lib/socks5-listener",
"sdk/rust/nym-sdk",
"service-providers/authenticator",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
+1 -1
View File
@@ -52,7 +52,7 @@ References for developers:
You can chat to us in two places:
* The #dev channel on [Matrix](https://matrix.to/#/#dev:nymtech.chat)
* The various developer channels on [Discord](https://discord.gg/FaTJb8q8)
* The various developer channels on [Discord](discord.gg/nymproject)
### Tokenomics & Rewards
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.37"
version = "1.1.36"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.37"
version = "1.1.36"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
-17
View File
@@ -1,17 +0,0 @@
[package]
name = "nym-authenticator-requests"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
[dependencies]
bincode = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" }
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub const CURRENT_VERSION: u8 = 1;
fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
@@ -1,7 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod request;
pub mod response;
const VERSION: u8 = 1;
@@ -1,70 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::{GatewayClient, InitMessage};
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub version: u8,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(gateway_client: GatewayClient, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
version: VERSION,
data: AuthenticatorRequestData::Final(gateway_client),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(GatewayClient),
}
@@ -1,88 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::registration::RegistrationData;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub version: u8,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(reply_to: Recipient, request_id: u64) -> Self {
Self {
version: VERSION,
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.reply_to
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
}
-13
View File
@@ -1,13 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// See other comments for other TaskStatus message enumds about abusing the Error trait when we
// should have a new trait for TaskStatus messages
#[derive(Debug, thiserror::Error)]
pub enum BandwidthStatusMessage {
#[error("remaining bandwidth: {0}")]
RemainingBandwidth(i64),
#[error("no bandwidth left")]
NoBandwidth,
}
-3
View File
@@ -14,11 +14,8 @@ use nym_validator_client::coconut::all_coconut_api_clients;
use nym_validator_client::nym_api::EpochId;
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
pub use event::BandwidthStatusMessage;
pub mod acquire;
pub mod error;
mod event;
mod utils;
#[derive(Debug)]
+12 -15
View File
@@ -11,7 +11,7 @@ use crate::traits::GatewayPacketRouter;
use crate::{cleanup_socket_message, try_decrypt_binary_message};
use futures::{SinkExt, StreamExt};
use log::*;
use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
use nym_bandwidth_controller::BandwidthController;
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
use nym_credential_storage::storage::Storage as CredentialStorage;
use nym_credentials::CredentialSpendingData;
@@ -105,8 +105,8 @@ pub struct GatewayClient<C, St = EphemeralCredentialStorage> {
// currently unused (but populated)
negotiated_protocol: Option<u8>,
/// Listen to shutdown messages and send notifications back to the task manager
task_client: TaskClient,
/// Listen to shutdown messages.
shutdown: TaskClient,
}
impl<C, St> GatewayClient<C, St> {
@@ -117,7 +117,7 @@ impl<C, St> GatewayClient<C, St> {
shared_key: Option<Arc<SharedKeys>>,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
task_client: TaskClient,
shutdown: TaskClient,
) -> Self {
GatewayClient {
authenticated: false,
@@ -135,7 +135,7 @@ impl<C, St> GatewayClient<C, St> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
@@ -299,7 +299,7 @@ impl<C, St> GatewayClient<C, St> {
loop {
tokio::select! {
_ = self.task_client.recv() => {
_ = self.shutdown.recv() => {
log::trace!("GatewayClient control response: Received shutdown");
log::debug!("GatewayClient control response: Exiting");
break Err(GatewayClientError::ConnectionClosedGatewayShutdown);
@@ -540,9 +540,6 @@ impl<C, St> GatewayClient<C, St> {
self.bandwidth_remaining = bandwidth_remaining;
self.negotiated_protocol = protocol_version;
log::debug!("authenticated: {status}, bandwidth remaining: {bandwidth_remaining}");
self.task_client.send_status_msg(Box::new(
BandwidthStatusMessage::RemainingBandwidth(bandwidth_remaining),
));
Ok(())
}
ServerResponse::Error { message } => Err(GatewayClientError::GatewayError(message)),
@@ -808,7 +805,7 @@ impl<C, St> GatewayClient<C, St> {
.as_ref()
.expect("no shared key present even though we're authenticated!"),
),
self.task_client.clone(),
self.shutdown.clone(),
)
}
_ => unreachable!(),
@@ -882,8 +879,8 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
// perfectly fine here, because it's not meant to be used
let (ack_tx, _) = mpsc::unbounded();
let (mix_tx, _) = mpsc::unbounded();
let task_client = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, task_client.clone());
let shutdown = TaskClient::dummy();
let packet_router = PacketRouter::new(ack_tx, mix_tx, shutdown.clone());
GatewayClient {
authenticated: false,
@@ -901,7 +898,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: DEFAULT_RECONNECTION_ATTEMPTS,
reconnection_backoff: DEFAULT_RECONNECTION_BACKOFF,
negotiated_protocol: None,
task_client,
shutdown,
}
}
@@ -909,7 +906,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
self,
packet_router: PacketRouter,
bandwidth_controller: Option<BandwidthController<C, St>>,
task_client: TaskClient,
shutdown: TaskClient,
) -> GatewayClient<C, St> {
// invariants that can't be broken
// (unless somebody decided to expose some field that wasn't meant to be exposed)
@@ -933,7 +930,7 @@ impl GatewayClient<InitOnly, EphemeralCredentialStorage> {
reconnection_attempts: self.reconnection_attempts,
reconnection_backoff: self.reconnection_backoff,
negotiated_protocol: self.negotiated_protocol,
task_client,
shutdown,
}
}
}
@@ -3,7 +3,7 @@
use crate::nyxd::cosmwasm_client::client_traits::CosmWasmClient;
use crate::nyxd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
use crate::nyxd::cosmwasm_client::logs::parse_raw_logs;
use crate::nyxd::cosmwasm_client::logs::{self, parse_raw_logs};
use crate::nyxd::cosmwasm_client::types::*;
use crate::nyxd::error::NyxdError;
use crate::nyxd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
@@ -19,7 +19,6 @@ use cosmrs::feegrant::{
};
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
use cosmrs::staking::{MsgDelegate, MsgUndelegate};
use cosmrs::tendermint::abci::{Event, EventAttribute};
use cosmrs::tx::{self, Msg};
use cosmrs::{cosmwasm, AccountId, Any, Tx};
use log::debug;
@@ -52,20 +51,6 @@ fn single_unspecified_signer_auth(
}
.auth_info(empty_fee())
}
// Searches in events for an event of the given event type which contains an
// attribute for with the given key.
fn find_attribute<'a>(
events: &'a [Event],
event_type: &str,
attr_key: &str,
) -> Option<&'a EventAttribute> {
events
.iter()
.find(|attr| attr.kind == event_type)?
.attributes
.iter()
.find(|attr| attr.key == attr_key)
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@@ -133,7 +118,6 @@ where
.check_response()?;
let logs = parse_raw_logs(tx_res.tx_result.log)?;
let events = tx_res.tx_result.events;
let gas_info = GasInfo {
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
@@ -143,7 +127,7 @@ where
// the reason I think unwrap here is fine is that if the transaction succeeded and those
// fields do not exist or code_id is not a number, there's no way we can recover, we're probably connected
// to wrong validator or something
let code_id = find_attribute(&events, "store_code", "code_id")
let code_id = logs::find_attribute(&logs, "store_code", "code_id")
.unwrap()
.value
.parse()
@@ -156,7 +140,6 @@ where
compressed_checksum,
code_id,
logs,
events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -199,7 +182,6 @@ where
.check_response()?;
let logs = parse_raw_logs(tx_res.tx_result.log)?;
let events = tx_res.tx_result.events;
let gas_info = GasInfo {
gas_wanted: tx_res.tx_result.gas_wanted.try_into().unwrap_or_default(),
gas_used: tx_res.tx_result.gas_used.try_into().unwrap_or_default(),
@@ -208,7 +190,7 @@ where
// the reason I think unwrap here is fine is that if the transaction succeeded and those
// fields do not exist or address is malformed, there's no way we can recover, we're probably connected
// to wrong validator or something
let contract_address = find_attribute(&events, "instantiate", "_contract_address")
let contract_address = logs::find_attribute(&logs, "instantiate", "_contract_address")
.unwrap()
.value
.parse()
@@ -217,7 +199,6 @@ where
Ok(InstantiateResult {
contract_address,
logs,
events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -250,7 +231,6 @@ where
};
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -281,7 +261,6 @@ where
};
Ok(ChangeAdminResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -319,7 +298,6 @@ where
};
Ok(MigrateResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
transaction_hash: tx_res.hash,
gas_info,
})
@@ -357,7 +335,6 @@ where
};
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
data: tx_res.tx_result.data.into(),
transaction_hash: tx_res.hash,
gas_info,
@@ -401,7 +378,6 @@ where
};
Ok(ExecuteResult {
logs: parse_raw_logs(tx_res.tx_result.log)?,
events: tx_res.tx_result.events,
data: tx_res.tx_result.data.into(),
transaction_hash: tx_res.hash,
gas_info,
@@ -9,12 +9,16 @@ pub use nym_coconut_bandwidth_contract_common::event_attributes::*;
pub use nym_coconut_dkg_common::event_attributes::*;
// it seems that currently validators just emit stringified events (which are also returned as part of deliverTx response)
// as their logs
// as theirs logs
#[derive(Debug, Serialize, Deserialize)]
pub struct Log {
#[serde(default)]
// weird thing is that the first msg_index seems to always be undefined on the raw logs
pub msg_index: usize,
// unless I'm missing something obvious, the "log" type in cosmjs is always an empty string
// and launchpad cosmos validator was setting it to what essentially is just the raw version of what
// we received (and we don't care about launchpad, we, as the time of writing this, work on the stargate)
// log: String,
pub events: Vec<cosmwasm_std::Event>,
}
@@ -33,13 +37,8 @@ pub fn find_attribute<'a>(
.find(|attr| attr.key == attribute_key)
}
// these two functions were separated so that the internal logic could actually be tested
// those two functions were separated so that the internal logic could actually be tested
fn parse_raw_str_logs(raw: &str) -> Result<Vec<Log>, NyxdError> {
// From Cosmos SDK > 0.50 onwards, log field is not populated
if raw.is_empty() {
return Ok(Vec::new());
}
let logs: Vec<Log> = serde_json::from_str(raw).map_err(|_| NyxdError::MalformedLogString)?;
if logs.len() != logs.iter().unique_by(|log| log.msg_index).count() {
// this check is only here because I don't yet fully understand raw log string generation and
@@ -232,8 +232,6 @@ pub struct UploadResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -271,8 +269,6 @@ pub struct InstantiateResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -283,8 +279,6 @@ pub struct InstantiateResult {
pub struct ChangeAdminResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -295,8 +289,6 @@ pub struct ChangeAdminResult {
pub struct MigrateResult {
pub logs: Vec<Log>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
@@ -309,8 +301,6 @@ pub struct ExecuteResult {
pub data: Vec<u8>,
pub events: Vec<abci::Event>,
/// Transaction hash (might be used as transaction ID)
pub transaction_hash: Hash,
+1 -1
View File
@@ -14,7 +14,7 @@ bytes = { workspace = true }
nym-bin-common = { path = "../bin-common" }
nym-crypto = { path = "../crypto" }
nym-sphinx = { path = "../nymsphinx" }
rand = { workspace = true }
rand = "0.8.5"
serde = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
time = { workspace = true }
+2 -1
View File
@@ -10,7 +10,8 @@ pub use config::Config;
pub use error::Error;
pub use public_key::PeerPublicKey;
pub use registration::{
ClientMac, ClientMessage, GatewayClient, GatewayClientRegistry, InitMessage, Nonce,
ClientMac, ClientMessage, ClientRegistrationResponse, GatewayClient, GatewayClientRegistry,
InitMessage, Nonce,
};
#[cfg(feature = "verify")]
+11 -3
View File
@@ -7,7 +7,6 @@ use base64::{engine::general_purpose, Engine};
use dashmap::DashMap;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
@@ -19,13 +18,13 @@ use sha2::Sha256;
pub type GatewayClientRegistry = DashMap<PeerPublicKey, GatewayClient>;
pub type PendingRegistrations = DashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = DashMap<IpAddr, Taken>;
pub type PrivateIPs = DashMap<IpAddr, Free>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub type Free = bool;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
@@ -54,6 +53,15 @@ impl InitMessage {
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub enum ClientRegistrationResponse {
PendingRegistration(RegistrationData),
Registered,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
+33 -39
View File
@@ -3,7 +3,7 @@ title = "Nym Docs"
authors = ["Max Hampshire, Serinko, Alexia Lorenza Martinel"]
description = "Nym technical documentation"
language = "en"
multilingual = false # for the moment - ideally work on chinese, brazillian ,portugese spanish next
multilingual = false # for the moment - ideally work on chinese, brazillian ,portugese spanish next
src = "src"
[rust]
@@ -14,19 +14,17 @@ edition = "2018"
#################
[preprocessor.theme]
pagetoc = true
sidebar-width = "280px"
content-max-width = "80%"
root-font-size = "70%"
# if you need to change anything in the index.hbs file you need to turn this to `false`, rebuild the book,
# probably remove the additional `comment` that gets appended to the header, and then change this back to `true`.
# this is because of a bug in the `mdbook-theme` plugin
turn-off = true
sidebar-width = "280px"
content-max-width = "70%"
content-main-margin-left = "5%"
content-main-margin-right = "5%"
root-font-size = "70%"
# DO NOT CHANGE or you might overwrite the custom hbs file
turn-off = false
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
# https://gitlab.com/tglman/mdbook-variables/
[preprocessor.variables.variables]
@@ -55,56 +53,52 @@ renderer = ["html"]
#########
[build]
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
##########
# OUTPUT #
##########
[output.html]
theme = "themes"
theme = "nym_themes"
default-theme = "coal"
preferred-dark-theme = "coal"
curly-quotes = true
copy-fonts = true
no-section-label = false
additional-css = [
"./themes/custom.css",
"./themes/mdbook-admonish.css",
"./themes/pagetoc.css",
]
additional-js = ["./themes/pagetoc.js"]
additional-css = ["./nym_themes/custom.css", "./nym_themes/mdbook-admonish.css", "./nym_themes/pagetoc.css"]
additional-js = ["./nym_themes/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
input-404 = "not-found.md"
[output.html.fold]
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
# controlling rust sample code blocks
[output.html.playground]
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
# options for the built in text search
[output.html.search]
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
[output.linkcheck]
warning-policy = "warn"
@@ -6,7 +6,7 @@
--sidebar-resize-indicator-width: 8px;
--sidebar-resize-indicator-space: 2px;
--page-padding: 15px;
--content-max-width: 80%;
--content-max-width: 70%;
--menu-bar-height: 40px;
--mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
--code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */
@@ -8,12 +8,10 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #121726;
background-color: #c5573d;
}
select option {
background-color: #121726;
}
@@ -23,18 +21,17 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #f2f2f2;
color:#f2f2f2;
background-color: #c5573d;
}
}
/*properly centering the title given the additional header items*/
.menu-title {
left: 45%;
position: absolute;
left: 50%;
}
.menu-bar .a:hover,
/*necessary because of ^*/
@@ -159,14 +159,20 @@
</ul>
<!-- CUSTOM -->
<select id="dropdown-menu" class="icon-button">
<select id="dropdown-menu3" class="icon-button">
<option value="">Network Protocol</option>
<option value="https://nymtech.net/docs">Network Docs</option>
<option value="https://nymtech.net/learn/papers">Academic Papers</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu" class="icon-button">
<option value="">Developer Docs</option>
<option value="https://nymtech.net/developers">Dev Portal</option>
<option value="https://nymtech.net/docs/sdk/rust/rust.html">Rust SDK</option>
<option value="https://sdk.nymtech.net">Typescript SDK</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu2" class="icon-button">
<option value="">Setup Guides</option>
<option value="https://nymtech.net/operators">Operators</option>
<option value="https://nymtech.net/developers/nymvpn/intro.html">NymVPN Testing</option>
@@ -180,7 +186,24 @@
}
});
</script>
<script>
document.getElementById('dropdown-menu2').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<script>
document.getElementById('dropdown-menu3').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<!-- END CUSTOM -->
</div>
@@ -240,8 +263,7 @@
<nav class="pagetoc"></nav>
</div>
<div class="content-wrap">
{{{ content }}}
{{{ content }}}
</div>
</main>
</main>
@@ -46,4 +46,4 @@ If you have successfully completed KYC on Synaps earlier and provided your Nym w
Using the Nym network is free for now, but user fees will be introduced in the future and those will be paid in NYM tokens, so set them aside! And until then, you can contribute to running our decentralized infrastructure and earn mix mining rewards by setting up Nym mix nodes and bonding your tokens to them. You don't need to run nodes to contribute to the security and performance of the Nym network though. You can pledge your trust in someone else's node by delegating your NYM tokens to it, and receive a share of their mix mining rewards.
You can find out more about how staking works in [this](https://www.youtube.com/watch?v=PcNGcTwlm0I) video from our Chief Scientist Claudia Diaz and if you need help setting up your mix node, choosing one to delegate your tokens to, or anything else, our community is there to help on [Discord](https://discord.gg/FaTJb8q8) and [Telegram](https://t.me/nymchan).
You can find out more about how staking works in [this](https://www.youtube.com/watch?v=PcNGcTwlm0I) video from our Chief Scientist Claudia Diaz and if you need help setting up your mix node, choosing one to delegate your tokens to, or anything else, our community is there to help on [Discord](https://discord.gg/nym) and [Telegram](https://t.me/nymchan).
@@ -39,5 +39,5 @@ Follow this [video](https://youtu.be/quj8H2qeOwY?t=97) to see the steps on Teleg
**Now your Telegram runs over NymConnect.**
NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our [Discord](http://discord.gg/FaTJb8q8) server.
NymConnect is currently available for several applications and service providers. Support for more apps is on the way. For any bug reports or feedback please reach out to us on Telegram or our [Discord](http://discord.gg/nym) server.
+1
View File
@@ -1,5 +1,6 @@
# mdbook files
book/
theme/
# Compiled assets
.sass-cache
+1 -1
View File
@@ -11,7 +11,7 @@ Since these docs autogenerate command output and import docs from binaries in `t
Changes merged to `master` will be autodeployed to the production site.
### Contributing a new translation
To contribute tranlsations in a new language, please get in touch via [Matrix](https://matrix.to/#/#general:nymtech.chat) or [Discord](https://discord.gg/FaTJb8q8).
To contribute tranlsations in a new language, please get in touch via [Matrix](https://matrix.to/#/#general:nymtech.chat) or [Discord](discord.gg/nym).
### Variables
There are some variables that are shared across the entire docs site, such as the current latest software version.
+34 -38
View File
@@ -3,7 +3,7 @@ title = "Nym Docs"
authors = ["Max Hampshire, Serinko, Alexia Lorenza Martinel"]
description = "Nym technical documentation"
language = "en"
multilingual = false # for the moment - ideally work on chinese, brazillian portugese, spanish next
multilingual = false # for the moment - ideally work on chinese, brazillian portugese, spanish next
src = "src"
[rust]
@@ -14,18 +14,18 @@ edition = "2018"
#################
[preprocessor.theme]
pagetoc = true
sidebar-width = "280px"
content-max-width = "80%"
root-font-size = "70%"
# if you need to change anything in the index.hbs file you need to turn this to `false`, rebuild the book,
# probably remove the additional `comment` that gets appended to the header, and then change this back to `true`.
# this is because of a bug in the `mdbook-theme` plugin
pagetoc = true
sidebar-width = "280px"
content-max-width = "70%"
content-main-margin-left = "5%"
content-main-margin-right = "5%"
root-font-size = "70%"
# DO NOT CHANGE or you might overwrite the custom hbs file
turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
# https://gitlab.com/tglman/mdbook-variables/
[preprocessor.variables.variables]
@@ -50,56 +50,52 @@ renderer = ["html"]
#########
[build]
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
##########
# OUTPUT #
##########
[output.html]
theme = "themes"
theme = "nym_themes"
default-theme = "coal"
preferred-dark-theme = "coal"
curly-quotes = true
copy-fonts = true
no-section-label = false
additional-css = [
"./themes/custom.css",
"./themes/mdbook-admonish.css",
"./themes/pagetoc.css",
]
additional-js = ["./themes/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym/documentation/"
additional-css = ["./nym_themes/custom.css", "./nym_themes/mdbook-admonish.css", "./nym_themes/pagetoc.css"]
additional-js = ["./nym_themes/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
input-404 = "not-found.md"
[output.html.fold]
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
# controlling rust sample code blocks
[output.html.playground]
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
# options for the built in text search
[output.html.search]
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
[output.linkcheck]
warning-policy = "warn"
@@ -6,7 +6,7 @@
--sidebar-resize-indicator-width: 8px;
--sidebar-resize-indicator-space: 2px;
--page-padding: 15px;
--content-max-width: 80%;
--content-max-width: 70%;
--menu-bar-height: 40px;
--mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
--code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */
@@ -8,12 +8,10 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #121726;
background-color: #c5573d;
}
select option {
background-color: #121726;
}
@@ -23,18 +21,17 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #f2f2f2;
color:#f2f2f2;
background-color: #c5573d;
}
}
/*properly centering the title given the additional header items*/
.menu-title {
left: 45%;
position: absolute;
left: 50%;
}
.menu-bar .a:hover,
/*necessary because of ^*/
@@ -159,14 +159,20 @@
</ul>
<!-- CUSTOM -->
<select id="dropdown-menu" class="icon-button">
<select id="dropdown-menu3" class="icon-button">
<option value="">Network Protocol</option>
<option value="https://nymtech.net/docs">Network Docs</option>
<option value="https://nymtech.net/learn/papers">Academic Papers</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu" class="icon-button">
<option value="">Developer Docs</option>
<option value="https://nymtech.net/developers">Dev Portal</option>
<option value="https://nymtech.net/docs/sdk/rust/rust.html">Rust SDK</option>
<option value="https://sdk.nymtech.net">Typescript SDK</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu2" class="icon-button">
<option value="">Setup Guides</option>
<option value="https://nymtech.net/operators">Operators</option>
<option value="https://nymtech.net/developers/nymvpn/intro.html">NymVPN Testing</option>
@@ -180,7 +186,24 @@
}
});
</script>
<script>
document.getElementById('dropdown-menu2').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<script>
document.getElementById('dropdown-menu3').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<!-- END CUSTOM -->
</div>
@@ -240,8 +263,7 @@
<nav class="pagetoc"></nav>
</div>
<div class="content-wrap">
{{{ content }}}
{{{ content }}}
</div>
</main>
</main>
@@ -36,7 +36,7 @@ Create an account on Sandbox using the nym-cli:
```./nym-cli --config-env-file <path-to>sandbox.env account create```
You will need `nymt` funds sent to this account. Get in touch via Nym [Telegram](https://t.me/nymchan) or [Discord](https://discord.gg/FaTJb8q8) and we can send them to you.
You will need `nymt` funds sent to this account. Get in touch via Nym [Telegram](https://t.me/nymchan) or [Discord](https://discord.com/invite/nym) and we can send them to you.
Next, you init the nym-client with the enabled credentials mode set to true:
+24 -22
View File
@@ -15,26 +15,27 @@ declare -a plugins=("admonish" "linkcheck" "last-changed" "theme" "variables" "c
install_mdbook_deps() {
printf "\ninstalling mdbook..."
# installing mdbook with only specific features for speed
# cargo install mdbook --no-default-features --features search --vers "^$MINOR_VERSION"
cargo install mdbook --no-default-features --vers "^$MINOR_VERSION"
# cargo install mdbook --no-default-features --features search --vers "^$MINOR_VERSION"
cargo install mdbook --vers "^$MINOR_VERSION"
printf "\ninstalling plugins..."
for i in "${plugins[@]}"; do
for i in "${plugins[@]}"
do
cargo install mdbook-$i
done
# mdbook-admonish config
# if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]; then
# printf "not in documentation/ - changing dir but something isn't right in the workflow file"
# cd documentation/
# mdbook-admonish install dev-portal
# mdbook-admonish install docs
# mdbook-admonish install operators
# else
# mdbook-admonish install dev-portal
# mdbook-admonish install docs
# mdbook-admonish install operators
# fi
# mdbook-admonish config
# if [ $(pwd | awk -F/ '{print $NF}') != "documentation" ]; then
# printf "not in documentation/ - changing dir but something isn't right in the workflow file"
# cd documentation/
# mdbook-admonish install dev-portal
# mdbook-admonish install docs
# mdbook-admonish install operators
# else
# mdbook-admonish install dev-portal
# mdbook-admonish install docs
# mdbook-admonish install operators
# fi
}
# uninstall mdbook + plugins
@@ -52,27 +53,28 @@ uninstall_mdbook_deps() {
# plugins
printf "\nuninstalling existing plugins...\n"
for i in "${plugins[@]}"; do
for i in "${plugins[@]}"
do
cargo uninstall mdbook-$i
# check it worked
if [ $? -ne 0 ]; then
printf "\nsomething went wrong, exiting"
exit 1
else
printf "\nmdbook-$i deleted\n"
fi
printf "\nmdbook-$i deleted\n"
fi
done
}
main() {
if test -f ~/.cargo/bin/mdbook; then
printf "mdbook already installed (located at: $(which mdbook))"
uninstall_mdbook_deps
install_mdbook_deps
uninstall_mdbook_deps;
install_mdbook_deps;
else
printf "mdbook not installed"
install_mdbook_deps
install_mdbook_deps;
fi
}
main
main;
+32 -37
View File
@@ -3,7 +3,7 @@ title = "Nym Operators Guide"
authors = ["Max Hampshire, Serinko, Alexia Lorenza Martinel"]
description = "Everything needed to run Nym Mixnet components"
language = "en"
multilingual = false # for the moment - ideally work on chinese, brazillian portugese, spanish next
multilingual = false # for the moment - ideally work on chinese, brazillian portugese, spanish next
src = "src"
[rust]
@@ -14,18 +14,17 @@ edition = "2018"
#################
[preprocessor.theme]
pagetoc = true
sidebar-width = "280px"
content-max-width = "80%"
root-font-size = "70%"
# if you need to change anything in the index.hbs file you need to turn this to `false`, rebuild the book,
# probably remove the additional `comment` that gets appended to the header, and then change this back to `true`.
# this is because of a bug in the `mdbook-theme` plugin
sidebar-width = "280px"
content-max-width = "70%"
content-main-margin-left = "5%"
content-main-margin-right = "5%"
root-font-size = "70%"
# DO NOT CHANGE or you might overwrite the custom hbs file
turn-off = true
[preprocessor.admonish]
command = "mdbook-admonish"
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
# https://gitlab.com/tglman/mdbook-variables/
[preprocessor.variables.variables]
@@ -56,57 +55,53 @@ renderer = ["html"]
#########
[build]
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
build-dir = "book" # the directory where the output is placed
create-missing = true # whether or not to create missing pages
use-default-preprocessors = true # use the default preprocessors
extra-watch-dirs = [] # directories to watch for triggering builds
##########
# OUTPUT #
##########
[output.html]
theme = "themes"
theme = "nym_themes"
default-theme = "coal"
preferred-dark-theme = "coal"
#curly-quotes = true
smart-punctuation = true
copy-fonts = true
no-section-label = false
additional-css = [
"./themes/custom.css",
"./themes/mdbook-admonish.css",
"./themes/pagetoc.css",
]
additional-js = ["./themes/pagetoc.js"]
additional-css = ["./nym_themes/custom.css", "./nym_themes/mdbook-admonish.css", "./nym_themes/pagetoc.css"]
additional-js = ["./nym_themes/pagetoc.js"]
git-repository-url = "https://github.com/nymtech/nym"
git-repository-icon = "fa-github"
input-404 = "not-found.md"
[output.html.fold]
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
enable = true # whether or not to enable section folding
level = 0 # the depth to start folding
# controlling rust sample code blocks
[output.html.playground]
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
editable = false # allows editing the source code
copyable = true # include the copy button for copying code snippets
copy-js = true # includes the JavaScript for the code editor
line-numbers = true # displays line numbers for editable code
runnable = true # displays a run button for rust code
# options for the built in text search
[output.html.search]
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
enable = true # enables the search feature
limit-results = 30 # maximum number of search results
teaser-word-count = 30 # number of words used for a search result teaser
use-boolean-and = true # multiple search terms must all match
boost-title = 2 # ranking boost factor for matches in headers
boost-hierarchy = 1 # ranking boost factor for matches in page names
boost-paragraph = 1 # ranking boost factor for matches in text
expand = true # partial words will match longer terms
heading-split-level = 3 # link results to heading levels
copy-js = true # include Javascript code for search
[output.linkcheck]
warning-policy = "warn"
@@ -6,7 +6,7 @@
--sidebar-resize-indicator-width: 8px;
--sidebar-resize-indicator-space: 2px;
--page-padding: 15px;
--content-max-width: 80%;
--content-max-width: 70%;
--menu-bar-height: 40px;
--mono-font: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace;
--code-font-size: 0.875em /* please adjust the ace font size accordingly in editor.js */
@@ -8,12 +8,10 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #121726;
background-color: #c5573d;
}
select option {
background-color: #121726;
}
@@ -23,18 +21,17 @@
--sidebar-active: #fb6e4e;
--icons-hover: #fb6e4e;
--links: #fb6e4e;
::selection {
color: #f2f2f2;
color:#f2f2f2;
background-color: #c5573d;
}
}
/*properly centering the title given the additional header items*/
.menu-title {
left: 45%;
position: absolute;
left: 50%;
}
.menu-bar .a:hover,
/*necessary because of ^*/
@@ -47,6 +44,8 @@ select {
font-size: 16px;
}
footer {
font-size: 0.8em;
text-align: center;
@@ -159,14 +159,20 @@
</ul>
<!-- CUSTOM -->
<select id="dropdown-menu" class="icon-button">
<select id="dropdown-menu3" class="icon-button">
<option value="">Network Protocol</option>
<option value="https://nymtech.net/docs">Network Docs</option>
<option value="https://nymtech.net/learn/papers">Academic Papers</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu" class="icon-button">
<option value="">Developer Docs</option>
<option value="https://nymtech.net/developers">Dev Portal</option>
<option value="https://nymtech.net/docs/sdk/rust/rust.html">Rust SDK</option>
<option value="https://sdk.nymtech.net">Typescript SDK</option>
<option value="">--------</option>
</select>
<select id="dropdown-menu2" class="icon-button">
<option value="">Setup Guides</option>
<option value="https://nymtech.net/operators">Operators</option>
<option value="https://nymtech.net/developers/nymvpn/intro.html">NymVPN Testing</option>
@@ -180,7 +186,24 @@
}
});
</script>
<script>
document.getElementById('dropdown-menu2').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<script>
document.getElementById('dropdown-menu3').addEventListener('change', function() {
const selected = this.options[this.selectedIndex];
if (selected.value !== '') {
window.location.href = selected.value;
}
});
</script>
<!-- END CUSTOM -->
</div>
@@ -240,8 +263,7 @@
<nav class="pagetoc"></nav>
</div>
<div class="content-wrap">
{{{ content }}}
{{{ content }}}
</div>
</main>
</main>
@@ -11,7 +11,7 @@ This document presents an initiative to further support Nyms mission of allow
All the technical changes on the side of Nym nodes - ***Project Smoosh*** - are described in the [FAQ section](../archive/faq/smoosh-faq.md).
```admonish warning
Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the operator channels ([Element](https://matrix.to/#/#operators:nymtech.chat), [Discord](https://discord.gg/FaTJb8q8), [Telegram](https://t.me/nymchan_help_chat)) to share best practices and experiences.
Nym core team cannot provide comprehensive legal advice across all jurisdictions. Knowledge and experience with the legalities are being built up with the help of our counsel and with you, the community of Nym node operators. We encourage Nym node operators to join the operator channels ([Element](https://matrix.to/#/#operators:nymtech.chat), [Discord](https://discord.com/invite/nym), [Telegram](https://t.me/nymchan_help_chat)) to share best practices and experiences.
```
@@ -11,6 +11,6 @@ If the `/dev/sda` partition is almost full, try pruning some of the `.gz` syslog
## Where can I get more help?
The fastest way to reach one of us or get a help from the community, visit our [Telegram Node Setup Help Chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://discord.gg/FaTJb8q8).
The fastest way to reach one of us or get a help from the community, visit our [Telegram Node Setup Help Chat](https://t.me/nymchan_help_chat) or head to our [Discord](https://Discord.gg/nym).
For more tech heavy question join our [Matrix core community channel](https://matrix.to/#/#general:nymtech.chat), where you can meet other builders and Nym core team members.
+58 -57
View File
@@ -8,80 +8,81 @@ import fs from "fs";
import { glob } from "glob";
async function main() {
const distDir = "../../../dist/docs";
const distDir = "../../../dist/docs";
const items = [];
const items = [];
const books = [
'developers',
'docs',
'operators',
];
const books = [
'developers',
'docs',
'operators',
];
for (const book of books) {
// only process the root `index.html` files, because they have absolute paths instead of relative paths
const filenames = [path.resolve(distDir, book, 'index.html')];
for(const book of books)
{
// only process the root `index.html` files, because they have absolute paths instead of relative paths
const filenames = [ path.resolve(distDir, book, 'index.html') ];
// leaving this here for a future where other files need to be processed
// const filenames = await glob(path.resolve(distDir, book) + '/**/*.html');
// leaving this here for a future where other files need to be processed
// const filenames = await glob(path.resolve(distDir, book) + '/**/*.html');
for (const f of filenames) {
// Create a Rehype processor with the inspectUrls plugin
const processor = unified()
.use(parse)
.use(inspectUrls, {
inspectEach(args) {
const { url: rawUrl, propertyName } = args;
const { tagName } = args.node;
const filename = args.file.history[0];
for (const f of filenames) {
// Create a Rehype processor with the inspectUrls plugin
const processor = unified()
.use(parse)
.use(inspectUrls, {
inspectEach(args) {
const { url: rawUrl, propertyName } = args;
const { tagName } = args.node;
const filename = args.file.history[0];
const relativeFilename = path.relative(distDir, filename);
const relativeDirectory = path.dirname(relativeFilename);
const relativeFilename = path.relative(distDir, filename);
const relativeDirectory = path.dirname(relativeFilename);
// remove relative paths from URL
const bareUrl = rawUrl.split('/').filter(c => c !== '.' && c !== '..').join('/');
let url;
// remove relative paths from URL
const bareUrl = rawUrl.split('/').filter(c => c !== '.' && c !== '..').join('/');
let url;
if (rawUrl.includes('.html#')) {
url = path.join(`/${relativeDirectory}`, bareUrl);
} else if (rawUrl.startsWith('#')) {
url = path.join(`/`, relativeFilename + bareUrl);
} else {
url = path.join(`/${book}`, bareUrl);
}
if(rawUrl.includes('.html#')) {
url = path.join(`/${relativeDirectory}`, bareUrl);
} else if(rawUrl.startsWith('#')) {
url = path.join(`/`, relativeFilename + bareUrl);
} else {
url = path.join(`/${book}`, bareUrl);
}
// const item = { filename, relativeDirectory, tagName, propertyName, rawUrl, url };
const item = { tagName, rawUrl, url };
// const item = { filename, relativeDirectory, tagName, propertyName, rawUrl, url };
const item = { tagName, rawUrl, url };
// if (tagName === 'a') {
// console.log(`tagName = a, args are: $args`);
// }
// if(tagName === 'a') {
// console.log(args);
// }
if (!rawUrl.startsWith('http')) {
if (tagName === 'link' || tagName === 'script' || tagName === 'a') {
args.node.properties[propertyName] = url;
items.push(item);
}
}
}
})
.use(stringify);
if(!rawUrl.startsWith('http')) {
if (tagName === 'link' || tagName === 'script' || tagName === 'a') {
args.node.properties[propertyName] = url;
items.push(item);
}
}
}
})
.use(stringify);
// Read the example HTML file
const filename = path.resolve(distDir, f);
console.log(`${filename}...`);
// Read the example HTML file
const filename = path.resolve(distDir, f);
console.log(`${filename}...`);
let file = await read(filename);
let file = await read(filename);
// Crawl the HTML file and find all the URLs
const res = await processor.process(file);
// Crawl the HTML file and find all the URLs
const res = await processor.process(file);
fs.writeFileSync(filename, res.value);
fs.writeFileSync(filename, res.value);
}
}
}
// console.table(items);
// console.log();
// console.table(items);
// console.log();
}
main();
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "explorer-api"
version = "1.1.36"
version = "1.1.35"
edition = "2021"
license.workspace = true
+1 -1
View File
@@ -10,7 +10,7 @@ import { DiscordIcon } from '../icons/socials/DiscordIcon'
export const TELEGRAM_LINK = 'https://t.me/nymchan'
export const TWITTER_LINK = 'https://twitter.com/nymproject'
export const GITHUB_LINK = 'https://github.com/nymtech'
export const DISCORD_LINK = 'https://discord.gg/FaTJb8q8'
export const DISCORD_LINK = 'https://discord.gg/nym'
export const Socials: FCWithChildren<{ isFooter?: boolean }> = ({
isFooter = false,
+1 -1
View File
@@ -10,7 +10,7 @@ import { DiscordIcon } from '../icons/socials/DiscordIcon';
export const TELEGRAM_LINK = 'https://t.me/nymchan';
export const TWITTER_LINK = 'https://twitter.com/nymproject';
export const GITHUB_LINK = 'https://github.com/nymtech';
export const DISCORD_LINK = 'https://discord.gg/FaTJb8q8';
export const DISCORD_LINK = 'https://discord.gg/nym';
export const Socials: FCWithChildren<{ isFooter?: boolean }> = ({ isFooter }) => {
const theme = useTheme();
-1
View File
@@ -58,7 +58,6 @@ zeroize = { workspace = true }
# internal
nym-authenticator = { path = "../service-providers/authenticator" }
nym-api-requests = { path = "../nym-api/nym-api-requests" }
nym-bin-common = { path = "../common/bin-common", features = ["output_format"] }
nym-config = { path = "../common/config" }
+3 -22
View File
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::node::storage::error::StorageError;
use nym_authenticator::error::AuthenticatorError;
use nym_ip_packet_router::error::IpPacketRouterError;
use nym_network_requester::error::{ClientCoreError, NetworkRequesterError};
use nym_validator_client::nyxd::error::NyxdError;
@@ -61,16 +60,6 @@ pub enum GatewayError {
source: io::Error,
},
#[error(
"failed to load config file for authenticator (gateway-id: '{id}') using path '{}'. detailed message: {source}",
path.display()
)]
AuthenticatorConfigLoadFailure {
id: String,
path: PathBuf,
source: io::Error,
},
#[error(
"failed to load config file for wireguard (gateway-id: '{id}') using path '{}'. detailed message: {source}",
path.display()
@@ -121,9 +110,6 @@ pub enum GatewayError {
#[error("Path to ip packet router configuration file hasn't been specified. Perhaps try to run `setup-ip-packet-router`?")]
UnspecifiedIpPacketRouterConfig,
#[error("Path to authenticator configuration file hasn't been specified. Perhaps try to run `setup-authenticator`?")]
UnspecifiedAuthenticatorConfig,
#[error("there was an issue with the local network requester: {source}")]
NetworkRequesterFailure {
#[from]
@@ -136,12 +122,6 @@ pub enum GatewayError {
source: IpPacketRouterError,
},
#[error("there was an issue with the local authenticator: {source}")]
AuthenticatorFailure {
#[from]
source: AuthenticatorError,
},
#[error("failed to startup local network requester")]
NetworkRequesterStartupFailure,
@@ -194,8 +174,9 @@ pub enum GatewayError {
#[error("wireguard not set")]
WireguardNotSet,
#[error("failed to start authenticator: {source}")]
AuthenticatorStartError {
#[cfg(all(feature = "wireguard", target_os = "linux"))]
#[error("failed to catch an interrupt: {source}")]
StdError {
source: Box<dyn std::error::Error + Send + Sync>,
},
}
+1 -1
View File
@@ -257,7 +257,7 @@ impl<'a> HttpApiBuilder<'a> {
}
let bind_address = self.gateway_config.http.bind_address;
let router = nym_node_http_api::NymNodeRouter::new(config, None);
let router = nym_node_http_api::NymNodeRouter::new(config, None, None);
tokio::spawn(async move {
let server = match router.build_server(&bind_address).await {
+15 -40
View File
@@ -89,7 +89,7 @@ pub async fn create_gateway(
let ip_opts = ip_packet_router_config.map(|config| LocalIpPacketRouterOpts {
config,
custom_mixnet_path: custom_mixnet.clone(),
custom_mixnet_path: custom_mixnet,
});
Gateway::new(config, nr_opts, ip_opts, storage)
@@ -109,13 +109,6 @@ pub struct LocalIpPacketRouterOpts {
pub custom_mixnet_path: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct LocalAuthenticatorOpts {
pub config: nym_authenticator::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
pub struct Gateway<St = PersistentStorage> {
config: Config,
@@ -123,10 +116,6 @@ pub struct Gateway<St = PersistentStorage> {
ip_packet_router_opts: Option<LocalIpPacketRouterOpts>,
// Use None when wireguard feature is not enabled too
#[allow(dead_code)]
authenticator_opts: Option<LocalAuthenticatorOpts>,
/// ed25519 keypair used to assert one's identity.
identity_keypair: Arc<identity::KeyPair>,
@@ -157,7 +146,6 @@ impl<St> Gateway<St> {
config,
network_requester_opts,
ip_packet_router_opts,
authenticator_opts: None,
#[cfg(all(feature = "wireguard", target_os = "linux"))]
wireguard_data: None,
run_http_server: true,
@@ -169,7 +157,6 @@ impl<St> Gateway<St> {
config: Config,
network_requester_opts: Option<LocalNetworkRequesterOpts>,
ip_packet_router_opts: Option<LocalIpPacketRouterOpts>,
authenticator_opts: Option<LocalAuthenticatorOpts>,
identity_keypair: Arc<identity::KeyPair>,
sphinx_keypair: Arc<encryption::KeyPair>,
storage: St,
@@ -178,7 +165,6 @@ impl<St> Gateway<St> {
config,
network_requester_opts,
ip_packet_router_opts,
authenticator_opts,
identity_keypair,
sphinx_keypair,
storage,
@@ -236,18 +222,11 @@ impl<St> Gateway<St> {
}
#[cfg(all(feature = "wireguard", target_os = "linux"))]
async fn start_authenticator(
async fn start_wireguard(
&mut self,
opts: &LocalAuthenticatorOpts,
shutdown: TaskClient,
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
if let Some(wireguard_data) = self.wireguard_data.take() {
let authenticator_server = nym_authenticator::Authenticator::new(
opts.config.clone(),
wireguard_data.inner.clone(),
)
.with_shutdown(shutdown.fork("authenticator"));
tokio::spawn(async move { authenticator_server.run_service_provider().await });
nym_wireguard::start_wireguard(shutdown, wireguard_data).await
} else {
Err(Box::new(GatewayError::WireguardNotSet))
@@ -255,12 +234,8 @@ impl<St> Gateway<St> {
}
#[cfg(all(feature = "wireguard", not(target_os = "linux")))]
async fn start_authenticator(
&self,
_opts: &LocalAuthenticatorOpts,
_shutdown: TaskClient,
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
todo!("Authenticator is currently only supported on Linux");
async fn start_wireguard(&self, _shutdown: TaskClient) {
nym_wireguard::start_wireguard().await
}
fn start_client_websocket_listener(
@@ -563,17 +538,6 @@ impl<St> Gateway<St> {
info!("embedded ip packet router is disabled");
};
#[cfg(feature = "wireguard")]
let _wg_api = if let Some(opts) = self.authenticator_opts.clone() {
Some(
self.start_authenticator(&opts, shutdown.fork("wireguard"))
.await
.map_err(|source| GatewayError::AuthenticatorStartError { source })?,
)
} else {
None
};
if self.run_http_server {
HttpApiBuilder::new(
&self.config,
@@ -586,6 +550,17 @@ impl<St> Gateway<St> {
.start(shutdown.fork("http-api"))?;
}
// Once this is a bit more mature, make this a commandline flag instead of a compile time
// flag
#[cfg(all(feature = "wireguard", target_os = "linux"))]
let _wg_api = self
.start_wireguard(shutdown.fork("wireguard"))
.await
.map_err(|source| GatewayError::StdError { source })?;
#[cfg(all(feature = "wireguard", not(target_os = "linux")))]
self.start_wireguard(shutdown.fork("wireguard")).await;
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
info!(
+1 -1
View File
@@ -103,7 +103,7 @@ impl<'a> HttpApiBuilder<'a> {
.with_mixnode(load_mixnode_details(self.mixnode_config)?)
.with_landing_page_assets(self.mixnode_config.http.landing_page_assets_path.as_ref());
let router = nym_node_http_api::NymNodeRouter::new(config, None);
let router = nym_node_http_api::NymNodeRouter::new(config, None, None);
tokio::spawn(async move {
let server = match router.build_server(&bind_address).await {
+1 -1
View File
@@ -4,7 +4,7 @@
[package]
name = "nym-api"
license = "GPL-3.0"
version = "1.1.40"
version = "1.1.39"
authors = [
"Dave Hrycyszyn <futurechimp@users.noreply.github.com>",
"Jędrzej Stuczyński <andrew@nymtech.net>",
+1 -28
View File
@@ -1,7 +1,6 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nym_nodes::NodeRole;
use crate::pagination::PaginatedResponse;
use cosmwasm_std::{Addr, Coin, Decimal};
use nym_mixnet_contract_common::families::FamilyHead;
@@ -9,7 +8,7 @@ use nym_mixnet_contract_common::mixnode::MixNodeDetails;
use nym_mixnet_contract_common::reward_params::{Performance, RewardingParams};
use nym_mixnet_contract_common::rewarding::RewardEstimate;
use nym_mixnet_contract_common::{
GatewayBond, IdentityKey, Interval, MixId, MixNode, MixNodeBond, Percent, RewardedSetNodeStatus,
GatewayBond, IdentityKey, Interval, MixId, MixNode, Percent, RewardedSetNodeStatus,
};
use nym_node_requests::api::v1::node::models::{AuxiliaryDetails, BinaryBuildInformationOwned};
use schemars::gen::SchemaGenerator;
@@ -606,13 +605,8 @@ pub struct NymNodeDescription {
#[serde(default)]
pub ip_packet_router: Option<IpPacketRouterDetails>,
#[serde(default)]
pub authenticator: Option<AuthenticatorDetails>,
// for now we only care about their ws/wss situation, nothing more
pub mixnet_websockets: WebSockets,
pub role: NodeRole,
}
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
@@ -630,21 +624,6 @@ impl From<GatewayBond> for DescribedGateway {
}
}
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct DescribedMixNode {
pub bond: MixNodeBond,
pub self_described: Option<NymNodeDescription>,
}
impl From<MixNodeBond> for DescribedMixNode {
fn from(bond: MixNodeBond) -> Self {
DescribedMixNode {
bond,
self_described: None,
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct NetworkRequesterDetails {
/// address of the embedded network requester
@@ -660,12 +639,6 @@ pub struct IpPacketRouterDetails {
pub address: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct AuthenticatorDetails {
/// address of the embedded authenticator
pub address: String,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, schemars::JsonSchema)]
pub struct ApiHealthResponse {
pub status: ApiStatus,
-4
View File
@@ -1034,7 +1034,6 @@ impl super::client::Client for DummyClient {
events: vec![cosmwasm_std::Event::new("wasm")
.add_attribute(NODE_INDEX, assigned_index.to_string())],
}],
events: Default::default(),
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
@@ -1068,7 +1067,6 @@ impl super::client::Client for DummyClient {
Ok(ExecuteResult {
logs: vec![],
events: Default::default(),
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
@@ -1103,7 +1101,6 @@ impl super::client::Client for DummyClient {
Ok(ExecuteResult {
logs: vec![],
events: Default::default(),
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
@@ -1180,7 +1177,6 @@ impl super::client::Client for DummyClient {
events: vec![cosmwasm_std::Event::new("wasm")
.add_attribute(DKG_PROPOSAL_ID, proposal_id.to_string())],
}],
events: Default::default(),
data: Default::default(),
transaction_hash,
gas_info: Default::default(),
+49 -116
View File
@@ -8,11 +8,11 @@ use crate::support::config;
use crate::support::config::DEFAULT_NODE_DESCRIBE_BATCH_SIZE;
use futures::{stream, StreamExt};
use nym_api_requests::models::{
AuthenticatorDetails, IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription,
IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription,
};
use nym_api_requests::nym_nodes::NodeRole;
use nym_config::defaults::{mainnet, DEFAULT_NYM_NODE_HTTP_PORT};
use nym_contracts_common::IdentityKey;
use nym_mixnet_contract_common::Gateway;
use nym_node_requests::api::client::{NymNodeApiClientError, NymNodeApiClientExt};
use std::collections::HashMap;
use thiserror::Error;
@@ -56,6 +56,8 @@ pub enum NodeDescribeCacheError {
}
pub struct NodeDescriptionProvider {
// for now we only care about gateways, nothing more
// network_gateways: SharedCache<Vec<GatewayBond>>,
contract_cache: NymContractCache,
batch_size: usize,
@@ -77,32 +79,27 @@ impl NodeDescriptionProvider {
}
async fn try_get_client(
host: &str,
identity_key: &IdentityKey,
port: Option<u16>,
gateway: &Gateway,
) -> Result<nym_node_requests::api::Client, NodeDescribeCacheError> {
let gateway_host = &gateway.host;
// first try the standard port in case the operator didn't put the node behind the proxy,
// then default https (443)
// finally default http (80)
let mut addresses_to_try = vec![
format!("http://{host}:{DEFAULT_NYM_NODE_HTTP_PORT}"),
format!("http://{host}:8000"),
format!("https://{host}"),
format!("http://{host}"),
let addresses_to_try = vec![
format!("http://{gateway_host}:{DEFAULT_NYM_NODE_HTTP_PORT}"),
format!("https://{gateway_host}"),
format!("http://{gateway_host}"),
];
if let Some(port) = port {
addresses_to_try.insert(0, format!("http://{host}:{port}"));
}
for address in addresses_to_try {
// if provided host was malformed, no point in continuing
let client = match nym_node_requests::api::Client::new_url(address, None) {
Ok(client) => client,
Err(err) => {
return Err(NodeDescribeCacheError::MalformedHost {
host: host.to_string(),
gateway: identity_key.clone(),
host: gateway_host.clone(),
gateway: gateway.identity_key.clone(),
source: err,
});
}
@@ -115,28 +112,28 @@ async fn try_get_client(
}
Err(NodeDescribeCacheError::NoHttpPortsAvailable {
host: host.to_string(),
gateway: identity_key.to_string(),
host: gateway_host.clone(),
gateway: gateway.identity_key.clone(),
})
}
async fn try_get_description(
data: RefreshData,
async fn get_gateway_description(
gateway: Gateway,
) -> Result<(IdentityKey, NymNodeDescription), NodeDescribeCacheError> {
let client = try_get_client(&data.host(), &data.identity_key(), data.port()).await?;
let client = try_get_client(&gateway).await?;
let host_info =
client
.get_host_information()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: data.identity_key().to_string(),
gateway: gateway.identity_key.clone(),
source: err,
})?;
if !host_info.verify_host_information() {
return Err(NodeDescribeCacheError::MissignedHostInformation {
gateway: data.identity_key().clone(),
gateway: gateway.identity_key,
});
}
@@ -145,13 +142,13 @@ async fn try_get_description(
.get_build_information()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: data.identity_key().clone(),
gateway: gateway.identity_key.clone(),
source: err,
})?;
// this can be an old node that hasn't yet exposed this
let auxiliary_details = client.get_auxiliary_details().await.inspect_err(|err| {
debug!("could not obtain auxiliary details of node {}: {err} is it running an old version?", data.identity_key());
debug!("could not obtain auxiliary details of gateway {}: {err} is it running an old version?", gateway.identity_key);
}).unwrap_or_default();
let websockets =
@@ -159,7 +156,7 @@ async fn try_get_description(
.get_mixnet_websockets()
.await
.map_err(|err| NodeDescribeCacheError::ApiFailure {
gateway: data.identity_key().clone(),
gateway: gateway.identity_key.clone(),
source: err,
})?;
@@ -167,7 +164,7 @@ async fn try_get_description(
if let Ok(nr) = client.get_network_requester().await {
let exit_policy = client.get_exit_policy().await.map_err(|err| {
NodeDescribeCacheError::ApiFailure {
gateway: data.identity_key().clone(),
gateway: gateway.identity_key.clone(),
source: err,
}
})?;
@@ -189,61 +186,17 @@ async fn try_get_description(
None
};
let authenticator = if let Ok(auth) = client.get_authenticator().await {
Some(AuthenticatorDetails {
address: auth.address,
})
} else {
None
};
let description = NymNodeDescription {
host_information: host_info.data.into(),
last_polled: OffsetDateTime::now_utc().into(),
build_information: build_info,
network_requester,
ip_packet_router,
authenticator,
mixnet_websockets: websockets.into(),
auxiliary_details,
role: data.role(),
};
Ok((data.identity_key().clone(), description))
}
struct RefreshData {
host: String,
identity_key: IdentityKey,
role: NodeRole,
port: Option<u16>,
}
impl RefreshData {
pub fn new(host: String, identity_key: IdentityKey, role: NodeRole, port: Option<u16>) -> Self {
RefreshData {
host,
identity_key,
role,
port,
}
}
pub fn host(&self) -> String {
self.host.clone()
}
pub fn identity_key(&self) -> IdentityKey {
self.identity_key.clone()
}
pub fn port(&self) -> Option<u16> {
self.port
}
pub fn role(&self) -> NodeRole {
self.role.clone()
}
Ok((gateway.identity_key, description))
}
#[async_trait]
@@ -256,56 +209,36 @@ impl CacheItemProvider for NodeDescriptionProvider {
}
async fn try_refresh(&self) -> Result<Self::Item, Self::Error> {
let mut host_id_pairs = self
.contract_cache
.gateways_all()
.await
.into_iter()
.map(|full| {
RefreshData::new(
full.gateway.host,
full.gateway.identity_key,
NodeRole::EntryGateway,
None,
)
})
.collect::<Vec<RefreshData>>();
let gateways = self.contract_cache.gateways_all().await;
host_id_pairs.extend(
self.contract_cache
.mixnodes_all()
.await
.into_iter()
.map(|full| {
RefreshData::new(
full.bond_information.mix_node.host,
full.bond_information.mix_node.identity_key,
NodeRole::Mixnode {
layer: full.bond_information.layer.into(),
},
Some(full.bond_information.mix_node.mix_port),
)
})
.collect::<Vec<RefreshData>>(),
);
// let guard = self.network_gateways.get().await?;
// let gateways = &*guard;
if host_id_pairs.is_empty() {
if gateways.is_empty() {
return Ok(HashMap::new());
}
let node_description = stream::iter(host_id_pairs.into_iter().map(try_get_description))
.buffer_unordered(self.batch_size)
.filter_map(|res| async move {
match res {
Ok((identity, description)) => Some((identity, description)),
Err(err) => {
debug!("failed to obtain gateway self-described data: {err}");
None
}
// TODO: somehow bypass the 'higher-ranked lifetime error' and remove that redundant clone
let node_description = stream::iter(
gateways
// .deref()
// .clone()
.into_iter()
.map(|bond| bond.gateway)
.map(get_gateway_description),
)
.buffer_unordered(self.batch_size)
.filter_map(|res| async move {
match res {
Ok((identity, description)) => Some((identity, description)),
Err(err) => {
debug!("failed to obtain gateway self-described data: {err}");
None
}
})
.collect::<HashMap<_, _>>()
.await;
}
})
.collect::<HashMap<_, _>>()
.await;
Ok(node_description)
}
+1 -1
View File
@@ -12,7 +12,7 @@ mod unstable_routes;
/// Merges the routes with http information and returns it to Rocket for serving
pub(crate) fn nym_node_routes(settings: &OpenApiSettings) -> (Vec<Route>, OpenApi) {
openapi_get_routes_spec![
settings: routes::get_gateways_described, routes::get_mixnodes_described
settings: routes::get_gateways_described
]
}
+1 -37
View File
@@ -4,8 +4,7 @@
use crate::node_describe_cache::DescribedNodes;
use crate::nym_contract_cache::cache::NymContractCache;
use crate::support::caching::cache::SharedCache;
use nym_api_requests::models::{DescribedGateway, DescribedMixNode};
use nym_mixnet_contract_common::MixNodeBond;
use nym_api_requests::models::DescribedGateway;
use rocket::serde::json::Json;
use rocket::State;
use rocket_okapi::openapi;
@@ -43,38 +42,3 @@ pub async fn get_gateways_described(
.collect(),
)
}
#[openapi(tag = "Nym Nodes")]
#[get("/mixnodes/described")]
pub async fn get_mixnodes_described(
contract_cache: &State<NymContractCache>,
describe_cache: &State<SharedCache<DescribedNodes>>,
) -> Json<Vec<DescribedMixNode>> {
let mixnodes = contract_cache
.mixnodes_filtered()
.await
.into_iter()
.map(|m| m.bond_information)
.collect::<Vec<MixNodeBond>>();
if mixnodes.is_empty() {
return Json(Vec::new());
}
// if the self describe cache is unavailable, well, don't attach describe data
let Ok(self_descriptions) = describe_cache.get().await else {
return Json(mixnodes.into_iter().map(Into::into).collect());
};
// TODO: this is extremely inefficient, but given we don't have many gateways,
// it shouldn't be too much of a problem until we go ahead with directory v3 / the smoosh 2: electric smoosharoo,
// but at that point (I hope) the whole caching situation should get refactored
Json(
mixnodes
.into_iter()
.map(|bond| DescribedMixNode {
self_described: self_descriptions.deref().get(bond.identity()).cloned(),
bond,
})
.collect(),
)
}
+1 -2
View File
@@ -3,7 +3,7 @@
[package]
name = "nym-node"
version = "1.1.4"
version = "1.1.3"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
@@ -55,7 +55,6 @@ nym-wireguard-types = { path = "../common/wireguard-types", default-features = f
# nodes:
nym-mixnode = { path = "../mixnode" }
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,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use crate::state::AppState;
use axum::Router;
use nym_node_requests::routes;
@@ -16,6 +17,9 @@ pub struct Config {
pub v1_config: v1::Config,
}
pub(super) fn routes(config: Config) -> Router<AppState> {
Router::new().nest(routes::api::V1, v1::routes(config.v1_config))
pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Router<AppState> {
Router::new().nest(
routes::api::V1,
v1::routes(config.v1_config, initial_wg_state),
)
}
@@ -1,23 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use axum::routing::get;
use axum::Router;
use nym_node_requests::api::v1::authenticator::models;
pub mod root;
#[derive(Debug, Clone, Default)]
pub struct Config {
pub details: Option<models::Authenticator>,
}
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
Router::new().route(
"/",
get({
let authenticator_details = config.details;
move |query| root::root_authenticator(authenticator_details, query)
}),
)
}
@@ -1,33 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::router::api::{FormattedResponse, OutputParams};
use axum::extract::Query;
use axum::http::StatusCode;
use nym_node_requests::api::v1::authenticator::models::Authenticator;
/// Returns root authenticator information
#[utoipa::path(
get,
path = "",
context_path = "/api/v1/authenticator",
tag = "Authenticator",
responses(
(status = 501, description = "the endpoint hasn't been implemented yet"),
(status = 200, content(
("application/json" = Authenticator),
("application/yaml" = Authenticator)
))
),
params(OutputParams)
)]
pub(crate) async fn root_authenticator(
details: Option<Authenticator>,
Query(output): Query<OutputParams>,
) -> Result<AuthenticatorResponse, StatusCode> {
let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?;
let output = output.output.unwrap_or_default();
Ok(output.to_response(details))
}
pub type AuthenticatorResponse = FormattedResponse<Authenticator>;
@@ -1,16 +1,20 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use crate::api::{FormattedResponse, OutputParams};
use axum::extract::Query;
use axum::http::StatusCode;
use axum::routing::get;
use axum::Router;
use nym_node_requests::api::v1::gateway::models::{ClientInterfaces, WebSockets};
use nym_node_requests::api::v1::gateway::models::{ClientInterfaces, WebSockets, Wireguard};
use nym_node_requests::routes::api::v1::gateway::client_interfaces;
pub(crate) mod wireguard;
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(
interfaces: Option<ClientInterfaces>,
initial_wg_state: WireguardAppState,
) -> Router<S> {
Router::new()
.route(
@@ -27,6 +31,17 @@ pub(crate) fn routes<S: Send + Sync + 'static + Clone>(
move |query| mixnet_websockets(websockets, query)
}),
)
.nest(
client_interfaces::WIREGUARD,
wireguard::routes(initial_wg_state),
)
.route(
client_interfaces::WIREGUARD,
get({
let wireguard_cfg_info = interfaces.and_then(|i| i.wireguard);
move |query| wireguard_info(wireguard_cfg_info, query)
}),
)
}
/// Returns client interfaces supported by this gateway.
@@ -55,6 +70,32 @@ pub(crate) async fn client_interfaces(
pub type ClientInterfacesResponse = FormattedResponse<ClientInterfaces>;
/// Returns client interfaces supported by this gateway.
#[utoipa::path(
get,
path = "/wireguard",
context_path = "/api/v1/gateway/client-interfaces",
tag = "Gateway",
responses(
(status = 501, description = "the endpoint hasn't been implemented yet"),
(status = 200, content(
("application/json" = Wireguard),
("application/yaml" = Wireguard)
))
),
params(OutputParams)
)]
pub(crate) async fn wireguard_info(
wireguard: Option<Wireguard>,
Query(output): Query<OutputParams>,
) -> Result<WireguardResponse, StatusCode> {
let wireguard = wireguard.ok_or(StatusCode::NOT_IMPLEMENTED)?;
let output = output.output.unwrap_or_default();
Ok(output.to_response(wireguard))
}
pub type WireguardResponse = FormattedResponse<Wireguard>;
/// Returns client interfaces supported by this gateway.
#[utoipa::path(
get,
@@ -0,0 +1,265 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use super::error::WireguardError;
use crate::api::v1::gateway::client_interfaces::wireguard::{
WireguardAppState, WireguardAppStateInner,
};
use crate::api::{FormattedResponse, OutputParams};
use crate::router::types::RequestError;
use axum::extract::{Path, Query, State};
use axum::http::StatusCode;
use axum::Json;
use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{
ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, PeerPublicKey,
};
use nym_wireguard_types::registration::RegistrationData;
use rand::{prelude::IteratorRandom, thread_rng};
fn remove_from_registry(
state: &WireguardAppStateInner,
remote_public: &PeerPublicKey,
gateway_client: &GatewayClient,
) -> Result<(), RequestError> {
state
.wireguard_gateway_data
.remove_peer(gateway_client)
.map_err(|err| RequestError::from_err(err, StatusCode::INTERNAL_SERVER_ERROR))?;
state
.wireguard_gateway_data
.client_registry()
.remove(remote_public);
Ok(())
}
async fn process_final_message(
client: GatewayClient,
state: &WireguardAppStateInner,
) -> Result<ClientRegistrationResponse, RequestError> {
let registration_data = state
.registration_in_progress
.get(&client.pub_key())
.ok_or(RequestError::from_err(
WireguardError::RegistrationNotInProgress,
StatusCode::BAD_REQUEST,
))?
.value()
.clone();
if client
.verify(
state.wireguard_gateway_data.keypair().private_key(),
registration_data.nonce,
)
.is_ok()
{
state
.wireguard_gateway_data
.add_peer(&client)
.map_err(|err| RequestError::from_err(err, StatusCode::INTERNAL_SERVER_ERROR))?;
state.registration_in_progress.remove(&client.pub_key());
state
.wireguard_gateway_data
.client_registry()
.insert(client.pub_key(), client);
Ok(ClientRegistrationResponse::Registered)
} else {
Err(RequestError::from_err(
WireguardError::MacVerificationFailure,
StatusCode::BAD_REQUEST,
))
}
}
async fn process_init_message(
init_message: InitMessage,
state: &WireguardAppStateInner,
) -> Result<ClientRegistrationResponse, RequestError> {
let remote_public = init_message.pub_key();
let nonce: u64 = fastrand::u64(..);
if let Some(registration_data) = state.registration_in_progress.get(&remote_public) {
return Ok(ClientRegistrationResponse::PendingRegistration(
registration_data.value().clone(),
));
}
let gateway_client_opt = if let Some(gateway_client) = state
.wireguard_gateway_data
.client_registry()
.get(&remote_public)
{
let mut private_ip_ref = state
.free_private_network_ips
.get_mut(&gateway_client.private_ip)
.ok_or(RequestError::new(
"Internal data corruption",
StatusCode::INTERNAL_SERVER_ERROR,
))?;
*private_ip_ref = true;
Some(gateway_client.clone())
} else {
None
};
if let Some(gateway_client) = gateway_client_opt {
remove_from_registry(state, &remote_public, &gateway_client)?;
}
let mut private_ip_ref = state
.free_private_network_ips
.iter_mut()
.filter(|r| **r)
.choose(&mut thread_rng())
.ok_or(RequestError::new(
"No more space in the network",
StatusCode::SERVICE_UNAVAILABLE,
))?;
// mark it as used, even though it's not final
*private_ip_ref = false;
let gateway_data = GatewayClient::new(
state.wireguard_gateway_data.keypair().private_key(),
remote_public.inner(),
*private_ip_ref.key(),
nonce,
);
let registration_data = RegistrationData {
nonce,
gateway_data,
wg_port: state.binding_port,
};
state
.registration_in_progress
.insert(remote_public, registration_data.clone());
Ok(ClientRegistrationResponse::PendingRegistration(
registration_data,
))
}
/// Perform wireguard client registration.
#[utoipa::path(
post,
path = "/client",
context_path = "/api/v1/gateway/client-interfaces/wireguard",
tag = "Wireguard (EXPERIMENTAL AND UNSTABLE)",
request_body(
content = ClientMessage,
description = "Data used for proceeding with client wireguard registration",
content_type = "application/json"
),
responses(
(status = 501, body = ErrorResponse, description = "the endpoint hasn't been implemented yet"),
(status = 400, body = ErrorResponse),
(status = 200, content(
("application/json" = ClientRegistrationResponse),
("application/yaml" = ClientRegistrationResponse)
))
),
params(OutputParams)
)]
pub(crate) async fn register_client(
State(state): State<WireguardAppState>,
Query(output): Query<OutputParams>,
Json(payload): Json<ClientMessage>,
) -> Result<RegisterClientResponse, RequestError> {
let output = output.output.unwrap_or_default();
let Some(state) = state.inner() else {
return Err(RequestError::new_status(StatusCode::NOT_IMPLEMENTED));
};
let response = match payload {
ClientMessage::Initial(init) => process_init_message(init, state).await?,
ClientMessage::Final(finalize) => process_final_message(finalize, state).await?,
};
Ok(output.to_response(response))
}
pub type RegisterClientResponse = FormattedResponse<ClientRegistrationResponse>;
/// Get public keys of all registered wireguard clients.
#[utoipa::path(
get,
path = "/clients",
context_path = "/api/v1/gateway/client-interfaces/wireguard",
tag = "Wireguard (EXPERIMENTAL AND UNSTABLE)",
responses(
(status = 501, body = ErrorResponse, description = "the endpoint hasn't been implemented yet"),
(status = 200, content(
("application/json" = Vec<String>),
("application/yaml" = Vec<String>)
))
),
params(OutputParams)
)]
pub(crate) async fn get_all_clients(
Query(output): Query<OutputParams>,
State(state): State<WireguardAppState>,
) -> Result<AllClientsResponse, RequestError> {
let output = output.output.unwrap_or_default();
let Some(state) = state.inner() else {
return Err(RequestError::new_status(StatusCode::NOT_IMPLEMENTED));
};
let clients = state
.wireguard_gateway_data
.client_registry()
.iter()
.map(|c| c.pub_key())
.collect::<Vec<PeerPublicKey>>();
Ok(output.to_response(clients))
}
pub type AllClientsResponse = FormattedResponse<Vec<PeerPublicKey>>;
/// Get client details of the registered wireguard client by its public key.
#[utoipa::path(
get,
path = "/client/{pub_key}",
context_path = "/api/v1/gateway/client-interfaces/wireguard",
tag = "Wireguard (EXPERIMENTAL AND UNSTABLE)",
params(
("pub_key", Path, description = "The public key of the client"),
OutputParams
),
responses(
(status = 501, body = ErrorResponse, description = "the endpoint hasn't been implemented yet"),
(status = 404, body = ErrorResponse, description = "there are no clients with the provided public key"),
(status = 400, body = ErrorResponse),
(status = 200, content(
("application/json" = Vec<GatewayClient>),
("application/yaml" = Vec<GatewayClient>)
))
),
)]
pub(crate) async fn get_client(
Path(pub_key): Path<PeerPublicKey>,
Query(output): Query<OutputParams>,
State(state): State<WireguardAppState>,
) -> Result<ClientResponse, RequestError> {
let output = output.output.unwrap_or_default();
let Some(state) = state.inner() else {
return Err(RequestError::new_status(StatusCode::NOT_IMPLEMENTED));
};
let clients = state
.wireguard_gateway_data
.client_registry()
.iter()
.filter_map(|c| {
if c.pub_key() == pub_key {
Some(c.clone())
} else {
None
}
})
.collect::<Vec<GatewayClient>>();
if clients.is_empty() {
return Err(RequestError::new_status(StatusCode::NOT_FOUND));
}
Ok(output.to_response(clients))
}
pub type ClientResponse = FormattedResponse<Vec<GatewayClient>>;
@@ -0,0 +1,13 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use thiserror::Error;
#[derive(Debug, Error)]
pub enum WireguardError {
#[error("the client is currently not in the process of being registered")]
RegistrationNotInProgress,
#[error("the client mac failed to get verified correctly")]
MacVerificationFailure,
}
@@ -0,0 +1,296 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::api::v1::gateway::client_interfaces::wireguard::client_registry::{
get_all_clients, get_client, register_client,
};
use crate::error::NymNodeHttpError;
use axum::routing::{get, post};
use axum::Router;
use ipnetwork::IpNetwork;
use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard;
use nym_wireguard::WireguardGatewayData;
use nym_wireguard_types::registration::PendingRegistrations;
use nym_wireguard_types::registration::PrivateIPs;
use std::sync::Arc;
pub(crate) mod client_registry;
mod error;
// I don't see any reason why this state should be accessible to any routes outside /wireguard
// if anyone finds compelling reason, it could be moved to the `AppState` struct instead
#[derive(Clone, Default)]
pub struct WireguardAppState {
inner: Option<WireguardAppStateInner>,
}
impl WireguardAppState {
pub fn new(
wireguard_gateway_data: WireguardGatewayData,
registration_in_progress: Arc<PendingRegistrations>,
binding_port: u16,
private_ip_network: IpNetwork,
) -> Result<Self, NymNodeHttpError> {
Ok(WireguardAppState {
inner: Some(WireguardAppStateInner {
wireguard_gateway_data,
registration_in_progress,
binding_port,
free_private_network_ips: Arc::new(
private_ip_network.iter().map(|ip| (ip, true)).collect(),
),
}),
})
}
// #[allow(dead_code)]
// pub(crate) fn dh_keypair(&self) -> Option<&encryption::KeyPair> {
// self.inner.as_ref().map(|s| s.dh_keypair.as_ref())
// }
//
// #[allow(dead_code)]
// pub(crate) fn client_registry(&self) -> Option<&RwLock<ClientRegistry>> {
// self.inner.as_ref().map(|s| s.client_registry.as_ref())
// }
//
// #[allow(dead_code)]
// pub(crate) fn registration_in_progress(&self) -> Option<&RwLock<PendingRegistrations>> {
// self.inner
// .as_ref()
// .map(|s| s.registration_in_progress.as_ref())
// }
// not sure what to feel about exposing this method
pub(crate) fn inner(&self) -> Option<&WireguardAppStateInner> {
self.inner.as_ref()
}
}
// helper macro to deal with missing wg state (if not being exposed by the node)
#[macro_export]
macro_rules! get_state {
( $state: ident, $field: ident ) => {{
let Some(ref inner) = $state.inner else {
return ::axum::http::StatusCode::NOT_IMPLEMENTED;
};
inner.$field.as_ref()
}};
}
#[derive(Clone)]
pub(crate) struct WireguardAppStateInner {
wireguard_gateway_data: WireguardGatewayData,
registration_in_progress: Arc<PendingRegistrations>,
binding_port: u16,
free_private_network_ips: Arc<PrivateIPs>,
}
pub(crate) fn routes<S>(initial_state: WireguardAppState) -> Router<S> {
Router::new()
// .route("/", get())
.route(wireguard::CLIENTS, get(get_all_clients))
.route(wireguard::CLIENT, post(register_client))
.route(&format!("{}/:pub_key", wireguard::CLIENT), get(get_client))
.with_state(initial_state)
}
#[cfg(test)]
mod test {
use crate::api::v1::gateway::client_interfaces::wireguard::{
routes, WireguardAppState, WireguardAppStateInner,
};
use axum::body::to_bytes;
use axum::body::Body;
use axum::http::Request;
use axum::http::StatusCode;
use base64::{engine::general_purpose, Engine as _};
use dashmap::DashMap;
use hmac::Mac;
use ipnetwork::IpNetwork;
use nym_crypto::asymmetric::encryption;
use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{
ClientMac, ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage,
PeerPublicKey,
};
use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard;
use nym_wireguard::{peer_controller::PeerControlMessage, WireguardGatewayData};
use nym_wireguard_types::registration::{HmacSha256, RegistrationData};
use std::net::IpAddr;
use std::str::FromStr;
use std::sync::Arc;
use tower::Service;
use tower::ServiceExt;
use x25519_dalek::{PublicKey, StaticSecret};
const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
fn decode_base64_key(base64_key: &str) -> [u8; 32] {
general_purpose::STANDARD
.decode(base64_key)
.unwrap()
.try_into()
.unwrap()
}
fn server_static_private_key() -> x25519_dalek::StaticSecret {
// TODO: this is a temporary solution for development
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY);
x25519_dalek::StaticSecret::from(static_private_bytes)
}
#[tokio::test]
async fn registration() {
// 1. Provision random keys for gateway and client
// 2. Generate DH shared secret
// 3. Client submits its public key to the gateway to start the handshake process, gateway responds with nonce
// 4. Client generates mac digest using DH shared secret, its own public key, socket address and port, and nonce
// 5. Client sends its public key, socket address and port, nonce and mac digest to the gateway
// 6. Gateway verifies mac digest and nonce, and stores client's public key and socket address and port
let mut rng = rand::thread_rng();
let gateway_private_key =
encryption::PrivateKey::from_bytes(server_static_private_key().as_bytes()).unwrap();
let gateway_public_key = encryption::PublicKey::from(&gateway_private_key);
let gateway_key_pair = encryption::KeyPair::from_bytes(
&gateway_private_key.to_bytes(),
&gateway_public_key.to_bytes(),
)
.unwrap();
let client_key_pair = encryption::KeyPair::new(&mut rng);
let gateway_static_public = PublicKey::from(gateway_key_pair.public_key().to_bytes());
let client_static_private = StaticSecret::from(client_key_pair.private_key().to_bytes());
let client_static_public = PublicKey::from(client_key_pair.public_key().to_bytes());
let client_dh = client_static_private.diffie_hellman(&gateway_static_public);
let registration_in_progress = Arc::new(DashMap::new());
let free_private_network_ips = Arc::new(
IpNetwork::from_str("10.1.0.0/24")
.unwrap()
.iter()
.map(|ip| (ip, true))
.collect(),
);
let client_private_ip = IpAddr::from_str("10.1.0.42").unwrap();
let (wireguard_gateway_data, mut peer_rx) = WireguardGatewayData::new(
nym_wireguard_types::Config {
bind_address: "0.0.0.0:51822".parse().unwrap(),
private_ip: "10.1.0.1".parse().unwrap(),
announced_port: 51822,
private_network_prefix: 16,
},
Arc::new(gateway_key_pair),
);
let state = WireguardAppState {
inner: Some(WireguardAppStateInner {
wireguard_gateway_data: wireguard_gateway_data.clone(),
registration_in_progress: Arc::clone(&registration_in_progress),
binding_port: 8080,
free_private_network_ips,
}),
};
// `Router` implements `tower::Service<Request<Body>>` so we can
// call it like any tower service, no need to run an HTTP server.
let mut app = routes(state);
let init_message = ClientMessage::Initial(InitMessage {
pub_key: PeerPublicKey::new(client_static_public),
});
let init_request = Request::builder()
.method("POST")
.uri(wireguard::CLIENT)
.header("Content-type", "application/json")
.body(Body::from(serde_json::to_vec(&init_message).unwrap()))
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(init_request)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
assert!(!registration_in_progress.is_empty());
let ClientRegistrationResponse::PendingRegistration(RegistrationData {
nonce,
gateway_data,
wg_port: 8080,
}) = serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
.unwrap()
else {
panic!("invalid response")
};
assert!(gateway_data
.verify(client_key_pair.private_key(), nonce)
.is_ok());
let mut mac = HmacSha256::new_from_slice(client_dh.as_bytes()).unwrap();
mac.update(client_static_public.as_bytes());
mac.update(client_private_ip.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
let mac = mac.finalize().into_bytes();
let finalized_message = ClientMessage::Final(GatewayClient {
pub_key: PeerPublicKey::new(client_static_public),
private_ip: client_private_ip,
mac: ClientMac::new(mac.as_slice().to_vec()),
});
let final_request = Request::builder()
.method("POST")
.uri(wireguard::CLIENT)
.header("Content-type", "application/json")
.body(Body::from(serde_json::to_vec(&finalized_message).unwrap()))
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(final_request)
.await
.unwrap();
let msg = peer_rx.recv().await.unwrap();
assert!(matches!(msg, PeerControlMessage::AddPeer(_)));
assert_eq!(response.status(), StatusCode::OK);
assert!(!wireguard_gateway_data.client_registry().is_empty());
let clients_request = Request::builder()
.method("GET")
.uri(wireguard::CLIENTS)
.body(Body::empty())
.unwrap();
let response = ServiceExt::<Request<Body>>::ready(&mut app)
.await
.unwrap()
.call(clients_request)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
let clients: Vec<PeerPublicKey> =
serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
.unwrap();
assert!(!clients.is_empty());
assert_eq!(
wireguard_gateway_data
.client_registry()
.iter()
.map(|c| c.value().pub_key())
.collect::<Vec<PeerPublicKey>>(),
clients
)
}
}
@@ -1,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use axum::routing::get;
use axum::Router;
use nym_node_requests::api::v1::gateway::models;
@@ -14,7 +15,10 @@ pub struct Config {
pub details: Option<models::Gateway>,
}
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router<S> {
pub(crate) fn routes<S: Send + Sync + 'static + Clone>(
config: Config,
initial_wg_state: WireguardAppState,
) -> Router<S> {
Router::new()
.route(
"/",
@@ -25,6 +29,9 @@ pub(crate) fn routes<S: Send + Sync + 'static + Clone>(config: Config) -> Router
)
.nest(
gateway::CLIENT_INTERFACES,
client_interfaces::routes(config.details.map(|g| g.client_interfaces)),
client_interfaces::routes(
config.details.map(|g| g.client_interfaces),
initial_wg_state,
),
)
}
@@ -1,12 +1,12 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use crate::state::AppState;
use axum::routing::get;
use axum::Router;
use nym_node_requests::routes::api::v1;
pub mod authenticator;
pub mod gateway;
pub mod health;
pub mod ip_packet_router;
@@ -24,14 +24,16 @@ pub struct Config {
pub mixnode: mixnode::Config,
pub network_requester: network_requester::Config,
pub ip_packet_router: ip_packet_router::Config,
pub authenticator: authenticator::Config,
}
pub(super) fn routes(config: Config) -> Router<AppState> {
pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Router<AppState> {
Router::new()
.route(v1::HEALTH, get(health::root_health))
.nest(v1::METRICS, metrics::routes(config.metrics))
.nest(v1::GATEWAY, gateway::routes(config.gateway))
.nest(
v1::GATEWAY,
gateway::routes(config.gateway, initial_wg_state),
)
.nest(v1::MIXNODE, mixnode::routes(config.mixnode))
.nest(
v1::NETWORK_REQUESTER,
@@ -41,10 +43,6 @@ pub(super) fn routes(config: Config) -> Router<AppState> {
v1::IP_PACKET_ROUTER,
ip_packet_router::routes(config.ip_packet_router),
)
.nest(
v1::AUTHENTICATOR,
authenticator::routes(config.authenticator),
)
.merge(node::routes(config.node))
.merge(openapi::route())
}
@@ -26,7 +26,11 @@ use utoipa_swagger_ui::SwaggerUi;
api::v1::health::root_health,
api::v1::gateway::root::root_gateway,
api::v1::gateway::client_interfaces::client_interfaces,
api::v1::gateway::client_interfaces::wireguard_info,
api::v1::gateway::client_interfaces::mixnet_websockets,
api::v1::gateway::client_interfaces::wireguard::client_registry::register_client,
api::v1::gateway::client_interfaces::wireguard::client_registry::get_all_clients,
api::v1::gateway::client_interfaces::wireguard::client_registry::get_client,
api::v1::mixnode::root::root_mixnode,
api::v1::network_requester::root::root_network_requester,
api::v1::network_requester::exit_policy::node_exit_policy,
@@ -63,6 +67,7 @@ use utoipa_swagger_ui::SwaggerUi;
api_requests::v1::gateway::client_interfaces::wireguard::models::ClientMessage,
api_requests::v1::gateway::client_interfaces::wireguard::models::InitMessage,
api_requests::v1::gateway::client_interfaces::wireguard::models::GatewayClient,
api_requests::v1::gateway::client_interfaces::wireguard::models::ClientRegistrationResponse,
api_requests::v1::mixnode::models::Mixnode,
api_requests::v1::network_requester::models::NetworkRequester,
api_requests::v1::network_requester::exit_policy::models::AddressPolicy,
+10 -10
View File
@@ -1,6 +1,7 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub use crate::api::v1::gateway::client_interfaces::wireguard::WireguardAppState;
use crate::error::NymNodeHttpError;
use crate::middleware::logging;
use crate::state::AppState;
@@ -8,7 +9,6 @@ use crate::NymNodeHTTPServer;
use axum::response::Redirect;
use axum::routing::get;
use axum::Router;
use nym_node_requests::api::v1::authenticator::models::Authenticator;
use nym_node_requests::api::v1::gateway::models::{Gateway, Wireguard};
use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter;
use nym_node_requests::api::v1::mixnode::models::Mixnode;
@@ -54,7 +54,6 @@ impl Config {
mixnode: Default::default(),
network_requester: Default::default(),
ip_packet_router: Default::default(),
authenticator: Default::default(),
},
},
}
@@ -149,12 +148,6 @@ impl Config {
self.api.v1_config.ip_packet_router.details = Some(ip_packet_router);
self
}
#[must_use]
pub fn with_authenticator_details(mut self, authenticator: Authenticator) -> Self {
self.api.v1_config.authenticator.details = Some(authenticator);
self
}
}
pub struct NymNodeRouter {
@@ -163,7 +156,11 @@ pub struct NymNodeRouter {
impl NymNodeRouter {
// TODO: move the wg state to a builder
pub fn new(config: Config, app_state: Option<AppState>) -> NymNodeRouter {
pub fn new(
config: Config,
app_state: Option<AppState>,
initial_wg_state: Option<WireguardAppState>,
) -> NymNodeRouter {
let state = app_state.unwrap_or(AppState::new());
NymNodeRouter {
@@ -192,7 +189,10 @@ impl NymNodeRouter {
}),
)
.nest(routes::LANDING_PAGE, landing_page::routes(config.landing))
.nest(routes::API, api::routes(config.api))
.nest(
routes::API,
api::routes(config.api, initial_wg_state.unwrap_or_default()),
)
.layer(axum::middleware::from_fn(logging::logger))
.with_state(state),
}
@@ -24,6 +24,19 @@ impl RequestError {
status,
}
}
pub(crate) fn new_status(status: StatusCode) -> Self {
RequestError {
inner: ErrorResponse {
message: String::new(),
},
status,
}
}
pub(crate) fn from_err<E: std::error::Error>(err: E, status: StatusCode) -> Self {
Self::new(err.to_string(), status)
}
}
impl IntoResponse for RequestError {
+10 -4
View File
@@ -8,8 +8,8 @@ use crate::routes;
use async_trait::async_trait;
use nym_bin_common::build_information::BinaryBuildInformationOwned;
use nym_http_api_client::{ApiClient, HttpClientError};
use nym_wireguard_types::{ClientMessage, ClientRegistrationResponse};
use crate::api::v1::authenticator::models::Authenticator;
use crate::api::v1::health::models::NodeHealth;
use crate::api::v1::ip_packet_router::models::IpPacketRouter;
use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy;
@@ -65,9 +65,15 @@ pub trait NymNodeApiClientExt: ApiClient {
.await
}
async fn get_authenticator(&self) -> Result<Authenticator, NymNodeApiClientError> {
self.get_json_from(routes::api::v1::authenticator_absolute())
.await
async fn post_gateway_register_client(
&self,
client_message: &ClientMessage,
) -> Result<ClientRegistrationResponse, NymNodeApiClientError> {
self.post_json_data_to(
routes::api::v1::gateway::client_interfaces::wireguard::client_absolute(),
client_message,
)
.await
}
}
@@ -1,4 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod models;
@@ -1,18 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct Authenticator {
/// Base58 encoded ed25519 EdDSA public key of the authenticator.
pub encoded_identity_key: String,
/// Base58-encoded x25519 public key used for performing key exchange with remote clients.
pub encoded_x25519_key: String,
/// Nym address of this ip packet router.
pub address: String,
}
@@ -2,5 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
pub use nym_wireguard_types::{
ClientMac, ClientMessage, GatewayClient, InitMessage, Nonce, PeerPublicKey,
ClientMac, ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, Nonce,
PeerPublicKey,
};
@@ -1,7 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod authenticator;
pub mod gateway;
pub mod health;
pub mod ip_packet_router;
-2
View File
@@ -42,7 +42,6 @@ pub mod routes {
pub const METRICS: &str = "/metrics";
pub const NETWORK_REQUESTER: &str = "/network-requester";
pub const IP_PACKET_ROUTER: &str = "/ip-packet-router";
pub const AUTHENTICATOR: &str = "/authenticator";
// define helper functions to get absolute routes
absolute_route!(health_absolute, v1_absolute(), HEALTH);
@@ -58,7 +57,6 @@ pub mod routes {
absolute_route!(metrics_absolute, v1_absolute(), METRICS);
absolute_route!(network_requester_absolute, v1_absolute(), NETWORK_REQUESTER);
absolute_route!(ip_packet_router_absolute, v1_absolute(), IP_PACKET_ROUTER);
absolute_route!(authenticator_absolute, v1_absolute(), AUTHENTICATOR);
absolute_route!(swagger_absolute, v1_absolute(), SWAGGER);
pub mod metrics {
-6
View File
@@ -409,9 +409,6 @@ async fn migrate_gateway(mut args: Args) -> Result<(), NymNodeError> {
bind_address: SocketAddr::new(ip, cfg.gateway.clients_port),
announce_ws_port: None,
announce_wss_port: cfg.gateway.clients_wss_port,
authenticator: config::authenticator::Authenticator {
debug: Default::default(),
},
debug: config::entry_gateway::Debug {
message_retrieval_limit: cfg.debug.message_retrieval_limit,
},
@@ -457,9 +454,6 @@ async fn migrate_gateway(mut args: Args) -> Result<(), NymNodeError> {
.unwrap_or_default(),
},
},
authenticator: config::authenticator::Authenticator {
debug: Default::default(),
},
}),
)
.build();
-48
View File
@@ -1,48 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct Authenticator {
#[serde(default)]
pub debug: AuthenticatorDebug,
}
#[allow(clippy::derivable_impls)]
impl Default for Authenticator {
fn default() -> Self {
Authenticator {
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct AuthenticatorDebug {
/// Specifies whether authenticator service is enabled in this process.
/// This is only here for debugging purposes as exit gateway should always run
/// the authenticator.
pub enabled: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting client_debug.traffic.disable_main_poisson_packet_distribution = true
/// (or is it (?))
pub disable_poisson_rate: bool,
/// Shared detailed client configuration options
#[serde(flatten)]
pub client_debug: ClientDebugConfig,
}
impl Default for AuthenticatorDebug {
fn default() -> Self {
AuthenticatorDebug {
enabled: true,
disable_poisson_rate: true,
client_debug: Default::default(),
}
}
}
-5
View File
@@ -12,8 +12,6 @@ use serde::{Deserialize, Serialize};
use std::net::SocketAddr;
use std::path::Path;
use super::authenticator::Authenticator;
pub const DEFAULT_WS_PORT: u16 = DEFAULT_CLIENT_LISTENING_PORT;
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -40,8 +38,6 @@ pub struct EntryGatewayConfig {
#[serde(deserialize_with = "de_maybe_port")]
pub announce_wss_port: Option<u16>,
pub authenticator: Authenticator,
#[serde(default)]
pub debug: Debug,
}
@@ -73,7 +69,6 @@ impl EntryGatewayConfig {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_WS_PORT),
announce_ws_port: None,
announce_wss_port: None,
authenticator: Default::default(),
debug: Default::default(),
}
}
+2 -29
View File
@@ -8,14 +8,12 @@ use crate::error::ExitGatewayError;
use clap::crate_version;
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
use nym_config::defaults::mainnet;
use nym_gateway::node::{
LocalAuthenticatorOpts, LocalIpPacketRouterOpts, LocalNetworkRequesterOpts,
};
use nym_gateway::node::{LocalIpPacketRouterOpts, LocalNetworkRequesterOpts};
use serde::{Deserialize, Serialize};
use std::path::Path;
use url::Url;
use super::{authenticator::Authenticator, LocalWireguardOpts};
use super::LocalWireguardOpts;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
@@ -32,8 +30,6 @@ pub struct ExitGatewayConfig {
pub network_requester: NetworkRequester,
pub ip_packet_router: IpPacketRouter,
pub authenticator: Authenticator,
}
impl ExitGatewayConfig {
@@ -49,7 +45,6 @@ impl ExitGatewayConfig {
.expect("invalid default exit policy URL"),
network_requester: Default::default(),
ip_packet_router: Default::default(),
authenticator: Default::default(),
}
}
}
@@ -143,7 +138,6 @@ pub struct EphemeralConfig {
pub gateway: nym_gateway::config::Config,
pub nr_opts: LocalNetworkRequesterOpts,
pub ipr_opts: LocalIpPacketRouterOpts,
pub auth_opts: LocalAuthenticatorOpts,
pub wg_opts: LocalWireguardOpts,
}
@@ -240,26 +234,6 @@ pub fn ephemeral_exit_gateway_config(
ipr_opts.config.base.set_no_poisson_process()
}
let auth_opts = LocalAuthenticatorOpts {
config: nym_authenticator::Config {
base: nym_client_core_config_types::Config {
client: base_client_config(&config),
debug: config.exit_gateway.authenticator.debug.client_debug,
},
authenticator: config.wireguard.clone().into(),
storage_paths: nym_authenticator::config::AuthenticatorPaths {
common_paths: config
.exit_gateway
.storage_paths
.authenticator
.to_common_client_paths(),
authenticator_description: Default::default(),
},
logging: config.logging,
},
custom_mixnet_path: None,
};
let pub_id_path = config
.storage_paths
.keys
@@ -292,7 +266,6 @@ pub fn ephemeral_exit_gateway_config(
Ok(EphemeralConfig {
nr_opts,
ipr_opts,
auth_opts,
wg_opts,
gateway,
})
-13
View File
@@ -25,12 +25,10 @@ use std::time::Duration;
use tracing::{debug, error};
use url::Url;
pub mod authenticator;
pub mod entry_gateway;
pub mod exit_gateway;
pub mod helpers;
pub mod mixnode;
mod old_configs;
pub mod persistence;
mod template;
pub mod upgrade_helpers;
@@ -545,17 +543,6 @@ impl From<Wireguard> for nym_wireguard_types::Config {
}
}
impl From<Wireguard> for nym_authenticator::config::Authenticator {
fn from(value: Wireguard) -> Self {
nym_authenticator::config::Authenticator {
bind_address: value.bind_address,
private_ip: value.private_ip,
announced_port: value.announced_port,
private_network_prefix: value.private_network_prefix,
}
}
}
#[derive(Debug, Clone)]
pub struct LocalWireguardOpts {
pub config: Wireguard,
-8
View File
@@ -1,8 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
mod old_config_1_1_2;
mod old_config_1_1_3;
pub use old_config_1_1_2::try_upgrade_config_1_1_2;
pub use old_config_1_1_3::try_upgrade_config_1_1_3;
@@ -1,978 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
#![allow(dead_code)]
use crate::config::*;
use crate::error::KeyIOFailure;
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
use nym_config::serde_helpers::de_maybe_port;
use nym_crypto::asymmetric::encryption::KeyPair;
use nym_pemstore::store_keypair;
use old_configs::old_config_1_1_3::*;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WireguardPaths1_1_2 {
pub private_diffie_hellman_key_file: PathBuf,
pub public_diffie_hellman_key_file: PathBuf,
}
impl WireguardPaths1_1_2 {
pub fn new<P: AsRef<Path>>(data_dir: P) -> Self {
let data_dir = data_dir.as_ref();
WireguardPaths1_1_2 {
private_diffie_hellman_key_file: data_dir
.join(persistence::DEFAULT_X25519_WG_DH_KEY_FILENAME),
public_diffie_hellman_key_file: data_dir
.join(persistence::DEFAULT_X25519_WG_PUBLIC_DH_KEY_FILENAME),
}
}
pub fn x25519_wireguard_storage_paths(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(
&self.private_diffie_hellman_key_file,
&self.public_diffie_hellman_key_file,
)
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Wireguard1_1_2 {
/// Specifies whether the wireguard service is enabled on this node.
pub enabled: bool,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51822`
pub bind_address: SocketAddr,
/// Ip address of the private wireguard network.
/// default: `10.1.0.0`
pub private_network_ip: IpAddr,
/// 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.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// Paths for wireguard keys, client registries, etc.
pub storage_paths: WireguardPaths1_1_2,
}
// a temporary solution until all "types" are run at the same time
#[derive(Debug, Default, Serialize, Deserialize, ValueEnum, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum NodeMode1_1_2 {
#[default]
#[clap(alias = "mix")]
Mixnode,
#[clap(alias = "entry", alias = "gateway")]
EntryGateway,
#[clap(alias = "exit")]
ExitGateway,
}
impl From<NodeMode1_1_2> for NodeMode1_1_3 {
fn from(config: NodeMode1_1_2) -> Self {
match config {
NodeMode1_1_2::Mixnode => NodeMode1_1_3::Mixnode,
NodeMode1_1_2::EntryGateway => NodeMode1_1_3::EntryGateway,
NodeMode1_1_2::ExitGateway => NodeMode1_1_3::ExitGateway,
}
}
}
// TODO: this is very much a WIP. we need proper ssl certificate support here
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Host1_1_2 {
/// Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections.
/// If no values are provided, when this node gets included in the network,
/// its ip addresses will be populated by whatever value is resolved by associated nym-api.
pub public_ips: Vec<IpAddr>,
/// Optional hostname of this node, for example nymtech.net.
// TODO: this is temporary. to be replaced by pulling the data directly from the certs.
#[serde(deserialize_with = "de_maybe_stringified")]
pub hostname: Option<String>,
/// Optional ISO 3166 alpha-2 two-letter country code of the node's **physical** location
#[serde(deserialize_with = "de_maybe_stringified")]
pub location: Option<Country>,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct MixnetDebug1_1_2 {
/// Initial value of an exponential backoff to reconnect to dropped TCP connection when
/// forwarding sphinx packets.
#[serde(with = "humantime_serde")]
pub packet_forwarding_initial_backoff: Duration,
/// Maximum value of an exponential backoff to reconnect to dropped TCP connection when
/// forwarding sphinx packets.
#[serde(with = "humantime_serde")]
pub packet_forwarding_maximum_backoff: Duration,
/// Timeout for establishing initial connection when trying to forward a sphinx packet.
#[serde(with = "humantime_serde")]
pub initial_connection_timeout: Duration,
/// Maximum number of packets that can be stored waiting to get sent to a particular connection.
pub maximum_connection_buffer_size: usize,
/// Specifies whether this node should **NOT** use noise protocol in the connections (currently not implemented)
pub unsafe_disable_noise: bool,
}
impl MixnetDebug1_1_2 {
const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000);
const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000);
const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500);
const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000;
}
impl Default for MixnetDebug1_1_2 {
fn default() -> Self {
MixnetDebug1_1_2 {
packet_forwarding_initial_backoff: Self::DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF,
packet_forwarding_maximum_backoff: Self::DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF,
initial_connection_timeout: Self::DEFAULT_INITIAL_CONNECTION_TIMEOUT,
maximum_connection_buffer_size: Self::DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE,
// to be changed by @SW once the implementation is there
unsafe_disable_noise: true,
}
}
}
impl Default for Mixnet1_1_2 {
fn default() -> Self {
// SAFETY:
// our hardcoded values should always be valid
#[allow(clippy::expect_used)]
// is if there's anything set in the environment, otherwise fallback to mainnet
let nym_api_urls = if let Ok(env_value) = env::var(var_names::NYM_API) {
parse_urls(&env_value)
} else {
vec![mainnet::NYM_API.parse().expect("Invalid default API URL")]
};
#[allow(clippy::expect_used)]
let nyxd_urls = if let Ok(env_value) = env::var(var_names::NYXD) {
parse_urls(&env_value)
} else {
vec![mainnet::NYXD_URL.parse().expect("Invalid default nyxd URL")]
};
Mixnet1_1_2 {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT),
nym_api_urls,
nyxd_urls,
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Mixnet1_1_2 {
/// Address this node will bind to for listening for mixnet packets
/// default: `0.0.0.0:1789`
pub bind_address: SocketAddr,
/// Addresses to nym APIs from which the node gets the view of the network.
pub nym_api_urls: Vec<Url>,
/// Addresses to nyxd which the node uses to interact with the nyx chain.
pub nyxd_urls: Vec<Url>,
#[serde(default)]
pub debug: MixnetDebug1_1_2,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct KeysPaths1_1_2 {
/// Path to file containing ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing x25519 sphinx private key.
pub private_x25519_sphinx_key_file: PathBuf,
/// Path to file containing x25519 sphinx public key.
pub public_x25519_sphinx_key_file: PathBuf,
/// Path to file containing x25519 noise private key.
pub private_x25519_noise_key_file: PathBuf,
/// Path to file containing x25519 noise public key.
pub public_x25519_noise_key_file: PathBuf,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NymNodePaths1_1_2 {
pub keys: KeysPaths1_1_2,
/// Path to a file containing basic node description: human-readable name, website, details, etc.
pub description: PathBuf,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Http1_1_2 {
/// Socket address this node will use for binding its http API.
/// default: `0.0.0.0:8080`
pub bind_address: SocketAddr,
/// Path to assets directory of custom landing page of this node.
#[serde(deserialize_with = "de_maybe_stringified")]
pub landing_page_assets_path: Option<PathBuf>,
/// An optional bearer token for accessing certain http endpoints.
/// Currently only used for obtaining mixnode's stats.
#[serde(default)]
pub access_token: Option<String>,
/// Specify whether basic system information should be exposed.
/// default: true
pub expose_system_info: bool,
/// Specify whether basic system hardware information should be exposed.
/// This option is superseded by `expose_system_info`
/// default: true
pub expose_system_hardware: bool,
/// Specify whether detailed system crypto hardware information should be exposed.
/// This option is superseded by `expose_system_hardware`
/// default: true
pub expose_crypto_hardware: bool,
}
impl Default for Http1_1_2 {
fn default() -> Self {
Http1_1_2 {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT),
landing_page_assets_path: None,
access_token: None,
expose_system_info: true,
expose_system_hardware: true,
expose_crypto_hardware: true,
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MixnodePaths1_1_2 {}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Debug1_1_2 {
/// Delay between each subsequent node statistics being logged to the console
#[serde(with = "humantime_serde")]
pub node_stats_logging_delay: Duration,
/// Delay between each subsequent node statistics being updated
#[serde(with = "humantime_serde")]
pub node_stats_updating_delay: Duration,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct VerlocDebug1_1_2 {
/// Specifies number of echo packets sent to each node during a measurement run.
pub packets_per_node: usize,
/// Specifies maximum amount of time to wait for the connection to get established.
#[serde(with = "humantime_serde")]
pub connection_timeout: Duration,
/// Specifies maximum amount of time to wait for the reply packet to arrive before abandoning the test.
#[serde(with = "humantime_serde")]
pub packet_timeout: Duration,
/// Specifies delay between subsequent test packets being sent (after receiving a reply).
#[serde(with = "humantime_serde")]
pub delay_between_packets: Duration,
/// Specifies number of nodes being tested at once.
pub tested_nodes_batch_size: usize,
/// Specifies delay between subsequent test runs.
#[serde(with = "humantime_serde")]
pub testing_interval: Duration,
/// Specifies delay between attempting to run the measurement again if the previous run failed
/// due to being unable to get the list of nodes.
#[serde(with = "humantime_serde")]
pub retry_timeout: Duration,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Verloc1_1_2 {
/// Socket address this node will use for binding its verloc API.
/// default: `0.0.0.0:1790`
pub bind_address: SocketAddr,
#[serde(default)]
pub debug: VerlocDebug1_1_2,
}
impl VerlocDebug1_1_2 {
const DEFAULT_PACKETS_PER_NODE: usize = 100;
const DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_millis(5000);
const DEFAULT_PACKET_TIMEOUT: Duration = Duration::from_millis(1500);
const DEFAULT_DELAY_BETWEEN_PACKETS: Duration = Duration::from_millis(50);
const DEFAULT_BATCH_SIZE: usize = 50;
const DEFAULT_TESTING_INTERVAL: Duration = Duration::from_secs(60 * 60 * 12);
const DEFAULT_RETRY_TIMEOUT: Duration = Duration::from_secs(60 * 30);
}
impl Default for VerlocDebug1_1_2 {
fn default() -> Self {
VerlocDebug1_1_2 {
packets_per_node: Self::DEFAULT_PACKETS_PER_NODE,
connection_timeout: Self::DEFAULT_CONNECTION_TIMEOUT,
packet_timeout: Self::DEFAULT_PACKET_TIMEOUT,
delay_between_packets: Self::DEFAULT_DELAY_BETWEEN_PACKETS,
tested_nodes_batch_size: Self::DEFAULT_BATCH_SIZE,
testing_interval: Self::DEFAULT_TESTING_INTERVAL,
retry_timeout: Self::DEFAULT_RETRY_TIMEOUT,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MixnodeConfig1_1_2 {
pub storage_paths: MixnodePaths1_1_2,
pub verloc: Verloc1_1_2,
#[serde(default)]
pub debug: Debug1_1_2,
}
impl Debug1_1_2 {
const DEFAULT_NODE_STATS_LOGGING_DELAY: Duration = Duration::from_millis(60_000);
const DEFAULT_NODE_STATS_UPDATING_DELAY: Duration = Duration::from_millis(30_000);
}
impl Default for Debug1_1_2 {
fn default() -> Self {
Debug1_1_2 {
node_stats_logging_delay: Self::DEFAULT_NODE_STATS_LOGGING_DELAY,
node_stats_updating_delay: Self::DEFAULT_NODE_STATS_UPDATING_DELAY,
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayPaths1_1_2 {
/// Path to sqlite database containing all persistent data: messages for offline clients,
/// derived shared keys and available client bandwidths.
pub clients_storage: PathBuf,
/// Path to file containing cosmos account mnemonic used for zk-nym redemption.
pub cosmos_mnemonic: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayConfigDebug1_1_2 {
/// Number of messages from offline client that can be pulled at once (i.e. with a single SQL query) from the storage.
pub message_retrieval_limit: i64,
}
impl EntryGatewayConfigDebug1_1_2 {
const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
}
impl Default for EntryGatewayConfigDebug1_1_2 {
fn default() -> Self {
EntryGatewayConfigDebug1_1_2 {
message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayConfig1_1_2 {
pub storage_paths: EntryGatewayPaths1_1_2,
/// Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet
/// or if it also accepts non-paying clients
pub enforce_zk_nyms: bool,
/// Socket address this node will use for binding its client websocket API.
/// default: `0.0.0.0:9000`
pub bind_address: SocketAddr,
/// Custom announced port for listening for websocket client traffic.
/// If unspecified, the value from the `bind_address` will be used instead
/// default: None
#[serde(deserialize_with = "de_maybe_port")]
pub announce_ws_port: Option<u16>,
/// If applicable, announced port for listening for secure websocket client traffic.
/// (default: None)
#[serde(deserialize_with = "de_maybe_port")]
pub announce_wss_port: Option<u16>,
#[serde(default)]
pub debug: EntryGatewayConfigDebug1_1_2,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NetworkRequesterPaths1_1_2 {
/// Path to file containing network requester ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing network requester ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing network requester x25519 diffie hellman private key.
pub private_x25519_diffie_hellman_key_file: PathBuf,
/// Path to file containing network requester x25519 diffie hellman public key.
pub public_x25519_diffie_hellman_key_file: PathBuf,
/// 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.
pub ack_key_file: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
/// Normally this is a 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.
/// but in this case it just has the basic information of "we're using custom gateway".
/// Due to how clients are started up, this file has to exist.
pub gateway_registrations: PathBuf,
// it's possible we might have to add credential storage here for return tickets
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct IpPacketRouterPaths1_1_2 {
/// Path to file containing ip packet router ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing ip packet router ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing ip packet router x25519 diffie hellman private key.
pub private_x25519_diffie_hellman_key_file: PathBuf,
/// Path to file containing ip packet router x25519 diffie hellman public key.
pub public_x25519_diffie_hellman_key_file: PathBuf,
/// 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.
pub ack_key_file: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
/// Normally this is a 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.
/// but in this case it just has the basic information of "we're using custom gateway".
/// Due to how clients are started up, this file has to exist.
pub gateway_registrations: PathBuf,
// it's possible we might have to add credential storage here for return tickets
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ExitGatewayPaths1_1_2 {
pub network_requester: NetworkRequesterPaths1_1_2,
pub ip_packet_router: IpPacketRouterPaths1_1_2,
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct IpPacketRouterDebug1_1_2 {
/// Specifies whether ip packet routing service is enabled in this process.
/// This is only here for debugging purposes as exit gateway should always run **both**
/// network requester and an ip packet router.
pub enabled: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting client_debug.traffic.disable_main_poisson_packet_distribution = true
/// (or is it (?))
pub disable_poisson_rate: bool,
/// Shared detailed client configuration options
#[serde(flatten)]
pub client_debug: ClientDebugConfig,
}
impl Default for IpPacketRouterDebug1_1_2 {
fn default() -> Self {
IpPacketRouterDebug1_1_2 {
enabled: true,
disable_poisson_rate: true,
client_debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct IpPacketRouter1_1_2 {
#[serde(default)]
pub debug: IpPacketRouterDebug1_1_2,
}
#[allow(clippy::derivable_impls)]
impl Default for IpPacketRouter1_1_2 {
fn default() -> Self {
IpPacketRouter1_1_2 {
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
pub struct NetworkRequesterDebug1_1_2 {
/// Specifies whether network requester service is enabled in this process.
/// This is only here for debugging purposes as exit gateway should always run **both**
/// network requester and an ip packet router.
pub enabled: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting client_debug.traffic.disable_main_poisson_packet_distribution = true
/// (or is it (?))
pub disable_poisson_rate: bool,
/// Shared detailed client configuration options
#[serde(flatten)]
pub client_debug: ClientDebugConfig,
}
impl Default for NetworkRequesterDebug1_1_2 {
fn default() -> Self {
NetworkRequesterDebug1_1_2 {
enabled: true,
disable_poisson_rate: true,
client_debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
pub struct NetworkRequester1_1_2 {
#[serde(default)]
pub debug: NetworkRequesterDebug1_1_2,
}
#[allow(clippy::derivable_impls)]
impl Default for NetworkRequester1_1_2 {
fn default() -> Self {
NetworkRequester1_1_2 {
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ExitGatewayConfig1_1_2 {
pub storage_paths: ExitGatewayPaths1_1_2,
/// specifies whether this exit node should run in 'open-proxy' mode
/// and thus would attempt to resolve **ANY** request it receives.
pub open_proxy: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
pub upstream_exit_policy_url: Url,
pub network_requester: NetworkRequester1_1_2,
pub ip_packet_router: IpPacketRouter1_1_2,
}
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings1_1_2 {
// well, we need to implement something here at some point...
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config1_1_2 {
// additional metadata holding on-disk location of this config file
#[serde(skip)]
pub(crate) save_path: Option<PathBuf>,
/// Human-readable ID of this particular node.
pub id: String,
/// Current mode of this nym-node.
/// Expect this field to be changed in the future to allow running the node in multiple modes (i.e. mixnode + gateway)
pub mode: NodeMode1_1_2,
pub host: Host1_1_2,
pub mixnet: Mixnet1_1_2,
/// Storage paths to persistent nym-node data, such as its long term keys.
pub storage_paths: NymNodePaths1_1_2,
#[serde(default)]
pub http: Http1_1_2,
pub wireguard: Wireguard1_1_2,
pub mixnode: MixnodeConfig1_1_2,
pub entry_gateway: EntryGatewayConfig1_1_2,
pub exit_gateway: ExitGatewayConfig1_1_2,
#[serde(default)]
pub logging: LoggingSettings1_1_2,
}
impl NymConfigTemplate for Config1_1_2 {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
impl Config1_1_2 {
pub fn save(&self) -> Result<(), NymNodeError> {
let save_location = self.save_location();
debug!(
"attempting to save config file to '{}'",
save_location.display()
);
save_formatted_config_to_file(self, &save_location).map_err(|source| {
NymNodeError::ConfigSaveFailure {
id: self.id.clone(),
path: save_location,
source,
}
})
}
pub fn save_location(&self) -> PathBuf {
self.save_path
.clone()
.unwrap_or(self.default_save_location())
}
pub fn default_save_location(&self) -> PathBuf {
default_config_filepath(&self.id)
}
pub fn default_data_directory<P: AsRef<Path>>(config_path: P) -> Result<PathBuf, NymNodeError> {
let config_path = config_path.as_ref();
// we got a proper path to the .toml file
let Some(config_dir) = config_path.parent() else {
error!(
"'{}' does not have a parent directory. Have you pointed to the fs root?",
config_path.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
let Some(config_dir_name) = config_dir.file_name() else {
error!(
"could not obtain parent directory name of '{}'. Have you used relative paths?",
config_path.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
if config_dir_name != DEFAULT_CONFIG_DIR {
error!(
"the parent directory of '{}' ({}) is not {DEFAULT_CONFIG_DIR}. currently this is not supported",
config_path.display(), config_dir_name.to_str().unwrap_or("UNKNOWN")
);
return Err(NymNodeError::DataDirDerivationFailure);
}
let Some(node_dir) = config_dir.parent() else {
error!(
"'{}' does not have a parent directory. Have you pointed to the fs root?",
config_dir.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
Ok(node_dir.join(DEFAULT_DATA_DIR))
}
// simple wrapper that reads config file and assigns path location
fn read_from_path<P: AsRef<Path>>(path: P) -> Result<Self, NymNodeError> {
let path = path.as_ref();
let mut loaded: Config1_1_2 =
read_config_from_toml_file(path).map_err(|source| NymNodeError::ConfigLoadFailure {
path: path.to_path_buf(),
source,
})?;
loaded.save_path = Some(path.to_path_buf());
debug!("loaded config file from {}", path.display());
Ok(loaded)
}
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> Result<Self, NymNodeError> {
Self::read_from_path(path)
}
}
fn initialise(config: &Wireguard1_1_3) -> std::io::Result<()> {
let mut rng = OsRng;
let x25519_keys = KeyPair::new(&mut rng);
store_keypair(
&x25519_keys,
&config.storage_paths.x25519_wireguard_storage_paths(),
)?;
Ok(())
}
// currently there are no upgrades
pub async fn try_upgrade_config_1_1_2<P: AsRef<Path>>(path: P) -> Result<(), NymNodeError> {
let old_cfg = Config1_1_2::read_from_path(&path)?;
let wireguard = Wireguard1_1_3 {
enabled: old_cfg.wireguard.enabled,
bind_address: old_cfg.wireguard.bind_address,
private_ip: old_cfg.wireguard.private_network_ip,
announced_port: old_cfg.wireguard.announced_port,
private_network_prefix: old_cfg.wireguard.private_network_prefix,
storage_paths: WireguardPaths1_1_3::new(Config1_1_3::default_data_directory(path)?),
};
initialise(&wireguard).map_err(|err| KeyIOFailure::KeyPairStoreFailure {
keys: "wg-x25519-dh".to_string(),
paths: wireguard.storage_paths.x25519_wireguard_storage_paths(),
err,
})?;
let cfg = Config1_1_3 {
save_path: old_cfg.save_path,
id: old_cfg.id,
mode: old_cfg.mode.into(),
host: Host1_1_3 {
public_ips: old_cfg.host.public_ips,
hostname: old_cfg.host.hostname,
location: old_cfg.host.location,
},
mixnet: Mixnet1_1_3 {
bind_address: old_cfg.mixnet.bind_address,
nym_api_urls: old_cfg.mixnet.nym_api_urls,
nyxd_urls: old_cfg.mixnet.nyxd_urls,
debug: MixnetDebug1_1_3 {
packet_forwarding_initial_backoff: old_cfg
.mixnet
.debug
.packet_forwarding_initial_backoff,
packet_forwarding_maximum_backoff: old_cfg
.mixnet
.debug
.packet_forwarding_maximum_backoff,
initial_connection_timeout: old_cfg.mixnet.debug.initial_connection_timeout,
maximum_connection_buffer_size: old_cfg.mixnet.debug.maximum_connection_buffer_size,
unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise,
},
},
storage_paths: NymNodePaths1_1_3 {
keys: KeysPaths1_1_3 {
private_ed25519_identity_key_file: old_cfg
.storage_paths
.keys
.private_ed25519_identity_key_file,
public_ed25519_identity_key_file: old_cfg
.storage_paths
.keys
.public_ed25519_identity_key_file,
private_x25519_sphinx_key_file: old_cfg
.storage_paths
.keys
.private_x25519_sphinx_key_file,
public_x25519_sphinx_key_file: old_cfg
.storage_paths
.keys
.public_x25519_sphinx_key_file,
private_x25519_noise_key_file: old_cfg
.storage_paths
.keys
.private_x25519_noise_key_file,
public_x25519_noise_key_file: old_cfg
.storage_paths
.keys
.public_x25519_noise_key_file,
},
description: old_cfg.storage_paths.description,
},
http: Http1_1_3 {
bind_address: old_cfg.http.bind_address,
landing_page_assets_path: old_cfg.http.landing_page_assets_path,
access_token: old_cfg.http.access_token,
expose_system_info: old_cfg.http.expose_system_info,
expose_system_hardware: old_cfg.http.expose_system_hardware,
expose_crypto_hardware: old_cfg.http.expose_crypto_hardware,
},
wireguard,
mixnode: MixnodeConfig1_1_3 {
storage_paths: MixnodePaths1_1_3 {},
verloc: Verloc1_1_3 {
bind_address: old_cfg.mixnode.verloc.bind_address,
debug: VerlocDebug1_1_3 {
packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node,
connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout,
packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout,
delay_between_packets: old_cfg.mixnode.verloc.debug.delay_between_packets,
tested_nodes_batch_size: old_cfg.mixnode.verloc.debug.tested_nodes_batch_size,
testing_interval: old_cfg.mixnode.verloc.debug.testing_interval,
retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout,
},
},
debug: Debug1_1_3 {
node_stats_logging_delay: old_cfg.mixnode.debug.node_stats_logging_delay,
node_stats_updating_delay: old_cfg.mixnode.debug.node_stats_updating_delay,
},
},
entry_gateway: EntryGatewayConfig1_1_3 {
storage_paths: EntryGatewayPaths1_1_3 {
clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage,
cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic,
},
enforce_zk_nyms: old_cfg.entry_gateway.enforce_zk_nyms,
bind_address: old_cfg.entry_gateway.bind_address,
announce_ws_port: old_cfg.entry_gateway.announce_ws_port,
announce_wss_port: old_cfg.entry_gateway.announce_wss_port,
debug: EntryGatewayConfigDebug1_1_3 {
message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit,
},
},
exit_gateway: ExitGatewayConfig1_1_3 {
storage_paths: ExitGatewayPaths1_1_3 {
network_requester: NetworkRequesterPaths1_1_3 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
.network_requester
.private_ed25519_identity_key_file,
public_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
.network_requester
.public_ed25519_identity_key_file,
private_x25519_diffie_hellman_key_file: old_cfg
.exit_gateway
.storage_paths
.network_requester
.private_x25519_diffie_hellman_key_file,
public_x25519_diffie_hellman_key_file: old_cfg
.exit_gateway
.storage_paths
.network_requester
.public_x25519_diffie_hellman_key_file,
ack_key_file: old_cfg
.exit_gateway
.storage_paths
.network_requester
.ack_key_file,
reply_surb_database: old_cfg
.exit_gateway
.storage_paths
.network_requester
.reply_surb_database,
gateway_registrations: old_cfg
.exit_gateway
.storage_paths
.network_requester
.gateway_registrations,
},
ip_packet_router: IpPacketRouterPaths1_1_3 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.private_ed25519_identity_key_file,
public_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.public_ed25519_identity_key_file,
private_x25519_diffie_hellman_key_file: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.private_x25519_diffie_hellman_key_file,
public_x25519_diffie_hellman_key_file: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.public_x25519_diffie_hellman_key_file,
ack_key_file: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.ack_key_file,
reply_surb_database: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.reply_surb_database,
gateway_registrations: old_cfg
.exit_gateway
.storage_paths
.ip_packet_router
.gateway_registrations,
},
},
open_proxy: old_cfg.exit_gateway.open_proxy,
upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url,
network_requester: NetworkRequester1_1_3 {
debug: NetworkRequesterDebug1_1_3 {
enabled: old_cfg.exit_gateway.network_requester.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
.network_requester
.debug
.disable_poisson_rate,
client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug,
},
},
ip_packet_router: IpPacketRouter1_1_3 {
debug: IpPacketRouterDebug1_1_3 {
enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
.ip_packet_router
.debug
.disable_poisson_rate,
client_debug: old_cfg.exit_gateway.ip_packet_router.debug.client_debug,
},
},
},
logging: LoggingSettings1_1_3 {},
};
cfg.save()?;
Ok(())
}
@@ -1,766 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
#![allow(dead_code)]
use crate::config::*;
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
use nym_config::serde_helpers::de_maybe_port;
use nym_crypto::asymmetric::encryption::KeyPair;
use nym_pemstore::store_keypair;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WireguardPaths1_1_3 {
pub private_diffie_hellman_key_file: PathBuf,
pub public_diffie_hellman_key_file: PathBuf,
}
impl WireguardPaths1_1_3 {
pub fn new<P: AsRef<Path>>(data_dir: P) -> Self {
let data_dir = data_dir.as_ref();
WireguardPaths1_1_3 {
private_diffie_hellman_key_file: data_dir
.join(persistence::DEFAULT_X25519_WG_DH_KEY_FILENAME),
public_diffie_hellman_key_file: data_dir
.join(persistence::DEFAULT_X25519_WG_PUBLIC_DH_KEY_FILENAME),
}
}
pub fn x25519_wireguard_storage_paths(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(
&self.private_diffie_hellman_key_file,
&self.public_diffie_hellman_key_file,
)
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Wireguard1_1_3 {
/// Specifies whether the wireguard service is enabled on this node.
pub enabled: bool,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51822`
pub bind_address: SocketAddr,
/// Ip address of the private wireguard network.
/// default: `10.1.0.0`
pub private_ip: IpAddr,
/// 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.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// Paths for wireguard keys, client registries, etc.
pub storage_paths: WireguardPaths1_1_3,
}
// a temporary solution until all "types" are run at the same time
#[derive(Debug, Default, Serialize, Deserialize, ValueEnum, Clone, Copy)]
#[serde(rename_all = "snake_case")]
pub enum NodeMode1_1_3 {
#[default]
#[clap(alias = "mix")]
Mixnode,
#[clap(alias = "entry", alias = "gateway")]
EntryGateway,
#[clap(alias = "exit")]
ExitGateway,
}
// TODO: this is very much a WIP. we need proper ssl certificate support here
#[derive(Debug, Clone, Default, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Host1_1_3 {
/// Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections.
/// If no values are provided, when this node gets included in the network,
/// its ip addresses will be populated by whatever value is resolved by associated nym-api.
pub public_ips: Vec<IpAddr>,
/// Optional hostname of this node, for example nymtech.net.
// TODO: this is temporary. to be replaced by pulling the data directly from the certs.
#[serde(deserialize_with = "de_maybe_stringified")]
pub hostname: Option<String>,
/// Optional ISO 3166 alpha-2 two-letter country code of the node's **physical** location
#[serde(deserialize_with = "de_maybe_stringified")]
pub location: Option<Country>,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct MixnetDebug1_1_3 {
/// Initial value of an exponential backoff to reconnect to dropped TCP connection when
/// forwarding sphinx packets.
#[serde(with = "humantime_serde")]
pub packet_forwarding_initial_backoff: Duration,
/// Maximum value of an exponential backoff to reconnect to dropped TCP connection when
/// forwarding sphinx packets.
#[serde(with = "humantime_serde")]
pub packet_forwarding_maximum_backoff: Duration,
/// Timeout for establishing initial connection when trying to forward a sphinx packet.
#[serde(with = "humantime_serde")]
pub initial_connection_timeout: Duration,
/// Maximum number of packets that can be stored waiting to get sent to a particular connection.
pub maximum_connection_buffer_size: usize,
/// Specifies whether this node should **NOT** use noise protocol in the connections (currently not implemented)
pub unsafe_disable_noise: bool,
}
impl MixnetDebug1_1_3 {
const DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF: Duration = Duration::from_millis(10_000);
const DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF: Duration = Duration::from_millis(300_000);
const DEFAULT_INITIAL_CONNECTION_TIMEOUT: Duration = Duration::from_millis(1_500);
const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000;
}
impl Default for MixnetDebug1_1_3 {
fn default() -> Self {
MixnetDebug1_1_3 {
packet_forwarding_initial_backoff: Self::DEFAULT_PACKET_FORWARDING_INITIAL_BACKOFF,
packet_forwarding_maximum_backoff: Self::DEFAULT_PACKET_FORWARDING_MAXIMUM_BACKOFF,
initial_connection_timeout: Self::DEFAULT_INITIAL_CONNECTION_TIMEOUT,
maximum_connection_buffer_size: Self::DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE,
// to be changed by @SW once the implementation is there
unsafe_disable_noise: true,
}
}
}
impl Default for Mixnet1_1_3 {
fn default() -> Self {
// SAFETY:
// our hardcoded values should always be valid
#[allow(clippy::expect_used)]
// is if there's anything set in the environment, otherwise fallback to mainnet
let nym_api_urls = if let Ok(env_value) = env::var(var_names::NYM_API) {
parse_urls(&env_value)
} else {
vec![mainnet::NYM_API.parse().expect("Invalid default API URL")]
};
#[allow(clippy::expect_used)]
let nyxd_urls = if let Ok(env_value) = env::var(var_names::NYXD) {
parse_urls(&env_value)
} else {
vec![mainnet::NYXD_URL.parse().expect("Invalid default nyxd URL")]
};
Mixnet1_1_3 {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_MIXNET_PORT),
nym_api_urls,
nyxd_urls,
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Mixnet1_1_3 {
/// Address this node will bind to for listening for mixnet packets
/// default: `0.0.0.0:1789`
pub bind_address: SocketAddr,
/// Addresses to nym APIs from which the node gets the view of the network.
pub nym_api_urls: Vec<Url>,
/// Addresses to nyxd which the node uses to interact with the nyx chain.
pub nyxd_urls: Vec<Url>,
#[serde(default)]
pub debug: MixnetDebug1_1_3,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct KeysPaths1_1_3 {
/// Path to file containing ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing x25519 sphinx private key.
pub private_x25519_sphinx_key_file: PathBuf,
/// Path to file containing x25519 sphinx public key.
pub public_x25519_sphinx_key_file: PathBuf,
/// Path to file containing x25519 noise private key.
pub private_x25519_noise_key_file: PathBuf,
/// Path to file containing x25519 noise public key.
pub public_x25519_noise_key_file: PathBuf,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NymNodePaths1_1_3 {
pub keys: KeysPaths1_1_3,
/// Path to a file containing basic node description: human-readable name, website, details, etc.
pub description: PathBuf,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Http1_1_3 {
/// Socket address this node will use for binding its http API.
/// default: `0.0.0.0:8080`
pub bind_address: SocketAddr,
/// Path to assets directory of custom landing page of this node.
#[serde(deserialize_with = "de_maybe_stringified")]
pub landing_page_assets_path: Option<PathBuf>,
/// An optional bearer token for accessing certain http endpoints.
/// Currently only used for obtaining mixnode's stats.
#[serde(default)]
pub access_token: Option<String>,
/// Specify whether basic system information should be exposed.
/// default: true
pub expose_system_info: bool,
/// Specify whether basic system hardware information should be exposed.
/// This option is superseded by `expose_system_info`
/// default: true
pub expose_system_hardware: bool,
/// Specify whether detailed system crypto hardware information should be exposed.
/// This option is superseded by `expose_system_hardware`
/// default: true
pub expose_crypto_hardware: bool,
}
impl Default for Http1_1_3 {
fn default() -> Self {
Http1_1_3 {
bind_address: SocketAddr::new(inaddr_any(), DEFAULT_HTTP_PORT),
landing_page_assets_path: None,
access_token: None,
expose_system_info: true,
expose_system_hardware: true,
expose_crypto_hardware: true,
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct MixnodePaths1_1_3 {}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Debug1_1_3 {
/// Delay between each subsequent node statistics being logged to the console
#[serde(with = "humantime_serde")]
pub node_stats_logging_delay: Duration,
/// Delay between each subsequent node statistics being updated
#[serde(with = "humantime_serde")]
pub node_stats_updating_delay: Duration,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct VerlocDebug1_1_3 {
/// Specifies number of echo packets sent to each node during a measurement run.
pub packets_per_node: usize,
/// Specifies maximum amount of time to wait for the connection to get established.
#[serde(with = "humantime_serde")]
pub connection_timeout: Duration,
/// Specifies maximum amount of time to wait for the reply packet to arrive before abandoning the test.
#[serde(with = "humantime_serde")]
pub packet_timeout: Duration,
/// Specifies delay between subsequent test packets being sent (after receiving a reply).
#[serde(with = "humantime_serde")]
pub delay_between_packets: Duration,
/// Specifies number of nodes being tested at once.
pub tested_nodes_batch_size: usize,
/// Specifies delay between subsequent test runs.
#[serde(with = "humantime_serde")]
pub testing_interval: Duration,
/// Specifies delay between attempting to run the measurement again if the previous run failed
/// due to being unable to get the list of nodes.
#[serde(with = "humantime_serde")]
pub retry_timeout: Duration,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Verloc1_1_3 {
/// Socket address this node will use for binding its verloc API.
/// default: `0.0.0.0:1790`
pub bind_address: SocketAddr,
#[serde(default)]
pub debug: VerlocDebug1_1_3,
}
impl VerlocDebug1_1_3 {
const DEFAULT_PACKETS_PER_NODE: usize = 100;
const DEFAULT_CONNECTION_TIMEOUT: Duration = Duration::from_millis(5000);
const DEFAULT_PACKET_TIMEOUT: Duration = Duration::from_millis(1500);
const DEFAULT_DELAY_BETWEEN_PACKETS: Duration = Duration::from_millis(50);
const DEFAULT_BATCH_SIZE: usize = 50;
const DEFAULT_TESTING_INTERVAL: Duration = Duration::from_secs(60 * 60 * 12);
const DEFAULT_RETRY_TIMEOUT: Duration = Duration::from_secs(60 * 30);
}
impl Default for VerlocDebug1_1_3 {
fn default() -> Self {
VerlocDebug1_1_3 {
packets_per_node: Self::DEFAULT_PACKETS_PER_NODE,
connection_timeout: Self::DEFAULT_CONNECTION_TIMEOUT,
packet_timeout: Self::DEFAULT_PACKET_TIMEOUT,
delay_between_packets: Self::DEFAULT_DELAY_BETWEEN_PACKETS,
tested_nodes_batch_size: Self::DEFAULT_BATCH_SIZE,
testing_interval: Self::DEFAULT_TESTING_INTERVAL,
retry_timeout: Self::DEFAULT_RETRY_TIMEOUT,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MixnodeConfig1_1_3 {
pub storage_paths: MixnodePaths1_1_3,
pub verloc: Verloc1_1_3,
#[serde(default)]
pub debug: Debug1_1_3,
}
impl Debug1_1_3 {
const DEFAULT_NODE_STATS_LOGGING_DELAY: Duration = Duration::from_millis(60_000);
const DEFAULT_NODE_STATS_UPDATING_DELAY: Duration = Duration::from_millis(30_000);
}
impl Default for Debug1_1_3 {
fn default() -> Self {
Debug1_1_3 {
node_stats_logging_delay: Self::DEFAULT_NODE_STATS_LOGGING_DELAY,
node_stats_updating_delay: Self::DEFAULT_NODE_STATS_UPDATING_DELAY,
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayPaths1_1_3 {
/// Path to sqlite database containing all persistent data: messages for offline clients,
/// derived shared keys and available client bandwidths.
pub clients_storage: PathBuf,
/// Path to file containing cosmos account mnemonic used for zk-nym redemption.
pub cosmos_mnemonic: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayConfigDebug1_1_3 {
/// Number of messages from offline client that can be pulled at once (i.e. with a single SQL query) from the storage.
pub message_retrieval_limit: i64,
}
impl EntryGatewayConfigDebug1_1_3 {
const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
}
impl Default for EntryGatewayConfigDebug1_1_3 {
fn default() -> Self {
EntryGatewayConfigDebug1_1_3 {
message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct EntryGatewayConfig1_1_3 {
pub storage_paths: EntryGatewayPaths1_1_3,
/// Indicates whether this gateway is accepting only coconut credentials for accessing the mixnet
/// or if it also accepts non-paying clients
pub enforce_zk_nyms: bool,
/// Socket address this node will use for binding its client websocket API.
/// default: `0.0.0.0:9000`
pub bind_address: SocketAddr,
/// Custom announced port for listening for websocket client traffic.
/// If unspecified, the value from the `bind_address` will be used instead
/// default: None
#[serde(deserialize_with = "de_maybe_port")]
pub announce_ws_port: Option<u16>,
/// If applicable, announced port for listening for secure websocket client traffic.
/// (default: None)
#[serde(deserialize_with = "de_maybe_port")]
pub announce_wss_port: Option<u16>,
#[serde(default)]
pub debug: EntryGatewayConfigDebug1_1_3,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct NetworkRequesterPaths1_1_3 {
/// Path to file containing network requester ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing network requester ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing network requester x25519 diffie hellman private key.
pub private_x25519_diffie_hellman_key_file: PathBuf,
/// Path to file containing network requester x25519 diffie hellman public key.
pub public_x25519_diffie_hellman_key_file: PathBuf,
/// 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.
pub ack_key_file: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
/// Normally this is a 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.
/// but in this case it just has the basic information of "we're using custom gateway".
/// Due to how clients are started up, this file has to exist.
pub gateway_registrations: PathBuf,
// it's possible we might have to add credential storage here for return tickets
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct IpPacketRouterPaths1_1_3 {
/// Path to file containing ip packet router ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing ip packet router ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing ip packet router x25519 diffie hellman private key.
pub private_x25519_diffie_hellman_key_file: PathBuf,
/// Path to file containing ip packet router x25519 diffie hellman public key.
pub public_x25519_diffie_hellman_key_file: PathBuf,
/// 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.
pub ack_key_file: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
/// Normally this is a 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.
/// but in this case it just has the basic information of "we're using custom gateway".
/// Due to how clients are started up, this file has to exist.
pub gateway_registrations: PathBuf,
// it's possible we might have to add credential storage here for return tickets
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ExitGatewayPaths1_1_3 {
pub network_requester: NetworkRequesterPaths1_1_3,
pub ip_packet_router: IpPacketRouterPaths1_1_3,
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default)]
pub struct IpPacketRouterDebug1_1_3 {
/// Specifies whether ip packet routing service is enabled in this process.
/// This is only here for debugging purposes as exit gateway should always run **both**
/// network requester and an ip packet router.
pub enabled: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting client_debug.traffic.disable_main_poisson_packet_distribution = true
/// (or is it (?))
pub disable_poisson_rate: bool,
/// Shared detailed client configuration options
#[serde(flatten)]
pub client_debug: ClientDebugConfig,
}
impl Default for IpPacketRouterDebug1_1_3 {
fn default() -> Self {
IpPacketRouterDebug1_1_3 {
enabled: true,
disable_poisson_rate: true,
client_debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct IpPacketRouter1_1_3 {
#[serde(default)]
pub debug: IpPacketRouterDebug1_1_3,
}
#[allow(clippy::derivable_impls)]
impl Default for IpPacketRouter1_1_3 {
fn default() -> Self {
IpPacketRouter1_1_3 {
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
pub struct NetworkRequesterDebug1_1_3 {
/// Specifies whether network requester service is enabled in this process.
/// This is only here for debugging purposes as exit gateway should always run **both**
/// network requester and an ip packet router.
pub enabled: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting client_debug.traffic.disable_main_poisson_packet_distribution = true
/// (or is it (?))
pub disable_poisson_rate: bool,
/// Shared detailed client configuration options
#[serde(flatten)]
pub client_debug: ClientDebugConfig,
}
impl Default for NetworkRequesterDebug1_1_3 {
fn default() -> Self {
NetworkRequesterDebug1_1_3 {
enabled: true,
disable_poisson_rate: true,
client_debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
pub struct NetworkRequester1_1_3 {
#[serde(default)]
pub debug: NetworkRequesterDebug1_1_3,
}
#[allow(clippy::derivable_impls)]
impl Default for NetworkRequester1_1_3 {
fn default() -> Self {
NetworkRequester1_1_3 {
debug: Default::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ExitGatewayConfig1_1_3 {
pub storage_paths: ExitGatewayPaths1_1_3,
/// specifies whether this exit node should run in 'open-proxy' mode
/// and thus would attempt to resolve **ANY** request it receives.
pub open_proxy: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
pub upstream_exit_policy_url: Url,
pub network_requester: NetworkRequester1_1_3,
pub ip_packet_router: IpPacketRouter1_1_3,
}
#[derive(Debug, Default, Copy, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct LoggingSettings1_1_3 {
// well, we need to implement something here at some point...
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config1_1_3 {
// additional metadata holding on-disk location of this config file
#[serde(skip)]
pub(crate) save_path: Option<PathBuf>,
/// Human-readable ID of this particular node.
pub id: String,
/// Current mode of this nym-node.
/// Expect this field to be changed in the future to allow running the node in multiple modes (i.e. mixnode + gateway)
pub mode: NodeMode1_1_3,
pub host: Host1_1_3,
pub mixnet: Mixnet1_1_3,
/// Storage paths to persistent nym-node data, such as its long term keys.
pub storage_paths: NymNodePaths1_1_3,
#[serde(default)]
pub http: Http1_1_3,
pub wireguard: Wireguard1_1_3,
pub mixnode: MixnodeConfig1_1_3,
pub entry_gateway: EntryGatewayConfig1_1_3,
pub exit_gateway: ExitGatewayConfig1_1_3,
#[serde(default)]
pub logging: LoggingSettings1_1_3,
}
impl NymConfigTemplate for Config1_1_3 {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
impl Config1_1_3 {
pub fn save(&self) -> Result<(), NymNodeError> {
let save_location = self.save_location();
debug!(
"attempting to save config file to '{}'",
save_location.display()
);
save_formatted_config_to_file(self, &save_location).map_err(|source| {
NymNodeError::ConfigSaveFailure {
id: self.id.clone(),
path: save_location,
source,
}
})
}
pub fn save_location(&self) -> PathBuf {
self.save_path
.clone()
.unwrap_or(self.default_save_location())
}
pub fn default_save_location(&self) -> PathBuf {
default_config_filepath(&self.id)
}
pub fn default_data_directory<P: AsRef<Path>>(config_path: P) -> Result<PathBuf, NymNodeError> {
let config_path = config_path.as_ref();
// we got a proper path to the .toml file
let Some(config_dir) = config_path.parent() else {
error!(
"'{}' does not have a parent directory. Have you pointed to the fs root?",
config_path.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
let Some(config_dir_name) = config_dir.file_name() else {
error!(
"could not obtain parent directory name of '{}'. Have you used relative paths?",
config_path.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
if config_dir_name != DEFAULT_CONFIG_DIR {
error!(
"the parent directory of '{}' ({}) is not {DEFAULT_CONFIG_DIR}. currently this is not supported",
config_path.display(), config_dir_name.to_str().unwrap_or("UNKNOWN")
);
return Err(NymNodeError::DataDirDerivationFailure);
}
let Some(node_dir) = config_dir.parent() else {
error!(
"'{}' does not have a parent directory. Have you pointed to the fs root?",
config_dir.display()
);
return Err(NymNodeError::DataDirDerivationFailure);
};
Ok(node_dir.join(DEFAULT_DATA_DIR))
}
// simple wrapper that reads config file and assigns path location
fn read_from_path<P: AsRef<Path>>(path: P) -> Result<Self, NymNodeError> {
let path = path.as_ref();
let mut loaded: Config1_1_3 =
read_config_from_toml_file(path).map_err(|source| NymNodeError::ConfigLoadFailure {
path: path.to_path_buf(),
source,
})?;
loaded.save_path = Some(path.to_path_buf());
debug!("loaded config file from {}", path.display());
Ok(loaded)
}
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> Result<Self, NymNodeError> {
Self::read_from_path(path)
}
}
fn initialise(config: &Wireguard1_1_3) -> std::io::Result<()> {
let mut rng = OsRng;
let x25519_keys = KeyPair::new(&mut rng);
store_keypair(
&x25519_keys,
&config.storage_paths.x25519_wireguard_storage_paths(),
)?;
Ok(())
}
// currently there are no upgrades
pub async fn try_upgrade_config_1_1_3<P: AsRef<Path>>(path: P) -> Result<(), NymNodeError> {
let old_cfg = Config::read_from_path(&path)?;
let cfg = Config {
save_path: old_cfg.save_path,
id: old_cfg.id,
mode: old_cfg.mode,
host: old_cfg.host,
mixnet: old_cfg.mixnet,
storage_paths: old_cfg.storage_paths,
http: old_cfg.http,
wireguard: old_cfg.wireguard,
mixnode: old_cfg.mixnode,
entry_gateway: old_cfg.entry_gateway,
exit_gateway: old_cfg.exit_gateway,
logging: old_cfg.logging,
};
cfg.save()?;
Ok(())
}
-91
View File
@@ -43,14 +43,6 @@ pub const DEFAULT_IPR_ACK_KEY_FILENAME: &str = "aes128ctr_ipr_ack";
pub const DEFAULT_IPR_REPLY_SURB_DB_FILENAME: &str = "ipr_persistent_reply_store.sqlite";
pub const DEFAULT_IPR_GATEWAYS_DB_FILENAME: &str = "ipr_gateways_info_store.sqlite";
pub const DEFAULT_ED25519_AUTH_PRIVATE_IDENTITY_KEY_FILENAME: &str = "ed25519_auth_identity";
pub const DEFAULT_ED25519_AUTH_PUBLIC_IDENTITY_KEY_FILENAME: &str = "ed25519_auth_identity.pub";
pub const DEFAULT_X25519_AUTH_PRIVATE_DH_KEY_FILENAME: &str = "x25519_auth_dh";
pub const DEFAULT_X25519_AUTH_PUBLIC_DH_KEY_FILENAME: &str = "x25519_auth_dh.pub";
pub const DEFAULT_AUTH_ACK_KEY_FILENAME: &str = "aes128ctr_auth_ack";
pub const DEFAULT_AUTH_REPLY_SURB_DB_FILENAME: &str = "auth_persistent_reply_store.sqlite";
pub const DEFAULT_AUTH_GATEWAYS_DB_FILENAME: &str = "auth_gateways_info_store.sqlite";
// Wireguard
pub const DEFAULT_X25519_WG_DH_KEY_FILENAME: &str = "x25519_wg_dh";
pub const DEFAULT_X25519_WG_PUBLIC_DH_KEY_FILENAME: &str = "x25519_wg_dh.pub";
@@ -203,8 +195,6 @@ pub struct ExitGatewayPaths {
pub network_requester: NetworkRequesterPaths,
pub ip_packet_router: IpPacketRouterPaths,
pub authenticator: AuthenticatorPaths,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
@@ -367,93 +357,12 @@ impl IpPacketRouterPaths {
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct AuthenticatorPaths {
/// Path to file containing authenticator ed25519 identity private key.
pub private_ed25519_identity_key_file: PathBuf,
/// Path to file containing authenticator ed25519 identity public key.
pub public_ed25519_identity_key_file: PathBuf,
/// Path to file containing authenticator x25519 diffie hellman private key.
pub private_x25519_diffie_hellman_key_file: PathBuf,
/// Path to file containing authenticator x25519 diffie hellman public key.
pub public_x25519_diffie_hellman_key_file: PathBuf,
/// 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.
pub ack_key_file: PathBuf,
/// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
pub reply_surb_database: PathBuf,
/// Normally this is a 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.
/// but in this case it just has the basic information of "we're using custom gateway".
/// Due to how clients are started up, this file has to exist.
pub gateway_registrations: PathBuf,
// it's possible we might have to add credential storage here for return tickets
}
impl AuthenticatorPaths {
pub fn new<P: AsRef<Path>>(data_dir: P) -> Self {
let data_dir = data_dir.as_ref();
AuthenticatorPaths {
private_ed25519_identity_key_file: data_dir
.join(DEFAULT_ED25519_AUTH_PRIVATE_IDENTITY_KEY_FILENAME),
public_ed25519_identity_key_file: data_dir
.join(DEFAULT_ED25519_AUTH_PUBLIC_IDENTITY_KEY_FILENAME),
private_x25519_diffie_hellman_key_file: data_dir
.join(DEFAULT_X25519_AUTH_PRIVATE_DH_KEY_FILENAME),
public_x25519_diffie_hellman_key_file: data_dir
.join(DEFAULT_X25519_AUTH_PUBLIC_DH_KEY_FILENAME),
ack_key_file: data_dir.join(DEFAULT_AUTH_ACK_KEY_FILENAME),
reply_surb_database: data_dir.join(DEFAULT_AUTH_REPLY_SURB_DB_FILENAME),
gateway_registrations: data_dir.join(DEFAULT_AUTH_GATEWAYS_DB_FILENAME),
}
}
pub fn to_common_client_paths(&self) -> CommonClientPaths {
CommonClientPaths {
keys: ClientKeysPaths {
private_identity_key_file: self.private_ed25519_identity_key_file.clone(),
public_identity_key_file: self.public_ed25519_identity_key_file.clone(),
private_encryption_key_file: self.private_x25519_diffie_hellman_key_file.clone(),
public_encryption_key_file: self.public_x25519_diffie_hellman_key_file.clone(),
ack_key_file: self.ack_key_file.clone(),
},
gateway_registrations: self.gateway_registrations.clone(),
// not needed for embedded providers
credentials_database: Default::default(),
reply_surb_database: self.reply_surb_database.clone(),
}
}
pub fn ed25519_identity_storage_paths(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(
&self.private_ed25519_identity_key_file,
&self.public_ed25519_identity_key_file,
)
}
pub fn x25519_diffie_hellman_storage_paths(&self) -> nym_pemstore::KeyPairPath {
nym_pemstore::KeyPairPath::new(
&self.private_x25519_diffie_hellman_key_file,
&self.public_x25519_diffie_hellman_key_file,
)
}
}
impl ExitGatewayPaths {
pub fn new<P: AsRef<Path>>(data_dir: P) -> Self {
let data_dir = data_dir.as_ref();
ExitGatewayPaths {
network_requester: NetworkRequesterPaths::new(data_dir),
ip_packet_router: IpPacketRouterPaths::new(data_dir),
authenticator: AuthenticatorPaths::new(data_dir),
}
}
}
+137 -8
View File
@@ -1,22 +1,151 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use tracing::debug;
use crate::config::old_configs::*;
use crate::config::persistence::WireguardPaths;
use crate::config::Config;
use crate::error::NymNodeError;
use std::path::Path;
// currently there are no upgrades
async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
if try_upgrade_config_1_1_2(path).await.is_ok() {
debug!("Updated from 1.1.2 or previous");
async fn try_upgrade_config<P: AsRef<Path>>(path: P) -> Result<(), NymNodeError> {
use crate::config::*;
use crate::error::KeyIOFailure;
use nym_crypto::asymmetric::encryption::KeyPair;
use nym_pemstore::store_keypair;
use rand::rngs::OsRng;
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldWireguardPaths {
// pub keys:
}
if try_upgrade_config_1_1_3(path).await.is_ok() {
debug!("Updated from 1.1.3");
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldWireguard {
/// Specifies whether the wireguard service is enabled on this node.
pub enabled: bool,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51822`
pub bind_address: SocketAddr,
/// Ip address of the private wireguard network.
/// default: `10.1.0.0`
pub private_network_ip: IpAddr,
/// 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.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// Paths for wireguard keys, client registries, etc.
pub storage_paths: OldWireguardPaths,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct OldConfig {
// additional metadata holding on-disk location of this config file
#[serde(skip)]
pub(crate) save_path: Option<PathBuf>,
/// Human-readable ID of this particular node.
pub id: String,
/// Current mode of this nym-node.
/// Expect this field to be changed in the future to allow running the node in multiple modes (i.e. mixnode + gateway)
pub mode: NodeMode,
pub host: Host,
pub mixnet: Mixnet,
/// Storage paths to persistent nym-node data, such as its long term keys.
pub storage_paths: NymNodePaths,
#[serde(default)]
pub http: Http,
pub wireguard: OldWireguard,
pub mixnode: MixnodeConfig,
pub entry_gateway: EntryGatewayConfig,
pub exit_gateway: ExitGatewayConfig,
#[serde(default)]
pub logging: LoggingSettings,
}
impl NymConfigTemplate for OldConfig {
fn template(&self) -> &'static str {
CONFIG_TEMPLATE
}
}
impl OldConfig {
fn read_from_path<P: AsRef<Path>>(path: P) -> Result<Self, NymNodeError> {
let path = path.as_ref();
let mut loaded: OldConfig = read_config_from_toml_file(path).map_err(|source| {
NymNodeError::ConfigLoadFailure {
path: path.to_path_buf(),
source,
}
})?;
loaded.save_path = Some(path.to_path_buf());
debug!("loaded config file from {}", path.display());
Ok(loaded)
}
}
fn initialise(config: &Wireguard) -> std::io::Result<()> {
let mut rng = OsRng;
let x25519_keys = KeyPair::new(&mut rng);
store_keypair(
&x25519_keys,
&config.storage_paths.x25519_wireguard_storage_paths(),
)?;
Ok(())
}
let old_cfg = OldConfig::read_from_path(&path)?;
let wireguard = Wireguard {
enabled: old_cfg.wireguard.enabled,
bind_address: old_cfg.wireguard.bind_address,
private_ip: old_cfg.wireguard.private_network_ip,
announced_port: old_cfg.wireguard.announced_port,
private_network_prefix: old_cfg.wireguard.private_network_prefix,
storage_paths: WireguardPaths::new(Config::default_data_directory(path)?),
};
initialise(&wireguard).map_err(|err| KeyIOFailure::KeyPairStoreFailure {
keys: "wg-x25519-dh".to_string(),
paths: wireguard.storage_paths.x25519_wireguard_storage_paths(),
err,
})?;
let cfg = Config {
save_path: old_cfg.save_path,
id: old_cfg.id,
mode: old_cfg.mode,
host: old_cfg.host,
mixnet: old_cfg.mixnet,
storage_paths: old_cfg.storage_paths,
http: old_cfg.http,
wireguard,
mixnode: old_cfg.mixnode,
entry_gateway: old_cfg.entry_gateway,
exit_gateway: old_cfg.exit_gateway,
logging: old_cfg.logging,
};
cfg.save()?;
Ok(())
}
+26 -37
View File
@@ -8,6 +8,7 @@ use crate::node::helpers::{
store_x25519_sphinx_keypair, DisplayDetails,
};
use crate::node::http::{sign_host_details, system_info::get_system_info};
use ipnetwork::IpNetwork;
use nym_bin_common::bin_info_owned;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_gateway::Gateway;
@@ -25,6 +26,7 @@ use nym_node::config::{
use nym_node::error::{EntryGatewayError, ExitGatewayError, MixnodeError, NymNodeError};
use nym_node_http_api::api::api_requests;
use nym_node_http_api::api::api_requests::v1::node::models::NodeDescription;
use nym_node_http_api::router::WireguardAppState;
use nym_node_http_api::state::metrics::{SharedMixingStats, SharedVerlocStats};
use nym_node_http_api::state::AppState;
use nym_node_http_api::{NymNodeHTTPServer, NymNodeRouter};
@@ -66,6 +68,7 @@ impl MixnodeData {
pub struct EntryGatewayData {
mnemonic: Zeroizing<bip39::Mnemonic>,
client_storage: nym_gateway::node::PersistentStorage,
wireguard_data: WireguardGatewayData,
}
impl EntryGatewayData {
@@ -83,7 +86,10 @@ impl EntryGatewayData {
Ok(())
}
async fn new(config: &EntryGatewayConfig) -> Result<EntryGatewayData, EntryGatewayError> {
async fn new(
config: &EntryGatewayConfig,
wireguard_data: WireguardGatewayData,
) -> Result<EntryGatewayData, EntryGatewayError> {
Ok(EntryGatewayData {
mnemonic: config.storage_paths.load_mnemonic_from_file()?,
client_storage: nym_gateway::node::PersistentStorage::init(
@@ -92,6 +98,7 @@ impl EntryGatewayData {
)
.await
.map_err(nym_gateway::GatewayError::from)?,
wireguard_data: wireguard_data.clone(),
})
}
}
@@ -106,9 +113,6 @@ pub struct ExitGatewayData {
ipr_ed25519: ed25519::PublicKey,
ipr_x25519: x25519::PublicKey,
auth_ed25519: ed25519::PublicKey,
auth_x25519: x25519::PublicKey,
}
impl ExitGatewayData {
@@ -239,24 +243,11 @@ impl ExitGatewayData {
"ip packet router x25519",
)?;
let auth_paths = &config.storage_paths.authenticator;
let auth_ed25519 = load_key(
&auth_paths.public_ed25519_identity_key_file,
"authenticator ed25519",
)?;
let auth_x25519 = load_key(
&auth_paths.public_x25519_diffie_hellman_key_file,
"authenticator x25519",
)?;
Ok(ExitGatewayData {
nr_ed25519,
nr_x25519,
ipr_ed25519,
ipr_x25519,
auth_ed25519,
auth_x25519,
})
}
}
@@ -395,7 +386,11 @@ impl NymNode {
description: load_node_description(&config.storage_paths.description)?,
verloc_stats: Default::default(),
mixnode: MixnodeData::new(&config.mixnode)?,
entry_gateway: EntryGatewayData::new(&config.entry_gateway).await?,
entry_gateway: EntryGatewayData::new(
&config.entry_gateway,
wireguard_data.inner.clone(),
)
.await?,
exit_gateway: ExitGatewayData::new(&config.exit_gateway)?,
wireguard: wireguard_data,
config,
@@ -427,14 +422,6 @@ impl NymNode {
)
}
fn exit_authenticator_address(&self) -> Recipient {
Recipient::new(
self.exit_gateway.auth_ed25519,
self.exit_gateway.auth_x25519,
*self.ed25519_identity_keys.public_key(),
)
}
fn x25519_wireguard_key(&self) -> &x25519::PublicKey {
self.wireguard.inner.keypair().public_key()
}
@@ -500,7 +487,6 @@ impl NymNode {
config,
None,
None,
None,
self.ed25519_identity_keys.clone(),
self.x25519_sphinx_keys.clone(),
self.entry_gateway.client_storage.clone(),
@@ -528,7 +514,6 @@ impl NymNode {
config.gateway,
Some(config.nr_opts),
Some(config.ipr_opts),
Some(config.auth_opts),
self.ed25519_identity_keys.clone(),
self.x25519_sphinx_keys.clone(),
self.entry_gateway.client_storage.clone(),
@@ -599,13 +584,6 @@ impl NymNode {
encoded_x25519_key: self.exit_gateway.ipr_x25519.to_base58_string(),
address: self.exit_ip_packet_router_address().to_string(),
};
let auth_details = api_requests::v1::authenticator::models::Authenticator {
encoded_identity_key: self.exit_gateway.auth_ed25519.to_base58_string(),
encoded_x25519_key: self.exit_gateway.auth_x25519.to_base58_string(),
address: self.exit_authenticator_address().to_string(),
};
let exit_policy_details =
api_requests::v1::network_requester::exit_policy::models::UsedExitPolicy {
enabled: true,
@@ -619,13 +597,24 @@ impl NymNode {
policy: None,
};
let wireguard_private_network = IpNetwork::new(
self.config.wireguard.private_ip,
self.config.wireguard.private_network_prefix,
)?;
let wg_state = WireguardAppState::new(
self.entry_gateway.wireguard_data.clone(),
Default::default(),
self.config.wireguard.bind_address.port(),
wireguard_private_network,
)?;
let mut config = nym_node_http_api::Config::new(bin_info_owned!(), host_details)
.with_landing_page_assets(self.config.http.landing_page_assets_path.as_ref())
.with_mixnode_details(mixnode_details)
.with_gateway_details(gateway_details)
.with_network_requester_details(nr_details)
.with_ip_packet_router_details(ipr_details)
.with_authenticator_details(auth_details)
.with_used_exit_policy(exit_policy_details)
.with_description(self.description.clone())
.with_auxiliary_details(auxiliary_details);
@@ -651,7 +640,7 @@ impl NymNode {
.with_verloc_stats(self.verloc_stats.clone())
.with_metrics_key(self.config.http.access_token.clone());
Ok(NymNodeRouter::new(config, Some(app_state))
Ok(NymNodeRouter::new(config, Some(app_state), Some(wg_state))
.build_server(&self.config.http.bind_address)
.await?)
}

Some files were not shown because too many files have changed in this diff Show More