Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f75cd90092 | |||
| 1164f66d7a | |||
| 8ddadf2aa5 | |||
| b0234d0140 | |||
| 6c2b917706 | |||
| 0b8a5d5d86 | |||
| 74623fa2b8 | |||
| 454712b520 | |||
| 5fe5541d02 | |||
| c25c4548b2 | |||
| d6e996e8e9 | |||
| cf88364dda | |||
| 24d32a64e0 | |||
| 28d1d9d989 | |||
| 74a4197b77 | |||
| 3bc7301d94 | |||
| cc342458f9 |
@@ -4,6 +4,26 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [2025.4-dorina-patched] (2025-03-06)
|
||||||
|
|
||||||
|
- bugfix: make sure to correctly decode response content when putting it into error message ([#5571])
|
||||||
|
- Tweak surb management to be more conservative ([#5570])
|
||||||
|
- Deserialize v5 authenticator requests ([#5568])
|
||||||
|
- chore: additional logs when attempting to load ecash keys ([#5567])
|
||||||
|
- add full response body to error message upon decoding failure ([#5566])
|
||||||
|
- hotfix: ensure we bail on merkle leaves insertion upon missing data ([#5565])
|
||||||
|
- feature: v2 authentication request (#5537) ([#5563])
|
||||||
|
- Create authenticator v5 request/response types ([#5561])
|
||||||
|
|
||||||
|
[#5571]: https://github.com/nymtech/nym/pull/5571
|
||||||
|
[#5570]: https://github.com/nymtech/nym/pull/5570
|
||||||
|
[#5568]: https://github.com/nymtech/nym/pull/5568
|
||||||
|
[#5567]: https://github.com/nymtech/nym/pull/5567
|
||||||
|
[#5566]: https://github.com/nymtech/nym/pull/5566
|
||||||
|
[#5565]: https://github.com/nymtech/nym/pull/5565
|
||||||
|
[#5563]: https://github.com/nymtech/nym/pull/5563
|
||||||
|
[#5561]: https://github.com/nymtech/nym/pull/5561
|
||||||
|
|
||||||
## [2025.4-dorina] (2025-03-04)
|
## [2025.4-dorina] (2025-03-04)
|
||||||
|
|
||||||
- fixed sphinx version metrics registration ([#5546])
|
- fixed sphinx version metrics registration ([#5546])
|
||||||
|
|||||||
Generated
+13
-8
@@ -2433,7 +2433,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "1.1.47"
|
version = "1.1.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -4780,7 +4780,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-api"
|
name = "nym-api"
|
||||||
version = "1.1.51"
|
version = "1.1.53"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -5029,7 +5029,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-cli"
|
name = "nym-cli"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
@@ -5112,7 +5112,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -5874,8 +5874,11 @@ name = "nym-http-api-client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
"hickory-resolver",
|
"hickory-resolver",
|
||||||
"http 1.2.0",
|
"http 1.2.0",
|
||||||
|
"mime",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"reqwest 0.12.4",
|
"reqwest 0.12.4",
|
||||||
@@ -6153,7 +6156,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
version = "1.1.50"
|
version = "1.1.51"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr",
|
"addr",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -6204,7 +6207,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-node"
|
name = "nym-node"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
@@ -6489,6 +6492,7 @@ name = "nym-pemstore"
|
|||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pem",
|
"pem",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6536,6 +6540,7 @@ dependencies = [
|
|||||||
"reqwest 0.12.4",
|
"reqwest 0.12.4",
|
||||||
"serde",
|
"serde",
|
||||||
"tap",
|
"tap",
|
||||||
|
"tempfile",
|
||||||
"thiserror 2.0.12",
|
"thiserror 2.0.12",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
@@ -6587,7 +6592,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bs58",
|
"bs58",
|
||||||
"clap",
|
"clap",
|
||||||
@@ -7192,7 +7197,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nymvisor"
|
name = "nymvisor"
|
||||||
version = "0.1.14"
|
version = "0.1.15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ doc-comment = "0.3"
|
|||||||
dotenvy = "0.15.6"
|
dotenvy = "0.15.6"
|
||||||
ecdsa = "0.16"
|
ecdsa = "0.16"
|
||||||
ed25519-dalek = "2.1"
|
ed25519-dalek = "2.1"
|
||||||
|
encoding_rs = "0.8.35"
|
||||||
env_logger = "0.11.6"
|
env_logger = "0.11.6"
|
||||||
envy = "0.4"
|
envy = "0.4"
|
||||||
etherparse = "0.13.0"
|
etherparse = "0.13.0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
description = "Implementation of the Nym Client"
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
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"
|
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ pub mod v1;
|
|||||||
pub mod v2;
|
pub mod v2;
|
||||||
pub mod v3;
|
pub mod v3;
|
||||||
pub mod v4;
|
pub mod v4;
|
||||||
|
pub mod v5;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use v4 as latest;
|
pub use v5 as latest;
|
||||||
|
|
||||||
pub const CURRENT_VERSION: u8 = 4;
|
pub const CURRENT_VERSION: u8 = 5;
|
||||||
|
|
||||||
fn make_bincode_serializer() -> impl bincode::Options {
|
fn make_bincode_serializer() -> impl bincode::Options {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use nym_sphinx::addressing::clients::Recipient;
|
|||||||
use nym_wireguard_types::PeerPublicKey;
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
v1, v2, v3,
|
v1, v2, v3, v4,
|
||||||
v4::{self, registration::IpPair},
|
v5::{self, registration::IpPair},
|
||||||
Error,
|
Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ pub enum AuthenticatorVersion {
|
|||||||
V2,
|
V2,
|
||||||
V3,
|
V3,
|
||||||
V4,
|
V4,
|
||||||
|
V5,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +35,8 @@ impl From<Protocol> for AuthenticatorVersion {
|
|||||||
AuthenticatorVersion::V3
|
AuthenticatorVersion::V3
|
||||||
} else if value.version == v4::VERSION {
|
} else if value.version == v4::VERSION {
|
||||||
AuthenticatorVersion::V4
|
AuthenticatorVersion::V4
|
||||||
|
} else if value.version == v5::VERSION {
|
||||||
|
AuthenticatorVersion::V5
|
||||||
} else {
|
} else {
|
||||||
AuthenticatorVersion::UNKNOWN
|
AuthenticatorVersion::UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -68,6 +71,12 @@ impl InitMessage for v4::registration::InitMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InitMessage for v5::registration::InitMessage {
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.pub_key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait FinalMessage {
|
pub trait FinalMessage {
|
||||||
fn pub_key(&self) -> PeerPublicKey;
|
fn pub_key(&self) -> PeerPublicKey;
|
||||||
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>;
|
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error>;
|
||||||
@@ -138,6 +147,24 @@ impl FinalMessage for v4::registration::FinalMessage {
|
|||||||
self.gateway_client.verify(private_key, nonce)
|
self.gateway_client.verify(private_key, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn private_ips(&self) -> IpPair {
|
||||||
|
self.gateway_client.private_ips.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn credential(&self) -> Option<CredentialSpendingData> {
|
||||||
|
self.credential.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FinalMessage for v5::registration::FinalMessage {
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.gateway_client.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(&self, private_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||||
|
self.gateway_client.verify(private_key, nonce)
|
||||||
|
}
|
||||||
|
|
||||||
fn private_ips(&self) -> IpPair {
|
fn private_ips(&self) -> IpPair {
|
||||||
self.gateway_client.private_ips
|
self.gateway_client.private_ips
|
||||||
}
|
}
|
||||||
@@ -182,29 +209,39 @@ impl TopUpMessage for v4::topup::TopUpMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TopUpMessage for v5::topup::TopUpMessage {
|
||||||
|
fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.pub_key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn credential(&self) -> CredentialSpendingData {
|
||||||
|
self.credential.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum AuthenticatorRequest {
|
pub enum AuthenticatorRequest {
|
||||||
Initial {
|
Initial {
|
||||||
msg: Box<dyn InitMessage + Send + Sync + 'static>,
|
msg: Box<dyn InitMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
},
|
},
|
||||||
Final {
|
Final {
|
||||||
msg: Box<dyn FinalMessage + Send + Sync + 'static>,
|
msg: Box<dyn FinalMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
},
|
},
|
||||||
QueryBandwidth {
|
QueryBandwidth {
|
||||||
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
},
|
},
|
||||||
TopUpBandwidth {
|
TopUpBandwidth {
|
||||||
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -218,7 +255,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
version: value.version,
|
version: value.version,
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
},
|
},
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final {
|
v1::request::AuthenticatorRequestData::Final(gateway_client) => Self::Final {
|
||||||
@@ -227,7 +264,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
version: value.version,
|
version: value.version,
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
},
|
},
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
v1::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
@@ -237,7 +274,7 @@ impl From<v1::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
version: value.version,
|
version: value.version,
|
||||||
service_provider_type: ServiceProviderType::Authenticator,
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
},
|
},
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -251,20 +288,20 @@ impl From<v2::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
v2::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
msg: Box::new(init_message),
|
msg: Box::new(init_message),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
v2::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
msg: final_message,
|
msg: final_message,
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
v2::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
Self::QueryBandwidth {
|
Self::QueryBandwidth {
|
||||||
msg: Box::new(peer_public_key),
|
msg: Box::new(peer_public_key),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,20 +315,20 @@ impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
v3::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
msg: Box::new(init_message),
|
msg: Box::new(init_message),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
v3::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
msg: final_message,
|
msg: final_message,
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
v3::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
Self::QueryBandwidth {
|
Self::QueryBandwidth {
|
||||||
msg: Box::new(peer_public_key),
|
msg: Box::new(peer_public_key),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,7 +336,7 @@ impl From<v3::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
Self::TopUpBandwidth {
|
Self::TopUpBandwidth {
|
||||||
msg: top_up_message,
|
msg: top_up_message,
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,20 +350,20 @@ impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
v4::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
msg: Box::new(init_message),
|
msg: Box::new(init_message),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
v4::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
msg: final_message,
|
msg: final_message,
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
},
|
},
|
||||||
v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
v4::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
Self::QueryBandwidth {
|
Self::QueryBandwidth {
|
||||||
msg: Box::new(peer_public_key),
|
msg: Box::new(peer_public_key),
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,7 +371,42 @@ impl From<v4::request::AuthenticatorRequest> for AuthenticatorRequest {
|
|||||||
Self::TopUpBandwidth {
|
Self::TopUpBandwidth {
|
||||||
msg: top_up_message,
|
msg: top_up_message,
|
||||||
protocol: value.protocol,
|
protocol: value.protocol,
|
||||||
reply_to: value.reply_to,
|
reply_to: Some(value.reply_to),
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::request::AuthenticatorRequest> for AuthenticatorRequest {
|
||||||
|
fn from(value: v5::request::AuthenticatorRequest) -> Self {
|
||||||
|
match value.data {
|
||||||
|
v5::request::AuthenticatorRequestData::Initial(init_message) => Self::Initial {
|
||||||
|
msg: Box::new(init_message),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v5::request::AuthenticatorRequestData::Final(final_message) => Self::Final {
|
||||||
|
msg: final_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
},
|
||||||
|
v5::request::AuthenticatorRequestData::QueryBandwidth(peer_public_key) => {
|
||||||
|
Self::QueryBandwidth {
|
||||||
|
msg: Box::new(peer_public_key),
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
|
request_id: value.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
|
Self::TopUpBandwidth {
|
||||||
|
msg: top_up_message,
|
||||||
|
protocol: value.protocol,
|
||||||
|
reply_to: None,
|
||||||
request_id: value.request_id,
|
request_id: value.request_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,478 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
|
||||||
|
use crate::{v4, v5};
|
||||||
|
|
||||||
|
impl From<v4::request::AuthenticatorRequest> for v5::request::AuthenticatorRequest {
|
||||||
|
fn from(authenticator_request: v4::request::AuthenticatorRequest) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
data: authenticator_request.data.into(),
|
||||||
|
request_id: authenticator_request.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::request::AuthenticatorRequestData> for v5::request::AuthenticatorRequestData {
|
||||||
|
fn from(authenticator_request_data: v4::request::AuthenticatorRequestData) -> Self {
|
||||||
|
match authenticator_request_data {
|
||||||
|
v4::request::AuthenticatorRequestData::Initial(init_msg) => {
|
||||||
|
v5::request::AuthenticatorRequestData::Initial(init_msg.into())
|
||||||
|
}
|
||||||
|
v4::request::AuthenticatorRequestData::Final(final_msg) => {
|
||||||
|
v5::request::AuthenticatorRequestData::Final(Box::new((*final_msg).into()))
|
||||||
|
}
|
||||||
|
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
|
||||||
|
v5::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||||
|
}
|
||||||
|
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
|
v5::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::InitMessage> for v5::registration::InitMessage {
|
||||||
|
fn from(init_msg: v4::registration::InitMessage) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: init_msg.pub_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::FinalMessage> for v5::registration::FinalMessage {
|
||||||
|
fn from(final_msg: v4::registration::FinalMessage) -> Self {
|
||||||
|
Self {
|
||||||
|
gateway_client: final_msg.gateway_client.into(),
|
||||||
|
credential: final_msg.credential,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::GatewayClient> for v5::registration::GatewayClient {
|
||||||
|
fn from(gateway_client: v4::registration::GatewayClient) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: gateway_client.pub_key,
|
||||||
|
private_ips: gateway_client.private_ips.into(),
|
||||||
|
mac: gateway_client.mac.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::registration::GatewayClient> for v4::registration::GatewayClient {
|
||||||
|
fn from(gateway_client: v5::registration::GatewayClient) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: gateway_client.pub_key,
|
||||||
|
private_ips: gateway_client.private_ips.into(),
|
||||||
|
mac: gateway_client.mac.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::ClientMac> for v5::registration::ClientMac {
|
||||||
|
fn from(client_mac: v4::registration::ClientMac) -> Self {
|
||||||
|
Self::new((*client_mac).clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::registration::ClientMac> for v4::registration::ClientMac {
|
||||||
|
fn from(client_mac: v5::registration::ClientMac) -> Self {
|
||||||
|
Self::new((*client_mac).clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<v4::topup::TopUpMessage>> for Box<v5::topup::TopUpMessage> {
|
||||||
|
fn from(top_up_message: Box<v4::topup::TopUpMessage>) -> Self {
|
||||||
|
Box::new(v5::topup::TopUpMessage {
|
||||||
|
pub_key: top_up_message.pub_key,
|
||||||
|
credential: top_up_message.credential,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::AuthenticatorResponse> for v5::response::AuthenticatorResponse {
|
||||||
|
fn from(value: v4::response::AuthenticatorResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: value.protocol.service_provider_type,
|
||||||
|
},
|
||||||
|
data: value.data.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::AuthenticatorResponseData> for v5::response::AuthenticatorResponseData {
|
||||||
|
fn from(authenticator_response_data: v4::response::AuthenticatorResponseData) -> Self {
|
||||||
|
match authenticator_response_data {
|
||||||
|
v4::response::AuthenticatorResponseData::PendingRegistration(pending_response) => {
|
||||||
|
v5::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_response.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
v4::response::AuthenticatorResponseData::Registered(registered_response) => {
|
||||||
|
v5::response::AuthenticatorResponseData::Registered(registered_response.into())
|
||||||
|
}
|
||||||
|
v4::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => v5::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response.into(),
|
||||||
|
),
|
||||||
|
v4::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response) => {
|
||||||
|
v5::response::AuthenticatorResponseData::TopUpBandwidth(top_up_response.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::RegisteredResponse> for v5::response::RegisteredResponse {
|
||||||
|
fn from(value: v4::response::RegisteredResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply: value.reply.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::PendingRegistrationResponse> for v5::response::PendingRegistrationResponse {
|
||||||
|
fn from(value: v4::response::PendingRegistrationResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply: value.reply.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::RegistrationData> for v5::registration::RegistrationData {
|
||||||
|
fn from(value: v4::registration::RegistrationData) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: value.nonce,
|
||||||
|
gateway_data: value.gateway_data.into(),
|
||||||
|
wg_port: value.wg_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::registration::RegistrationData> for v4::registration::RegistrationData {
|
||||||
|
fn from(value: v5::registration::RegistrationData) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: value.nonce,
|
||||||
|
gateway_data: value.gateway_data.into(),
|
||||||
|
wg_port: value.wg_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::RemainingBandwidthResponse> for v5::response::RemainingBandwidthResponse {
|
||||||
|
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply: value.reply.map(Into::into),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::response::TopUpBandwidthResponse> for v5::response::TopUpBandwidthResponse {
|
||||||
|
fn from(value: v4::response::TopUpBandwidthResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply: value.reply.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::RegistredData> for v5::registration::RegistredData {
|
||||||
|
fn from(value: v4::registration::RegistredData) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: value.pub_key,
|
||||||
|
private_ips: value.private_ips.into(),
|
||||||
|
wg_port: value.wg_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::RemainingBandwidthData> for v5::registration::RemainingBandwidthData {
|
||||||
|
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
|
||||||
|
Self {
|
||||||
|
available_bandwidth: value.available_bandwidth,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v4::registration::IpPair> for v5::registration::IpPair {
|
||||||
|
fn from(value: v4::registration::IpPair) -> Self {
|
||||||
|
Self {
|
||||||
|
ipv4: value.ipv4,
|
||||||
|
ipv6: value.ipv6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v5::registration::IpPair> for v4::registration::IpPair {
|
||||||
|
fn from(value: v5::registration::IpPair) -> Self {
|
||||||
|
Self {
|
||||||
|
ipv4: value.ipv4,
|
||||||
|
ipv6: value.ipv6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
net::{Ipv4Addr, Ipv6Addr},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
|
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||||
|
use nym_sphinx::addressing::Recipient;
|
||||||
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
use x25519_dalek::PublicKey;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::{
|
||||||
|
util::tests::{CREDENTIAL_BYTES, RECIPIENT},
|
||||||
|
v4,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_initial_req() {
|
||||||
|
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let (msg, _) = v4::request::AuthenticatorRequest::new_initial_request(
|
||||||
|
v4::registration::InitMessage::new(pub_key),
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::request::AuthenticatorRequestData::Initial(v5::registration::InitMessage {
|
||||||
|
pub_key
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_final_req() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let local_secret = PrivateKey::new(&mut rng);
|
||||||
|
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||||
|
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
|
||||||
|
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
|
||||||
|
let ips = v4::registration::IpPair::new(ipv4, ipv6);
|
||||||
|
let nonce = 42;
|
||||||
|
let gateway_client = v4::registration::GatewayClient::new(
|
||||||
|
&local_secret,
|
||||||
|
(&remote_secret).into(),
|
||||||
|
ips,
|
||||||
|
nonce,
|
||||||
|
);
|
||||||
|
let credential = Some(CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap());
|
||||||
|
let final_message = v4::registration::FinalMessage {
|
||||||
|
gateway_client: gateway_client.clone(),
|
||||||
|
credential: credential.clone(),
|
||||||
|
};
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let (msg, _) =
|
||||||
|
v4::request::AuthenticatorRequest::new_final_request(final_message, reply_to);
|
||||||
|
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::request::AuthenticatorRequestData::Final(Box::new(
|
||||||
|
v5::registration::FinalMessage {
|
||||||
|
gateway_client: v5::registration::GatewayClient::new(
|
||||||
|
&local_secret,
|
||||||
|
(&remote_secret).into(),
|
||||||
|
v5::registration::IpPair::new(ipv4, ipv6),
|
||||||
|
nonce
|
||||||
|
),
|
||||||
|
credential
|
||||||
|
}
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_query_req() {
|
||||||
|
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let (msg, _) = v4::request::AuthenticatorRequest::new_query_request(pub_key, reply_to);
|
||||||
|
let upgraded_msg = v5::request::AuthenticatorRequest::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_pending_reg_resp() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let local_secret = PrivateKey::new(&mut rng);
|
||||||
|
let remote_secret = x25519_dalek::StaticSecret::random_from_rng(&mut rng);
|
||||||
|
let ipv4 = Ipv4Addr::from_str("10.10.10.10").unwrap();
|
||||||
|
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
|
||||||
|
let ips = v4::registration::IpPair::new(ipv4, ipv6);
|
||||||
|
let nonce = 42;
|
||||||
|
let wg_port = 51822;
|
||||||
|
let gateway_data = v4::registration::GatewayClient::new(
|
||||||
|
&local_secret,
|
||||||
|
(&remote_secret).into(),
|
||||||
|
ips,
|
||||||
|
nonce,
|
||||||
|
);
|
||||||
|
let registration_data = v4::registration::RegistrationData {
|
||||||
|
nonce,
|
||||||
|
gateway_data,
|
||||||
|
wg_port,
|
||||||
|
};
|
||||||
|
let request_id = 123;
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let msg = v4::response::AuthenticatorResponse::new_pending_registration_success(
|
||||||
|
registration_data,
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
);
|
||||||
|
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
v5::response::PendingRegistrationResponse {
|
||||||
|
request_id,
|
||||||
|
reply: v5::registration::RegistrationData {
|
||||||
|
nonce,
|
||||||
|
gateway_data: v5::registration::GatewayClient::new(
|
||||||
|
&local_secret,
|
||||||
|
(&remote_secret).into(),
|
||||||
|
v5::registration::IpPair::new(ipv4, ipv6),
|
||||||
|
nonce
|
||||||
|
),
|
||||||
|
wg_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_registered_resp() {
|
||||||
|
let pub_key = PeerPublicKey::new(PublicKey::from([0; 32]));
|
||||||
|
let ipv4 = Ipv4Addr::from_str("10.1.10.10").unwrap();
|
||||||
|
let ipv6 = Ipv6Addr::from_str("fc01::a0a").unwrap();
|
||||||
|
let private_ips = v4::registration::IpPair::new(ipv4, ipv6);
|
||||||
|
let wg_port = 51822;
|
||||||
|
let registred_data = v4::registration::RegistredData {
|
||||||
|
pub_key,
|
||||||
|
private_ips,
|
||||||
|
wg_port,
|
||||||
|
};
|
||||||
|
let request_id = 123;
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let msg = v4::response::AuthenticatorResponse::new_registered(
|
||||||
|
registred_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::response::AuthenticatorResponseData::Registered(v5::response::RegisteredResponse {
|
||||||
|
request_id,
|
||||||
|
reply: v5::registration::RegistredData {
|
||||||
|
wg_port,
|
||||||
|
pub_key,
|
||||||
|
private_ips: v5::registration::IpPair::new(ipv4, ipv6)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn upgrade_remaining_bandwidth_resp() {
|
||||||
|
let available_bandwidth = 42;
|
||||||
|
let remaining_bandwidth_data = Some(v4::registration::RemainingBandwidthData {
|
||||||
|
available_bandwidth,
|
||||||
|
});
|
||||||
|
let request_id = 123;
|
||||||
|
let reply_to = Recipient::try_from_base58_string(RECIPIENT).unwrap();
|
||||||
|
|
||||||
|
let msg = v4::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||||
|
remaining_bandwidth_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
);
|
||||||
|
let upgraded_msg = v5::response::AuthenticatorResponse::from(msg);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.protocol,
|
||||||
|
Protocol {
|
||||||
|
version: 5,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator
|
||||||
|
}
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
upgraded_msg.data,
|
||||||
|
v5::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
v5::response::RemainingBandwidthResponse {
|
||||||
|
request_id,
|
||||||
|
reply: Some(v5::registration::RemainingBandwidthData {
|
||||||
|
available_bandwidth,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
pub mod conversion;
|
||||||
|
pub mod registration;
|
||||||
|
pub mod request;
|
||||||
|
pub mod response;
|
||||||
|
pub mod topup;
|
||||||
|
|
||||||
|
pub const VERSION: u8 = 5;
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
// -2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use base64::{engine::general_purpose, Engine};
|
||||||
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
|
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
|
||||||
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
use std::time::SystemTime;
|
||||||
|
use std::{fmt, ops::Deref, str::FromStr};
|
||||||
|
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
use nym_crypto::asymmetric::encryption::PrivateKey;
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
use sha2::Sha256;
|
||||||
|
|
||||||
|
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
|
||||||
|
pub type PrivateIPs = HashMap<IpPair, Taken>;
|
||||||
|
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
pub type HmacSha256 = Hmac<Sha256>;
|
||||||
|
|
||||||
|
pub type Nonce = u64;
|
||||||
|
pub type Taken = Option<SystemTime>;
|
||||||
|
|
||||||
|
pub const BANDWIDTH_CAP_PER_DAY: u64 = 250 * 1024 * 1024 * 1024; // 250 GB
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
|
pub struct IpPair {
|
||||||
|
pub ipv4: Ipv4Addr,
|
||||||
|
pub ipv6: Ipv6Addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpPair {
|
||||||
|
pub fn new(ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Self {
|
||||||
|
IpPair { ipv4, ipv6 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(Ipv4Addr, Ipv6Addr)> for IpPair {
|
||||||
|
fn from((ipv4, ipv6): (Ipv4Addr, Ipv6Addr)) -> Self {
|
||||||
|
IpPair { ipv4, ipv6 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IpPair {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "({}, {})", self.ipv4, self.ipv6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IpAddr> for IpPair {
|
||||||
|
fn from(value: IpAddr) -> Self {
|
||||||
|
let (before_last_byte, last_byte) = match value {
|
||||||
|
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr.octets()[2], ipv4_addr.octets()[3]),
|
||||||
|
std::net::IpAddr::V6(ipv6_addr) => (ipv6_addr.octets()[14], ipv6_addr.octets()[15]),
|
||||||
|
};
|
||||||
|
let last_bytes = ((before_last_byte as u16) << 8) | last_byte as u16;
|
||||||
|
let ipv4 = Ipv4Addr::new(
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[0],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V4.octets()[1],
|
||||||
|
before_last_byte,
|
||||||
|
last_byte,
|
||||||
|
);
|
||||||
|
let ipv6 = Ipv6Addr::new(
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[0],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[1],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[2],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[3],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[4],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[5],
|
||||||
|
WG_TUN_DEVICE_IP_ADDRESS_V6.segments()[6],
|
||||||
|
last_bytes,
|
||||||
|
);
|
||||||
|
IpPair::new(ipv4, ipv6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct InitMessage {
|
||||||
|
/// Base64 encoded x25519 public key
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InitMessage {
|
||||||
|
pub fn new(pub_key: PeerPublicKey) -> Self {
|
||||||
|
InitMessage { pub_key }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct FinalMessage {
|
||||||
|
/// Gateway client data
|
||||||
|
pub gateway_client: GatewayClient,
|
||||||
|
|
||||||
|
/// Ecash credential
|
||||||
|
pub credential: Option<CredentialSpendingData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct RegistrationData {
|
||||||
|
pub nonce: u64,
|
||||||
|
pub gateway_data: GatewayClient,
|
||||||
|
pub wg_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct RegistredData {
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
pub private_ips: IpPair,
|
||||||
|
pub wg_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct RemainingBandwidthData {
|
||||||
|
pub available_bandwidth: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
|
||||||
|
/// Gateway/Nym node can then verify pub_key payload using the same process
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct GatewayClient {
|
||||||
|
/// Base64 encoded x25519 public key
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
|
||||||
|
/// Assigned private IPs (v4 and v6)
|
||||||
|
pub private_ips: IpPair,
|
||||||
|
|
||||||
|
/// Sha256 hmac on the data (alongside the prior nonce)
|
||||||
|
pub mac: ClientMac,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GatewayClient {
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
pub fn new(
|
||||||
|
local_secret: &PrivateKey,
|
||||||
|
remote_public: x25519_dalek::PublicKey,
|
||||||
|
private_ips: IpPair,
|
||||||
|
nonce: u64,
|
||||||
|
) -> Self {
|
||||||
|
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
|
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
|
||||||
|
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
|
||||||
|
|
||||||
|
let dh = static_secret.diffie_hellman(&remote_public);
|
||||||
|
|
||||||
|
// TODO: change that to use our nym_crypto::hmac module instead
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
|
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||||
|
.expect("x25519 shared secret is always 32 bytes long");
|
||||||
|
|
||||||
|
mac.update(local_public.as_bytes());
|
||||||
|
mac.update(private_ips.to_string().as_bytes());
|
||||||
|
mac.update(&nonce.to_le_bytes());
|
||||||
|
|
||||||
|
GatewayClient {
|
||||||
|
pub_key: PeerPublicKey::new(local_public),
|
||||||
|
private_ips,
|
||||||
|
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reusable secret should be gateways Wireguard PK
|
||||||
|
// Client should perform this step when generating its payload, using its own WG PK
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
|
||||||
|
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
|
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
|
||||||
|
|
||||||
|
let dh = static_secret.diffie_hellman(&self.pub_key);
|
||||||
|
|
||||||
|
// TODO: change that to use our nym_crypto::hmac module instead
|
||||||
|
#[allow(clippy::expect_used)]
|
||||||
|
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
|
||||||
|
.expect("x25519 shared secret is always 32 bytes long");
|
||||||
|
|
||||||
|
mac.update(self.pub_key.as_bytes());
|
||||||
|
mac.update(self.private_ips.to_string().as_bytes());
|
||||||
|
mac.update(&nonce.to_le_bytes());
|
||||||
|
|
||||||
|
mac.verify_slice(&self.mac)
|
||||||
|
.map_err(|source| Error::FailedClientMacVerification {
|
||||||
|
client: self.pub_key.to_string(),
|
||||||
|
source,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pub_key(&self) -> PeerPublicKey {
|
||||||
|
self.pub_key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
|
||||||
|
// TODO2: rely on our internal crypto/hmac
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ClientMac(Vec<u8>);
|
||||||
|
|
||||||
|
impl fmt::Display for ClientMac {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", general_purpose::STANDARD.encode(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ClientMac {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(mac: Vec<u8>) -> Self {
|
||||||
|
ClientMac(mac)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ClientMac {
|
||||||
|
type Target = Vec<u8>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ClientMac {
|
||||||
|
type Err = Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mac_bytes: Vec<u8> =
|
||||||
|
general_purpose::STANDARD
|
||||||
|
.decode(s)
|
||||||
|
.map_err(|source| Error::MalformedClientMac {
|
||||||
|
mac: s.to_string(),
|
||||||
|
source,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(ClientMac(mac_bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for ClientMac {
|
||||||
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
|
||||||
|
serializer.serialize_str(&encoded_key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for ClientMac {
|
||||||
|
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||||
|
let encoded_key = String::deserialize(deserializer)?;
|
||||||
|
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use nym_crypto::asymmetric::encryption;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_ip_pair() {
|
||||||
|
let ipv4: IpAddr = Ipv4Addr::from_str("10.1.10.50").unwrap().into();
|
||||||
|
let ipv6: IpAddr = Ipv6Addr::from_str("fc01::0a32").unwrap().into();
|
||||||
|
|
||||||
|
assert_eq!(IpPair::from(ipv4), IpPair::from(ipv6));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "verify")]
|
||||||
|
fn client_request_roundtrip() {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
|
||||||
|
let client_key_pair = encryption::KeyPair::new(&mut rng);
|
||||||
|
|
||||||
|
let nonce = 1234567890;
|
||||||
|
|
||||||
|
let client = GatewayClient::new(
|
||||||
|
client_key_pair.private_key(),
|
||||||
|
x25519_dalek::PublicKey::from(gateway_key_pair.public_key().to_bytes()),
|
||||||
|
IpPair::new("10.0.0.42".parse().unwrap(), "fc00::42".parse().unwrap()),
|
||||||
|
nonce,
|
||||||
|
);
|
||||||
|
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
registration::{FinalMessage, InitMessage},
|
||||||
|
topup::TopUpMessage,
|
||||||
|
};
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
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, PartialEq)]
|
||||||
|
pub struct AuthenticatorRequest {
|
||||||
|
pub protocol: Protocol,
|
||||||
|
pub data: AuthenticatorRequestData,
|
||||||
|
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) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::Initial(init_message),
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_final_request(final_message: FinalMessage) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::Final(Box::new(final_message)),
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_query_request(peer_public_key: PeerPublicKey) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_topup_request(top_up_message: TopUpMessage) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::TopUpBandwidth(Box::new(top_up_message)),
|
||||||
|
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, PartialEq)]
|
||||||
|
pub enum AuthenticatorRequestData {
|
||||||
|
Initial(InitMessage),
|
||||||
|
Final(Box<FinalMessage>),
|
||||||
|
QueryBandwidth(PeerPublicKey),
|
||||||
|
TopUpBandwidth(Box<TopUpMessage>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_first_bytes_protocol() {
|
||||||
|
let version = 5;
|
||||||
|
let data = AuthenticatorRequest {
|
||||||
|
protocol: Protocol {
|
||||||
|
version,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::Initial(InitMessage::new(
|
||||||
|
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
|
||||||
|
)),
|
||||||
|
request_id: 1,
|
||||||
|
};
|
||||||
|
let bytes = *data.to_bytes().unwrap().first_chunk::<2>().unwrap();
|
||||||
|
assert_eq!(bytes, [version, ServiceProviderType::Authenticator as u8]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::make_bincode_serializer;
|
||||||
|
|
||||||
|
use super::VERSION;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct AuthenticatorResponse {
|
||||||
|
pub protocol: Protocol,
|
||||||
|
pub data: AuthenticatorResponseData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthenticatorResponse {
|
||||||
|
pub fn new_pending_registration_success(
|
||||||
|
registration_data: RegistrationData,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
|
||||||
|
reply: registration_data,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_registered(registred_data: RegistredData, request_id: u64) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::Registered(RegisteredResponse {
|
||||||
|
reply: registred_data,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_remaining_bandwidth(
|
||||||
|
remaining_bandwidth_data: Option<RemainingBandwidthData>,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
|
||||||
|
reply: remaining_bandwidth_data,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_topup_bandwidth(
|
||||||
|
remaining_bandwidth_data: RemainingBandwidthData,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
|
||||||
|
reply: remaining_bandwidth_data,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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),
|
||||||
|
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
|
||||||
|
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub enum AuthenticatorResponseData {
|
||||||
|
PendingRegistration(PendingRegistrationResponse),
|
||||||
|
Registered(RegisteredResponse),
|
||||||
|
RemainingBandwidth(RemainingBandwidthResponse),
|
||||||
|
TopUpBandwidth(TopUpBandwidthResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct PendingRegistrationResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply: RegistrationData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct RegisteredResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply: RegistredData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct RemainingBandwidthResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply: Option<RemainingBandwidthData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct TopUpBandwidthResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply: RemainingBandwidthData,
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use nym_credentials_interface::CredentialSpendingData;
|
||||||
|
use nym_wireguard_types::PeerPublicKey;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct TopUpMessage {
|
||||||
|
/// Base64 encoded x25519 public key
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
|
||||||
|
/// Ecash credential
|
||||||
|
pub credential: CredentialSpendingData,
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@ const DEFAULT_MINIMUM_REPLY_SURB_THRESHOLD_BUFFER: usize = 0;
|
|||||||
// define how much to request at once
|
// define how much to request at once
|
||||||
// clients/client-core/src/client/replies/reply_controller.rs
|
// clients/client-core/src/client/replies/reply_controller.rs
|
||||||
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10;
|
||||||
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100;
|
const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 50;
|
||||||
|
|
||||||
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500;
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,12 @@ pub enum PreparationError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
NymTopologyError(#[from] NymTopologyError),
|
NymTopologyError(#[from] NymTopologyError),
|
||||||
|
|
||||||
#[error("The received message cannot be sent using a single reply surb. It ended up getting split into {fragments} fragments.")]
|
#[error("message too long for a single SURB, splitting into {fragments} fragments.")]
|
||||||
MessageTooLongForSingleSurb { fragments: usize },
|
MessageTooLongForSingleSurb { fragments: usize },
|
||||||
|
|
||||||
#[error("Not enough reply SURBs to send the message. We have {available} available and require at least {required}.")]
|
#[error(
|
||||||
|
"not enough reply SURBs to send the message, available: {available} required: {required}."
|
||||||
|
)]
|
||||||
NotEnoughSurbs { available: usize, required: usize },
|
NotEnoughSurbs { available: usize, required: usize },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -746,7 +746,7 @@ where
|
|||||||
.request_additional_reply_surbs(target, request_size)
|
.request_additional_reply_surbs(target, request_size)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("failed to request additional surbs... - {err}")
|
info!("{err}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ serde_json = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
||||||
|
# used for decoding text responses (they were already implicitly included)
|
||||||
|
bytes = { workspace = true }
|
||||||
|
encoding_rs = { workspace = true }
|
||||||
|
mime = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
nym-bin-common = { path = "../bin-common" }
|
nym-bin-common = { path = "../bin-common" }
|
||||||
|
|
||||||
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
[target."cfg(not(target_arch = \"wasm32\"))".dependencies]
|
||||||
@@ -32,4 +38,4 @@ workspace = true
|
|||||||
features = ["tokio"]
|
features = ["tokio"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { workspace = true, features=["rt", "macros"] }
|
tokio = { workspace = true, features = ["rt", "macros"] }
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ use thiserror::Error;
|
|||||||
use tracing::{instrument, warn};
|
use tracing::{instrument, warn};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
use http::HeaderMap;
|
||||||
|
pub use reqwest::IntoUrl;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use reqwest::IntoUrl;
|
|
||||||
|
|
||||||
mod user_agent;
|
mod user_agent;
|
||||||
pub use user_agent::UserAgent;
|
pub use user_agent::UserAgent;
|
||||||
|
|
||||||
@@ -210,6 +210,12 @@ pub enum HttpClientError<E: Display = String> {
|
|||||||
#[error("failed to resolve request. status: '{status}', additional error message: {error}")]
|
#[error("failed to resolve request. status: '{status}', additional error message: {error}")]
|
||||||
EndpointFailure { status: StatusCode, error: E },
|
EndpointFailure { status: StatusCode, error: E },
|
||||||
|
|
||||||
|
#[error("failed to decode response body: {source} from {content}")]
|
||||||
|
ResponseDecodeFailure {
|
||||||
|
source: serde_json::Error,
|
||||||
|
content: String,
|
||||||
|
},
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
#[error("the request has timed out")]
|
#[error("the request has timed out")]
|
||||||
RequestTimeout,
|
RequestTimeout,
|
||||||
@@ -849,6 +855,26 @@ fn sanitize_url<K: AsRef<str>, V: AsRef<str>>(
|
|||||||
url
|
url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_as_text(bytes: &bytes::Bytes, headers: HeaderMap) -> String {
|
||||||
|
use encoding_rs::{Encoding, UTF_8};
|
||||||
|
use mime::Mime;
|
||||||
|
|
||||||
|
let content_type = headers
|
||||||
|
.get(http::header::CONTENT_TYPE)
|
||||||
|
.and_then(|value| value.to_str().ok())
|
||||||
|
.and_then(|value| value.parse::<Mime>().ok());
|
||||||
|
|
||||||
|
let encoding_name = content_type
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|mime| mime.get_param("charset").map(|charset| charset.as_str()))
|
||||||
|
.unwrap_or("utf-8");
|
||||||
|
|
||||||
|
let encoding = Encoding::for_label(encoding_name.as_bytes()).unwrap_or(UTF_8);
|
||||||
|
|
||||||
|
let (text, _, _) = encoding.decode(bytes);
|
||||||
|
text.into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempt to parse a json object from an HTTP response
|
/// Attempt to parse a json object from an HTTP response
|
||||||
#[instrument(level = "debug", skip_all)]
|
#[instrument(level = "debug", skip_all)]
|
||||||
pub async fn parse_response<T, E>(res: Response, allow_empty: bool) -> Result<T, HttpClientError<E>>
|
pub async fn parse_response<T, E>(res: Response, allow_empty: bool) -> Result<T, HttpClientError<E>>
|
||||||
@@ -864,21 +890,23 @@ where
|
|||||||
return Err(HttpClientError::EmptyResponse { status });
|
return Err(HttpClientError::EmptyResponse { status });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let headers = res.headers().clone();
|
||||||
|
tracing::trace!("headers: {:?}", headers);
|
||||||
|
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
#[cfg(debug_assertions)]
|
// internally reqwest is first retrieving bytes and then performing parsing via serde_json
|
||||||
{
|
// (and similarly does the same thing for text())
|
||||||
let text = res.text().await.inspect_err(|err| {
|
let full = res.bytes().await?;
|
||||||
tracing::error!("Couldn't even get response text: {err}");
|
match serde_json::from_slice(&full) {
|
||||||
})?;
|
Ok(data) => Ok(data),
|
||||||
tracing::trace!("Result:\n{:#?}", text);
|
Err(err) => {
|
||||||
|
let content = decode_as_text(&full, headers);
|
||||||
serde_json::from_str(&text)
|
Err(HttpClientError::ResponseDecodeFailure {
|
||||||
.map_err(|err| HttpClientError::GenericRequestFailure(err.to_string()))
|
source: err,
|
||||||
|
content,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
Ok(res.json().await?)
|
|
||||||
} else if res.status() == StatusCode::NOT_FOUND {
|
} else if res.status() == StatusCode::NOT_FOUND {
|
||||||
Err(HttpClientError::NotFound)
|
Err(HttpClientError::NotFound)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ repository = { workspace = true }
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pem = { workspace = true }
|
pem = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
@@ -6,6 +6,7 @@ use pem::Pem;
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
|
|
||||||
@@ -46,6 +47,10 @@ where
|
|||||||
T: PemStorableKey,
|
T: PemStorableKey,
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
{
|
{
|
||||||
|
debug!(
|
||||||
|
"attempting to load key with the following pem type: {}",
|
||||||
|
T::pem_type()
|
||||||
|
);
|
||||||
let key_pem = read_pem_file(path)?;
|
let key_pem = read_pem_file(path)?;
|
||||||
|
|
||||||
if T::pem_type() != key_pem.tag {
|
if T::pem_type() != key_pem.tag {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "explorer-api"
|
name = "explorer-api"
|
||||||
version = "1.1.47"
|
version = "1.1.48"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
|
|||||||
@@ -426,6 +426,11 @@ impl<R, S> FreshHandler<R, S> {
|
|||||||
return Ok(2);
|
return Ok(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// a v4 gateway will understand v3 requests (aes256gcm-siv)
|
||||||
|
if client_protocol_version == 3 {
|
||||||
|
return Ok(3);
|
||||||
|
}
|
||||||
|
|
||||||
// we can't handle clients with higher protocol than ours
|
// we can't handle clients with higher protocol than ours
|
||||||
// (perhaps we could try to negotiate downgrade on our end? sounds like a nice future improvement)
|
// (perhaps we could try to negotiate downgrade on our end? sounds like a nice future improvement)
|
||||||
if client_protocol_version <= CURRENT_PROTOCOL_VERSION {
|
if client_protocol_version <= CURRENT_PROTOCOL_VERSION {
|
||||||
|
|||||||
+2
-2
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-api"
|
name = "nym-api"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
version = "1.1.51"
|
version = "1.1.53"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
@@ -144,4 +144,4 @@ rand_chacha = { workspace = true }
|
|||||||
sha2 = "0.9"
|
sha2 = "0.9"
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use nym_dkg::bte::keys::KeyPair as DkgKeyPair;
|
|||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use thiserror::__private::AsDisplay;
|
use thiserror::__private::AsDisplay;
|
||||||
use tracing::warn;
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
pub(crate) fn init_bte_keypair<R: RngCore + CryptoRng>(
|
pub(crate) fn init_bte_keypair<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
@@ -39,17 +39,20 @@ pub(crate) fn load_bte_keypair(config: &config::EcashSigner) -> anyhow::Result<D
|
|||||||
pub(crate) fn load_ecash_keypair_if_exists(
|
pub(crate) fn load_ecash_keypair_if_exists(
|
||||||
config: &config::EcashSigner,
|
config: &config::EcashSigner,
|
||||||
) -> anyhow::Result<Option<KeyPairWithEpoch>> {
|
) -> anyhow::Result<Option<KeyPairWithEpoch>> {
|
||||||
|
let storage_path = &config.storage_paths.ecash_key_path;
|
||||||
|
debug!(
|
||||||
|
"attempting to ecash keypair from {}",
|
||||||
|
storage_path.display()
|
||||||
|
);
|
||||||
if !config.storage_paths.ecash_key_path.exists() {
|
if !config.storage_paths.ecash_key_path.exists() {
|
||||||
|
debug!("the provided filepath doesn't exist - the key won't be loaded");
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(ecash_key) =
|
let ecash_key =
|
||||||
nym_pemstore::load_key::<KeyPairWithEpoch, _>(&config.storage_paths.ecash_key_path)
|
nym_pemstore::load_key::<KeyPairWithEpoch, _>(&config.storage_paths.ecash_key_path)
|
||||||
{
|
.context("failed to load ecash key")?;
|
||||||
return Ok(Some(ecash_key));
|
Ok(Some(ecash_key))
|
||||||
}
|
|
||||||
|
|
||||||
bail!("ecash key load failure")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the keys can be considered valid if they were generated for the current dkg epoch
|
// the keys can be considered valid if they were generated for the current dkg epoch
|
||||||
|
|||||||
@@ -33,14 +33,17 @@ impl DailyMerkleTree {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|l| (l.merkle_index, l))
|
.map(|l| (l.merkle_index, l))
|
||||||
.collect();
|
.collect();
|
||||||
|
let total_leaves = leaves.len();
|
||||||
|
|
||||||
let mut sorted_leaves = Vec::new();
|
let mut sorted_leaves = Vec::new();
|
||||||
for i in 0..leaves.len() {
|
for i in 0..leaves.len() {
|
||||||
if let Some(next_leaf) = leaves.remove(&i) {
|
if let Some(next_leaf) = leaves.remove(&i) {
|
||||||
sorted_leaves.push(next_leaf);
|
sorted_leaves.push(next_leaf);
|
||||||
} else {
|
} else {
|
||||||
let lost = leaves.len() - i + 1;
|
let lost = total_leaves - i + 1;
|
||||||
error!("failed to produce consistent merkle tree. there was no leaf with index {i}. at least {lost} leaves got lost")
|
error!("failed to produce consistent merkle tree. there was no leaf with index {i}. at least {lost} leaves got lost");
|
||||||
|
// we have to drop all data above that height because we can't rebuild the full tree
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "nym-node"
|
name = "nym-node"
|
||||||
version = "1.6.0"
|
version = "1.6.1"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
@@ -101,4 +101,4 @@ cargo_metadata = { workspace = true }
|
|||||||
|
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ pub struct Debug {
|
|||||||
/// The maximum number of client connections the gateway will keep open at once.
|
/// The maximum number of client connections the gateway will keep open at once.
|
||||||
pub maximum_open_connections: usize,
|
pub maximum_open_connections: usize,
|
||||||
|
|
||||||
/// Specifies the minimum performance of mixnodes in the network that are to be used in internal topologies
|
|
||||||
/// of the services providers
|
|
||||||
pub minimum_mix_performance: u8,
|
|
||||||
|
|
||||||
/// Defines the maximum age of a signed authentication request before it's deemed too stale to process.
|
/// Defines the maximum age of a signed authentication request before it's deemed too stale to process.
|
||||||
pub maximum_auth_request_age: Duration,
|
pub maximum_auth_request_age: Duration,
|
||||||
|
|
||||||
@@ -65,10 +61,9 @@ pub struct Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Debug {
|
impl Debug {
|
||||||
|
pub const DEFAULT_MAXIMUM_OPEN_CONNECTIONS: usize = 8192;
|
||||||
pub const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
|
pub const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
|
||||||
pub const DEFAULT_MINIMUM_MIX_PERFORMANCE: u8 = 50;
|
|
||||||
pub const DEFAULT_MAXIMUM_AUTH_REQUEST_AGE: Duration = Duration::from_secs(30);
|
pub const DEFAULT_MAXIMUM_AUTH_REQUEST_AGE: Duration = Duration::from_secs(30);
|
||||||
const DEFAULT_MAXIMUM_OPEN_CONNECTIONS: usize = 8192;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Debug {
|
impl Default for Debug {
|
||||||
@@ -77,7 +72,6 @@ impl Default for Debug {
|
|||||||
message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
|
message_retrieval_limit: Self::DEFAULT_MESSAGE_RETRIEVAL_LIMIT,
|
||||||
maximum_open_connections: Self::DEFAULT_MAXIMUM_OPEN_CONNECTIONS,
|
maximum_open_connections: Self::DEFAULT_MAXIMUM_OPEN_CONNECTIONS,
|
||||||
maximum_auth_request_age: Self::DEFAULT_MAXIMUM_AUTH_REQUEST_AGE,
|
maximum_auth_request_age: Self::DEFAULT_MAXIMUM_AUTH_REQUEST_AGE,
|
||||||
minimum_mix_performance: Self::DEFAULT_MINIMUM_MIX_PERFORMANCE,
|
|
||||||
stale_messages: Default::default(),
|
stale_messages: Default::default(),
|
||||||
client_bandwidth: Default::default(),
|
client_bandwidth: Default::default(),
|
||||||
zk_nym_tickets: Default::default(),
|
zk_nym_tickets: Default::default(),
|
||||||
|
|||||||
Generated
+7
-4
@@ -465,9 +465,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.5.0"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -1487,9 +1487,9 @@ checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.32"
|
version = "0.8.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
@@ -3463,8 +3463,11 @@ name = "nym-http-api-client"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
"bytes",
|
||||||
|
"encoding_rs",
|
||||||
"hickory-resolver",
|
"hickory-resolver",
|
||||||
"http 1.1.0",
|
"http 1.1.0",
|
||||||
|
"mime",
|
||||||
"nym-bin-common",
|
"nym-bin-common",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"reqwest 0.12.4",
|
"reqwest 0.12.4",
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ tap = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
toml = { workspace = true }
|
toml = { workspace = true }
|
||||||
|
tempfile = { workspace = true }
|
||||||
|
|
||||||
# tcpproxy dependencies
|
# tcpproxy dependencies
|
||||||
clap = { workspace = true, features = ["derive"] }
|
clap = { workspace = true, features = ["derive"] }
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
use nym_sdk::mixnet::{
|
use nym_sdk::mixnet::{
|
||||||
AnonymousSenderTag, MixnetClientBuilder, MixnetMessageSender, ReconstructedMessage,
|
self, AnonymousSenderTag, MixnetClientBuilder, MixnetMessageSender, ReconstructedMessage,
|
||||||
StoragePaths,
|
StoragePaths,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
nym_bin_common::logging::setup_logging();
|
nym_bin_common::logging::setup_logging();
|
||||||
|
|
||||||
// Specify some config options
|
// Specify some config options
|
||||||
let config_dir = PathBuf::from("/tmp/surb-example");
|
let config_dir: PathBuf = TempDir::new().unwrap().path().to_path_buf();
|
||||||
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
|
let storage_paths = StoragePaths::new_from_dir(&config_dir).unwrap();
|
||||||
|
|
||||||
// Create the client with a storage backend, and enable it by giving it some paths. If keys
|
// Create the client with a storage backend, and enable it by giving it some paths. If keys
|
||||||
@@ -28,8 +29,16 @@ async fn main() {
|
|||||||
println!("\nOur client nym address is: {our_address}");
|
println!("\nOur client nym address is: {our_address}");
|
||||||
|
|
||||||
// Send a message through the mixnet to ourselves using our nym address
|
// Send a message through the mixnet to ourselves using our nym address
|
||||||
|
// client
|
||||||
|
// .send_plain_message(*our_address, "hello there")
|
||||||
|
// .await
|
||||||
|
// .unwrap();
|
||||||
client
|
client
|
||||||
.send_plain_message(*our_address, "hello there")
|
.send_message(
|
||||||
|
*our_address,
|
||||||
|
"hello there",
|
||||||
|
mixnet::IncludedSurbs::Amount(40),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
@@ -111,16 +111,16 @@ pub(crate) async fn execute(args: &Request) -> Result<(), AuthenticatorError> {
|
|||||||
let authenticator_recipient = Recipient::from_str(&args.authenticator_recipient)?;
|
let authenticator_recipient = Recipient::from_str(&args.authenticator_recipient)?;
|
||||||
let (request, _) = match request_data {
|
let (request, _) = match request_data {
|
||||||
AuthenticatorRequestData::Initial(init_message) => {
|
AuthenticatorRequestData::Initial(init_message) => {
|
||||||
AuthenticatorRequest::new_initial_request(init_message, *mixnet_client.nym_address())
|
AuthenticatorRequest::new_initial_request(init_message)
|
||||||
}
|
}
|
||||||
AuthenticatorRequestData::Final(final_message) => {
|
AuthenticatorRequestData::Final(final_message) => {
|
||||||
AuthenticatorRequest::new_final_request(*final_message, *mixnet_client.nym_address())
|
AuthenticatorRequest::new_final_request(*final_message)
|
||||||
}
|
}
|
||||||
AuthenticatorRequestData::QueryBandwidth(query_message) => {
|
AuthenticatorRequestData::QueryBandwidth(query_message) => {
|
||||||
AuthenticatorRequest::new_query_request(query_message, *mixnet_client.nym_address())
|
AuthenticatorRequest::new_query_request(query_message)
|
||||||
}
|
}
|
||||||
AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
|
||||||
AuthenticatorRequest::new_topup_request(*top_up_message, *mixnet_client.nym_address())
|
AuthenticatorRequest::new_topup_request(*top_up_message)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mixnet_client
|
mixnet_client
|
||||||
|
|||||||
@@ -89,6 +89,9 @@ pub enum AuthenticatorError {
|
|||||||
#[error("unknown version number")]
|
#[error("unknown version number")]
|
||||||
UnknownVersion,
|
UnknownVersion,
|
||||||
|
|
||||||
|
#[error("missing reply_to for old client")]
|
||||||
|
MissingReplyToForOldClient,
|
||||||
|
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
PublicKey(#[from] nym_wireguard_types::Error),
|
PublicKey(#[from] nym_wireguard_types::Error),
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use nym_authenticator_requests::{
|
|||||||
AuthenticatorRequest, AuthenticatorVersion, FinalMessage, InitMessage,
|
AuthenticatorRequest, AuthenticatorVersion, FinalMessage, InitMessage,
|
||||||
QueryBandwidthMessage, TopUpMessage,
|
QueryBandwidthMessage, TopUpMessage,
|
||||||
},
|
},
|
||||||
v1, v2, v3, v4, CURRENT_VERSION,
|
v1, v2, v3, v4, v5, CURRENT_VERSION,
|
||||||
};
|
};
|
||||||
use nym_credential_verification::{
|
use nym_credential_verification::{
|
||||||
bandwidth_storage_manager::BandwidthStorageManager, ecash::EcashManager,
|
bandwidth_storage_manager::BandwidthStorageManager, ecash::EcashManager,
|
||||||
@@ -42,7 +42,7 @@ use rand::{prelude::IteratorRandom, thread_rng};
|
|||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tokio_stream::wrappers::IntervalStream;
|
use tokio_stream::wrappers::IntervalStream;
|
||||||
|
|
||||||
type AuthenticatorHandleResult = Result<(Vec<u8>, Recipient)>;
|
type AuthenticatorHandleResult = Result<(Vec<u8>, Option<Recipient>)>;
|
||||||
const DEFAULT_REGISTRATION_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
|
const DEFAULT_REGISTRATION_TIMEOUT_CHECK: Duration = Duration::from_secs(60); // 1 minute
|
||||||
|
|
||||||
pub(crate) struct RegistredAndFree {
|
pub(crate) struct RegistredAndFree {
|
||||||
@@ -155,7 +155,7 @@ impl MixnetListener {
|
|||||||
init_message: Box<dyn InitMessage + Send + Sync + 'static>,
|
init_message: Box<dyn InitMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
) -> AuthenticatorHandleResult {
|
) -> AuthenticatorHandleResult {
|
||||||
let remote_public = init_message.pub_key();
|
let remote_public = init_message.pub_key();
|
||||||
let nonce: u64 = fastrand::u64(..);
|
let nonce: u64 = fastrand::u64(..);
|
||||||
@@ -178,7 +178,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -198,7 +198,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -218,7 +218,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -228,12 +228,26 @@ impl MixnetListener {
|
|||||||
AuthenticatorVersion::V4 => {
|
AuthenticatorVersion::V4 => {
|
||||||
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
||||||
v4::registration::RegistrationData {
|
v4::registration::RegistrationData {
|
||||||
|
nonce: registration_data.nonce,
|
||||||
|
gateway_data: registration_data.gateway_data.clone().into(),
|
||||||
|
wg_port: registration_data.wg_port,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| {
|
||||||
|
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V5 => {
|
||||||
|
v5::response::AuthenticatorResponse::new_pending_registration_success(
|
||||||
|
v5::registration::RegistrationData {
|
||||||
nonce: registration_data.nonce,
|
nonce: registration_data.nonce,
|
||||||
gateway_data: registration_data.gateway_data.clone(),
|
gateway_data: registration_data.gateway_data.clone(),
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -272,7 +286,7 @@ impl MixnetListener {
|
|||||||
private_ip: allowed_ipv4.into(),
|
private_ip: allowed_ipv4.into(),
|
||||||
wg_port: self.config.authenticator.announced_port,
|
wg_port: self.config.authenticator.announced_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -285,7 +299,7 @@ impl MixnetListener {
|
|||||||
private_ip: allowed_ipv4.into(),
|
private_ip: allowed_ipv4.into(),
|
||||||
wg_port: self.config.authenticator.announced_port,
|
wg_port: self.config.authenticator.announced_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -298,7 +312,7 @@ impl MixnetListener {
|
|||||||
private_ip: allowed_ipv4.into(),
|
private_ip: allowed_ipv4.into(),
|
||||||
wg_port: self.config.authenticator.announced_port,
|
wg_port: self.config.authenticator.announced_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -311,7 +325,19 @@ impl MixnetListener {
|
|||||||
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||||
wg_port: self.config.authenticator.announced_port,
|
wg_port: self.config.authenticator.announced_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| {
|
||||||
|
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||||
|
})?,
|
||||||
|
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_registered(
|
||||||
|
v5::registration::RegistredData {
|
||||||
|
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||||
|
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||||
|
wg_port: self.config.authenticator.announced_port,
|
||||||
|
},
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -360,7 +386,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -380,7 +406,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -400,7 +426,7 @@ impl MixnetListener {
|
|||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -410,12 +436,26 @@ impl MixnetListener {
|
|||||||
AuthenticatorVersion::V4 => {
|
AuthenticatorVersion::V4 => {
|
||||||
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
v4::response::AuthenticatorResponse::new_pending_registration_success(
|
||||||
v4::registration::RegistrationData {
|
v4::registration::RegistrationData {
|
||||||
|
nonce: registration_data.nonce,
|
||||||
|
gateway_data: registration_data.gateway_data.into(),
|
||||||
|
wg_port: registration_data.wg_port,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| {
|
||||||
|
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V5 => {
|
||||||
|
v5::response::AuthenticatorResponse::new_pending_registration_success(
|
||||||
|
v5::registration::RegistrationData {
|
||||||
nonce: registration_data.nonce,
|
nonce: registration_data.nonce,
|
||||||
gateway_data: registration_data.gateway_data,
|
gateway_data: registration_data.gateway_data,
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
request_id,
|
request_id,
|
||||||
reply_to,
|
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@@ -433,7 +473,7 @@ impl MixnetListener {
|
|||||||
final_message: Box<dyn FinalMessage + Send + Sync + 'static>,
|
final_message: Box<dyn FinalMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
) -> AuthenticatorHandleResult {
|
) -> AuthenticatorHandleResult {
|
||||||
let mut registred_and_free = self.registred_and_free.write().await;
|
let mut registred_and_free = self.registred_and_free.write().await;
|
||||||
let registration_data = registred_and_free
|
let registration_data = registred_and_free
|
||||||
@@ -500,7 +540,7 @@ impl MixnetListener {
|
|||||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -511,7 +551,7 @@ impl MixnetListener {
|
|||||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -522,18 +562,28 @@ impl MixnetListener {
|
|||||||
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
private_ip: registration_data.gateway_data.private_ips.ipv4.into(),
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||||
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_registered(
|
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_registered(
|
||||||
v4::registration::RegistredData {
|
v4::registration::RegistredData {
|
||||||
|
pub_key: registration_data.gateway_data.pub_key,
|
||||||
|
private_ips: registration_data.gateway_data.private_ips.into(),
|
||||||
|
wg_port: registration_data.wg_port,
|
||||||
|
},
|
||||||
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||||
|
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_registered(
|
||||||
|
v5::registration::RegistredData {
|
||||||
pub_key: registration_data.gateway_data.pub_key,
|
pub_key: registration_data.gateway_data.pub_key,
|
||||||
private_ips: registration_data.gateway_data.private_ips,
|
private_ips: registration_data.gateway_data.private_ips,
|
||||||
wg_port: registration_data.wg_port,
|
wg_port: registration_data.wg_port,
|
||||||
},
|
},
|
||||||
reply_to,
|
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -579,7 +629,7 @@ impl MixnetListener {
|
|||||||
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
msg: Box<dyn QueryBandwidthMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
) -> AuthenticatorHandleResult {
|
) -> AuthenticatorHandleResult {
|
||||||
let bandwidth_data = self.peer_manager.query_bandwidth(msg).await?;
|
let bandwidth_data = self.peer_manager.query_bandwidth(msg).await?;
|
||||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||||
@@ -589,7 +639,7 @@ impl MixnetListener {
|
|||||||
available_bandwidth: data.available_bandwidth as u64,
|
available_bandwidth: data.available_bandwidth as u64,
|
||||||
suspended: false,
|
suspended: false,
|
||||||
}),
|
}),
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -602,7 +652,7 @@ impl MixnetListener {
|
|||||||
bandwidth_data.map(|data| v2::registration::RemainingBandwidthData {
|
bandwidth_data.map(|data| v2::registration::RemainingBandwidthData {
|
||||||
available_bandwidth: data.available_bandwidth,
|
available_bandwidth: data.available_bandwidth,
|
||||||
}),
|
}),
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -615,7 +665,7 @@ impl MixnetListener {
|
|||||||
bandwidth_data.map(|data| v3::registration::RemainingBandwidthData {
|
bandwidth_data.map(|data| v3::registration::RemainingBandwidthData {
|
||||||
available_bandwidth: data.available_bandwidth,
|
available_bandwidth: data.available_bandwidth,
|
||||||
}),
|
}),
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -628,7 +678,19 @@ impl MixnetListener {
|
|||||||
bandwidth_data.map(|data| v4::registration::RemainingBandwidthData {
|
bandwidth_data.map(|data| v4::registration::RemainingBandwidthData {
|
||||||
available_bandwidth: data.available_bandwidth,
|
available_bandwidth: data.available_bandwidth,
|
||||||
}),
|
}),
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| {
|
||||||
|
AuthenticatorError::FailedToSerializeResponsePacket { source: err }
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
AuthenticatorVersion::V5 => {
|
||||||
|
v5::response::AuthenticatorResponse::new_remaining_bandwidth(
|
||||||
|
bandwidth_data.map(|data| v5::registration::RemainingBandwidthData {
|
||||||
|
available_bandwidth: data.available_bandwidth,
|
||||||
|
}),
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -646,7 +708,7 @@ impl MixnetListener {
|
|||||||
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
msg: Box<dyn TopUpMessage + Send + Sync + 'static>,
|
||||||
protocol: Protocol,
|
protocol: Protocol,
|
||||||
request_id: u64,
|
request_id: u64,
|
||||||
reply_to: Recipient,
|
reply_to: Option<Recipient>,
|
||||||
) -> AuthenticatorHandleResult {
|
) -> AuthenticatorHandleResult {
|
||||||
let Some(ecash_verifier) = self.ecash_verifier.clone() else {
|
let Some(ecash_verifier) = self.ecash_verifier.clone() else {
|
||||||
return Err(AuthenticatorError::UnsupportedOperation);
|
return Err(AuthenticatorError::UnsupportedOperation);
|
||||||
@@ -681,11 +743,19 @@ impl MixnetListener {
|
|||||||
let available_bandwidth = verifier.verify().await?;
|
let available_bandwidth = verifier.verify().await?;
|
||||||
|
|
||||||
let bytes = match AuthenticatorVersion::from(protocol) {
|
let bytes = match AuthenticatorVersion::from(protocol) {
|
||||||
|
AuthenticatorVersion::V5 => v5::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||||
|
v5::registration::RemainingBandwidthData {
|
||||||
|
available_bandwidth,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
.to_bytes()
|
||||||
|
.map_err(|err| AuthenticatorError::FailedToSerializeResponsePacket { source: err })?,
|
||||||
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_topup_bandwidth(
|
AuthenticatorVersion::V4 => v4::response::AuthenticatorResponse::new_topup_bandwidth(
|
||||||
v4::registration::RemainingBandwidthData {
|
v4::registration::RemainingBandwidthData {
|
||||||
available_bandwidth,
|
available_bandwidth,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -694,7 +764,7 @@ impl MixnetListener {
|
|||||||
v3::registration::RemainingBandwidthData {
|
v3::registration::RemainingBandwidthData {
|
||||||
available_bandwidth,
|
available_bandwidth,
|
||||||
},
|
},
|
||||||
reply_to,
|
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||||
request_id,
|
request_id,
|
||||||
)
|
)
|
||||||
.to_bytes()
|
.to_bytes()
|
||||||
@@ -762,10 +832,10 @@ impl MixnetListener {
|
|||||||
async fn handle_response(
|
async fn handle_response(
|
||||||
&self,
|
&self,
|
||||||
response: Vec<u8>,
|
response: Vec<u8>,
|
||||||
recipient: Recipient,
|
recipient: Option<Recipient>,
|
||||||
sender_tag: Option<AnonymousSenderTag>,
|
sender_tag: Option<AnonymousSenderTag>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let input_message = create_input_message(recipient, sender_tag, response);
|
let input_message = create_input_message(recipient, sender_tag, response)?;
|
||||||
self.mixnet_client
|
self.mixnet_client
|
||||||
.send(input_message)
|
.send(input_message)
|
||||||
.await
|
.await
|
||||||
@@ -858,6 +928,17 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
|
|||||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[5, request_type] => {
|
||||||
|
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||||
|
v5::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||||
|
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||||
|
source: err,
|
||||||
|
})
|
||||||
|
.map(Into::into)
|
||||||
|
} else {
|
||||||
|
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||||
|
}
|
||||||
|
}
|
||||||
[version, _] => {
|
[version, _] => {
|
||||||
log::info!("Received packet with invalid version: v{version}");
|
log::info!("Received packet with invalid version: v{version}");
|
||||||
Err(AuthenticatorError::InvalidPacketVersion(version))
|
Err(AuthenticatorError::InvalidPacketVersion(version))
|
||||||
@@ -866,17 +947,30 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn create_input_message(
|
fn create_input_message(
|
||||||
nym_address: Recipient,
|
nym_address: Option<Recipient>,
|
||||||
reply_to_tag: Option<AnonymousSenderTag>,
|
reply_to_tag: Option<AnonymousSenderTag>,
|
||||||
response_packet: Vec<u8>,
|
response_packet: Vec<u8>,
|
||||||
) -> InputMessage {
|
) -> Result<InputMessage> {
|
||||||
let lane = TransmissionLane::General;
|
let lane = TransmissionLane::General;
|
||||||
let packet_type = None;
|
let packet_type = None;
|
||||||
if let Some(reply_to_tag) = reply_to_tag {
|
if let Some(reply_to_tag) = reply_to_tag {
|
||||||
log::debug!("Creating message using SURB");
|
log::debug!("Creating message using SURB");
|
||||||
InputMessage::new_reply(reply_to_tag, response_packet, lane, packet_type)
|
Ok(InputMessage::new_reply(
|
||||||
} else {
|
reply_to_tag,
|
||||||
|
response_packet,
|
||||||
|
lane,
|
||||||
|
packet_type,
|
||||||
|
))
|
||||||
|
} else if let Some(nym_address) = nym_address {
|
||||||
log::debug!("Creating message using nym_address");
|
log::debug!("Creating message using nym_address");
|
||||||
InputMessage::new_regular(nym_address, response_packet, lane, packet_type)
|
Ok(InputMessage::new_regular(
|
||||||
|
nym_address,
|
||||||
|
response_packet,
|
||||||
|
lane,
|
||||||
|
packet_type,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
log::error!("No nym-address or sender tag provided");
|
||||||
|
Err(AuthenticatorError::MissingReplyToForOldClient)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use nym_sdk::mixnet::{AnonymousSenderTag, Recipient};
|
|||||||
|
|
||||||
use crate::error::{IpPacketRouterError, Result};
|
use crate::error::{IpPacketRouterError, Result};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub(crate) enum ConnectedClientId {
|
pub(crate) enum ConnectedClientId {
|
||||||
AnonymousSenderTag(AnonymousSenderTag),
|
AnonymousSenderTag(AnonymousSenderTag),
|
||||||
NymAddress(Box<Recipient>),
|
NymAddress(Box<Recipient>),
|
||||||
|
|||||||
@@ -59,23 +59,42 @@ impl ConnectedClients {
|
|||||||
.any(|client| client.client_id == *client_id)
|
.any(|client| client.client_id == *client_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
//fn lookup_ip_from_client_id(&self, client_id: &ConnectedClientId) -> Option<IpPair> {
|
pub(crate) fn disconnect_client(&mut self, client_id: &ConnectedClientId) {
|
||||||
// self.clients_ipv4_mapping
|
if let Some(ips) = self.lookup_ip_from_client_id(client_id) {
|
||||||
// .iter()
|
log::debug!("Disconnect client that requested to do so: {ips}");
|
||||||
// .find_map(|(ipv4, connected_client)| {
|
self.disconnect_client_handle(ips);
|
||||||
// if connected_client.client_id == *client_id {
|
}
|
||||||
// Some(IpPair::new(*ipv4, connected_client.ipv6))
|
}
|
||||||
// } else {
|
|
||||||
// None
|
fn disconnect_client_handle(&mut self, ips: IpPair) {
|
||||||
// }
|
self.clients_ipv4_mapping.remove(&ips.ipv4);
|
||||||
// })
|
self.clients_ipv6_mapping.remove(&ips.ipv6);
|
||||||
//}
|
self.tun_listener_connected_client_tx
|
||||||
//
|
.send(ConnectedClientEvent::Disconnect(DisconnectEvent(ips)))
|
||||||
//fn lookup_client(&self, client_id: &ConnectedClientId) -> Option<&ConnectedClient> {
|
.inspect_err(|err| {
|
||||||
// self.clients_ipv4_mapping
|
log::error!("Failed to send disconnect event: {err}");
|
||||||
// .values()
|
})
|
||||||
// .find(|connected_client| connected_client.client_id == *client_id)
|
.ok();
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lookup_ip_from_client_id(&self, client_id: &ConnectedClientId) -> Option<IpPair> {
|
||||||
|
self.clients_ipv4_mapping
|
||||||
|
.iter()
|
||||||
|
.find_map(|(ipv4, connected_client)| {
|
||||||
|
if connected_client.client_id == *client_id {
|
||||||
|
Some(IpPair::new(*ipv4, connected_client.ipv6))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
fn lookup_client(&self, client_id: &ConnectedClientId) -> Option<&ConnectedClient> {
|
||||||
|
self.clients_ipv4_mapping
|
||||||
|
.values()
|
||||||
|
.find(|connected_client| connected_client.client_id == *client_id)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn connect(
|
pub(crate) fn connect(
|
||||||
&mut self,
|
&mut self,
|
||||||
@@ -163,14 +182,7 @@ impl ConnectedClients {
|
|||||||
) {
|
) {
|
||||||
for (ips, _) in &stopped_clients {
|
for (ips, _) in &stopped_clients {
|
||||||
log::info!("Disconnect stopped client: {ips}");
|
log::info!("Disconnect stopped client: {ips}");
|
||||||
self.clients_ipv4_mapping.remove(&ips.ipv4);
|
self.disconnect_client_handle(*ips);
|
||||||
self.clients_ipv6_mapping.remove(&ips.ipv6);
|
|
||||||
self.tun_listener_connected_client_tx
|
|
||||||
.send(ConnectedClientEvent::Disconnect(DisconnectEvent(*ips)))
|
|
||||||
.inspect_err(|err| {
|
|
||||||
log::error!("Failed to send disconnect event: {err}");
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,14 +192,7 @@ impl ConnectedClients {
|
|||||||
) {
|
) {
|
||||||
for (ips, _) in &inactive_clients {
|
for (ips, _) in &inactive_clients {
|
||||||
log::info!("Disconnect inactive client: {ips}");
|
log::info!("Disconnect inactive client: {ips}");
|
||||||
self.clients_ipv4_mapping.remove(&ips.ipv4);
|
self.disconnect_client_handle(*ips);
|
||||||
self.clients_ipv6_mapping.remove(&ips.ipv6);
|
|
||||||
self.tun_listener_connected_client_tx
|
|
||||||
.send(ConnectedClientEvent::Disconnect(DisconnectEvent(*ips)))
|
|
||||||
.inspect_err(|err| {
|
|
||||||
log::error!("Failed to send disconnect event: {err}");
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ use std::time::Duration;
|
|||||||
pub(crate) const DISCONNECT_TIMER_INTERVAL: Duration = Duration::from_secs(10);
|
pub(crate) const DISCONNECT_TIMER_INTERVAL: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
// We consider a client inactive if it hasn't sent any mixnet packets in this duration
|
// We consider a client inactive if it hasn't sent any mixnet packets in this duration
|
||||||
pub(crate) const CLIENT_MIXNET_INACTIVITY_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
pub(crate) const CLIENT_MIXNET_INACTIVITY_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
// We consider a client handler inactive if it hasn't received any packets from the tun device in
|
// We consider a client handler inactive if it hasn't received any packets from the tun device in
|
||||||
// this duration
|
// this duration
|
||||||
pub(crate) const CLIENT_HANDLER_ACTIVITY_TIMEOUT: Duration = Duration::from_secs(10 * 60);
|
pub(crate) const CLIENT_HANDLER_ACTIVITY_TIMEOUT: Duration = Duration::from_secs(5 * 60);
|
||||||
|
|||||||
@@ -90,9 +90,6 @@ pub(crate) struct DynamicConnectSuccess {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, thiserror::Error)]
|
#[derive(Clone, Debug, thiserror::Error)]
|
||||||
pub(crate) enum DynamicConnectFailureReason {
|
pub(crate) enum DynamicConnectFailureReason {
|
||||||
#[error("client already connected")]
|
|
||||||
ClientAlreadyConnected,
|
|
||||||
|
|
||||||
#[error("no available ip address")]
|
#[error("no available ip address")]
|
||||||
NoAvailableIp,
|
NoAvailableIp,
|
||||||
|
|
||||||
|
|||||||
@@ -119,9 +119,6 @@ impl From<DynamicConnectResponse> for DynamicConnectResponseReplyV6 {
|
|||||||
impl From<DynamicConnectFailureReason> for DynamicConnectFailureReasonV6 {
|
impl From<DynamicConnectFailureReason> for DynamicConnectFailureReasonV6 {
|
||||||
fn from(reason: DynamicConnectFailureReason) -> Self {
|
fn from(reason: DynamicConnectFailureReason) -> Self {
|
||||||
match reason {
|
match reason {
|
||||||
DynamicConnectFailureReason::ClientAlreadyConnected => {
|
|
||||||
DynamicConnectFailureReasonV6::RequestedNymAddressAlreadyInUse
|
|
||||||
}
|
|
||||||
DynamicConnectFailureReason::NoAvailableIp => {
|
DynamicConnectFailureReason::NoAvailableIp => {
|
||||||
DynamicConnectFailureReasonV6::NoAvailableIp
|
DynamicConnectFailureReasonV6::NoAvailableIp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,9 +119,6 @@ impl From<DynamicConnectResponse> for DynamicConnectResponseReplyV7 {
|
|||||||
impl From<DynamicConnectFailureReason> for DynamicConnectFailureReasonV7 {
|
impl From<DynamicConnectFailureReason> for DynamicConnectFailureReasonV7 {
|
||||||
fn from(reason: DynamicConnectFailureReason) -> Self {
|
fn from(reason: DynamicConnectFailureReason) -> Self {
|
||||||
match reason {
|
match reason {
|
||||||
DynamicConnectFailureReason::ClientAlreadyConnected => {
|
|
||||||
DynamicConnectFailureReasonV7::RequestedNymAddressAlreadyInUse
|
|
||||||
}
|
|
||||||
DynamicConnectFailureReason::NoAvailableIp => {
|
DynamicConnectFailureReason::NoAvailableIp => {
|
||||||
DynamicConnectFailureReasonV7::NoAvailableIp
|
DynamicConnectFailureReasonV7::NoAvailableIp
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,9 +82,6 @@ impl From<DynamicConnectResponse> for ConnectResponseReplyV8 {
|
|||||||
impl From<DynamicConnectFailureReason> for ConnectFailureReasonV8 {
|
impl From<DynamicConnectFailureReason> for ConnectFailureReasonV8 {
|
||||||
fn from(reason: DynamicConnectFailureReason) -> Self {
|
fn from(reason: DynamicConnectFailureReason) -> Self {
|
||||||
match reason {
|
match reason {
|
||||||
DynamicConnectFailureReason::ClientAlreadyConnected => {
|
|
||||||
ConnectFailureReasonV8::ClientAlreadyConnected
|
|
||||||
}
|
|
||||||
DynamicConnectFailureReason::NoAvailableIp => ConnectFailureReasonV8::NoAvailableIp,
|
DynamicConnectFailureReason::NoAvailableIp => ConnectFailureReasonV8::NoAvailableIp,
|
||||||
DynamicConnectFailureReason::Other(err) => ConnectFailureReasonV8::Other(err),
|
DynamicConnectFailureReason::Other(err) => ConnectFailureReasonV8::Other(err),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ use crate::{
|
|||||||
IpPacketRequest, PingRequest, StaticConnectRequest,
|
IpPacketRequest, PingRequest, StaticConnectRequest,
|
||||||
},
|
},
|
||||||
response::{
|
response::{
|
||||||
DynamicConnectFailureReason, DynamicConnectSuccess, HealthResponse, InfoLevel,
|
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
|
||||||
InfoResponse, InfoResponseReply, Response, StaticConnectFailureReason,
|
DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponse, InfoResponseReply,
|
||||||
StaticConnectResponse, VersionedResponse,
|
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
|
||||||
},
|
},
|
||||||
ClientVersion,
|
ClientVersion,
|
||||||
},
|
},
|
||||||
@@ -225,7 +225,7 @@ impl MixnetListener {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_dynamic_connect_request(
|
fn on_dynamic_connect_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
connect_request: DynamicConnectRequest,
|
connect_request: DynamicConnectRequest,
|
||||||
) -> PacketHandleResult {
|
) -> PacketHandleResult {
|
||||||
@@ -242,13 +242,14 @@ impl MixnetListener {
|
|||||||
.map(Duration::from_millis)
|
.map(Duration::from_millis)
|
||||||
.unwrap_or(nym_ip_packet_requests::codec::BUFFER_TIMEOUT);
|
.unwrap_or(nym_ip_packet_requests::codec::BUFFER_TIMEOUT);
|
||||||
|
|
||||||
if self.connected_clients.is_client_connected(&reply_to) {
|
if let Some(ips) = self.connected_clients.lookup_ip_from_client_id(&reply_to) {
|
||||||
|
log::debug!("Reconnecting to the previous session");
|
||||||
return Ok(Some(VersionedResponse {
|
return Ok(Some(VersionedResponse {
|
||||||
version,
|
version,
|
||||||
reply_to,
|
reply_to,
|
||||||
response: Response::DynamicConnect {
|
response: Response::DynamicConnect {
|
||||||
request_id,
|
request_id,
|
||||||
reply: DynamicConnectFailureReason::ClientAlreadyConnected.into(),
|
reply: DynamicConnectSuccess { ips }.into(),
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -292,12 +293,47 @@ impl MixnetListener {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disconnect_request(&self, _disconnect_request: DisconnectRequest) -> PacketHandleResult {
|
fn on_disconnect_request(
|
||||||
log::info!("Received disconnect request: not implemented, dropping");
|
&mut self,
|
||||||
Ok(None)
|
disconnect_request: DisconnectRequest,
|
||||||
|
) -> PacketHandleResult {
|
||||||
|
log::info!(
|
||||||
|
"Received disconnect request from {}",
|
||||||
|
disconnect_request.sent_by
|
||||||
|
);
|
||||||
|
|
||||||
|
let version = disconnect_request.version;
|
||||||
|
let request_id = disconnect_request.request_id;
|
||||||
|
let client_id = disconnect_request.sent_by;
|
||||||
|
|
||||||
|
// Check if the client is connected
|
||||||
|
if !self.connected_clients.is_client_connected(&client_id) {
|
||||||
|
log::info!("Client {} is not connected, cannot disconnect", client_id);
|
||||||
|
return Ok(Some(VersionedResponse {
|
||||||
|
version,
|
||||||
|
reply_to: client_id,
|
||||||
|
response: Response::Disconnect {
|
||||||
|
request_id,
|
||||||
|
reply: DisconnectResponse::Failure(DisconnectFailureReason::ClientNotConnected),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect the client
|
||||||
|
log::info!("Disconnecting client {}", client_id);
|
||||||
|
self.connected_clients.disconnect_client(&client_id);
|
||||||
|
|
||||||
|
Ok(Some(VersionedResponse {
|
||||||
|
version,
|
||||||
|
reply_to: client_id,
|
||||||
|
response: Response::Disconnect {
|
||||||
|
request_id,
|
||||||
|
reply: DisconnectResponse::Success,
|
||||||
|
},
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_ping_request(&self, ping_request: PingRequest) -> PacketHandleResult {
|
fn on_ping_request(&self, ping_request: PingRequest) -> PacketHandleResult {
|
||||||
Ok(Some(VersionedResponse {
|
Ok(Some(VersionedResponse {
|
||||||
version: ping_request.version,
|
version: ping_request.version,
|
||||||
reply_to: ping_request.sent_by,
|
reply_to: ping_request.sent_by,
|
||||||
@@ -307,7 +343,7 @@ impl MixnetListener {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn on_health_request(&self, health_request: HealthRequest) -> PacketHandleResult {
|
fn on_health_request(&self, health_request: HealthRequest) -> PacketHandleResult {
|
||||||
Ok(Some(VersionedResponse {
|
Ok(Some(VersionedResponse {
|
||||||
version: health_request.version,
|
version: health_request.version,
|
||||||
reply_to: health_request.sent_by,
|
reply_to: health_request.sent_by,
|
||||||
@@ -324,10 +360,10 @@ impl MixnetListener {
|
|||||||
async fn on_control_request(&mut self, control_request: ControlRequest) -> PacketHandleResult {
|
async fn on_control_request(&mut self, control_request: ControlRequest) -> PacketHandleResult {
|
||||||
match control_request {
|
match control_request {
|
||||||
ControlRequest::StaticConnect(r) => self.on_static_connect_request(r).await,
|
ControlRequest::StaticConnect(r) => self.on_static_connect_request(r).await,
|
||||||
ControlRequest::DynamicConnect(r) => self.on_dynamic_connect_request(r).await,
|
ControlRequest::DynamicConnect(r) => self.on_dynamic_connect_request(r),
|
||||||
ControlRequest::Disconnect(r) => self.on_disconnect_request(r),
|
ControlRequest::Disconnect(r) => self.on_disconnect_request(r),
|
||||||
ControlRequest::Ping(r) => self.on_ping_request(r).await,
|
ControlRequest::Ping(r) => self.on_ping_request(r),
|
||||||
ControlRequest::Health(r) => self.on_health_request(r).await,
|
ControlRequest::Health(r) => self.on_health_request(r),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ impl TunListener {
|
|||||||
.update(ConnectedClientEvent::Disconnect(DisconnectEvent(*ips)));
|
.update(ConnectedClientEvent::Disconnect(DisconnectEvent(*ips)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::info!(
|
log::debug!(
|
||||||
"dropping packet from network: no registered client for destination: {dst_addr}"
|
"dropping packet from network: no registered client for destination: {dst_addr}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-network-requester"
|
name = "nym-network-requester"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
version = "1.1.50"
|
version = "1.1.51"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version = "1.70"
|
rust-version = "1.70"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nym-cli"
|
name = "nym-cli"
|
||||||
version = "1.1.49"
|
version = "1.1.50"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "nymvisor"
|
name = "nymvisor"
|
||||||
version = "0.1.14"
|
version = "0.1.15"
|
||||||
authors.workspace = true
|
authors.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
|
|||||||
Reference in New Issue
Block a user