Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d305c29eb | |||
| e057f672fa | |||
| edc2a367c0 | |||
| e78040f0ec |
Generated
+1
@@ -5211,6 +5211,7 @@ dependencies = [
|
|||||||
"nym-bandwidth-controller",
|
"nym-bandwidth-controller",
|
||||||
"nym-credential-storage",
|
"nym-credential-storage",
|
||||||
"nym-credentials",
|
"nym-credentials",
|
||||||
|
"nym-credentials-interface",
|
||||||
"nym-crypto",
|
"nym-crypto",
|
||||||
"nym-gateway-requests",
|
"nym-gateway-requests",
|
||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
|
|||||||
@@ -19,4 +19,7 @@ pub enum Error {
|
|||||||
#[source]
|
#[source]
|
||||||
source: hmac::digest::MacError,
|
source: hmac::digest::MacError,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("conversion: {0}")]
|
||||||
|
Conversion(String),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
pub mod v1;
|
pub mod v1;
|
||||||
pub mod v2;
|
pub mod v2;
|
||||||
|
pub mod v3;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
pub use v2 as latest;
|
pub use v3 as latest;
|
||||||
|
|
||||||
pub const CURRENT_VERSION: u8 = 2;
|
pub const CURRENT_VERSION: u8 = 3;
|
||||||
|
|
||||||
fn make_bincode_serializer() -> impl bincode::Options {
|
fn make_bincode_serializer() -> impl bincode::Options {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
|
||||||
|
|
||||||
|
use crate::{v2, v3};
|
||||||
|
|
||||||
|
impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorRequest {
|
||||||
|
fn from(authenticator_request: v2::request::AuthenticatorRequest) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
version: 2,
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
},
|
||||||
|
data: authenticator_request.data.into(),
|
||||||
|
reply_to: authenticator_request.reply_to,
|
||||||
|
request_id: authenticator_request.request_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::request::AuthenticatorRequestData> for v3::request::AuthenticatorRequestData {
|
||||||
|
fn from(authenticator_request_data: v2::request::AuthenticatorRequestData) -> Self {
|
||||||
|
match authenticator_request_data {
|
||||||
|
v2::request::AuthenticatorRequestData::Initial(init_msg) => {
|
||||||
|
v3::request::AuthenticatorRequestData::Initial(init_msg.into())
|
||||||
|
}
|
||||||
|
v2::request::AuthenticatorRequestData::Final(gw_client) => {
|
||||||
|
v3::request::AuthenticatorRequestData::Final(gw_client.into())
|
||||||
|
}
|
||||||
|
v2::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
|
||||||
|
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::registration::InitMessage> for v3::registration::InitMessage {
|
||||||
|
fn from(init_msg: v2::registration::InitMessage) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: init_msg.pub_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Box<v2::registration::FinalMessage>> for Box<v3::registration::FinalMessage> {
|
||||||
|
fn from(gw_client: Box<v2::registration::FinalMessage>) -> Self {
|
||||||
|
Box::new(v3::registration::FinalMessage {
|
||||||
|
gateway_client: gw_client.gateway_client.into(),
|
||||||
|
credential: gw_client.credential,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::registration::GatewayClient> for v3::registration::GatewayClient {
|
||||||
|
fn from(gw_client: v2::registration::GatewayClient) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: gw_client.pub_key,
|
||||||
|
private_ip: gw_client.private_ip,
|
||||||
|
mac: gw_client.mac.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::registration::GatewayClient> for v2::registration::GatewayClient {
|
||||||
|
fn from(gw_client: v3::registration::GatewayClient) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: gw_client.pub_key,
|
||||||
|
private_ip: gw_client.private_ip,
|
||||||
|
mac: gw_client.mac.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v2::registration::ClientMac> for v3::registration::ClientMac {
|
||||||
|
fn from(mac: v2::registration::ClientMac) -> Self {
|
||||||
|
Self::new(mac.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::registration::ClientMac> for v2::registration::ClientMac {
|
||||||
|
fn from(mac: v3::registration::ClientMac) -> Self {
|
||||||
|
Self::new(mac.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<v3::response::AuthenticatorResponse> for v2::response::AuthenticatorResponse {
|
||||||
|
type Error = crate::Error;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
authenticator_response: v3::response::AuthenticatorResponse,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
data: authenticator_response.data.try_into()?,
|
||||||
|
reply_to: authenticator_response.reply_to,
|
||||||
|
protocol: authenticator_response.protocol,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<v3::response::AuthenticatorResponseData> for v2::response::AuthenticatorResponseData {
|
||||||
|
type Error = crate::Error;
|
||||||
|
|
||||||
|
fn try_from(
|
||||||
|
authenticator_response_data: v3::response::AuthenticatorResponseData,
|
||||||
|
) -> Result<Self, Self::Error> {
|
||||||
|
match authenticator_response_data {
|
||||||
|
v3::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response,
|
||||||
|
) => Ok(
|
||||||
|
v2::response::AuthenticatorResponseData::PendingRegistration(
|
||||||
|
pending_registration_response.into(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
v3::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
|
||||||
|
v2::response::AuthenticatorResponseData::Registered(registered_response.into()),
|
||||||
|
),
|
||||||
|
v3::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response,
|
||||||
|
) => Ok(v2::response::AuthenticatorResponseData::RemainingBandwidth(
|
||||||
|
remaining_bandwidth_response.into(),
|
||||||
|
)),
|
||||||
|
v3::response::AuthenticatorResponseData::TopUpBandwidth(_) => {
|
||||||
|
Err(Self::Error::Conversion(
|
||||||
|
"a v2 request couldn't produce a v3 only type of response".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::response::PendingRegistrationResponse> for v2::response::PendingRegistrationResponse {
|
||||||
|
fn from(value: v3::response::PendingRegistrationResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply_to: value.reply_to,
|
||||||
|
reply: value.reply.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::response::RegisteredResponse> for v2::response::RegisteredResponse {
|
||||||
|
fn from(value: v3::response::RegisteredResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply_to: value.reply_to,
|
||||||
|
reply: value.reply.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::response::RemainingBandwidthResponse> for v2::response::RemainingBandwidthResponse {
|
||||||
|
fn from(value: v3::response::RemainingBandwidthResponse) -> Self {
|
||||||
|
Self {
|
||||||
|
request_id: value.request_id,
|
||||||
|
reply_to: value.reply_to,
|
||||||
|
reply: value.reply.map(Into::into),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::registration::RegistrationData> for v2::registration::RegistrationData {
|
||||||
|
fn from(value: v3::registration::RegistrationData) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: value.nonce,
|
||||||
|
gateway_data: value.gateway_data.into(),
|
||||||
|
wg_port: value.wg_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::registration::RegistredData> for v2::registration::RegistredData {
|
||||||
|
fn from(value: v3::registration::RegistredData) -> Self {
|
||||||
|
Self {
|
||||||
|
pub_key: value.pub_key,
|
||||||
|
private_ip: value.private_ip,
|
||||||
|
wg_port: value.wg_port,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<v3::registration::RemainingBandwidthData> for v2::registration::RemainingBandwidthData {
|
||||||
|
fn from(value: v3::registration::RemainingBandwidthData) -> Self {
|
||||||
|
Self {
|
||||||
|
available_bandwidth: value.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 = 3;
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
// -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_wireguard_types::PeerPublicKey;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::IpAddr;
|
||||||
|
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<IpAddr, 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 = 1024 * 1024 * 1024; // 1 GB
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
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)]
|
||||||
|
pub struct FinalMessage {
|
||||||
|
/// Gateway client data
|
||||||
|
pub gateway_client: GatewayClient,
|
||||||
|
|
||||||
|
/// Ecash credential
|
||||||
|
pub credential: Option<CredentialSpendingData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct RegistrationData {
|
||||||
|
pub nonce: u64,
|
||||||
|
pub gateway_data: GatewayClient,
|
||||||
|
pub wg_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct RegistredData {
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
pub private_ip: IpAddr,
|
||||||
|
pub wg_port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
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)]
|
||||||
|
pub struct GatewayClient {
|
||||||
|
/// Base64 encoded x25519 public key
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
|
||||||
|
/// Assigned private IP
|
||||||
|
pub private_ip: IpAddr,
|
||||||
|
|
||||||
|
/// 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_ip: IpAddr,
|
||||||
|
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_ip.to_string().as_bytes());
|
||||||
|
mac.update(&nonce.to_le_bytes());
|
||||||
|
|
||||||
|
GatewayClient {
|
||||||
|
pub_key: PeerPublicKey::new(local_public),
|
||||||
|
private_ip,
|
||||||
|
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_ip.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)]
|
||||||
|
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]
|
||||||
|
#[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()),
|
||||||
|
"10.0.0.42".parse().unwrap(),
|
||||||
|
nonce,
|
||||||
|
);
|
||||||
|
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
// 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_sphinx::addressing::Recipient;
|
||||||
|
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)]
|
||||||
|
pub struct AuthenticatorRequest {
|
||||||
|
pub protocol: Protocol,
|
||||||
|
pub data: AuthenticatorRequestData,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub request_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthenticatorRequest {
|
||||||
|
pub fn from_reconstructed_message(
|
||||||
|
message: &nym_sphinx::receiver::ReconstructedMessage,
|
||||||
|
) -> Result<Self, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().deserialize(&message.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::Initial(init_message),
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_final_request(final_message: FinalMessage, reply_to: Recipient) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::Final(Box::new(final_message)),
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_topup_request(top_up_message: TopUpMessage, reply_to: Recipient) -> (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)),
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().serialize(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum AuthenticatorRequestData {
|
||||||
|
Initial(InitMessage),
|
||||||
|
Final(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 = 2;
|
||||||
|
let data = AuthenticatorRequest {
|
||||||
|
protocol: Protocol { version, service_provider_type: ServiceProviderType::Authenticator },
|
||||||
|
data: AuthenticatorRequestData::Initial(InitMessage::new(
|
||||||
|
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
|
||||||
|
)),
|
||||||
|
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").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,157 @@
|
|||||||
|
// 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 nym_sphinx::addressing::Recipient;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::make_bincode_serializer;
|
||||||
|
|
||||||
|
use super::VERSION;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct AuthenticatorResponse {
|
||||||
|
pub protocol: Protocol,
|
||||||
|
pub data: AuthenticatorResponseData,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AuthenticatorResponse {
|
||||||
|
pub fn new_pending_registration_success(
|
||||||
|
registration_data: RegistrationData,
|
||||||
|
request_id: u64,
|
||||||
|
reply_to: Recipient,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
|
||||||
|
reply: registration_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
reply_to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_registered(
|
||||||
|
registred_data: RegistredData,
|
||||||
|
reply_to: Recipient,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::Registered(RegisteredResponse {
|
||||||
|
reply: registred_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
reply_to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_remaining_bandwidth(
|
||||||
|
remaining_bandwidth_data: Option<RemainingBandwidthData>,
|
||||||
|
reply_to: Recipient,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
|
||||||
|
reply: remaining_bandwidth_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
reply_to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_topup_bandwidth(
|
||||||
|
remaining_bandwidth_data: RemainingBandwidthData,
|
||||||
|
reply_to: Recipient,
|
||||||
|
request_id: u64,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
protocol: Protocol {
|
||||||
|
service_provider_type: ServiceProviderType::Authenticator,
|
||||||
|
version: VERSION,
|
||||||
|
},
|
||||||
|
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
|
||||||
|
reply: remaining_bandwidth_data,
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
}),
|
||||||
|
reply_to,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recipient(&self) -> Recipient {
|
||||||
|
self.reply_to
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_reconstructed_message(
|
||||||
|
message: &nym_sphinx::receiver::ReconstructedMessage,
|
||||||
|
) -> Result<Self, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().deserialize(&message.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> Option<u64> {
|
||||||
|
match &self.data {
|
||||||
|
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
|
||||||
|
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
|
||||||
|
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
|
||||||
|
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum AuthenticatorResponseData {
|
||||||
|
PendingRegistration(PendingRegistrationResponse),
|
||||||
|
Registered(RegisteredResponse),
|
||||||
|
RemainingBandwidth(RemainingBandwidthResponse),
|
||||||
|
TopUpBandwidth(TopUpBandwidthResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct PendingRegistrationResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub reply: RegistrationData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RegisteredResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub reply: RegistredData,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct RemainingBandwidthResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub reply: Option<RemainingBandwidthData>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TopUpBandwidthResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
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)]
|
||||||
|
pub struct TopUpMessage {
|
||||||
|
/// Base64 encoded x25519 public key
|
||||||
|
pub pub_key: PeerPublicKey,
|
||||||
|
|
||||||
|
/// Ecash credential
|
||||||
|
pub credential: CredentialSpendingData,
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ use nym_credential_storage::models::RetrievedTicketbook;
|
|||||||
use nym_credential_storage::storage::Storage;
|
use nym_credential_storage::storage::Storage;
|
||||||
use nym_credentials::ecash::bandwidth::CredentialSpendingData;
|
use nym_credentials::ecash::bandwidth::CredentialSpendingData;
|
||||||
use nym_credentials_interface::{
|
use nym_credentials_interface::{
|
||||||
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, VerificationKeyAuth,
|
AnnotatedCoinIndexSignature, AnnotatedExpirationDateSignature, TicketType, VerificationKeyAuth,
|
||||||
};
|
};
|
||||||
use nym_ecash_time::Date;
|
use nym_ecash_time::Date;
|
||||||
use nym_validator_client::nym_api::EpochId;
|
use nym_validator_client::nym_api::EpochId;
|
||||||
@@ -64,9 +64,10 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
|||||||
BandwidthController { storage, client }
|
BandwidthController { storage, client }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve one of the stored, unused credentials that hasn't yet expired.
|
/// Tries to retrieve one of the stored, unused credentials for the given type that hasn't yet expired.
|
||||||
pub async fn get_next_usable_ticketbook(
|
pub async fn get_next_usable_ticketbook(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: TicketType,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Result<RetrievedTicketbook, BandwidthControllerError>
|
) -> Result<RetrievedTicketbook, BandwidthControllerError>
|
||||||
where
|
where
|
||||||
@@ -74,7 +75,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
|||||||
{
|
{
|
||||||
let Some(ticketbook) = self
|
let Some(ticketbook) = self
|
||||||
.storage
|
.storage
|
||||||
.get_next_unspent_usable_ticketbook(tickets)
|
.get_next_unspent_usable_ticketbook(ticketbook_type.to_string(), tickets)
|
||||||
.await
|
.await
|
||||||
.map_err(BandwidthControllerError::credential_storage_error)?
|
.map_err(BandwidthControllerError::credential_storage_error)?
|
||||||
else {
|
else {
|
||||||
@@ -181,6 +182,7 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
|||||||
|
|
||||||
pub async fn prepare_ecash_ticket(
|
pub async fn prepare_ecash_ticket(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: TicketType,
|
||||||
provider_pk: [u8; 32],
|
provider_pk: [u8; 32],
|
||||||
tickets_to_spend: u32,
|
tickets_to_spend: u32,
|
||||||
) -> Result<PreparedCredential, BandwidthControllerError>
|
) -> Result<PreparedCredential, BandwidthControllerError>
|
||||||
@@ -188,7 +190,9 @@ impl<C, St: Storage> BandwidthController<C, St> {
|
|||||||
C: DkgQueryClient + Sync + Send,
|
C: DkgQueryClient + Sync + Send,
|
||||||
<St as Storage>::StorageError: Send + Sync + 'static,
|
<St as Storage>::StorageError: Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let retrieved_ticketbook = self.get_next_usable_ticketbook(tickets_to_spend).await?;
|
let retrieved_ticketbook = self
|
||||||
|
.get_next_usable_ticketbook(ticketbook_type, tickets_to_spend)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let ticketbook_id = retrieved_ticketbook.ticketbook_id;
|
let ticketbook_id = retrieved_ticketbook.ticketbook_id;
|
||||||
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
|
let epoch_id = retrieved_ticketbook.ticketbook.epoch_id();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ zeroize.workspace = true
|
|||||||
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
nym-bandwidth-controller = { path = "../../bandwidth-controller" }
|
||||||
nym-credentials = { path = "../../credentials" }
|
nym-credentials = { path = "../../credentials" }
|
||||||
nym-credential-storage = { path = "../../credential-storage" }
|
nym-credential-storage = { path = "../../credential-storage" }
|
||||||
|
nym-credentials-interface = { path = "../../credentials-interface" }
|
||||||
nym-crypto = { path = "../../crypto" }
|
nym-crypto = { path = "../../crypto" }
|
||||||
nym-gateway-requests = { path = "../../gateway-requests" }
|
nym-gateway-requests = { path = "../../gateway-requests" }
|
||||||
nym-network-defaults = { path = "../../network-defaults" }
|
nym-network-defaults = { path = "../../network-defaults" }
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use nym_bandwidth_controller::{BandwidthController, BandwidthStatusMessage};
|
|||||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
||||||
use nym_credential_storage::storage::Storage as CredentialStorage;
|
use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||||
use nym_credentials::CredentialSpendingData;
|
use nym_credentials::CredentialSpendingData;
|
||||||
|
use nym_credentials_interface::TicketType;
|
||||||
use nym_crypto::asymmetric::identity;
|
use nym_crypto::asymmetric::identity;
|
||||||
use nym_gateway_requests::registration::handshake::client_handshake;
|
use nym_gateway_requests::registration::handshake::client_handshake;
|
||||||
use nym_gateway_requests::{
|
use nym_gateway_requests::{
|
||||||
@@ -748,7 +749,11 @@ impl<C, St> GatewayClient<C, St> {
|
|||||||
}
|
}
|
||||||
let prepared_credential = self
|
let prepared_credential = self
|
||||||
.unchecked_bandwidth_controller()
|
.unchecked_bandwidth_controller()
|
||||||
.prepare_ecash_ticket(self.gateway_identity.to_bytes(), TICKETS_TO_SPEND)
|
.prepare_ecash_ticket(
|
||||||
|
TicketType::V1MixnetEntry,
|
||||||
|
self.gateway_identity.to_bytes(),
|
||||||
|
TICKETS_TO_SPEND,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match self.claim_ecash_bandwidth(prepared_credential.data).await {
|
match self.claim_ecash_bandwidth(prepared_credential.data).await {
|
||||||
|
|||||||
@@ -9,10 +9,15 @@ use comfy_table::Table;
|
|||||||
use nym_credential_storage::initialise_persistent_storage;
|
use nym_credential_storage::initialise_persistent_storage;
|
||||||
use nym_credential_storage::storage::Storage;
|
use nym_credential_storage::storage::Storage;
|
||||||
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
|
use nym_credentials::ecash::bandwidth::serialiser::VersionedSerialise;
|
||||||
|
use nym_credentials_interface::TicketType;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
|
/// Specify which type of ticketbook
|
||||||
|
#[clap(long, default_value_t = TicketType::V1MixnetEntry)]
|
||||||
|
pub(crate) ticketbook_type: TicketType,
|
||||||
|
|
||||||
/// Specify the index of the ticket to retrieve from the ticketbook.
|
/// Specify the index of the ticket to retrieve from the ticketbook.
|
||||||
/// By default, the current unspent value is used.
|
/// By default, the current unspent value is used.
|
||||||
#[clap(long, group = "output")]
|
#[clap(long, group = "output")]
|
||||||
@@ -62,7 +67,7 @@ pub async fn execute(args: Args) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let persistent_storage = initialise_persistent_storage(&credentials_store).await;
|
let persistent_storage = initialise_persistent_storage(&credentials_store).await;
|
||||||
let Some(mut next_ticketbook) = persistent_storage
|
let Some(mut next_ticketbook) = persistent_storage
|
||||||
.get_next_unspent_usable_ticketbook(0)
|
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0)
|
||||||
.await?
|
.await?
|
||||||
else {
|
else {
|
||||||
bail!(
|
bail!(
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::utils::CommonConfigsWrapper;
|
|
||||||
use anyhow::bail;
|
|
||||||
use clap::ArgGroup;
|
use clap::ArgGroup;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use nym_credential_storage::initialise_persistent_storage;
|
use nym_credential_storage::initialise_persistent_storage;
|
||||||
@@ -31,7 +29,7 @@ impl FromStr for CredentialDataWrapper {
|
|||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Config file of the client that is supposed to use the credential.
|
/// Config file of the client that is supposed to use the credential.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
pub(crate) client_config: PathBuf,
|
pub(crate) credentials_store: PathBuf,
|
||||||
|
|
||||||
/// Explicitly provide the encoded credential data (as base58)
|
/// Explicitly provide the encoded credential data (as base58)
|
||||||
#[clap(long, group = "cred_data")]
|
#[clap(long, group = "cred_data")]
|
||||||
@@ -70,21 +68,7 @@ impl Args {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
pub async fn execute(args: Args) -> anyhow::Result<()> {
|
||||||
let loaded = CommonConfigsWrapper::try_load(&args.client_config)?;
|
let credentials_store = initialise_persistent_storage(args.credentials_store.clone()).await;
|
||||||
|
|
||||||
if let Ok(id) = loaded.try_get_id() {
|
|
||||||
println!("loaded config file for client '{id}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
let Ok(credentials_store) = loaded.try_get_credentials_store() else {
|
|
||||||
bail!("the loaded config does not have a credentials store information")
|
|
||||||
};
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"using credentials store at '{}'",
|
|
||||||
credentials_store.display()
|
|
||||||
);
|
|
||||||
let credentials_store = initialise_persistent_storage(credentials_store).await;
|
|
||||||
|
|
||||||
let version = args.version;
|
let version = args.version;
|
||||||
let standalone = args.standalone;
|
let standalone = args.standalone;
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ async fn issue_to_file(args: Args, client: SigningClient) -> anyhow::Result<()>
|
|||||||
utils::issue_credential(&client, &credentials_store, &secret, args.ticketbook_type).await?;
|
utils::issue_credential(&client, &credentials_store, &secret, args.ticketbook_type).await?;
|
||||||
|
|
||||||
let ticketbook = credentials_store
|
let ticketbook = credentials_store
|
||||||
.get_next_unspent_usable_ticketbook(0)
|
.get_next_unspent_usable_ticketbook(args.ticketbook_type.to_string(), 0)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(anyhow!("we just issued a ticketbook, it must be present!"))?
|
.ok_or(anyhow!("we just issued a ticketbook, it must be present!"))?
|
||||||
.ticketbook;
|
.ticketbook;
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ impl MemoryEcachTicketbookManager {
|
|||||||
|
|
||||||
pub async fn get_next_unspent_ticketbook_and_update(
|
pub async fn get_next_unspent_ticketbook_and_update(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: String,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Option<RetrievedTicketbook> {
|
) -> Option<RetrievedTicketbook> {
|
||||||
let mut guard = self.inner.write().await;
|
let mut guard = self.inner.write().await;
|
||||||
@@ -81,6 +82,7 @@ impl MemoryEcachTicketbookManager {
|
|||||||
if !t.ticketbook.expired()
|
if !t.ticketbook.expired()
|
||||||
&& t.ticketbook.spent_tickets() + tickets as u64
|
&& t.ticketbook.spent_tickets() + tickets as u64
|
||||||
<= t.ticketbook.params_total_tickets()
|
<= t.ticketbook.params_total_tickets()
|
||||||
|
&& t.ticketbook.ticketbook_type().to_string() == ticketbook_type
|
||||||
{
|
{
|
||||||
t.ticketbook
|
t.ticketbook
|
||||||
.update_spent_tickets(t.ticketbook.spent_tickets() + tickets as u64);
|
.update_spent_tickets(t.ticketbook.spent_tickets() + tickets as u64);
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ impl SqliteEcashTicketbookManager {
|
|||||||
|
|
||||||
pub(crate) async fn get_next_unspent_ticketbook<'a, E>(
|
pub(crate) async fn get_next_unspent_ticketbook<'a, E>(
|
||||||
executor: E,
|
executor: E,
|
||||||
|
ticketbook_type: String,
|
||||||
deadline: Date,
|
deadline: Date,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Result<Option<StoredIssuedTicketbook>, sqlx::Error>
|
) -> Result<Option<StoredIssuedTicketbook>, sqlx::Error>
|
||||||
@@ -296,12 +297,14 @@ where
|
|||||||
FROM ecash_ticketbook
|
FROM ecash_ticketbook
|
||||||
WHERE used_tickets + ? <= total_tickets
|
WHERE used_tickets + ? <= total_tickets
|
||||||
AND expiration_date >= ?
|
AND expiration_date >= ?
|
||||||
|
AND ticketbook_type = ?
|
||||||
ORDER BY expiration_date ASC
|
ORDER BY expiration_date ASC
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.bind(tickets)
|
.bind(tickets)
|
||||||
.bind(deadline)
|
.bind(deadline)
|
||||||
|
.bind(ticketbook_type)
|
||||||
.fetch_optional(executor)
|
.fetch_optional(executor)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,17 +85,18 @@ impl Storage for EphemeralStorage {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to retrieve one of the stored ticketbook,
|
/// Tries to retrieve one of the stored ticketbook for the specified type,
|
||||||
/// that has not yet expired and has required number of unspent tickets.
|
/// that has not yet expired and has required number of unspent tickets.
|
||||||
/// it immediately updated the on-disk number of used tickets so that another task
|
/// it immediately updated the on-disk number of used tickets so that another task
|
||||||
/// could obtain their own tickets at the same time
|
/// could obtain their own tickets at the same time
|
||||||
async fn get_next_unspent_usable_ticketbook(
|
async fn get_next_unspent_usable_ticketbook(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: String,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Result<Option<RetrievedTicketbook>, Self::StorageError> {
|
) -> Result<Option<RetrievedTicketbook>, Self::StorageError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.storage_manager
|
.storage_manager
|
||||||
.get_next_unspent_ticketbook_and_update(tickets)
|
.get_next_unspent_ticketbook_and_update(ticketbook_type, tickets)
|
||||||
.await)
|
.await)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -171,13 +171,16 @@ impl Storage for PersistentStorage {
|
|||||||
/// could obtain their own tickets at the same time
|
/// could obtain their own tickets at the same time
|
||||||
async fn get_next_unspent_usable_ticketbook(
|
async fn get_next_unspent_usable_ticketbook(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: String,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Result<Option<RetrievedTicketbook>, Self::StorageError> {
|
) -> Result<Option<RetrievedTicketbook>, Self::StorageError> {
|
||||||
let deadline = ecash_today().ecash_date();
|
let deadline = ecash_today().ecash_date();
|
||||||
let mut tx = self.storage_manager.begin_storage_tx().await?;
|
let mut tx = self.storage_manager.begin_storage_tx().await?;
|
||||||
|
|
||||||
// we don't want ticketbooks with expiration in the past
|
// we don't want ticketbooks with expiration in the past
|
||||||
let Some(raw) = get_next_unspent_ticketbook(&mut tx, deadline, tickets).await? else {
|
let Some(raw) =
|
||||||
|
get_next_unspent_ticketbook(&mut tx, ticketbook_type, deadline, tickets).await?
|
||||||
|
else {
|
||||||
// make sure to finish our tx
|
// make sure to finish our tx
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
|
|||||||
@@ -45,12 +45,13 @@ pub trait Storage: Send + Sync {
|
|||||||
|
|
||||||
async fn remove_pending_ticketbook(&self, pending_id: i64) -> Result<(), Self::StorageError>;
|
async fn remove_pending_ticketbook(&self, pending_id: i64) -> Result<(), Self::StorageError>;
|
||||||
|
|
||||||
/// Tries to retrieve one of the stored ticketbook,
|
/// Tries to retrieve one of the stored ticketbook for the specified type,
|
||||||
/// that has not yet expired and has required number of unspent tickets.
|
/// that has not yet expired and has required number of unspent tickets.
|
||||||
/// it immediately updated the on-disk number of used tickets so that another task
|
/// it immediately updated the on-disk number of used tickets so that another task
|
||||||
/// could obtain their own tickets at the same time
|
/// could obtain their own tickets at the same time
|
||||||
async fn get_next_unspent_usable_ticketbook(
|
async fn get_next_unspent_usable_ticketbook(
|
||||||
&self,
|
&self,
|
||||||
|
ticketbook_type: String,
|
||||||
tickets: u32,
|
tickets: u32,
|
||||||
) -> Result<Option<RetrievedTicketbook>, Self::StorageError>;
|
) -> Result<Option<RetrievedTicketbook>, Self::StorageError>;
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,6 @@
|
|||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("peers in wireguard don't match with in-memory ")]
|
|
||||||
PeerMismatch,
|
|
||||||
|
|
||||||
#[error("traffic byte data needs to be increasing")]
|
#[error("traffic byte data needs to be increasing")]
|
||||||
InconsistentConsumedBytes,
|
InconsistentConsumedBytes,
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use defguard_wireguard_rs::{
|
|||||||
};
|
};
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use nym_authenticator_requests::{
|
use nym_authenticator_requests::{
|
||||||
v1::registration::BANDWIDTH_CAP_PER_DAY, v2::registration::RemainingBandwidthData,
|
latest::registration::RemainingBandwidthData, v1::registration::BANDWIDTH_CAP_PER_DAY,
|
||||||
};
|
};
|
||||||
use nym_credential_verification::{
|
use nym_credential_verification::{
|
||||||
bandwidth_storage_manager::BandwidthStorageManager, BandwidthFlushingBehaviourConfig,
|
bandwidth_storage_manager::BandwidthStorageManager, BandwidthFlushingBehaviourConfig,
|
||||||
@@ -160,13 +160,10 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
|||||||
.ok_or(Error::MissingClientBandwidthEntry)?
|
.ok_or(Error::MissingClientBandwidthEntry)?
|
||||||
.client_id
|
.client_id
|
||||||
{
|
{
|
||||||
let bandwidth = storage
|
storage.create_bandwidth_entry(client_id).await?;
|
||||||
.get_available_bandwidth(client_id)
|
|
||||||
.await?
|
|
||||||
.ok_or(Error::MissingClientBandwidthEntry)?;
|
|
||||||
Ok(Some(BandwidthStorageManager::new(
|
Ok(Some(BandwidthStorageManager::new(
|
||||||
storage,
|
storage,
|
||||||
ClientBandwidth::new(bandwidth.into()),
|
ClientBandwidth::new(Default::default()),
|
||||||
client_id,
|
client_id,
|
||||||
BandwidthFlushingBehaviourConfig::default(),
|
BandwidthFlushingBehaviourConfig::default(),
|
||||||
true,
|
true,
|
||||||
@@ -228,14 +225,10 @@ impl<St: Storage + Clone + 'static> PeerController<St> {
|
|||||||
.available_bandwidth()
|
.available_bandwidth()
|
||||||
.await
|
.await
|
||||||
} else {
|
} else {
|
||||||
let peer = self
|
let Some(peer) = self.host_information.read().await.peers.get(key).cloned() else {
|
||||||
.host_information
|
// host information not updated yet
|
||||||
.read()
|
return Ok(None);
|
||||||
.await
|
};
|
||||||
.peers
|
|
||||||
.get(key)
|
|
||||||
.ok_or(Error::PeerMismatch)?
|
|
||||||
.clone();
|
|
||||||
BANDWIDTH_CAP_PER_DAY.saturating_sub((peer.rx_bytes + peer.tx_bytes) as i64)
|
BANDWIDTH_CAP_PER_DAY.saturating_sub((peer.rx_bytes + peer.tx_bytes) as i64)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::peer_controller::PeerControlRequest;
|
use crate::peer_controller::PeerControlRequest;
|
||||||
|
use defguard_wireguard_rs::host::Peer;
|
||||||
use defguard_wireguard_rs::{host::Host, key::Key};
|
use defguard_wireguard_rs::{host::Host, key::Key};
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use nym_authenticator_requests::v2::registration::BANDWIDTH_CAP_PER_DAY;
|
use nym_authenticator_requests::v2::registration::BANDWIDTH_CAP_PER_DAY;
|
||||||
@@ -71,15 +72,11 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
|||||||
Ok(success)
|
Ok(success)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn active_peer(&mut self, storage_peer: WireguardPeer) -> Result<bool, Error> {
|
async fn active_peer(
|
||||||
let kernel_peer = self
|
&mut self,
|
||||||
.host_information
|
storage_peer: WireguardPeer,
|
||||||
.read()
|
kernel_peer: Peer,
|
||||||
.await
|
) -> Result<bool, Error> {
|
||||||
.peers
|
|
||||||
.get(&self.public_key)
|
|
||||||
.ok_or(Error::PeerMismatch)?
|
|
||||||
.clone();
|
|
||||||
if let Some(bandwidth_manager) = &self.bandwidth_storage_manager {
|
if let Some(bandwidth_manager) = &self.bandwidth_storage_manager {
|
||||||
let spent_bandwidth = (kernel_peer.rx_bytes + kernel_peer.tx_bytes)
|
let spent_bandwidth = (kernel_peer.rx_bytes + kernel_peer.tx_bytes)
|
||||||
.checked_sub(storage_peer.rx_bytes as u64 + storage_peer.tx_bytes as u64)
|
.checked_sub(storage_peer.rx_bytes as u64 + storage_peer.tx_bytes as u64)
|
||||||
@@ -111,11 +108,21 @@ impl<St: Storage + Clone + 'static> PeerHandle<St> {
|
|||||||
while !self.task_client.is_shutdown() {
|
while !self.task_client.is_shutdown() {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = self.timeout_check_interval.next() => {
|
_ = self.timeout_check_interval.next() => {
|
||||||
let Some(peer) = self.storage.get_wireguard_peer(&self.public_key.to_string()).await? else {
|
let Some(kernel_peer) = self
|
||||||
|
.host_information
|
||||||
|
.read()
|
||||||
|
.await
|
||||||
|
.peers
|
||||||
|
.get(&self.public_key)
|
||||||
|
.cloned() else {
|
||||||
|
// the host information hasn't beed updated yet
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(storage_peer) = self.storage.get_wireguard_peer(&self.public_key.to_string()).await? else {
|
||||||
log::debug!("Peer {:?} not in storage anymore, shutting down handle", self.public_key);
|
log::debug!("Peer {:?} not in storage anymore, shutting down handle", self.public_key);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
if !self.active_peer(peer).await? {
|
if !self.active_peer(storage_peer, kernel_peer).await? {
|
||||||
log::debug!("Peer {:?} doesn't have bandwidth anymore, shutting down handle", self.public_key);
|
log::debug!("Peer {:?} doesn't have bandwidth anymore, shutting down handle", self.public_key);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,15 @@ pub enum AuthenticatorError {
|
|||||||
|
|
||||||
#[error("peers can't be interacted with anymore")]
|
#[error("peers can't be interacted with anymore")]
|
||||||
PeerInteractionStopped,
|
PeerInteractionStopped,
|
||||||
|
|
||||||
|
#[error("operation is not supported")]
|
||||||
|
UnsupportedOperation,
|
||||||
|
|
||||||
|
#[error("operation unavailable for older client")]
|
||||||
|
OldClient,
|
||||||
|
|
||||||
|
#[error("storage should have the requested bandwidht entry")]
|
||||||
|
MissingClientBandwidthEntry,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, AuthenticatorError>;
|
pub type Result<T> = std::result::Result<T, AuthenticatorError>;
|
||||||
|
|||||||
@@ -9,25 +9,24 @@ use std::{
|
|||||||
use crate::{error::AuthenticatorError, peer_manager::PeerManager};
|
use crate::{error::AuthenticatorError, peer_manager::PeerManager};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use nym_authenticator_requests::v2::{
|
|
||||||
self,
|
|
||||||
registration::{
|
|
||||||
FinalMessage, GatewayClient, InitMessage, PendingRegistrations, PrivateIPs,
|
|
||||||
RegistrationData, RegistredData,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
use nym_authenticator_requests::{
|
use nym_authenticator_requests::{
|
||||||
v1,
|
v1, v2,
|
||||||
v2::{
|
v3::{
|
||||||
|
self,
|
||||||
|
registration::{
|
||||||
|
FinalMessage, GatewayClient, InitMessage, PendingRegistrations, PrivateIPs,
|
||||||
|
RegistrationData, RegistredData, RemainingBandwidthData,
|
||||||
|
},
|
||||||
request::{AuthenticatorRequest, AuthenticatorRequestData},
|
request::{AuthenticatorRequest, AuthenticatorRequestData},
|
||||||
response::AuthenticatorResponse,
|
response::AuthenticatorResponse,
|
||||||
},
|
},
|
||||||
|
CURRENT_VERSION,
|
||||||
};
|
};
|
||||||
use nym_credential_verification::{
|
use nym_credential_verification::{
|
||||||
bandwidth_storage_manager::BandwidthStorageManager, ecash::EcashManager,
|
bandwidth_storage_manager::BandwidthStorageManager, ecash::EcashManager,
|
||||||
BandwidthFlushingBehaviourConfig, ClientBandwidth, CredentialVerifier,
|
BandwidthFlushingBehaviourConfig, ClientBandwidth, CredentialVerifier,
|
||||||
};
|
};
|
||||||
use nym_credentials_interface::CredentialSpendingData;
|
use nym_credentials_interface::{CredentialSpendingData, TicketType};
|
||||||
use nym_crypto::asymmetric::x25519::KeyPair;
|
use nym_crypto::asymmetric::x25519::KeyPair;
|
||||||
use nym_gateway_requests::models::CredentialSpendingRequest;
|
use nym_gateway_requests::models::CredentialSpendingRequest;
|
||||||
use nym_gateway_storage::Storage;
|
use nym_gateway_storage::Storage;
|
||||||
@@ -289,10 +288,6 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
|
|||||||
credential: CredentialSpendingData,
|
credential: CredentialSpendingData,
|
||||||
client_id: i64,
|
client_id: i64,
|
||||||
) -> Result<i64> {
|
) -> Result<i64> {
|
||||||
ecash_verifier
|
|
||||||
.storage()
|
|
||||||
.create_bandwidth_entry(client_id)
|
|
||||||
.await?;
|
|
||||||
let bandwidth = ecash_verifier
|
let bandwidth = ecash_verifier
|
||||||
.storage()
|
.storage()
|
||||||
.get_available_bandwidth(client_id)
|
.get_available_bandwidth(client_id)
|
||||||
@@ -329,6 +324,68 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn on_topup_bandwidth_request(
|
||||||
|
&mut self,
|
||||||
|
peer_public_key: PeerPublicKey,
|
||||||
|
credential: CredentialSpendingData,
|
||||||
|
request_id: u64,
|
||||||
|
reply_to: Recipient,
|
||||||
|
) -> AuthenticatorHandleResult {
|
||||||
|
let Some(ecash_verifier) = self.ecash_verifier.clone() else {
|
||||||
|
return Err(AuthenticatorError::UnsupportedOperation);
|
||||||
|
};
|
||||||
|
let client_id = ecash_verifier
|
||||||
|
.storage()
|
||||||
|
.get_wireguard_peer(&peer_public_key.to_string())
|
||||||
|
.await?
|
||||||
|
.ok_or(AuthenticatorError::MissingClientBandwidthEntry)?
|
||||||
|
.client_id
|
||||||
|
.ok_or(AuthenticatorError::OldClient)?;
|
||||||
|
let bandwidth = ecash_verifier
|
||||||
|
.storage()
|
||||||
|
.get_available_bandwidth(client_id)
|
||||||
|
.await?
|
||||||
|
.ok_or(AuthenticatorError::InternalError(
|
||||||
|
"bandwidth entry should have just been created".to_string(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let t_type = credential.payment.t_type;
|
||||||
|
let client_bandwidth = ClientBandwidth::new(bandwidth.into());
|
||||||
|
let mut verifier = CredentialVerifier::new(
|
||||||
|
CredentialSpendingRequest::new(credential),
|
||||||
|
ecash_verifier.clone(),
|
||||||
|
BandwidthStorageManager::new(
|
||||||
|
ecash_verifier.storage().clone(),
|
||||||
|
client_bandwidth,
|
||||||
|
client_id,
|
||||||
|
BandwidthFlushingBehaviourConfig::default(),
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
verifier.verify().await?;
|
||||||
|
|
||||||
|
let amount = TicketType::try_from_encoded(t_type)
|
||||||
|
.map_err(|e| {
|
||||||
|
AuthenticatorError::CredentialVerificationError(
|
||||||
|
nym_credential_verification::Error::UnknownTicketType(e),
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.to_repr()
|
||||||
|
.bandwidth_value() as i64;
|
||||||
|
let available_bandwidth = ecash_verifier
|
||||||
|
.storage()
|
||||||
|
.increase_bandwidth(client_id, amount)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(AuthenticatorResponse::new_topup_bandwidth(
|
||||||
|
RemainingBandwidthData {
|
||||||
|
available_bandwidth,
|
||||||
|
},
|
||||||
|
reply_to,
|
||||||
|
request_id,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
async fn on_reconstructed_message(
|
async fn on_reconstructed_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
reconstructed: ReconstructedMessage,
|
reconstructed: ReconstructedMessage,
|
||||||
@@ -362,6 +419,15 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
AuthenticatorRequestData::TopUpBandwidth(topup_message) => {
|
||||||
|
self.on_topup_bandwidth_request(
|
||||||
|
topup_message.pub_key,
|
||||||
|
topup_message.credential,
|
||||||
|
request.request_id,
|
||||||
|
request.reply_to,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,6 +458,7 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn run(mut self) -> Result<()> {
|
pub(crate) async fn run(mut self) -> Result<()> {
|
||||||
|
log::info!("Using authenticator version {}", CURRENT_VERSION);
|
||||||
let mut task_client = self.task_handle.fork("main_loop");
|
let mut task_client = self.task_handle.fork("main_loop");
|
||||||
|
|
||||||
while !task_client.is_shutdown() {
|
while !task_client.is_shutdown() {
|
||||||
@@ -440,6 +507,7 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
|
|||||||
match request_version {
|
match request_version {
|
||||||
[1, _] => v1::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
[1, _] => v1::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||||
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket { source: err })
|
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket { source: err })
|
||||||
|
.map(Into::<v2::request::AuthenticatorRequest>::into)
|
||||||
.map(Into::into),
|
.map(Into::into),
|
||||||
[2, request_type] => {
|
[2, request_type] => {
|
||||||
if request_type == ServiceProviderType::Authenticator as u8 {
|
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||||
@@ -452,6 +520,16 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
|
|||||||
Err(AuthenticatorError::InvalidPacketType(request_type))
|
Err(AuthenticatorError::InvalidPacketType(request_type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[3, request_type] => {
|
||||||
|
if request_type == ServiceProviderType::Authenticator as u8 {
|
||||||
|
v3::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
|
||||||
|
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
|
||||||
|
source: err,
|
||||||
|
})
|
||||||
|
} 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))
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask};
|
use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask};
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use nym_authenticator_requests::v2::registration::{GatewayClient, RemainingBandwidthData};
|
use nym_authenticator_requests::latest::registration::{GatewayClient, RemainingBandwidthData};
|
||||||
use nym_wireguard::{
|
use nym_wireguard::{
|
||||||
peer_controller::{
|
peer_controller::{
|
||||||
AddPeerControlResponse, PeerControlRequest, QueryBandwidthControlResponse,
|
AddPeerControlResponse, PeerControlRequest, QueryBandwidthControlResponse,
|
||||||
|
|||||||
Reference in New Issue
Block a user