diff --git a/common/authenticator-requests/src/response.rs b/common/authenticator-requests/src/response.rs index a04233444c..5c20cdd0c9 100644 --- a/common/authenticator-requests/src/response.rs +++ b/common/authenticator-requests/src/response.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::traits::{ - Id, PendingRegistrationResponse, RegisteredResponse, RemainingBandwidthResponse, - TopUpBandwidthResponse, + CurrentUpgradeModeStatus, Id, PendingRegistrationResponse, RegisteredResponse, + RemainingBandwidthResponse, TopUpBandwidthResponse, UpgradeModeStatus, }; use crate::{v2, v3, v4, v5, v6}; @@ -15,6 +15,25 @@ pub enum AuthenticatorResponse { TopUpBandwidth(Box), } +impl UpgradeModeStatus for AuthenticatorResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + match self { + AuthenticatorResponse::PendingRegistration(pending_registration_response) => { + pending_registration_response.upgrade_mode_status() + } + AuthenticatorResponse::Registered(registered_response) => { + registered_response.upgrade_mode_status() + } + AuthenticatorResponse::RemainingBandwidth(remaining_bandwidth_response) => { + remaining_bandwidth_response.upgrade_mode_status() + } + AuthenticatorResponse::TopUpBandwidth(top_up_bandwidth_response) => { + top_up_bandwidth_response.upgrade_mode_status() + } + } + } +} + impl Id for AuthenticatorResponse { fn id(&self) -> u64 { match self { diff --git a/common/authenticator-requests/src/traits.rs b/common/authenticator-requests/src/traits.rs index 2681cbe389..3f90495e4d 100644 --- a/common/authenticator-requests/src/traits.rs +++ b/common/authenticator-requests/src/traits.rs @@ -14,6 +14,24 @@ use nym_wireguard_types::PeerPublicKey; use serde::{Deserialize, Serialize}; use tracing::error; +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)] +pub enum CurrentUpgradeModeStatus { + Enabled, + Disabled, + // everything pre-v6 + Unknown, +} + +impl From for CurrentUpgradeModeStatus { + fn from(value: bool) -> Self { + if value { + CurrentUpgradeModeStatus::Enabled + } else { + CurrentUpgradeModeStatus::Disabled + } + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct BandwidthClaim { pub credential: BandwidthCredential, @@ -136,6 +154,141 @@ impl Versionable for v6::topup::TopUpMessage { } } +pub trait UpgradeModeStatus { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus; +} + +impl UpgradeModeStatus for v1::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v1::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v1::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v2::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v2::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v2::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} +impl UpgradeModeStatus for v3::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v3::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v3::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v3::response::TopUpBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v4::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v4::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v4::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v4::response::TopUpBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v5::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v5::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v5::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v5::response::TopUpBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + CurrentUpgradeModeStatus::Unknown + } +} + +impl UpgradeModeStatus for v6::response::PendingRegistrationResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + self.upgrade_mode_enabled.into() + } +} + +impl UpgradeModeStatus for v6::response::RegisteredResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + self.upgrade_mode_enabled.into() + } +} + +impl UpgradeModeStatus for v6::response::RemainingBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + self.upgrade_mode_enabled.into() + } +} + +impl UpgradeModeStatus for v6::response::TopUpBandwidthResponse { + fn upgrade_mode_status(&self) -> CurrentUpgradeModeStatus { + self.upgrade_mode_enabled.into() + } +} + pub trait InitMessage: Versionable + fmt::Debug { fn pub_key(&self) -> PeerPublicKey; } @@ -565,7 +718,7 @@ impl Id for v6::response::TopUpBandwidthResponse { } } -pub trait PendingRegistrationResponse: Id + fmt::Debug { +pub trait PendingRegistrationResponse: Id + UpgradeModeStatus + fmt::Debug { fn nonce(&self) -> u64; fn verify(&self, gateway_key: &x25519::PrivateKey) -> Result<(), Error>; fn pub_key(&self) -> PeerPublicKey; @@ -748,7 +901,7 @@ impl PendingRegistrationResponse for v6::response::PendingRegistrationResponse { } } -pub trait RegisteredResponse: Id + fmt::Debug { +pub trait RegisteredResponse: Id + UpgradeModeStatus + fmt::Debug { fn private_ips(&self) -> IpPair; fn pub_key(&self) -> PeerPublicKey; fn wg_port(&self) -> u16; @@ -824,7 +977,7 @@ impl RegisteredResponse for v6::response::RegisteredResponse { } } -pub trait RemainingBandwidthResponse: Id + fmt::Debug { +pub trait RemainingBandwidthResponse: Id + UpgradeModeStatus + fmt::Debug { fn available_bandwidth(&self) -> Option; } @@ -858,7 +1011,7 @@ impl RemainingBandwidthResponse for v6::response::RemainingBandwidthResponse { } } -pub trait TopUpBandwidthResponse: Id + fmt::Debug { +pub trait TopUpBandwidthResponse: Id + UpgradeModeStatus + fmt::Debug { fn available_bandwidth(&self) -> i64; } diff --git a/common/authenticator-requests/src/version.rs b/common/authenticator-requests/src/version.rs index 225726edfe..ba2e729bb4 100644 --- a/common/authenticator-requests/src/version.rs +++ b/common/authenticator-requests/src/version.rs @@ -22,7 +22,7 @@ pub enum AuthenticatorVersion { /// introduced in dorina-patched release (1.6.1) V5, - /// introduced in yet to be named release, currently aiming for Kase (1.21.0) + /// introduced in yet to be named release, currently aiming for Leerdammer (1.22.0) V6, /// an unknown, future, variant that can be present if running outdated software @@ -42,7 +42,7 @@ impl AuthenticatorVersion { AuthenticatorVersion::V3 => semver::Version::new(1, 1, 10), AuthenticatorVersion::V4 => semver::Version::new(1, 2, 0), AuthenticatorVersion::V5 => semver::Version::new(1, 6, 1), - AuthenticatorVersion::V6 => semver::Version::new(1, 21, 0), + AuthenticatorVersion::V6 => semver::Version::new(1, 22, 0), AuthenticatorVersion::UNKNOWN => semver::Version::new(0, 0, 0), } } diff --git a/common/wireguard-private-metadata/shared/src/models/v1/interface.rs b/common/wireguard-private-metadata/shared/src/models/v1/interface.rs index 261fab6ca4..7a02463956 100644 --- a/common/wireguard-private-metadata/shared/src/models/v1/interface.rs +++ b/common/wireguard-private-metadata/shared/src/models/v1/interface.rs @@ -5,6 +5,8 @@ use nym_credentials_interface::CredentialSpendingData; #[cfg(feature = "testing")] use super::super::v0 as previous; +#[cfg(feature = "testing")] +use crate::{Request, Response, v0}; use super::{ QueryType, VERSION, VersionedRequest, VersionedResponse, @@ -14,7 +16,6 @@ use super::{ topup_bandwidth::{request::InnerTopUpRequest, response::InnerTopUpResponse}, }; use crate::models::{Construct, Extract, Version, error::Error}; -use crate::{Request, Response, v0}; #[derive(Debug, Clone, PartialEq)] pub enum RequestData { diff --git a/nym-authenticator-client/src/lib.rs b/nym-authenticator-client/src/lib.rs index 07c0d73a38..734526a6ea 100644 --- a/nym-authenticator-client/src/lib.rs +++ b/nym-authenticator-client/src/lib.rs @@ -12,6 +12,7 @@ use std::time::Duration; use tracing::{debug, error, trace}; use crate::mixnet_listener::{MixnetMessageBroadcastReceiver, MixnetMessageInputSender}; +use nym_authenticator_requests::traits::UpgradeModeStatus; use nym_authenticator_requests::{ AuthenticatorVersion, client_message::ClientMessage, response::AuthenticatorResponse, traits::Id, v2, v3, v4, v5, v6, @@ -24,9 +25,11 @@ use nym_wireguard_types::PeerPublicKey; mod error; mod helpers; mod mixnet_listener; +pub mod types; pub use crate::error::{Error, Result}; pub use crate::mixnet_listener::{AuthClientMixnetListener, AuthClientMixnetListenerHandle}; +use crate::types::{AvailableBandwidthClientResponse, TopUpClientResponse}; pub struct AuthenticatorClient { mixnet_listener: MixnetMessageBroadcastReceiver, @@ -299,7 +302,7 @@ impl AuthenticatorClient { Ok(gateway_data) } - pub async fn query_bandwidth(&mut self) -> Result> { + pub async fn query_bandwidth(&mut self) -> Result { let pub_key = self.peer_public_key(); let version = self.auth_version; @@ -316,6 +319,7 @@ impl AuthenticatorClient { } }; let response = self.send_and_wait_for_response(&query_message).await?; + let current_upgrade_mode_status = response.upgrade_mode_status(); let available_bandwidth = match response { AuthenticatorResponse::RemainingBandwidth(remaining_bandwidth_response) => { @@ -324,7 +328,10 @@ impl AuthenticatorClient { { available_bandwidth } else { - return Ok(None); + return Ok(AvailableBandwidthClientResponse { + available_bandwidth_bytes: None, + current_upgrade_mode_status, + }); } } _ => return Err(Error::InvalidGatewayAuthResponse), @@ -345,10 +352,16 @@ impl AuthenticatorClient { "Remaining bandwidth is under 1 MB. The wireguard mode will get suspended after that until tomorrow, UTC time. The client might shutdown with timeout soon" ); } - Ok(Some(available_bandwidth)) + Ok(AvailableBandwidthClientResponse { + available_bandwidth_bytes: None, + current_upgrade_mode_status, + }) } - pub async fn top_up(&mut self, credential: CredentialSpendingData) -> Result { + pub async fn top_up( + &mut self, + credential: CredentialSpendingData, + ) -> Result { let pub_key = self.peer_public_key(); let top_up_message = match self.auth_version { @@ -375,14 +388,18 @@ impl AuthenticatorClient { } }; let response = self.send_and_wait_for_response(&top_up_message).await?; + let current_upgrade_mode_status = response.upgrade_mode_status(); - let remaining_bandwidth = match response { + let remaining_bandwidth_bytes = match response { AuthenticatorResponse::TopUpBandwidth(top_up_bandwidth_response) => { top_up_bandwidth_response.available_bandwidth() } _ => return Err(Error::InvalidGatewayAuthResponse), }; - Ok(remaining_bandwidth) + Ok(TopUpClientResponse { + remaining_bandwidth_bytes, + current_upgrade_mode_status, + }) } } diff --git a/nym-authenticator-client/src/types.rs b/nym-authenticator-client/src/types.rs new file mode 100644 index 0000000000..753d8a1422 --- /dev/null +++ b/nym-authenticator-client/src/types.rs @@ -0,0 +1,16 @@ +// Copyright 2025 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +pub use nym_authenticator_requests::traits::CurrentUpgradeModeStatus; + +#[derive(Debug, Clone, Copy)] +pub struct TopUpClientResponse { + pub remaining_bandwidth_bytes: i64, + pub current_upgrade_mode_status: CurrentUpgradeModeStatus, +} + +#[derive(Debug, Clone, Copy)] +pub struct AvailableBandwidthClientResponse { + pub available_bandwidth_bytes: Option, + pub current_upgrade_mode_status: CurrentUpgradeModeStatus, +}