additional fixes to key creation
This commit is contained in:
@@ -12,9 +12,6 @@ use clap::{Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::base_client::storage::OnDiskGatewaysDetails;
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
|
||||
@@ -13,9 +13,6 @@ use clap::{Parser, Subcommand};
|
||||
use log::{error, info};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup;
|
||||
use nym_client_core::config::{GatewayEndpointConfig, GroupBy, TopologyStructure};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::types::{GatewayDetails, GatewayRegistration};
|
||||
use crate::types::GatewayRegistration;
|
||||
use crate::{GatewaysDetailsStore, StorageError};
|
||||
use async_trait::async_trait;
|
||||
use manager::StorageManager;
|
||||
@@ -26,6 +26,7 @@ impl OnDiskGatewaysDetails {
|
||||
#[async_trait]
|
||||
impl GatewaysDetailsStore for OnDiskGatewaysDetails {
|
||||
type StorageError = error::StorageError;
|
||||
|
||||
async fn has_gateway_details(&self, gateway_id: &str) -> Result<bool, Self::StorageError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -26,52 +26,81 @@ pub struct InMemGatewaysDetails {
|
||||
#[derive(Debug, Default)]
|
||||
struct InMemStorageInner {
|
||||
active_gateway: Option<String>,
|
||||
gateways: HashMap<String, GatewayDetails>,
|
||||
gateways: HashMap<String, GatewayRegistration>,
|
||||
}
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl GatewaysDetailsStore for InMemGatewaysDetails {
|
||||
type StorageError = InMemStorageError;
|
||||
async fn has_gateway_details(&self, gateway_id: &str) -> Result<bool, Self::StorageError> {
|
||||
todo!()
|
||||
}
|
||||
async fn active_gateway(&self) -> Result<Option<GatewayRegistration>, Self::StorageError> {
|
||||
// let guard = self.inner.read().await;
|
||||
//
|
||||
// let foo = guard.active_gateway.map(|id| {
|
||||
// // SAFETY: if particular gateway is set as active, its details MUST exist
|
||||
// #[allow(clippy::unwrap_used)]
|
||||
// guard.gateways.get(&id).unwrap()
|
||||
// });
|
||||
|
||||
todo!()
|
||||
// foo.cloned()
|
||||
async fn has_gateway_details(&self, gateway_id: &str) -> Result<bool, Self::StorageError> {
|
||||
Ok(self.inner.read().await.gateways.contains_key(gateway_id))
|
||||
}
|
||||
|
||||
async fn active_gateway(&self) -> Result<Option<GatewayRegistration>, Self::StorageError> {
|
||||
let guard = self.inner.read().await;
|
||||
|
||||
Ok(guard.active_gateway.as_ref().map(|id| {
|
||||
// SAFETY: if particular gateway is set as active, its details MUST exist
|
||||
#[allow(clippy::unwrap_used)]
|
||||
guard.gateways.get(id).unwrap().clone()
|
||||
}))
|
||||
}
|
||||
|
||||
async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> {
|
||||
todo!()
|
||||
// ensure the gateway with provided id exists
|
||||
let mut guard = self.inner.write().await;
|
||||
|
||||
if !guard.gateways.contains_key(gateway_id) {
|
||||
return Err(InMemStorageError::GatewayDoesNotExist {
|
||||
gateway_id: gateway_id.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
guard.active_gateway = Some(gateway_id.to_string());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn all_gateways(&self) -> Result<Vec<GatewayRegistration>, Self::StorageError> {
|
||||
todo!()
|
||||
Ok(self.inner.read().await.gateways.values().cloned().collect())
|
||||
}
|
||||
|
||||
async fn load_gateway_details(
|
||||
&self,
|
||||
gateway_id: &str,
|
||||
) -> Result<GatewayRegistration, Self::StorageError> {
|
||||
todo!()
|
||||
self.inner
|
||||
.read()
|
||||
.await
|
||||
.gateways
|
||||
.get(gateway_id)
|
||||
.cloned()
|
||||
.ok_or(InMemStorageError::GatewayDoesNotExist {
|
||||
gateway_id: gateway_id.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
details: &GatewayRegistration,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
todo!()
|
||||
self.inner.write().await.gateways.insert(
|
||||
details.details.gateway_id().to_base58_string(),
|
||||
details.clone(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> {
|
||||
todo!()
|
||||
let mut guard = self.inner.write().await;
|
||||
if let Some(active) = guard.active_gateway.as_ref() {
|
||||
if active == gateway_id {
|
||||
guard.active_gateway = None
|
||||
}
|
||||
}
|
||||
guard.gateways.remove(gateway_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@ use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
pub const REMOTE_GATEWAY_TYPE: &str = "remote";
|
||||
pub const CUSTOM_GATEWAY_TYPE: &str = "custom";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GatewayRegistration {
|
||||
pub details: GatewayDetails,
|
||||
pub registration_timestamp: OffsetDateTime,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum GatewayDetails {
|
||||
/// Standard details of a remote gateway
|
||||
Remote(RemoteGatewayDetails),
|
||||
@@ -197,7 +197,7 @@ impl From<RemoteGatewayDetails> for RawRemoteGatewayDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteGatewayDetails {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
|
||||
@@ -245,7 +245,7 @@ impl From<CustomGatewayDetails> for RawCustomGatewayDetails {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CustomGatewayDetails {
|
||||
pub gateway_id: identity::PublicKey,
|
||||
pub data: Option<Vec<u8>>,
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
use super::packet_statistics_control::PacketStatisticsReporter;
|
||||
use super::received_buffer::ReceivedBufferMessage;
|
||||
use super::topology_control::geo_aware_provider::GeoAwareTopologyProvider;
|
||||
use crate::client::base_client::storage::helpers::store_client_keys;
|
||||
use crate::client::base_client::storage::MixnetClientStorage;
|
||||
use crate::client::cover_traffic_stream::LoopCoverTrafficStream;
|
||||
use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender};
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use crate::client::mix_traffic::transceiver::{GatewayReceiver, GatewayTransceiver, RemoteGateway};
|
||||
use crate::client::mix_traffic::{BatchMixMessageSender, MixTrafficController};
|
||||
use crate::client::packet_statistics_control::PacketStatisticsControl;
|
||||
@@ -51,6 +53,7 @@ use nym_task::{TaskClient, TaskHandle};
|
||||
use nym_topology::provider_trait::TopologyProvider;
|
||||
use nym_topology::HardcodedTopologyProvider;
|
||||
use nym_validator_client::nyxd::contract_traits::DkgQueryClient;
|
||||
use rand::rngs::OsRng;
|
||||
use std::fmt::Debug;
|
||||
use std::os::raw::c_int as RawFd;
|
||||
use std::path::Path;
|
||||
@@ -577,6 +580,14 @@ where
|
||||
<S::KeyStore as KeyStore>::StorageError: Sync + Send,
|
||||
<S::GatewaysDetailsStore as GatewaysDetailsStore>::StorageError: Sync + Send,
|
||||
{
|
||||
// if client keys do not exist already, create and persist them
|
||||
if key_store.load_keys().await.is_err() {
|
||||
info!("could not find valid client keys - a new set will be generated");
|
||||
let mut rng = OsRng;
|
||||
let keys = ClientKeys::generate_new(&mut rng);
|
||||
store_client_keys(keys, key_store).await?;
|
||||
}
|
||||
|
||||
setup_gateway(setup_method, key_store, details_store).await
|
||||
}
|
||||
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::GatewayEndpointConfig;
|
||||
use crate::error::ClientCoreError;
|
||||
use async_trait::async_trait;
|
||||
use log::error;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::error::Error;
|
||||
use std::ops::Deref;
|
||||
use tokio::sync::Mutex;
|
||||
use zeroize::Zeroizing;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
pub trait GatewayDetailsStore {
|
||||
type StorageError: Error;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError>;
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum PersistedGatewayDetails {
|
||||
/// Standard details of a remote gateway
|
||||
Default(PersistedGatewayConfig),
|
||||
|
||||
/// Custom gateway setup, such as for a client embedded inside gateway itself
|
||||
Custom(PersistedCustomGatewayDetails),
|
||||
}
|
||||
|
||||
impl PersistedGatewayDetails {
|
||||
// TODO: this should probably allow for custom verification over T
|
||||
pub fn validate(&self, shared_key: Option<&SharedKeys>) -> Result<(), ClientCoreError> {
|
||||
match self {
|
||||
PersistedGatewayDetails::Default(details) => {
|
||||
if !details.verify(shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?) {
|
||||
Err(ClientCoreError::MismatchedGatewayDetails {
|
||||
gateway_id: details.details.gateway_id.clone(),
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
PersistedGatewayDetails::Custom(_) => {
|
||||
if shared_key.is_some() {
|
||||
error!("using custom persisted gateway setup with shared key present - are you sure that's what you want?");
|
||||
// but technically we could still continue. just ignore the key
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PersistedGatewayConfig {
|
||||
// TODO: should we also verify correctness of the details themselves?
|
||||
// i.e. we could include a checksum or tag (via the shared keys)
|
||||
// counterargument: if we wanted to modify, say, the host information in the stored file on disk,
|
||||
// in order to actually use it, we'd have to recompute the whole checksum which would be a huge pain.
|
||||
/// The hash of the shared keys to ensure the correct ones are used with those gateway details.
|
||||
#[serde(with = "base64")]
|
||||
key_hash: Vec<u8>,
|
||||
|
||||
/// Actual gateway details being persisted.
|
||||
pub details: GatewayEndpointConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PersistedCustomGatewayDetails {
|
||||
// whatever custom method is used, gateway's identity must be known
|
||||
pub gateway_id: String,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub additional_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl PersistedGatewayConfig {
|
||||
pub fn new(details: GatewayEndpointConfig, shared_key: &SharedKeys) -> Self {
|
||||
let key_bytes = Zeroizing::new(shared_key.to_bytes());
|
||||
|
||||
let mut key_hasher = Sha256::new();
|
||||
key_hasher.update(&key_bytes);
|
||||
let key_hash = key_hasher.finalize().to_vec();
|
||||
|
||||
PersistedGatewayConfig { key_hash, details }
|
||||
}
|
||||
|
||||
pub fn verify(&self, shared_key: &SharedKeys) -> bool {
|
||||
let key_bytes = Zeroizing::new(shared_key.to_bytes());
|
||||
|
||||
let mut key_hasher = Sha256::new();
|
||||
key_hasher.update(&key_bytes);
|
||||
let key_hash = key_hasher.finalize();
|
||||
|
||||
self.key_hash == key_hash.deref()
|
||||
}
|
||||
}
|
||||
|
||||
impl PersistedGatewayDetails {
|
||||
// pub fn new(
|
||||
// details: GatewayDetails,
|
||||
// shared_key: Option<&SharedKeys>,
|
||||
// ) -> Result<Self, ClientCoreError> {
|
||||
// match details {
|
||||
// GatewayDetails::Configured(cfg) => {
|
||||
// let shared_key = shared_key.ok_or(ClientCoreError::UnavailableSharedKey)?;
|
||||
// Ok(PersistedGatewayDetails::Default(
|
||||
// PersistedGatewayConfig::new(cfg, shared_key),
|
||||
// ))
|
||||
// }
|
||||
// GatewayDetails::Custom(custom) => Ok(PersistedGatewayDetails::Custom(custom.into())),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn is_custom(&self) -> bool {
|
||||
// matches!(self, PersistedGatewayDetails::Custom(..))
|
||||
// }
|
||||
//
|
||||
// pub fn matches(&self, other: &GatewayDetails) -> bool {
|
||||
// match self {
|
||||
// PersistedGatewayDetails::Default(default) => {
|
||||
// if let GatewayDetails::Configured(other_configured) = other {
|
||||
// &default.details == other_configured
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
// PersistedGatewayDetails::Custom(custom) => {
|
||||
// if let GatewayDetails::Custom(other_custom) = other {
|
||||
// custom.gateway_id == other_custom.gateway_id
|
||||
// && custom.additional_data == other_custom.additional_data
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// helper to make Vec<u8> serialization use base64 representation to make it human readable
|
||||
// so that it would be easier for users to copy contents from the disk if they wanted to use it elsewhere
|
||||
mod base64 {
|
||||
use base64::{engine::general_purpose::STANDARD, Engine as _};
|
||||
use serde::{Deserialize, Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<S: Serializer>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
|
||||
serializer.serialize_str(&STANDARD.encode(bytes))
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
|
||||
let s = <String>::deserialize(deserializer)?;
|
||||
STANDARD.decode(s).map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum OnDiskGatewayDetailsError {
|
||||
#[error("JSON failure: {0}")]
|
||||
SerializationFailure(#[from] serde_json::Error),
|
||||
|
||||
#[error("failed to store gateway details to {path}: {err}")]
|
||||
StoreFailure {
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
|
||||
#[error("failed to load gateway details from {path}: {err}")]
|
||||
LoadFailure {
|
||||
path: String,
|
||||
#[source]
|
||||
err: std::io::Error,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
pub struct OnDiskGatewayDetails {
|
||||
file_location: std::path::PathBuf,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl OnDiskGatewayDetails {
|
||||
pub fn new<P: AsRef<std::path::Path>>(path: P) -> Self {
|
||||
OnDiskGatewayDetails {
|
||||
file_location: path.as_ref().to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_from_disk(&self) -> Result<PersistedGatewayDetails, OnDiskGatewayDetailsError> {
|
||||
let file = std::fs::File::open(&self.file_location).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::LoadFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(serde_json::from_reader(file)?)
|
||||
}
|
||||
|
||||
pub fn store_to_disk(
|
||||
&self,
|
||||
details: &PersistedGatewayDetails,
|
||||
) -> Result<(), OnDiskGatewayDetailsError> {
|
||||
// ensure the whole directory structure exists
|
||||
if let Some(parent_dir) = &self.file_location.parent() {
|
||||
std::fs::create_dir_all(parent_dir).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::StoreFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?
|
||||
}
|
||||
|
||||
let file = std::fs::File::create(&self.file_location).map_err(|err| {
|
||||
OnDiskGatewayDetailsError::StoreFailure {
|
||||
path: self.file_location.display().to_string(),
|
||||
err,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(serde_json::to_writer_pretty(file, details)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl GatewayDetailsStore for OnDiskGatewayDetails {
|
||||
type StorageError = OnDiskGatewayDetailsError;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
|
||||
self.load_from_disk()
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
gateway_details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
self.store_to_disk(gateway_details)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InMemGatewayDetails {
|
||||
details: Mutex<Option<PersistedGatewayDetails>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("old ephemeral gateway details can't be loaded from storage")]
|
||||
pub struct EphemeralGatewayDetailsError;
|
||||
|
||||
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
||||
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
|
||||
impl GatewayDetailsStore for InMemGatewayDetails {
|
||||
type StorageError = EphemeralGatewayDetailsError;
|
||||
|
||||
async fn load_gateway_details(&self) -> Result<PersistedGatewayDetails, Self::StorageError> {
|
||||
self.details
|
||||
.lock()
|
||||
.await
|
||||
.clone()
|
||||
.ok_or(EphemeralGatewayDetailsError)
|
||||
}
|
||||
|
||||
async fn store_gateway_details(
|
||||
&self,
|
||||
gateway_details: &PersistedGatewayDetails,
|
||||
) -> Result<(), Self::StorageError> {
|
||||
*self.details.lock().await = Some(gateway_details.clone());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::KeyManager;
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use crate::error::ClientCoreError;
|
||||
use nym_client_core_gateways_storage::{GatewayRegistration, GatewaysDetailsStore};
|
||||
|
||||
@@ -88,12 +88,24 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn load_client_keys<K>(key_store: &K) -> Result<KeyManager, ClientCoreError>
|
||||
pub async fn load_client_keys<K>(key_store: &K) -> Result<ClientKeys, ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
KeyManager::load_keys(key_store)
|
||||
ClientKeys::load_keys(key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn store_client_keys<K>(keys: ClientKeys, key_store: &K) -> Result<(), ClientCoreError>
|
||||
where
|
||||
K: KeyStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
keys.persist_keys(key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
source: Box::new(source),
|
||||
|
||||
@@ -4,9 +4,6 @@
|
||||
// TODO: combine those more closely. Perhaps into a single underlying store.
|
||||
// Like for persistent, on-disk, storage, what's the point of having 3 different databases?
|
||||
|
||||
// use crate::client::base_client::storage::gateway_details::{
|
||||
// GatewayDetailsStore, InMemGatewayDetails,
|
||||
// };
|
||||
use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore};
|
||||
use crate::client::replies::reply_storage;
|
||||
use crate::client::replies::reply_storage::ReplyStorageBackend;
|
||||
@@ -18,30 +15,24 @@ use nym_credential_storage::storage::Storage as CredentialStorage;
|
||||
feature = "fs-surb-storage",
|
||||
feature = "fs-gateways-storage"
|
||||
))]
|
||||
use crate::client::base_client::non_wasm_helpers;
|
||||
// #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
// use crate::client::base_client::storage::gateway_details::OnDiskGatewayDetails;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use crate::client::key_manager::persistence::OnDiskKeys;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::client::replies::reply_storage::fs_backend;
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::config::{self, disk_persistence::CommonClientPaths};
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::{
|
||||
client::{
|
||||
base_client::non_wasm_helpers, key_manager::persistence::OnDiskKeys,
|
||||
replies::reply_storage::fs_backend,
|
||||
},
|
||||
config::{self, disk_persistence::CommonClientPaths},
|
||||
error::ClientCoreError,
|
||||
};
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))]
|
||||
use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage;
|
||||
|
||||
// fs-gateways
|
||||
pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails};
|
||||
|
||||
#[deprecated]
|
||||
pub mod gateway_details;
|
||||
pub mod helpers;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))]
|
||||
pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError};
|
||||
|
||||
pub mod helpers;
|
||||
|
||||
// TODO: ideally this should be changed into
|
||||
// `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewayDetailsStore`
|
||||
pub trait MixnetClientStorage {
|
||||
|
||||
@@ -6,230 +6,11 @@ use nym_crypto::asymmetric::{encryption, identity};
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::acknowledgements::AckKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::sync::Arc;
|
||||
use zeroize::ZeroizeOnDrop;
|
||||
|
||||
pub mod persistence;
|
||||
|
||||
pub struct ManagedKeys {
|
||||
client_keys: KeyManager,
|
||||
active_gateway_keys: Option<Arc<SharedKeys>>,
|
||||
}
|
||||
//
|
||||
// pub enum ManagedKeys {
|
||||
// Initial(KeyManagerBuilder),
|
||||
// FullyDerived(KeyManager),
|
||||
//
|
||||
// // I really hate the existence of this variant, but I couldn't come up with a better way to handle
|
||||
// // `Self::deal_with_gateway_key` otherwise.
|
||||
// Invalidated,
|
||||
// }
|
||||
//
|
||||
// impl Debug for ManagedKeys {
|
||||
// fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(_) => write!(f, "initial"),
|
||||
// ManagedKeys::FullyDerived(_) => write!(f, "fully derived"),
|
||||
// ManagedKeys::Invalidated => write!(f, "invalidated"),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<KeyManagerBuilder> for ManagedKeys {
|
||||
// fn from(value: KeyManagerBuilder) -> Self {
|
||||
// ManagedKeys::Initial(value)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<KeyManager> for ManagedKeys {
|
||||
// fn from(value: KeyManager) -> Self {
|
||||
// ManagedKeys::FullyDerived(value)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
impl ManagedKeys {
|
||||
// pub fn is_valid(&self) -> bool {
|
||||
// !matches!(self, ManagedKeys::Invalidated)
|
||||
// }
|
||||
//
|
||||
// pub async fn try_load<S: KeyStore>(key_store: &S) -> Result<Self, S::StorageError> {
|
||||
// Ok(ManagedKeys::FullyDerived(
|
||||
// KeyManager::load_keys(key_store).await?,
|
||||
// ))
|
||||
// }
|
||||
//
|
||||
// pub fn generate_new<R>(rng: &mut R) -> Self
|
||||
// where
|
||||
// R: RngCore + CryptoRng,
|
||||
// {
|
||||
// ManagedKeys::Initial(KeyManagerBuilder::new(rng))
|
||||
// }
|
||||
//
|
||||
// pub async fn load_or_generate<R, S>(rng: &mut R, key_store: &S) -> Self
|
||||
// where
|
||||
// R: RngCore + CryptoRng,
|
||||
// S: KeyStore,
|
||||
// {
|
||||
// Self::try_load(key_store)
|
||||
// .await
|
||||
// .unwrap_or_else(|_| Self::generate_new(rng))
|
||||
// }
|
||||
//
|
||||
// pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(keys) => keys.identity_keypair(),
|
||||
// ManagedKeys::FullyDerived(keys) => keys.identity_keypair(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(keys) => keys.encryption_keypair(),
|
||||
// ManagedKeys::FullyDerived(keys) => keys.encryption_keypair(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn ack_key(&self) -> Arc<AckKey> {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(keys) => keys.ack_key(),
|
||||
// ManagedKeys::FullyDerived(keys) => keys.ack_key(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn must_get_gateway_shared_key(&self) -> Arc<SharedKeys> {
|
||||
// self.gateway_shared_key()
|
||||
// .expect("failed to extract gateway shared key")
|
||||
// }
|
||||
//
|
||||
// pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(_) => None,
|
||||
// ManagedKeys::FullyDerived(keys) => keys.gateway_shared_key(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn identity_public_key(&self) -> &identity::PublicKey {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(keys) => keys.identity_keypair.public_key(),
|
||||
// ManagedKeys::FullyDerived(keys) => keys.identity_keypair.public_key(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn encryption_public_key(&self) -> &encryption::PublicKey {
|
||||
// match self {
|
||||
// ManagedKeys::Initial(keys) => keys.encryption_keypair.public_key(),
|
||||
// ManagedKeys::FullyDerived(keys) => keys.encryption_keypair.public_key(),
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn ensure_gateway_key(&self, gateway_shared_key: Option<Arc<SharedKeys>>) {
|
||||
// if let ManagedKeys::FullyDerived(key_manager) = &self {
|
||||
// if self.gateway_shared_key().is_none() && gateway_shared_key.is_none() {
|
||||
// // the key doesn't exist in either state
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if gateway_shared_key.is_some() && self.gateway_shared_key().is_none()
|
||||
// || gateway_shared_key.is_none() && self.gateway_shared_key().is_some()
|
||||
// {
|
||||
// // if one is provided whilst the other is not...
|
||||
// // TODO: should this actually panic or return an error? would this branch be possible
|
||||
// // under normal operation?
|
||||
// panic!("inconsistent re-derived gateway key")
|
||||
// }
|
||||
//
|
||||
// // here we know both keys MUST exist
|
||||
// let provided = gateway_shared_key.unwrap();
|
||||
// if !Arc::ptr_eq(key_manager.must_get_gateway_shared_key(), &provided)
|
||||
// || *key_manager.must_get_gateway_shared_key() != provided
|
||||
// {
|
||||
// // this should NEVER happen thus panic here
|
||||
// panic!("derived fresh gateway shared key whilst already holding one!")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub async fn deal_with_gateway_key<S: KeyStore>(
|
||||
// &mut self,
|
||||
// gateway_shared_key: Option<Arc<SharedKeys>>,
|
||||
// key_store: &S,
|
||||
// ) -> Result<(), S::StorageError> {
|
||||
// let key_manager = match std::mem::replace(self, ManagedKeys::Invalidated) {
|
||||
// ManagedKeys::Initial(keys) => {
|
||||
// let key_manager = keys.insert_maybe_gateway_shared_key(gateway_shared_key);
|
||||
// key_manager.persist_keys(key_store).await?;
|
||||
// key_manager
|
||||
// }
|
||||
// ManagedKeys::FullyDerived(key_manager) => {
|
||||
// self.ensure_gateway_key(gateway_shared_key);
|
||||
// key_manager
|
||||
// }
|
||||
// ManagedKeys::Invalidated => unreachable!("the managed keys got invalidated"),
|
||||
// };
|
||||
//
|
||||
// *self = ManagedKeys::FullyDerived(key_manager);
|
||||
// Ok(())
|
||||
// }
|
||||
}
|
||||
//
|
||||
// // all of the keys really shouldn't be wrapped in `Arc`, but due to how the gateway client is currently
|
||||
// // constructed, changing that would require more work than what it's worth
|
||||
// pub struct KeyManagerBuilder {
|
||||
// /// identity key associated with the client instance.
|
||||
// identity_keypair: Arc<identity::KeyPair>,
|
||||
//
|
||||
// /// encryption key associated with the client instance.
|
||||
// encryption_keypair: Arc<encryption::KeyPair>,
|
||||
//
|
||||
// /// key used for producing and processing acknowledgement packets.
|
||||
// ack_key: Arc<AckKey>,
|
||||
// }
|
||||
//
|
||||
// impl KeyManagerBuilder {
|
||||
// /// Creates new instance of a [`KeyManager`]
|
||||
// pub fn new<R>(rng: &mut R) -> Self
|
||||
// where
|
||||
// R: RngCore + CryptoRng,
|
||||
// {
|
||||
// KeyManagerBuilder {
|
||||
// identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||
// encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
// ack_key: Arc::new(AckKey::new(rng)),
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn insert_maybe_gateway_shared_key(
|
||||
// self,
|
||||
// gateway_shared_key: Option<Arc<SharedKeys>>,
|
||||
// ) -> KeyManager {
|
||||
// KeyManager {
|
||||
// identity_keypair: self.identity_keypair,
|
||||
// encryption_keypair: self.encryption_keypair,
|
||||
// gateway_shared_key,
|
||||
// ack_key: self.ack_key,
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn identity_keypair(&self) -> Arc<identity::KeyPair> {
|
||||
// Arc::clone(&self.identity_keypair)
|
||||
// }
|
||||
//
|
||||
// pub fn encryption_keypair(&self) -> Arc<encryption::KeyPair> {
|
||||
// Arc::clone(&self.encryption_keypair)
|
||||
// }
|
||||
//
|
||||
// pub fn ack_key(&self) -> Arc<AckKey> {
|
||||
// Arc::clone(&self.ack_key)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Note: to support key rotation in the future, all keys will require adding an extra smart pointer,
|
||||
// most likely an AtomicCell, or if it doesn't work as I think it does, a Mutex. Although I think
|
||||
// AtomicCell includes a Mutex implicitly if the underlying type does not work atomically.
|
||||
@@ -238,30 +19,24 @@ impl ManagedKeys {
|
||||
|
||||
// Remember that Arc<T> has Deref implementation for T
|
||||
#[derive(Clone)]
|
||||
pub struct KeyManager {
|
||||
pub struct ClientKeys {
|
||||
/// identity key associated with the client instance.
|
||||
identity_keypair: Arc<identity::KeyPair>,
|
||||
|
||||
/// encryption key associated with the client instance.
|
||||
encryption_keypair: Arc<encryption::KeyPair>,
|
||||
|
||||
// /// shared key derived with the gateway during "registration handshake"
|
||||
// // I'm not a fan of how we broke the nice transition of `KeyManagerBuilder` -> `KeyManager`
|
||||
// // by making this field optional.
|
||||
// // However, it has to be optional for when we use embedded NR inside a gateway,
|
||||
// // since it won't have a shared key (because why would it?)
|
||||
// gateway_shared_key: Option<Arc<SharedKeys>>,
|
||||
/// key used for producing and processing acknowledgement packets.
|
||||
ack_key: Arc<AckKey>,
|
||||
}
|
||||
|
||||
impl KeyManager {
|
||||
/// Creates new instance of a [`KeyManager`]
|
||||
impl ClientKeys {
|
||||
/// Creates new instance of a [`ClientKeys`]
|
||||
pub fn generate_new<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
KeyManager {
|
||||
ClientKeys {
|
||||
identity_keypair: Arc::new(identity::KeyPair::new(rng)),
|
||||
encryption_keypair: Arc::new(encryption::KeyPair::new(rng)),
|
||||
ack_key: Arc::new(AckKey::new(rng)),
|
||||
@@ -271,13 +46,11 @@ impl KeyManager {
|
||||
pub fn from_keys(
|
||||
id_keypair: identity::KeyPair,
|
||||
enc_keypair: encryption::KeyPair,
|
||||
// gateway_shared_key: Option<SharedKeys>,
|
||||
ack_key: AckKey,
|
||||
) -> Self {
|
||||
Self {
|
||||
identity_keypair: Arc::new(id_keypair),
|
||||
encryption_keypair: Arc::new(enc_keypair),
|
||||
// gateway_shared_key: gateway_shared_key.map(Arc::new),
|
||||
ack_key: Arc::new(ack_key),
|
||||
}
|
||||
}
|
||||
@@ -303,32 +76,6 @@ impl KeyManager {
|
||||
pub fn ack_key(&self) -> Arc<AckKey> {
|
||||
Arc::clone(&self.ack_key)
|
||||
}
|
||||
|
||||
// fn must_get_gateway_shared_key(&self) -> &Arc<SharedKeys> {
|
||||
// self.gateway_shared_key
|
||||
// .as_ref()
|
||||
// .expect("gateway shared key is unavailable")
|
||||
// }
|
||||
//
|
||||
// pub fn uses_custom_gateway(&self) -> bool {
|
||||
// self.gateway_shared_key.is_none()
|
||||
// }
|
||||
//
|
||||
// /// Gets an atomically reference counted pointer to [`SharedKey`].
|
||||
// pub fn gateway_shared_key(&self) -> Option<Arc<SharedKeys>> {
|
||||
// self.gateway_shared_key.as_ref().map(Arc::clone)
|
||||
// }
|
||||
|
||||
// pub fn remove_gateway_key(self) -> KeyManagerBuilder {
|
||||
// if Arc::strong_count(self.must_get_gateway_shared_key()) > 1 {
|
||||
// panic!("attempted to remove gateway key whilst still holding multiple references!")
|
||||
// }
|
||||
// KeyManagerBuilder {
|
||||
// identity_keypair: self.identity_keypair,
|
||||
// encryption_keypair: self.encryption_keypair,
|
||||
// ack_key: self.ack_key,
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn _assert_keys_zeroize_on_drop() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::key_manager::KeyManager;
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -25,9 +25,9 @@ use nym_sphinx::acknowledgements::AckKey;
|
||||
pub trait KeyStore {
|
||||
type StorageError: Error;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError>;
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError>;
|
||||
|
||||
async fn store_keys(&self, keys: &KeyManager) -> Result<(), Self::StorageError>;
|
||||
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError>;
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -148,19 +148,19 @@ impl OnDiskKeys {
|
||||
})
|
||||
}
|
||||
|
||||
fn load_keys(&self) -> Result<KeyManager, OnDiskKeysError> {
|
||||
fn load_keys(&self) -> Result<ClientKeys, OnDiskKeysError> {
|
||||
let identity_keypair = self.load_identity_keypair()?;
|
||||
let encryption_keypair = self.load_encryption_keypair()?;
|
||||
let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?;
|
||||
|
||||
Ok(KeyManager::from_keys(
|
||||
Ok(ClientKeys::from_keys(
|
||||
identity_keypair,
|
||||
encryption_keypair,
|
||||
ack_key,
|
||||
))
|
||||
}
|
||||
|
||||
fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> {
|
||||
fn store_keys(&self, keys: &ClientKeys) -> Result<(), OnDiskKeysError> {
|
||||
let identity_paths = self.paths.identity_key_pair_path();
|
||||
let encryption_paths = self.paths.encryption_key_pair_path();
|
||||
|
||||
@@ -186,18 +186,18 @@ impl OnDiskKeys {
|
||||
impl KeyStore for OnDiskKeys {
|
||||
type StorageError = OnDiskKeysError;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError> {
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
|
||||
self.load_keys()
|
||||
}
|
||||
|
||||
async fn store_keys(&self, keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
|
||||
self.store_keys(keys)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InMemEphemeralKeys {
|
||||
keys: Mutex<Option<KeyManager>>,
|
||||
keys: Mutex<Option<ClientKeys>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
@@ -209,11 +209,11 @@ pub struct EphemeralKeysError;
|
||||
impl KeyStore for InMemEphemeralKeys {
|
||||
type StorageError = EphemeralKeysError;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError> {
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
|
||||
self.keys.lock().await.clone().ok_or(EphemeralKeysError)
|
||||
}
|
||||
|
||||
async fn store_keys(&self, keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
|
||||
*self.keys.lock().await = Some(keys.clone());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::config::GatewayEndpointConfig;
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::init::types::RegistrationResult;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::client::base_client::storage::helpers::{
|
||||
store_gateway_details,
|
||||
};
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::KeyManager;
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::init::helpers::{
|
||||
choose_gateway_by_latency, get_specified_gateway, uniformly_random_gateway,
|
||||
@@ -38,7 +38,7 @@ where
|
||||
K: KeyStore,
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
KeyManager::generate_new(rng)
|
||||
ClientKeys::generate_new(rng)
|
||||
.persist_keys(key_store)
|
||||
.await
|
||||
.map_err(|source| ClientCoreError::KeyStoreError {
|
||||
@@ -176,7 +176,7 @@ where
|
||||
fn reuse_gateway_connection(
|
||||
authenticated_ephemeral_client: InitGatewayClient,
|
||||
gateway_registration: GatewayRegistration,
|
||||
client_keys: KeyManager,
|
||||
client_keys: ClientKeys,
|
||||
) -> InitialisationResult {
|
||||
InitialisationResult {
|
||||
gateway_registration,
|
||||
@@ -218,10 +218,10 @@ where
|
||||
GatewaySetup::ReuseConnection {
|
||||
authenticated_ephemeral_client,
|
||||
gateway_details,
|
||||
managed_keys,
|
||||
client_keys: managed_keys,
|
||||
} => Ok(reuse_gateway_connection(
|
||||
authenticated_ephemeral_client,
|
||||
gateway_details,
|
||||
*gateway_details,
|
||||
managed_keys,
|
||||
)),
|
||||
}
|
||||
|
||||
@@ -2,23 +2,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::client::key_manager::persistence::KeyStore;
|
||||
use crate::client::key_manager::{KeyManager, ManagedKeys};
|
||||
use crate::config::{Config, GatewayEndpointConfig};
|
||||
use crate::client::key_manager::ClientKeys;
|
||||
use crate::config::Config;
|
||||
use crate::error::ClientCoreError;
|
||||
use crate::init::{setup_gateway, use_loaded_gateway_details};
|
||||
use nym_client_core_gateways_storage::{
|
||||
BadGateway, GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails,
|
||||
GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails,
|
||||
};
|
||||
use nym_crypto::asymmetric::identity;
|
||||
use nym_gateway_client::client::InitGatewayClient;
|
||||
use nym_gateway_requests::registration::handshake::SharedKeys;
|
||||
use nym_sphinx::addressing::clients::Recipient;
|
||||
use nym_sphinx::addressing::nodes::NodeIdentity;
|
||||
use nym_topology::gateway;
|
||||
use nym_validator_client::client::IdentityKey;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
@@ -111,12 +109,12 @@ pub struct RegistrationResult {
|
||||
/// if this was the first time this client registered
|
||||
pub struct InitialisationResult {
|
||||
pub gateway_registration: GatewayRegistration,
|
||||
pub client_keys: KeyManager,
|
||||
pub client_keys: ClientKeys,
|
||||
pub authenticated_ephemeral_client: Option<InitGatewayClient>,
|
||||
}
|
||||
|
||||
impl InitialisationResult {
|
||||
pub fn new_loaded(gateway_registration: GatewayRegistration, client_keys: KeyManager) -> Self {
|
||||
pub fn new_loaded(gateway_registration: GatewayRegistration, client_keys: ClientKeys) -> Self {
|
||||
InitialisationResult {
|
||||
gateway_registration,
|
||||
client_keys,
|
||||
@@ -144,89 +142,6 @@ impl InitialisationResult {
|
||||
)
|
||||
}
|
||||
}
|
||||
//
|
||||
// /// Details of particular gateway client got registered with
|
||||
// #[derive(Debug, Clone)]
|
||||
// pub enum GatewayDetails {
|
||||
// /// Standard details of a remote gateway
|
||||
// Configured(GatewayEndpointConfig),
|
||||
//
|
||||
// /// Custom gateway setup, such as for a client embedded inside gateway itself
|
||||
// Custom(CustomGatewayDetails),
|
||||
// }
|
||||
//
|
||||
// #[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
// pub struct CustomGatewayDetails {
|
||||
// // whatever custom method is used, gateway's identity must be known
|
||||
// pub gateway_id: String,
|
||||
//
|
||||
// pub additional_data: Vec<u8>,
|
||||
// }
|
||||
//
|
||||
// impl CustomGatewayDetails {
|
||||
// pub fn new(gateway_id: String, additional_data: Vec<u8>) -> Self {
|
||||
// Self {
|
||||
// gateway_id,
|
||||
// additional_data,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl GatewayDetails {
|
||||
// pub fn try_get_configured_endpoint(&self) -> Option<&GatewayEndpointConfig> {
|
||||
// if let GatewayDetails::Configured(endpoint) = &self {
|
||||
// Some(endpoint)
|
||||
// } else {
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn is_custom(&self) -> bool {
|
||||
// matches!(self, GatewayDetails::Custom(_))
|
||||
// }
|
||||
//
|
||||
// pub fn gateway_id(&self) -> &str {
|
||||
// match self {
|
||||
// GatewayDetails::Configured(cfg) => &cfg.gateway_id,
|
||||
// GatewayDetails::Custom(custom) => &custom.gateway_id,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<GatewayEndpointConfig> for GatewayDetails {
|
||||
// fn from(value: GatewayEndpointConfig) -> Self {
|
||||
// GatewayDetails::Configured(value)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<PersistedCustomGatewayDetails> for CustomGatewayDetails {
|
||||
// fn from(value: PersistedCustomGatewayDetails) -> Self {
|
||||
// CustomGatewayDetails {
|
||||
// gateway_id: value.gateway_id,
|
||||
// additional_data: value.additional_data,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<CustomGatewayDetails> for PersistedCustomGatewayDetails {
|
||||
// fn from(value: CustomGatewayDetails) -> Self {
|
||||
// PersistedCustomGatewayDetails {
|
||||
// gateway_id: value.gateway_id,
|
||||
// additional_data: value.additional_data,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl From<PersistedGatewayDetails> for GatewayDetails {
|
||||
// fn from(value: PersistedGatewayDetails) -> Self {
|
||||
// match value {
|
||||
// PersistedGatewayDetails::Default(default) => {
|
||||
// GatewayDetails::Configured(default.details)
|
||||
// }
|
||||
// PersistedGatewayDetails::Custom(custom) => GatewayDetails::Custom(custom.into()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum GatewaySelectionSpecification {
|
||||
@@ -301,24 +216,23 @@ pub enum GatewaySetup {
|
||||
authenticated_ephemeral_client: InitGatewayClient,
|
||||
|
||||
// Details of this pre-initialised client (i.e. gateway and keys)
|
||||
gateway_details: GatewayRegistration,
|
||||
gateway_details: Box<GatewayRegistration>,
|
||||
|
||||
managed_keys: KeyManager,
|
||||
client_keys: ClientKeys,
|
||||
},
|
||||
}
|
||||
|
||||
impl GatewaySetup {
|
||||
pub fn try_reuse_connection(init_res: InitialisationResult) -> Result<Self, ClientCoreError> {
|
||||
todo!()
|
||||
// if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client {
|
||||
// Ok(GatewaySetup::ReuseConnection {
|
||||
// authenticated_ephemeral_client,
|
||||
// gateway_details: init_res.gateway_details,
|
||||
// managed_keys: init_res.managed_keys,
|
||||
// })
|
||||
// } else {
|
||||
// Err(ClientCoreError::NoInitClientPresent)
|
||||
// }
|
||||
if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client {
|
||||
Ok(GatewaySetup::ReuseConnection {
|
||||
authenticated_ephemeral_client,
|
||||
gateway_details: Box::new(init_res.gateway_registration),
|
||||
client_keys: init_res.client_keys,
|
||||
})
|
||||
} else {
|
||||
Err(ClientCoreError::NoInitClientPresent)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn try_setup<K, D>(
|
||||
@@ -332,8 +246,7 @@ impl GatewaySetup {
|
||||
K::StorageError: Send + Sync + 'static,
|
||||
D::StorageError: Send + Sync + 'static,
|
||||
{
|
||||
todo!()
|
||||
// setup_gateway(self, key_store, details_store).await
|
||||
setup_gateway(self, key_store, details_store).await
|
||||
}
|
||||
|
||||
pub fn is_must_load(&self) -> bool {
|
||||
|
||||
@@ -7,12 +7,9 @@ use crate::helpers::setup_reply_surb_storage_backend;
|
||||
use crate::storage::wasm_client_traits::WasmClientStorage;
|
||||
use crate::storage::ClientStorage;
|
||||
use async_trait::async_trait;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::base_client::storage::MixnetClientStorage;
|
||||
use nym_client_core::client::key_manager::persistence::KeyStore;
|
||||
use nym_client_core::client::key_manager::KeyManager;
|
||||
use nym_client_core::client::key_manager::ClientKeys;
|
||||
use nym_client_core::client::replies::reply_storage::browser_backend;
|
||||
use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage;
|
||||
use wasm_utils::console_log;
|
||||
@@ -68,7 +65,7 @@ impl MixnetClientStorage for FullWasmClientStorage {
|
||||
impl KeyStore for ClientStorage {
|
||||
type StorageError = WasmCoreError;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError> {
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
|
||||
console_log!("attempting to load cryptographic keys...");
|
||||
|
||||
// all keys implement `ZeroizeOnDrop`, so if we return an Error, whatever was already loaded will be cleared
|
||||
@@ -77,7 +74,7 @@ impl KeyStore for ClientStorage {
|
||||
let ack_keypair = self.must_read_ack_key().await?;
|
||||
let gateway_shared_key = self.must_read_gateway_shared_key().await?;
|
||||
|
||||
Ok(KeyManager::from_keys(
|
||||
Ok(ClientKeys::from_keys(
|
||||
identity_keypair,
|
||||
encryption_keypair,
|
||||
Some(gateway_shared_key),
|
||||
@@ -85,7 +82,7 @@ impl KeyStore for ClientStorage {
|
||||
))
|
||||
}
|
||||
|
||||
async fn store_keys(&self, keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
async fn store_keys(&self, keys: &ClientKeys) -> Result<(), Self::StorageError> {
|
||||
console_log!("attempting to store cryptographic keys...");
|
||||
|
||||
self.store_identity_keypair(&keys.identity_keypair())
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
state::State,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::client::key_manager::KeyManager;
|
||||
use nym_client_core::client::key_manager::ClientKeys;
|
||||
use nym_crypto::asymmetric::identity;
|
||||
|
||||
pub async fn get_identity_key(
|
||||
@@ -23,7 +23,7 @@ pub async fn get_identity_key(
|
||||
// wtf, why are we loading EVERYTHING to just get identity key??
|
||||
let key_store = OnDiskKeys::from(paths);
|
||||
let key_manager =
|
||||
KeyManager::load_keys(&key_store)
|
||||
ClientKeys::load_keys(&key_store)
|
||||
.await
|
||||
.map_err(|err| BackendError::UnableToLoadKeys {
|
||||
source: Box::new(err),
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
nym_bin_common::logging::setup_logging();
|
||||
|
||||
todo!()
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_sdk::mixnet::{
|
||||
self, EmptyReplyStorage, EphemeralCredentialStorage, KeyManager, KeyStore, MixnetClientStorage,
|
||||
self, ClientKeys, EmptyReplyStorage, EphemeralCredentialStorage, KeyStore, MixnetClientStorage,
|
||||
MixnetMessageSender,
|
||||
};
|
||||
use nym_topology::provider_trait::async_trait;
|
||||
@@ -93,13 +90,13 @@ struct MockKeyStore;
|
||||
impl KeyStore for MockKeyStore {
|
||||
type StorageError = MyError;
|
||||
|
||||
async fn load_keys(&self) -> Result<KeyManager, Self::StorageError> {
|
||||
async fn load_keys(&self) -> Result<ClientKeys, Self::StorageError> {
|
||||
println!("loading stored keys");
|
||||
|
||||
Err(MyError)
|
||||
}
|
||||
|
||||
async fn store_keys(&self, _keys: &KeyManager) -> Result<(), Self::StorageError> {
|
||||
async fn store_keys(&self, _keys: &ClientKeys) -> Result<(), Self::StorageError> {
|
||||
println!("storing keys");
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -12,7 +12,7 @@ async fn main() {
|
||||
let our_address = client.nym_address();
|
||||
println!("Our client nym address is: {our_address}");
|
||||
|
||||
// Send a message throught the mixnet to ourselves
|
||||
// Send a message through the mixnet to ourselves
|
||||
client
|
||||
.send_plain_message(*our_address, "hello there")
|
||||
.await
|
||||
|
||||
@@ -48,7 +48,7 @@ pub use nym_client_core::{
|
||||
inbound_messages::InputMessage,
|
||||
key_manager::{
|
||||
persistence::{InMemEphemeralKeys, KeyStore, OnDiskKeys},
|
||||
KeyManager,
|
||||
ClientKeys,
|
||||
},
|
||||
replies::reply_storage::{
|
||||
fs_backend::Backend as ReplyStorage, CombinedReplyStorage, Empty as EmptyReplyStorage,
|
||||
|
||||
@@ -11,9 +11,6 @@ use crate::{Error, Result};
|
||||
use futures::channel::mpsc;
|
||||
use futures::StreamExt;
|
||||
use log::warn;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
GatewayDetailsStore, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::base_client::storage::{
|
||||
Ephemeral, GatewaysDetailsStore, MixnetClientStorage, OnDiskPersistent,
|
||||
};
|
||||
|
||||
@@ -2,9 +2,6 @@ use clap::{CommandFactory, Parser, Subcommand};
|
||||
use log::{error, trace};
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_bin_common::{bin_info, version_checker};
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
|
||||
@@ -14,9 +14,6 @@ use log::{error, info, trace};
|
||||
use nym_bin_common::bin_info;
|
||||
use nym_bin_common::completions::{fig_generate, ArgShell};
|
||||
use nym_bin_common::version_checker;
|
||||
use nym_client_core::client::base_client::storage::gateway_details::{
|
||||
OnDiskGatewayDetails, PersistedGatewayDetails,
|
||||
};
|
||||
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
|
||||
use nym_client_core::config::GatewayEndpointConfig;
|
||||
use nym_client_core::error::ClientCoreError;
|
||||
|
||||
Reference in New Issue
Block a user