Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 313f700885 |
@@ -67,6 +67,9 @@ pub enum Error {
|
|||||||
#[error("bandwidth controller error: {0}")]
|
#[error("bandwidth controller error: {0}")]
|
||||||
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
||||||
|
|
||||||
|
#[error("coconut error: {0}")]
|
||||||
|
CoconutApiError(#[from] nym_validator_client::coconut::CoconutApiError),
|
||||||
|
|
||||||
#[error("invalid voucher blob")]
|
#[error("invalid voucher blob")]
|
||||||
InvalidVoucherBlob,
|
InvalidVoucherBlob,
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
mod client;
|
mod client;
|
||||||
mod config;
|
mod config;
|
||||||
mod connection_state;
|
mod connection_state;
|
||||||
|
mod credential;
|
||||||
mod native_client;
|
mod native_client;
|
||||||
mod paths;
|
mod paths;
|
||||||
mod socks5_client;
|
mod socks5_client;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use super::credential::verify_credential;
|
||||||
use super::{connection_state::BuilderState, Config, StoragePaths};
|
use super::{connection_state::BuilderState, Config, StoragePaths};
|
||||||
use crate::bandwidth::BandwidthAcquireClient;
|
use crate::bandwidth::BandwidthAcquireClient;
|
||||||
use crate::mixnet::socks5_client::Socks5MixnetClient;
|
use crate::mixnet::socks5_client::Socks5MixnetClient;
|
||||||
@@ -28,11 +29,15 @@ use nym_client_core::error::ClientCoreError;
|
|||||||
use nym_client_core::init::helpers::current_gateways;
|
use nym_client_core::init::helpers::current_gateways;
|
||||||
use nym_client_core::init::setup_gateway;
|
use nym_client_core::init::setup_gateway;
|
||||||
use nym_client_core::init::types::{GatewaySelectionSpecification, GatewaySetup};
|
use nym_client_core::init::types::{GatewaySelectionSpecification, GatewaySetup};
|
||||||
|
use nym_credentials::coconut::bandwidth::issued::BandwidthCredentialIssuedDataVariant;
|
||||||
|
use nym_credentials::IssuedBandwidthCredential;
|
||||||
use nym_network_defaults::WG_TUN_DEVICE_IP_ADDRESS;
|
use nym_network_defaults::WG_TUN_DEVICE_IP_ADDRESS;
|
||||||
use nym_socks5_client_core::config::Socks5;
|
use nym_socks5_client_core::config::Socks5;
|
||||||
use nym_task::manager::TaskStatus;
|
use nym_task::manager::TaskStatus;
|
||||||
use nym_task::{TaskClient, TaskHandle};
|
use nym_task::{TaskClient, TaskHandle};
|
||||||
use nym_topology::provider_trait::TopologyProvider;
|
use nym_topology::provider_trait::TopologyProvider;
|
||||||
|
use nym_validator_client::coconut::{all_coconut_api_clients, CoconutApiError};
|
||||||
|
use nym_validator_client::nyxd::error::NyxdError;
|
||||||
use nym_validator_client::{nyxd, QueryHttpRpcNyxdClient};
|
use nym_validator_client::{nyxd, QueryHttpRpcNyxdClient};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
@@ -188,6 +193,18 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn enable_local_credentials_check(mut self) -> Self {
|
||||||
|
self.config.enabled_local_credentials_check = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn local_credentials_check(mut self, local_credentials_check: bool) -> Self {
|
||||||
|
self.config.enabled_local_credentials_check = local_credentials_check;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Use a custom debugging configuration.
|
/// Use a custom debugging configuration.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn debug_config(mut self, debug_config: DebugConfig) -> Self {
|
pub fn debug_config(mut self, debug_config: DebugConfig) -> Self {
|
||||||
@@ -334,17 +351,18 @@ where
|
|||||||
storage: S,
|
storage: S,
|
||||||
) -> Result<DisconnectedMixnetClient<S>> {
|
) -> Result<DisconnectedMixnetClient<S>> {
|
||||||
// don't create dkg client for the bandwidth controller if credentials are disabled
|
// don't create dkg client for the bandwidth controller if credentials are disabled
|
||||||
let dkg_query_client = if config.enabled_credentials_mode {
|
let dkg_query_client =
|
||||||
let client_config =
|
if config.enabled_credentials_mode || config.enabled_local_credentials_check {
|
||||||
nyxd::Config::try_from_nym_network_details(&config.network_details)?;
|
let client_config =
|
||||||
let client = QueryHttpRpcNyxdClient::connect(
|
nyxd::Config::try_from_nym_network_details(&config.network_details)?;
|
||||||
client_config,
|
let client = QueryHttpRpcNyxdClient::connect(
|
||||||
config.network_details.endpoints[0].nyxd_url.as_str(),
|
client_config,
|
||||||
)?;
|
config.network_details.endpoints[0].nyxd_url.as_str(),
|
||||||
Some(client)
|
)?;
|
||||||
} else {
|
Some(client)
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Ok(DisconnectedMixnetClient {
|
Ok(DisconnectedMixnetClient {
|
||||||
config,
|
config,
|
||||||
@@ -549,9 +567,89 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn fetch_valid_credential(
|
||||||
|
&self,
|
||||||
|
gateway_id: &str,
|
||||||
|
) -> Result<(IssuedBandwidthCredential, i64)> {
|
||||||
|
debug!(
|
||||||
|
"Checking if there is an unspent credential for gateway: {}",
|
||||||
|
gateway_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let stored_issued_credential = self
|
||||||
|
.storage
|
||||||
|
.credential_store()
|
||||||
|
.get_next_unspent_credential(gateway_id)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
debug!("Found unspent credential: {}", stored_issued_credential.id);
|
||||||
|
|
||||||
|
let credential_id = stored_issued_credential.id;
|
||||||
|
let issued_credential =
|
||||||
|
IssuedBandwidthCredential::unpack_v1(&stored_issued_credential.credential_data)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let valid_credential = match issued_credential.variant_data() {
|
||||||
|
BandwidthCredentialIssuedDataVariant::Voucher(_) => {
|
||||||
|
debug!("Credential {credential_id} is a voucher");
|
||||||
|
issued_credential
|
||||||
|
}
|
||||||
|
BandwidthCredentialIssuedDataVariant::FreePass(freepass_info) => {
|
||||||
|
debug!("Credential {credential_id} is a free pass");
|
||||||
|
if freepass_info.expired() {
|
||||||
|
warn!(
|
||||||
|
"the free pass (id: {credential_id}) has already expired! The expiration was set to {}",
|
||||||
|
freepass_info.expiry_date()
|
||||||
|
);
|
||||||
|
self.storage
|
||||||
|
.credential_store()
|
||||||
|
.mark_expired(credential_id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
panic!("credential {credential_id} has already expired");
|
||||||
|
}
|
||||||
|
issued_credential
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Ok((valid_credential, credential_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_coconut_api_clients(&self, epoch_id: u64) -> Result<CoconutClients> {
|
||||||
|
let nyxd_client = self.dkg_query_client.as_ref().unwrap();
|
||||||
|
match all_coconut_api_clients(nyxd_client, epoch_id).await {
|
||||||
|
Ok(clients) => Ok(CoconutClients::Clients(clients)),
|
||||||
|
Err(CoconutApiError::ContractQueryFailure { source }) => match source {
|
||||||
|
NyxdError::NoContractAddressAvailable(_) => Ok(CoconutClients::NoContractAvailable),
|
||||||
|
_ => panic!("failed to query contract"),
|
||||||
|
},
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_credential(&self) -> Result<()> {
|
||||||
|
let (valid_credential, credential_id) =
|
||||||
|
self.fetch_valid_credential("gateway_id").await.unwrap();
|
||||||
|
|
||||||
|
let epoch_id = valid_credential.epoch_id();
|
||||||
|
let coconut_api_clients = match self.get_coconut_api_clients(epoch_id).await? {
|
||||||
|
CoconutClients::Clients(clients) => clients,
|
||||||
|
CoconutClients::NoContractAvailable => {
|
||||||
|
log::info!("No Coconut API clients on this network, we are ok");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
verify_credential(&valid_credential, credential_id, coconut_api_clients).await
|
||||||
|
}
|
||||||
|
|
||||||
async fn connect_to_mixnet_common(mut self) -> Result<(BaseClient, Recipient)> {
|
async fn connect_to_mixnet_common(mut self) -> Result<(BaseClient, Recipient)> {
|
||||||
self.setup_client_keys().await?;
|
self.setup_client_keys().await?;
|
||||||
self.setup_gateway().await?;
|
self.setup_gateway().await?;
|
||||||
|
if self.config.enabled_local_credentials_check {
|
||||||
|
self.check_credential().await?;
|
||||||
|
}
|
||||||
|
|
||||||
let nyxd_endpoints = self.get_nyxd_endpoints();
|
let nyxd_endpoints = self.get_nyxd_endpoints();
|
||||||
let nym_api_endpoints = self.get_api_endpoints();
|
let nym_api_endpoints = self.get_api_endpoints();
|
||||||
@@ -756,6 +854,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum CoconutClients {
|
||||||
|
Clients(Vec<nym_validator_client::coconut::CoconutApiClient>),
|
||||||
|
NoContractAvailable,
|
||||||
|
}
|
||||||
|
|
||||||
pub enum IncludedSurbs {
|
pub enum IncludedSurbs {
|
||||||
Amount(u32),
|
Amount(u32),
|
||||||
ExposeSelfAddress,
|
ExposeSelfAddress,
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ pub struct Config {
|
|||||||
/// Whether to attempt to use gateway with bandwidth credential requirement.
|
/// Whether to attempt to use gateway with bandwidth credential requirement.
|
||||||
pub enabled_credentials_mode: bool,
|
pub enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// Whether to locally check credential before attempting to pass it to the
|
||||||
|
/// entry gateway
|
||||||
|
pub enabled_local_credentials_check: bool,
|
||||||
|
|
||||||
/// Flags controlling all sorts of internal client behaviour.
|
/// Flags controlling all sorts of internal client behaviour.
|
||||||
/// Changing these risk compromising network anonymity!
|
/// Changing these risk compromising network anonymity!
|
||||||
pub debug_config: DebugConfig,
|
pub debug_config: DebugConfig,
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use nym_bandwidth_controller::PreparedCredential;
|
||||||
|
use nym_credentials::{
|
||||||
|
coconut::bandwidth::bandwidth_credential_params, obtain_aggregate_verification_key,
|
||||||
|
IssuedBandwidthCredential,
|
||||||
|
};
|
||||||
|
use nym_validator_client::coconut::CoconutApiClient;
|
||||||
|
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
|
pub(super) async fn verify_credential(
|
||||||
|
valid_credential: &IssuedBandwidthCredential,
|
||||||
|
credential_id: i64,
|
||||||
|
coconut_api_clients: Vec<CoconutApiClient>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients).unwrap();
|
||||||
|
let spend_request = valid_credential
|
||||||
|
.prepare_for_spending(&verification_key)
|
||||||
|
.unwrap();
|
||||||
|
let prepared_credential = PreparedCredential {
|
||||||
|
data: spend_request,
|
||||||
|
epoch_id: valid_credential.epoch_id(),
|
||||||
|
credential_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
if !prepared_credential.data.validate_type_attribute() {
|
||||||
|
panic!("missing bandwidth type attribute");
|
||||||
|
}
|
||||||
|
|
||||||
|
let params = bandwidth_credential_params();
|
||||||
|
if prepared_credential.data.verify(params, &verification_key) {
|
||||||
|
log::info!("Successfully validated credential");
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
panic!("failed to validate credential");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user