Compare commits

...

1 Commits

Author SHA1 Message Date
Jon Häggblad 313f700885 Optional local credential check in sdk 2024-04-17 14:29:41 +02:00
5 changed files with 158 additions and 11 deletions
+3
View File
@@ -67,6 +67,9 @@ pub enum Error {
#[error("bandwidth controller error: {0}")]
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
#[error("coconut error: {0}")]
CoconutApiError(#[from] nym_validator_client::coconut::CoconutApiError),
#[error("invalid voucher blob")]
InvalidVoucherBlob,
+1
View File
@@ -33,6 +33,7 @@
mod client;
mod config;
mod connection_state;
mod credential;
mod native_client;
mod paths;
mod socks5_client;
+114 -11
View File
@@ -1,6 +1,7 @@
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::credential::verify_credential;
use super::{connection_state::BuilderState, Config, StoragePaths};
use crate::bandwidth::BandwidthAcquireClient;
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::setup_gateway;
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_socks5_client_core::config::Socks5;
use nym_task::manager::TaskStatus;
use nym_task::{TaskClient, TaskHandle};
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 rand::rngs::OsRng;
use std::net::IpAddr;
@@ -188,6 +193,18 @@ where
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.
#[must_use]
pub fn debug_config(mut self, debug_config: DebugConfig) -> Self {
@@ -334,17 +351,18 @@ where
storage: S,
) -> Result<DisconnectedMixnetClient<S>> {
// don't create dkg client for the bandwidth controller if credentials are disabled
let dkg_query_client = if config.enabled_credentials_mode {
let client_config =
nyxd::Config::try_from_nym_network_details(&config.network_details)?;
let client = QueryHttpRpcNyxdClient::connect(
client_config,
config.network_details.endpoints[0].nyxd_url.as_str(),
)?;
Some(client)
} else {
None
};
let dkg_query_client =
if config.enabled_credentials_mode || config.enabled_local_credentials_check {
let client_config =
nyxd::Config::try_from_nym_network_details(&config.network_details)?;
let client = QueryHttpRpcNyxdClient::connect(
client_config,
config.network_details.endpoints[0].nyxd_url.as_str(),
)?;
Some(client)
} else {
None
};
Ok(DisconnectedMixnetClient {
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)> {
self.setup_client_keys().await?;
self.setup_gateway().await?;
if self.config.enabled_local_credentials_check {
self.check_credential().await?;
}
let nyxd_endpoints = self.get_nyxd_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 {
Amount(u32),
ExposeSelfAddress,
+4
View File
@@ -17,6 +17,10 @@ pub struct Config {
/// Whether to attempt to use gateway with bandwidth credential requirement.
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.
/// Changing these risk compromising network anonymity!
pub debug_config: DebugConfig,
+36
View File
@@ -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");
}
}