-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Credential check * Loop over credentials * Use bandwidth controller instead * Restructure credentials module * Seperate error mod * Error type reorder * reorder * clippy * Task handling when exiting early * Log tweak * fix * log * clippy * disarm * formatting
- Loading branch information
Showing
14 changed files
with
378 additions
and
126 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use std::{fs, path::PathBuf}; | ||
|
||
use nym_bandwidth_controller::{BandwidthController, PreparedCredential, RetrievedCredential}; | ||
use nym_credentials::{ | ||
coconut::bandwidth::{ | ||
bandwidth_credential_params, issued::BandwidthCredentialIssuedDataVariant, | ||
}, | ||
obtain_aggregate_verification_key, IssuedBandwidthCredential, | ||
}; | ||
|
||
use tracing::{debug, info}; | ||
|
||
use super::{ | ||
helpers::{get_coconut_api_clients, get_credentials_store, get_nyxd_client, CoconutClients}, | ||
CredentialError, | ||
}; | ||
|
||
pub async fn check_raw_credential(raw_credential: Vec<u8>) -> Result<(), CredentialError> { | ||
let version = None; | ||
let credential = IssuedBandwidthCredential::try_unpack(&raw_credential, version)?; | ||
|
||
// Check expiry | ||
match credential.variant_data() { | ||
BandwidthCredentialIssuedDataVariant::Voucher(_) => { | ||
debug!("credential is a bandwidth voucher"); | ||
} | ||
BandwidthCredentialIssuedDataVariant::FreePass(freepass_info) => { | ||
debug!("credential is a free pass"); | ||
if freepass_info.expired() { | ||
return Err(CredentialError::FreepassExpired { | ||
expiry_date: freepass_info.expiry_date().to_string(), | ||
}); | ||
} | ||
} | ||
} | ||
|
||
// TODO: verify? | ||
|
||
Ok(()) | ||
} | ||
|
||
pub async fn check_credential_base58(credential: &str) -> Result<(), CredentialError> { | ||
let raw_credential = bs58::decode(credential) | ||
.into_vec() | ||
.map_err(|err| CredentialError::FailedToDecodeBase58Credential { source: err })?; | ||
check_raw_credential(raw_credential).await | ||
} | ||
|
||
pub async fn check_credential_file(credential_file: PathBuf) -> Result<(), CredentialError> { | ||
let raw_credential = fs::read(credential_file)?; | ||
check_raw_credential(raw_credential).await | ||
} | ||
|
||
pub async fn check_imported_credential( | ||
data_path: PathBuf, | ||
gateway_id: &str, | ||
) -> Result<(), CredentialError> { | ||
let client = get_nyxd_client()?; | ||
let (credentials_store, _location) = get_credentials_store(data_path.clone()).await?; | ||
let bandwidth_controller = BandwidthController::new(credentials_store, client); | ||
let usable_credential = bandwidth_controller | ||
.get_next_usable_credential(gateway_id) | ||
.await | ||
.map_err(|err| CredentialError::FailedToGetNextUsableCredential { | ||
location: data_path, | ||
reason: err.to_string(), | ||
})?; | ||
|
||
let epoch_id = usable_credential.credential.epoch_id(); | ||
let client = get_nyxd_client()?; | ||
let coconut_api_clients = match get_coconut_api_clients(client, epoch_id).await? { | ||
CoconutClients::Clients(clients) => clients, | ||
CoconutClients::NoContactAvailable => { | ||
info!("No Coconut API clients on this network, we are ok"); | ||
return Ok(()); | ||
} | ||
}; | ||
|
||
verify_credential(usable_credential, coconut_api_clients).await | ||
} | ||
|
||
async fn verify_credential( | ||
usable_credential: RetrievedCredential, | ||
coconut_api_clients: Vec<nym_validator_client::coconut::CoconutApiClient>, | ||
) -> Result<(), CredentialError> { | ||
let verification_key = obtain_aggregate_verification_key(&coconut_api_clients)?; | ||
let spend_request = usable_credential | ||
.credential | ||
.prepare_for_spending(&verification_key)?; | ||
let prepared_credential = PreparedCredential { | ||
data: spend_request, | ||
epoch_id: usable_credential.credential.epoch_id(), | ||
credential_id: usable_credential.credential_id, | ||
}; | ||
|
||
if !prepared_credential.data.validate_type_attribute() { | ||
return Err(CredentialError::MissingBandwidthTypeAttribute); | ||
} | ||
|
||
let params = bandwidth_credential_params(); | ||
if prepared_credential.data.verify(params, &verification_key) { | ||
info!("Successfully verified credential"); | ||
Ok(()) | ||
} else { | ||
Err(CredentialError::FailedToVerifyCredential) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#[derive(Debug, thiserror::Error)] | ||
pub enum CredentialError { | ||
#[error(transparent)] | ||
CoconutApiError(#[from] nym_validator_client::coconut::CoconutApiError), | ||
|
||
#[error(transparent)] | ||
NymSdkError(#[from] nym_sdk::Error), | ||
|
||
#[error(transparent)] | ||
NymCredentialsError(#[from] nym_credentials::Error), | ||
|
||
#[error(transparent)] | ||
IoError(#[from] std::io::Error), | ||
|
||
#[error("the free pass has already expired! The expiration was set to {expiry_date}")] | ||
FreepassExpired { expiry_date: String }, | ||
|
||
#[error("failed to import credential to: {location}: {source}")] | ||
FailedToImportCredential { | ||
location: std::path::PathBuf, | ||
source: nym_id::NymIdError, | ||
}, | ||
|
||
#[error("failed decode base58 credential: {source}")] | ||
FailedToDecodeBase58Credential { source: bs58::decode::Error }, | ||
|
||
#[error("failed to get next usable credential: {reason}")] | ||
FailedToGetNextUsableCredential { | ||
location: std::path::PathBuf, | ||
reason: String, | ||
}, | ||
|
||
#[error("missing bandwidth type attribute")] | ||
MissingBandwidthTypeAttribute, | ||
|
||
#[error("failed to verify credential")] | ||
FailedToVerifyCredential, | ||
|
||
#[error("failed to get nyxd client: {0}")] | ||
NyxdError(#[from] nym_validator_client::nyxd::error::NyxdError), | ||
|
||
#[error("no nyxd endpoints found")] | ||
NoNyxdEndpointsFound, | ||
|
||
#[error("failed to query contract")] | ||
FailedToQueryContract, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
use std::path::PathBuf; | ||
|
||
use nym_credential_storage::persistent_storage::PersistentStorage; | ||
|
||
use nym_sdk::{mixnet::StoragePaths, NymNetworkDetails}; | ||
use nym_validator_client::{ | ||
coconut::{all_coconut_api_clients, CoconutApiError}, | ||
nyxd::{error::NyxdError, Config as NyxdClientConfig, NyxdClient}, | ||
QueryHttpRpcNyxdClient, | ||
}; | ||
use tracing::debug; | ||
|
||
use super::CredentialError; | ||
|
||
pub(super) async fn get_credentials_store( | ||
data_path: PathBuf, | ||
) -> Result<(PersistentStorage, PathBuf), CredentialError> { | ||
let storage_path = StoragePaths::new_from_dir(data_path)?; | ||
let credential_db_path = storage_path.credential_database_path; | ||
debug!("Credential store: {}", credential_db_path.display()); | ||
Ok(( | ||
nym_credential_storage::initialise_persistent_storage(credential_db_path.clone()).await, | ||
credential_db_path, | ||
)) | ||
} | ||
|
||
pub(super) fn get_nyxd_client() -> Result<QueryHttpRpcNyxdClient, CredentialError> { | ||
let network = NymNetworkDetails::new_from_env(); | ||
let config = NyxdClientConfig::try_from_nym_network_details(&network)?; | ||
|
||
// Safe to use pick the first one? | ||
let nyxd_url = network | ||
.endpoints | ||
.first() | ||
.ok_or(CredentialError::NoNyxdEndpointsFound)? | ||
.nyxd_url(); | ||
|
||
debug!("Connecting to nyx validator at: {}", nyxd_url); | ||
Ok(NyxdClient::connect(config, nyxd_url.as_str())?) | ||
} | ||
|
||
pub(super) enum CoconutClients { | ||
Clients(Vec<nym_validator_client::coconut::CoconutApiClient>), | ||
NoContactAvailable, | ||
} | ||
|
||
pub(super) async fn get_coconut_api_clients( | ||
nyxd_client: QueryHttpRpcNyxdClient, | ||
epoch_id: u64, | ||
) -> Result<CoconutClients, CredentialError> { | ||
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::NoContactAvailable), | ||
_ => Err(CredentialError::FailedToQueryContract), | ||
}, | ||
Err(err) => Err(err.into()), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
use std::{fs, path::PathBuf}; | ||
use tracing::info; | ||
|
||
use super::{helpers::get_credentials_store, CredentialError}; | ||
|
||
// Import binary credential data | ||
pub async fn import_credential( | ||
raw_credential: Vec<u8>, | ||
data_path: PathBuf, | ||
) -> Result<(), CredentialError> { | ||
info!("Importing credential"); | ||
let (credentials_store, location) = get_credentials_store(data_path).await?; | ||
let version = None; | ||
nym_id::import_credential(credentials_store, raw_credential, version) | ||
.await | ||
.map_err(|err| CredentialError::FailedToImportCredential { | ||
location, | ||
source: err, | ||
}) | ||
} | ||
|
||
// Import credential data from a base58 string | ||
pub async fn import_credential_base58( | ||
credential: &str, | ||
data_path: PathBuf, | ||
) -> Result<(), CredentialError> { | ||
let raw_credential = bs58::decode(credential) | ||
.into_vec() | ||
.map_err(|err| CredentialError::FailedToDecodeBase58Credential { source: err })?; | ||
import_credential(raw_credential, data_path).await | ||
} | ||
|
||
// Import credential data from a binary file | ||
pub async fn import_credential_file( | ||
credential_file: PathBuf, | ||
data_path: PathBuf, | ||
) -> Result<(), CredentialError> { | ||
let raw_credential = fs::read(credential_file)?; | ||
import_credential(raw_credential, data_path).await | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
mod check; | ||
mod helpers; | ||
mod import; | ||
|
||
mod error; | ||
|
||
pub use check::{ | ||
check_credential_base58, check_credential_file, check_imported_credential, check_raw_credential, | ||
}; | ||
pub use error::CredentialError; | ||
pub use import::{import_credential, import_credential_base58, import_credential_file}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.