From f0072ce828c59d51922254178455a3b7d5a40cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 4 Mar 2024 12:12:27 +0000 Subject: [PATCH 01/56] moved reply surb storage to separate subcrate --- Cargo.lock | 17 +++++ Cargo.toml | 1 + common/client-core/Cargo.toml | 24 ++----- common/client-core/src/client/replies/mod.rs | 4 +- common/client-core/surb-storage/Cargo.toml | 30 +++++++++ .../client-core/{ => surb-storage}/build.rs | 0 .../20221130120000_create_initial_tables.sql | 0 .../src}/backend/browser_backend.rs | 4 +- .../src}/backend/fs_backend/error.rs | 0 .../src}/backend/fs_backend/manager.rs | 58 ++++++++--------- .../src}/backend/fs_backend/mod.rs | 8 +-- .../src}/backend/fs_backend/models.rs | 48 +++++++------- .../src}/backend/mod.rs | 2 +- .../src}/combined.rs | 4 +- .../src}/key_storage.rs | 26 +++++--- .../mod.rs => surb-storage/src/lib.rs} | 8 +-- .../src}/surb_storage.rs | 63 +++++++++---------- .../src}/tag_storage.rs | 20 +++--- 18 files changed, 177 insertions(+), 140 deletions(-) create mode 100644 common/client-core/surb-storage/Cargo.toml rename common/client-core/{ => surb-storage}/build.rs (100%) rename common/client-core/{ => surb-storage}/fs_surbs_migrations/20221130120000_create_initial_tables.sql (100%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/browser_backend.rs (88%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/fs_backend/error.rs (100%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/fs_backend/manager.rs (77%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/fs_backend/mod.rs (97%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/fs_backend/models.rs (79%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/backend/mod.rs (97%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/combined.rs (90%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/key_storage.rs (72%) rename common/client-core/{src/client/replies/reply_storage/mod.rs => surb-storage/src/lib.rs} (85%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/surb_storage.rs (77%) rename common/client-core/{src/client/replies/reply_storage => surb-storage/src}/tag_storage.rs (68%) diff --git a/Cargo.lock b/Cargo.lock index 28efbd69ef..89f8e79715 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5242,6 +5242,7 @@ dependencies = [ "hyper-util", "log", "nym-bandwidth-controller", + "nym-client-core-surb-storage", "nym-config", "nym-credential-storage", "nym-crypto", @@ -5279,6 +5280,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nym-client-core-surb-storage" +version = "0.1.0" +dependencies = [ + "async-trait", + "dashmap", + "log", + "nym-crypto", + "nym-sphinx", + "nym-task", + "sqlx", + "thiserror", + "time", + "tokio", +] + [[package]] name = "nym-client-wasm" version = "1.2.4-rc.2" diff --git a/Cargo.toml b/Cargo.toml index 6e322cc32a..13359ec2db 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ members = [ "common/bandwidth-controller", "common/bin-common", "common/client-core", + "common/client-core/surb-storage", "common/client-libs/gateway-client", "common/client-libs/mixnet-client", "common/client-libs/validator-client", diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index ae452c3e9b..9052001f15 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -13,22 +13,20 @@ async-trait = { workspace = true } base64 = "0.21.2" cfg-if = "1.0.0" clap = { workspace = true, optional = true } -dashmap = { workspace = true } -dirs = "4.0" futures = { workspace = true } humantime-serde = "1.0" log = { workspace = true } rand = { version = "0.7.3", features = ["wasm-bindgen"] } -reqwest = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } sha2 = "0.10.6" +si-scale = "0.2.2" tap = "1.0.1" thiserror = { workspace = true } url = { workspace = true, features = ["serde"] } tungstenite = { workspace = true, default-features = false } tokio = { workspace = true, features = ["macros"] } -time = "0.3.17" +time = { workspace = true } zeroize = { workspace = true } # internal @@ -47,7 +45,7 @@ nym-validator-client = { path = "../client-libs/validator-client", default-featu nym-task = { path = "../task" } nym-credential-storage = { path = "../credential-storage" } nym-network-defaults = { path = "../network-defaults" } -si-scale = "0.2.2" +nym-client-core-surb-storage = { path = "./surb-storage" } ### For serving prometheus metrics [target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper] @@ -74,11 +72,6 @@ features = ["time"] version = "0.20.1" features = ["rustls-tls-native-roots"] -[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] -workspace = true -features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] -optional = true - [target."cfg(target_arch = \"wasm32\")".dependencies.wasm-bindgen-futures] workspace = true @@ -104,18 +97,9 @@ features = ["wasm-bindgen"] [dev-dependencies] tempfile = "3.1.0" -[build-dependencies] -tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } -sqlx = { workspace = true, features = [ - "runtime-tokio-rustls", - "sqlite", - "macros", - "migrate", -] } - [features] default = [] cli = ["clap"] -fs-surb-storage = ["sqlx"] +fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"] wasm = ["nym-gateway-client/wasm"] metrics-server = [] diff --git a/common/client-core/src/client/replies/mod.rs b/common/client-core/src/client/replies/mod.rs index 61b5f19abf..7f425dbd38 100644 --- a/common/client-core/src/client/replies/mod.rs +++ b/common/client-core/src/client/replies/mod.rs @@ -2,4 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 pub mod reply_controller; -pub mod reply_storage; + +// re-export it under the old name to preserve import paths +pub use nym_client_core_surb_storage as reply_storage; diff --git a/common/client-core/surb-storage/Cargo.toml b/common/client-core/surb-storage/Cargo.toml new file mode 100644 index 0000000000..24f466e1e3 --- /dev/null +++ b/common/client-core/surb-storage/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "nym-client-core-surb-storage" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait.workspace = true +dashmap.workspace = true +log.workspace = true +thiserror.workspace = true +time.workspace = true + +nym-crypto = { path = "../../crypto", optional = true, default-features = false } +nym-sphinx = { path = "../../nymsphinx" } +nym-task = { path = "../../task" } + + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] +workspace = true +features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] +optional = true + +[build-dependencies] +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } + +[features] +fs-surb-storage = ["sqlx", "nym-crypto", "nym-crypto/hashing"] diff --git a/common/client-core/build.rs b/common/client-core/surb-storage/build.rs similarity index 100% rename from common/client-core/build.rs rename to common/client-core/surb-storage/build.rs diff --git a/common/client-core/fs_surbs_migrations/20221130120000_create_initial_tables.sql b/common/client-core/surb-storage/fs_surbs_migrations/20221130120000_create_initial_tables.sql similarity index 100% rename from common/client-core/fs_surbs_migrations/20221130120000_create_initial_tables.sql rename to common/client-core/surb-storage/fs_surbs_migrations/20221130120000_create_initial_tables.sql diff --git a/common/client-core/src/client/replies/reply_storage/backend/browser_backend.rs b/common/client-core/surb-storage/src/backend/browser_backend.rs similarity index 88% rename from common/client-core/src/client/replies/reply_storage/backend/browser_backend.rs rename to common/client-core/surb-storage/src/backend/browser_backend.rs index ff2da4ab72..de39fd49b6 100644 --- a/common/client-core/src/client/replies/reply_storage/backend/browser_backend.rs +++ b/common/client-core/surb-storage/src/backend/browser_backend.rs @@ -1,8 +1,8 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::backend::Empty; -use crate::client::replies::reply_storage::{CombinedReplyStorage, ReplyStorageBackend}; +use crate::backend::Empty; +use crate::{CombinedReplyStorage, ReplyStorageBackend}; use async_trait::async_trait; // well, right now we don't have the browser storage : ( diff --git a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/error.rs b/common/client-core/surb-storage/src/backend/fs_backend/error.rs similarity index 100% rename from common/client-core/src/client/replies/reply_storage/backend/fs_backend/error.rs rename to common/client-core/surb-storage/src/backend/fs_backend/error.rs diff --git a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/manager.rs b/common/client-core/surb-storage/src/backend/fs_backend/manager.rs similarity index 77% rename from common/client-core/src/client/replies/reply_storage/backend/fs_backend/manager.rs rename to common/client-core/surb-storage/src/backend/fs_backend/manager.rs index 40c4da18fa..8b663b5c9a 100644 --- a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/manager.rs +++ b/common/client-core/surb-storage/src/backend/fs_backend/manager.rs @@ -1,8 +1,8 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::backend::fs_backend::error::StorageError; -use crate::client::replies::reply_storage::backend::fs_backend::models::{ +use crate::backend::fs_backend::error::StorageError; +use crate::backend::fs_backend::models::{ ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender, }; use log::{error, info}; @@ -10,16 +10,13 @@ use sqlx::ConnectOptions; use std::path::Path; #[derive(Debug, Clone)] -pub(crate) struct StorageManager { - pub(crate) connection_pool: sqlx::SqlitePool, +pub struct StorageManager { + pub connection_pool: sqlx::SqlitePool, } // all SQL goes here impl StorageManager { - pub(crate) async fn init>( - database_path: P, - fresh: bool, - ) -> Result { + pub async fn init>(database_path: P, fresh: bool) -> Result { // ensure the whole directory structure exists if let Some(parent_dir) = database_path.as_ref().parent() { std::fs::create_dir_all(parent_dir).map_err(|source| { @@ -57,45 +54,42 @@ impl StorageManager { } #[allow(dead_code)] - pub(crate) async fn status_table_exists(&self) -> Result { + pub async fn status_table_exists(&self) -> Result { sqlx::query!("SELECT name FROM sqlite_master WHERE type='table' AND name='status'") .fetch_optional(&self.connection_pool) .await .map(|r| r.is_some()) } - pub(crate) async fn create_status_table(&self) -> Result<(), sqlx::Error> { + pub async fn create_status_table(&self) -> Result<(), sqlx::Error> { sqlx::query!("INSERT INTO status(flush_in_progress, previous_flush_timestamp, client_in_use) VALUES (0, 0, 1)") .execute(&self.connection_pool) .await?; Ok(()) } - pub(crate) async fn get_flush_status(&self) -> Result { + pub async fn get_flush_status(&self) -> Result { sqlx::query!("SELECT flush_in_progress FROM status;") .fetch_one(&self.connection_pool) .await .map(|r| r.flush_in_progress > 0) } - pub(crate) async fn set_previous_flush_timestamp( - &self, - timestamp: i64, - ) -> Result<(), sqlx::Error> { + pub async fn set_previous_flush_timestamp(&self, timestamp: i64) -> Result<(), sqlx::Error> { sqlx::query!("UPDATE status SET previous_flush_timestamp = ?", timestamp) .execute(&self.connection_pool) .await?; Ok(()) } - pub(crate) async fn get_previous_flush_timestamp(&self) -> Result { + pub async fn get_previous_flush_timestamp(&self) -> Result { sqlx::query!("SELECT previous_flush_timestamp FROM status;") .fetch_one(&self.connection_pool) .await .map(|r| r.previous_flush_timestamp) } - pub(crate) async fn set_flush_status(&self, in_progress: bool) -> Result<(), sqlx::Error> { + pub async fn set_flush_status(&self, in_progress: bool) -> Result<(), sqlx::Error> { let in_progress_int = i64::from(in_progress); sqlx::query!("UPDATE status SET flush_in_progress = ?", in_progress_int) .execute(&self.connection_pool) @@ -103,14 +97,14 @@ impl StorageManager { Ok(()) } - pub(crate) async fn get_client_in_use_status(&self) -> Result { + pub async fn get_client_in_use_status(&self) -> Result { sqlx::query!("SELECT client_in_use FROM status;") .fetch_one(&self.connection_pool) .await .map(|r| r.client_in_use > 0) } - pub(crate) async fn set_client_in_use_status(&self, in_use: bool) -> Result<(), sqlx::Error> { + pub async fn set_client_in_use_status(&self, in_use: bool) -> Result<(), sqlx::Error> { let in_use_int = i64::from(in_use); sqlx::query!("UPDATE status SET client_in_use = ?", in_use_int) .execute(&self.connection_pool) @@ -118,20 +112,20 @@ impl StorageManager { Ok(()) } - pub(crate) async fn delete_all_tags(&self) -> Result<(), sqlx::Error> { + pub async fn delete_all_tags(&self) -> Result<(), sqlx::Error> { sqlx::query!("DELETE FROM sender_tag;") .execute(&self.connection_pool) .await?; Ok(()) } - pub(crate) async fn get_tags(&self) -> Result, sqlx::Error> { + pub async fn get_tags(&self) -> Result, sqlx::Error> { sqlx::query_as!(StoredSenderTag, "SELECT * FROM sender_tag;",) .fetch_all(&self.connection_pool) .await } - pub(crate) async fn insert_tag(&self, stored_tag: StoredSenderTag) -> Result<(), sqlx::Error> { + pub async fn insert_tag(&self, stored_tag: StoredSenderTag) -> Result<(), sqlx::Error> { sqlx::query!( r#" INSERT INTO sender_tag(recipient, tag) VALUES (?, ?); @@ -144,20 +138,20 @@ impl StorageManager { Ok(()) } - pub(crate) async fn delete_all_reply_keys(&self) -> Result<(), sqlx::Error> { + pub async fn delete_all_reply_keys(&self) -> Result<(), sqlx::Error> { sqlx::query!("DELETE FROM reply_key;") .execute(&self.connection_pool) .await?; Ok(()) } - pub(crate) async fn get_reply_keys(&self) -> Result, sqlx::Error> { + pub async fn get_reply_keys(&self) -> Result, sqlx::Error> { sqlx::query_as!(StoredReplyKey, "SELECT * FROM reply_key;",) .fetch_all(&self.connection_pool) .await } - pub(crate) async fn insert_reply_key( + pub async fn insert_reply_key( &self, stored_reply_key: StoredReplyKey, ) -> Result<(), sqlx::Error> { @@ -174,13 +168,13 @@ impl StorageManager { Ok(()) } - pub(crate) async fn get_surb_senders(&self) -> Result, sqlx::Error> { + pub async fn get_surb_senders(&self) -> Result, sqlx::Error> { sqlx::query_as!(StoredSurbSender, "SELECT * FROM reply_surb_sender;",) .fetch_all(&self.connection_pool) .await } - pub(crate) async fn insert_surb_sender( + pub async fn insert_surb_sender( &self, stored_surb_sender: StoredSurbSender, ) -> Result { @@ -197,7 +191,7 @@ impl StorageManager { Ok(id) } - pub(crate) async fn get_reply_surbs( + pub async fn get_reply_surbs( &self, sender_id: i64, ) -> Result, sqlx::Error> { @@ -210,7 +204,7 @@ impl StorageManager { .await } - pub(crate) async fn delete_all_reply_surb_data(&self) -> Result<(), sqlx::Error> { + pub async fn delete_all_reply_surb_data(&self) -> Result<(), sqlx::Error> { sqlx::query!("DELETE FROM reply_surb;") .execute(&self.connection_pool) .await?; @@ -222,7 +216,7 @@ impl StorageManager { Ok(()) } - pub(crate) async fn insert_reply_surb( + pub async fn insert_reply_surb( &self, stored_reply_surb: StoredReplySurb, ) -> Result<(), sqlx::Error> { @@ -238,7 +232,7 @@ impl StorageManager { Ok(()) } - pub(crate) async fn get_reply_surb_storage_metadata( + pub async fn get_reply_surb_storage_metadata( &self, ) -> Result { sqlx::query_as!( @@ -251,7 +245,7 @@ impl StorageManager { .await } - pub(crate) async fn insert_reply_surb_storage_metadata( + pub async fn insert_reply_surb_storage_metadata( &self, metadata: ReplySurbStorageMetadata, ) -> Result<(), sqlx::Error> { diff --git a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/mod.rs b/common/client-core/surb-storage/src/backend/fs_backend/mod.rs similarity index 97% rename from common/client-core/src/client/replies/reply_storage/backend/fs_backend/mod.rs rename to common/client-core/surb-storage/src/backend/fs_backend/mod.rs index 4800634563..6f68c59201 100644 --- a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/mod.rs +++ b/common/client-core/surb-storage/src/backend/fs_backend/mod.rs @@ -1,12 +1,12 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::backend::fs_backend::manager::StorageManager; -use crate::client::replies::reply_storage::backend::fs_backend::models::{ +use crate::backend::fs_backend::manager::StorageManager; +use crate::backend::fs_backend::models::{ ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender, }; -use crate::client::replies::reply_storage::surb_storage::ReceivedReplySurbs; -use crate::client::replies::reply_storage::{ +use crate::surb_storage::ReceivedReplySurbs; +use crate::{ CombinedReplyStorage, ReceivedReplySurbsMap, ReplyStorageBackend, SentReplyKeys, UsedSenderTags, }; use async_trait::async_trait; diff --git a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/models.rs b/common/client-core/surb-storage/src/backend/fs_backend/models.rs similarity index 79% rename from common/client-core/src/client/replies/reply_storage/backend/fs_backend/models.rs rename to common/client-core/surb-storage/src/backend/fs_backend/models.rs index c7b5196654..8acf83f676 100644 --- a/common/client-core/src/client/replies/reply_storage/backend/fs_backend/models.rs +++ b/common/client-core/surb-storage/src/backend/fs_backend/models.rs @@ -1,8 +1,8 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::backend::fs_backend::error::StorageError; -use crate::client::replies::reply_storage::key_storage::UsedReplyKey; +use crate::backend::fs_backend::error::StorageError; +use crate::key_storage::UsedReplyKey; use nym_crypto::generic_array::typenum::Unsigned; use nym_crypto::Digest; use nym_sphinx::addressing::clients::{Recipient, RecipientBytes}; @@ -12,13 +12,13 @@ use nym_sphinx::anonymous_replies::{ReplySurb, SurbEncryptionKey, SurbEncryption use nym_sphinx::params::ReplySurbKeyDigestAlgorithm; #[derive(Debug, Clone)] -pub(crate) struct StoredSenderTag { - pub(crate) recipient: Vec, - pub(crate) tag: Vec, +pub struct StoredSenderTag { + pub recipient: Vec, + pub tag: Vec, } impl StoredSenderTag { - pub(crate) fn new(recipient: RecipientBytes, tag: AnonymousSenderTag) -> StoredSenderTag { + pub fn new(recipient: RecipientBytes, tag: AnonymousSenderTag) -> StoredSenderTag { StoredSenderTag { recipient: recipient.to_vec(), tag: tag.to_bytes().to_vec(), @@ -57,14 +57,14 @@ impl TryFrom for (RecipientBytes, AnonymousSenderTag) { } #[derive(Debug, Clone)] -pub(crate) struct StoredReplyKey { - pub(crate) key_digest: Vec, - pub(crate) reply_key: Vec, - pub(crate) sent_at_timestamp: i64, +pub struct StoredReplyKey { + pub key_digest: Vec, + pub reply_key: Vec, + pub sent_at_timestamp: i64, } impl StoredReplyKey { - pub(crate) fn new(key_digest: EncryptionKeyDigest, reply_key: UsedReplyKey) -> StoredReplyKey { + pub fn new(key_digest: EncryptionKeyDigest, reply_key: UsedReplyKey) -> StoredReplyKey { StoredReplyKey { key_digest: key_digest.to_vec(), reply_key: (*reply_key).to_bytes(), @@ -105,14 +105,14 @@ impl TryFrom for (EncryptionKeyDigest, UsedReplyKey) { } } -pub(crate) struct StoredSurbSender { - pub(crate) id: i64, - pub(crate) tag: Vec, - pub(crate) last_sent_timestamp: i64, +pub struct StoredSurbSender { + pub id: i64, + pub tag: Vec, + pub last_sent_timestamp: i64, } impl StoredSurbSender { - pub(crate) fn new(tag: AnonymousSenderTag, last_sent_timestamp: i64) -> Self { + pub fn new(tag: AnonymousSenderTag, last_sent_timestamp: i64) -> Self { StoredSurbSender { // for the purposes of STORING data, // we ignore that field anyway @@ -143,13 +143,13 @@ impl TryFrom for (AnonymousSenderTag, i64) { } } -pub(crate) struct StoredReplySurb { - pub(crate) reply_surb_sender_id: i64, - pub(crate) reply_surb: Vec, +pub struct StoredReplySurb { + pub reply_surb_sender_id: i64, + pub reply_surb: Vec, } impl StoredReplySurb { - pub(crate) fn new(reply_surb_sender_id: i64, reply_surb: &ReplySurb) -> Self { + pub fn new(reply_surb_sender_id: i64, reply_surb: &ReplySurb) -> Self { StoredReplySurb { reply_surb_sender_id, reply_surb: reply_surb.to_bytes(), @@ -168,13 +168,13 @@ impl TryFrom for ReplySurb { } #[derive(Copy, Clone)] -pub(crate) struct ReplySurbStorageMetadata { - pub(crate) min_reply_surb_threshold: u32, - pub(crate) max_reply_surb_threshold: u32, +pub struct ReplySurbStorageMetadata { + pub min_reply_surb_threshold: u32, + pub max_reply_surb_threshold: u32, } impl ReplySurbStorageMetadata { - pub(crate) fn new(min_reply_surb_threshold: usize, max_reply_surb_threshold: usize) -> Self { + pub fn new(min_reply_surb_threshold: usize, max_reply_surb_threshold: usize) -> Self { Self { min_reply_surb_threshold: min_reply_surb_threshold as u32, max_reply_surb_threshold: max_reply_surb_threshold as u32, diff --git a/common/client-core/src/client/replies/reply_storage/backend/mod.rs b/common/client-core/surb-storage/src/backend/mod.rs similarity index 97% rename from common/client-core/src/client/replies/reply_storage/backend/mod.rs rename to common/client-core/surb-storage/src/backend/mod.rs index 557346a2da..e195051e4e 100644 --- a/common/client-core/src/client/replies/reply_storage/backend/mod.rs +++ b/common/client-core/surb-storage/src/backend/mod.rs @@ -1,7 +1,7 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::CombinedReplyStorage; +use crate::CombinedReplyStorage; use async_trait::async_trait; use std::error::Error; use thiserror::Error; diff --git a/common/client-core/src/client/replies/reply_storage/combined.rs b/common/client-core/surb-storage/src/combined.rs similarity index 90% rename from common/client-core/src/client/replies/reply_storage/combined.rs rename to common/client-core/surb-storage/src/combined.rs index c9fb9e4a5c..9d44e53923 100644 --- a/common/client-core/src/client/replies/reply_storage/combined.rs +++ b/common/client-core/surb-storage/src/combined.rs @@ -1,7 +1,7 @@ -// Copyright 2022 - Nym Technologies SA +// Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::replies::reply_storage::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags}; +use crate::{ReceivedReplySurbsMap, SentReplyKeys, UsedSenderTags}; #[derive(Debug, Clone)] pub struct CombinedReplyStorage { diff --git a/common/client-core/src/client/replies/reply_storage/key_storage.rs b/common/client-core/surb-storage/src/key_storage.rs similarity index 72% rename from common/client-core/src/client/replies/reply_storage/key_storage.rs rename to common/client-core/surb-storage/src/key_storage.rs index 310a44e0eb..61a474ad5c 100644 --- a/common/client-core/src/client/replies/reply_storage/key_storage.rs +++ b/common/client-core/surb-storage/src/key_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2022 - Nym Technologies SA +// Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use dashmap::iter::Iter; @@ -14,13 +14,19 @@ pub struct SentReplyKeys { inner: Arc, } +impl Default for SentReplyKeys { + fn default() -> Self { + SentReplyKeys::new() + } +} + #[derive(Debug)] struct SentReplyKeysInner { data: DashMap, } impl SentReplyKeys { - pub(crate) fn new() -> SentReplyKeys { + pub fn new() -> SentReplyKeys { SentReplyKeys { inner: Arc::new(SentReplyKeysInner { data: DashMap::new(), @@ -29,7 +35,7 @@ impl SentReplyKeys { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn from_raw(raw: Vec<(EncryptionKeyDigest, UsedReplyKey)>) -> SentReplyKeys { + pub fn from_raw(raw: Vec<(EncryptionKeyDigest, UsedReplyKey)>) -> SentReplyKeys { SentReplyKeys { inner: Arc::new(SentReplyKeysInner { data: raw.into_iter().collect(), @@ -37,35 +43,35 @@ impl SentReplyKeys { } } - pub(crate) fn as_raw_iter(&self) -> Iter<'_, EncryptionKeyDigest, UsedReplyKey> { + pub fn as_raw_iter(&self) -> Iter<'_, EncryptionKeyDigest, UsedReplyKey> { self.inner.data.iter() } - pub(crate) fn insert_multiple(&self, keys: Vec) { + pub fn insert_multiple(&self, keys: Vec) { let now = OffsetDateTime::now_utc().unix_timestamp(); for key in keys { self.insert(UsedReplyKey::new(key, now)) } } - pub(crate) fn insert(&self, key: UsedReplyKey) { + pub fn insert(&self, key: UsedReplyKey) { self.inner.data.insert(key.compute_digest(), key); } - pub(crate) fn try_pop(&self, digest: EncryptionKeyDigest) -> Option { + pub fn try_pop(&self, digest: EncryptionKeyDigest) -> Option { self.inner.data.remove(&digest).map(|(_k, v)| v) } - pub(crate) fn remove(&self, digest: EncryptionKeyDigest) { + pub fn remove(&self, digest: EncryptionKeyDigest) { self.inner.data.remove(&digest); } } #[derive(Debug, Copy, Clone)] -pub(crate) struct UsedReplyKey { +pub struct UsedReplyKey { key: SurbEncryptionKey, // the purpose of this field is to perform invalidation at relatively very long intervals - pub(crate) sent_at_timestamp: i64, + pub sent_at_timestamp: i64, } impl UsedReplyKey { diff --git a/common/client-core/src/client/replies/reply_storage/mod.rs b/common/client-core/surb-storage/src/lib.rs similarity index 85% rename from common/client-core/src/client/replies/reply_storage/mod.rs rename to common/client-core/surb-storage/src/lib.rs index 16a0a36cd4..9e0ba14b34 100644 --- a/common/client-core/src/client/replies/reply_storage/mod.rs +++ b/common/client-core/surb-storage/src/lib.rs @@ -1,11 +1,11 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -pub use crate::client::replies::reply_storage::combined::CombinedReplyStorage; -pub use crate::client::replies::reply_storage::key_storage::SentReplyKeys; -pub use crate::client::replies::reply_storage::surb_storage::ReceivedReplySurbsMap; -pub use crate::client::replies::reply_storage::tag_storage::UsedSenderTags; pub use backend::*; +pub use combined::CombinedReplyStorage; +pub use key_storage::SentReplyKeys; +pub use surb_storage::ReceivedReplySurbsMap; +pub use tag_storage::UsedSenderTags; mod backend; mod combined; diff --git a/common/client-core/src/client/replies/reply_storage/surb_storage.rs b/common/client-core/surb-storage/src/surb_storage.rs similarity index 77% rename from common/client-core/src/client/replies/reply_storage/surb_storage.rs rename to common/client-core/surb-storage/src/surb_storage.rs index cb88e30a90..92050c0104 100644 --- a/common/client-core/src/client/replies/reply_storage/surb_storage.rs +++ b/common/client-core/surb-storage/src/surb_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2022 - Nym Technologies SA +// Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use dashmap::iter::Iter; @@ -28,10 +28,7 @@ struct ReceivedReplySurbsMapInner { } impl ReceivedReplySurbsMap { - pub(crate) fn new( - min_surb_threshold: usize, - max_surb_threshold: usize, - ) -> ReceivedReplySurbsMap { + pub fn new(min_surb_threshold: usize, max_surb_threshold: usize) -> ReceivedReplySurbsMap { ReceivedReplySurbsMap { inner: Arc::new(ReceivedReplySurbsMapInner { data: DashMap::new(), @@ -42,7 +39,7 @@ impl ReceivedReplySurbsMap { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn from_raw( + pub fn from_raw( min_surb_threshold: usize, max_surb_threshold: usize, raw: Vec<(AnonymousSenderTag, ReceivedReplySurbs)>, @@ -56,28 +53,28 @@ impl ReceivedReplySurbsMap { } } - pub(crate) fn as_raw_iter(&self) -> Iter<'_, AnonymousSenderTag, ReceivedReplySurbs> { + pub fn as_raw_iter(&self) -> Iter<'_, AnonymousSenderTag, ReceivedReplySurbs> { self.inner.data.iter() } - pub(crate) fn remove(&self, target: &AnonymousSenderTag) { + pub fn remove(&self, target: &AnonymousSenderTag) { self.inner.data.remove(target); } - pub(crate) fn reset_surbs_last_received_at(&self, target: &AnonymousSenderTag) { + pub fn reset_surbs_last_received_at(&self, target: &AnonymousSenderTag) { if let Some(mut entry) = self.inner.data.get_mut(target) { entry.surbs_last_received_at_timestamp = OffsetDateTime::now_utc().unix_timestamp(); } } - pub(crate) fn surbs_last_received_at(&self, target: &AnonymousSenderTag) -> Option { + pub fn surbs_last_received_at(&self, target: &AnonymousSenderTag) -> Option { self.inner .data .get(target) .map(|e| e.surbs_last_received_at()) } - pub(crate) fn pending_reception(&self, target: &AnonymousSenderTag) -> u32 { + pub fn pending_reception(&self, target: &AnonymousSenderTag) -> u32 { self.inner .data .get(target) @@ -85,7 +82,7 @@ impl ReceivedReplySurbsMap { .unwrap_or_default() } - pub(crate) fn increment_pending_reception( + pub fn increment_pending_reception( &self, target: &AnonymousSenderTag, amount: u32, @@ -96,7 +93,7 @@ impl ReceivedReplySurbsMap { .map(|mut e| e.increment_pending_reception(amount)) } - pub(crate) fn decrement_pending_reception( + pub fn decrement_pending_reception( &self, target: &AnonymousSenderTag, amount: u32, @@ -107,21 +104,21 @@ impl ReceivedReplySurbsMap { .map(|mut e| e.decrement_pending_reception(amount)) } - pub(crate) fn reset_pending_reception(&self, target: &AnonymousSenderTag) { + pub fn reset_pending_reception(&self, target: &AnonymousSenderTag) { if let Some(mut e) = self.inner.data.get_mut(target) { e.reset_pending_reception() } } - pub(crate) fn min_surb_threshold(&self) -> usize { + pub fn min_surb_threshold(&self) -> usize { self.inner.min_surb_threshold.load(Ordering::Relaxed) } - pub(crate) fn max_surb_threshold(&self) -> usize { + pub fn max_surb_threshold(&self) -> usize { self.inner.max_surb_threshold.load(Ordering::Relaxed) } - pub(crate) fn available_surbs(&self, target: &AnonymousSenderTag) -> usize { + pub fn available_surbs(&self, target: &AnonymousSenderTag) -> usize { self.inner .data .get(target) @@ -129,11 +126,11 @@ impl ReceivedReplySurbsMap { .unwrap_or_default() } - pub(crate) fn contains_surbs_for(&self, target: &AnonymousSenderTag) -> bool { + pub fn contains_surbs_for(&self, target: &AnonymousSenderTag) -> bool { self.inner.data.contains_key(target) } - pub(crate) fn get_reply_surbs( + pub fn get_reply_surbs( &self, target: &AnonymousSenderTag, amount: usize, @@ -150,7 +147,7 @@ impl ReceivedReplySurbsMap { } } - pub(crate) fn get_reply_surb_ignoring_threshold( + pub fn get_reply_surb_ignoring_threshold( &self, target: &AnonymousSenderTag, ) -> Option<(Option, usize)> { @@ -160,7 +157,7 @@ impl ReceivedReplySurbsMap { .map(|mut s| s.get_reply_surb()) } - pub(crate) fn get_reply_surb( + pub fn get_reply_surb( &self, target: &AnonymousSenderTag, ) -> Option<(Option, usize)> { @@ -174,7 +171,7 @@ impl ReceivedReplySurbsMap { }) } - pub(crate) fn insert_surbs>( + pub fn insert_surbs>( &self, target: &AnonymousSenderTag, surbs: I, @@ -189,7 +186,7 @@ impl ReceivedReplySurbsMap { } #[derive(Debug)] -pub(crate) struct ReceivedReplySurbs { +pub struct ReceivedReplySurbs { // in the future we'd probably want to put extra data here to indicate when the SURBs got received // so we could invalidate entries from the previous key rotations data: VecDeque, @@ -208,7 +205,7 @@ impl ReceivedReplySurbs { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn new_retrieved( + pub fn new_retrieved( surbs: Vec, surbs_last_received_at_timestamp: i64, ) -> ReceivedReplySurbs { @@ -220,33 +217,33 @@ impl ReceivedReplySurbs { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn surbs_ref(&self) -> &VecDeque { + pub fn surbs_ref(&self) -> &VecDeque { &self.data } - pub(crate) fn surbs_last_received_at(&self) -> i64 { + pub fn surbs_last_received_at(&self) -> i64 { self.surbs_last_received_at_timestamp } - pub(crate) fn pending_reception(&self) -> u32 { + pub fn pending_reception(&self) -> u32 { self.pending_reception } - pub(crate) fn increment_pending_reception(&mut self, amount: u32) -> u32 { + pub fn increment_pending_reception(&mut self, amount: u32) -> u32 { self.pending_reception += amount; self.pending_reception } - pub(crate) fn decrement_pending_reception(&mut self, amount: u32) -> u32 { + pub fn decrement_pending_reception(&mut self, amount: u32) -> u32 { self.pending_reception = self.pending_reception.saturating_sub(amount); self.pending_reception } - pub(crate) fn reset_pending_reception(&mut self) { + pub fn reset_pending_reception(&mut self) { self.pending_reception = 0; } - pub(crate) fn get_reply_surbs(&mut self, amount: usize) -> (Option>, usize) { + pub fn get_reply_surbs(&mut self, amount: usize) -> (Option>, usize) { if self.items_left() < amount { (None, self.items_left()) } else { @@ -255,7 +252,7 @@ impl ReceivedReplySurbs { } } - pub(crate) fn get_reply_surb(&mut self) -> (Option, usize) { + pub fn get_reply_surb(&mut self) -> (Option, usize) { (self.pop_surb(), self.items_left()) } @@ -268,7 +265,7 @@ impl ReceivedReplySurbs { } // realistically we're always going to be getting multiple surbs at once - pub(crate) fn insert_reply_surbs>(&mut self, surbs: I) { + pub fn insert_reply_surbs>(&mut self, surbs: I) { let mut v = surbs.into_iter().collect::>(); trace!("storing {} surbs in the storage", v.len()); self.data.append(&mut v); diff --git a/common/client-core/src/client/replies/reply_storage/tag_storage.rs b/common/client-core/surb-storage/src/tag_storage.rs similarity index 68% rename from common/client-core/src/client/replies/reply_storage/tag_storage.rs rename to common/client-core/surb-storage/src/tag_storage.rs index 892018b6fc..8c72daffea 100644 --- a/common/client-core/src/client/replies/reply_storage/tag_storage.rs +++ b/common/client-core/surb-storage/src/tag_storage.rs @@ -1,4 +1,4 @@ -// Copyright 2021 - Nym Technologies SA +// Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use dashmap::DashMap; @@ -14,13 +14,19 @@ pub struct UsedSenderTags { inner: Arc, } +impl Default for UsedSenderTags { + fn default() -> Self { + UsedSenderTags::new() + } +} + #[derive(Debug)] struct UsedSenderTagsInner { data: DashMap, } impl UsedSenderTags { - pub(crate) fn new() -> UsedSenderTags { + pub fn new() -> UsedSenderTags { UsedSenderTags { inner: Arc::new(UsedSenderTagsInner { data: DashMap::new(), @@ -29,7 +35,7 @@ impl UsedSenderTags { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn from_raw(raw: Vec<(RecipientBytes, AnonymousSenderTag)>) -> UsedSenderTags { + pub fn from_raw(raw: Vec<(RecipientBytes, AnonymousSenderTag)>) -> UsedSenderTags { UsedSenderTags { inner: Arc::new(UsedSenderTagsInner { data: raw.into_iter().collect(), @@ -38,22 +44,22 @@ impl UsedSenderTags { } #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] - pub(crate) fn as_raw_iter(&self) -> Iter<'_, RecipientBytes, AnonymousSenderTag> { + pub fn as_raw_iter(&self) -> Iter<'_, RecipientBytes, AnonymousSenderTag> { self.inner.data.iter() } - pub(crate) fn insert_new(&self, recipient: &Recipient, tag: AnonymousSenderTag) { + pub fn insert_new(&self, recipient: &Recipient, tag: AnonymousSenderTag) { self.inner.data.insert(recipient.to_bytes(), tag); } - pub(crate) fn try_get_existing(&self, recipient: &Recipient) -> Option { + pub fn try_get_existing(&self, recipient: &Recipient) -> Option { self.inner .data .get(&recipient.to_bytes()) .map(|r| *r.value()) } - pub(crate) fn exists(&self, recipient: &Recipient) -> bool { + pub fn exists(&self, recipient: &Recipient) -> bool { self.inner.data.contains_key(&recipient.to_bytes()) } } From f7edc223e9bca83871566036a7800862eb05ce7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 4 Mar 2024 13:04:35 +0000 Subject: [PATCH 02/56] initial db schema --- .../client-core/gateways-storage/Cargo.toml | 23 ++++++++++++++ common/client-core/gateways-storage/build.rs | 31 +++++++++++++++++++ .../20240304120000_create_initial_tables.sql | 31 +++++++++++++++++++ .../client-core/gateways-storage/src/lib.rs | 14 +++++++++ 4 files changed, 99 insertions(+) create mode 100644 common/client-core/gateways-storage/Cargo.toml create mode 100644 common/client-core/gateways-storage/build.rs create mode 100644 common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql create mode 100644 common/client-core/gateways-storage/src/lib.rs diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml new file mode 100644 index 0000000000..f51396a354 --- /dev/null +++ b/common/client-core/gateways-storage/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "nym-client-core-gateways-storage" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +async-trait.workspace = true +log.workspace = true +thiserror.workspace = true + +[target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] +workspace = true +features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] +optional = true + +[build-dependencies] +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +sqlx = { workspace = true, features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] } + +[features] +fs-gateways-storage = ["sqlx"] \ No newline at end of file diff --git a/common/client-core/gateways-storage/build.rs b/common/client-core/gateways-storage/build.rs new file mode 100644 index 0000000000..f8b85cbb4a --- /dev/null +++ b/common/client-core/gateways-storage/build.rs @@ -0,0 +1,31 @@ +// Copyright 2022 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#[tokio::main] +async fn main() { + #[cfg(feature = "fs-gateways-storage")] + { + use sqlx::{Connection, SqliteConnection}; + use std::env; + + let out_dir = env::var("OUT_DIR").unwrap(); + let database_path = format!("{out_dir}/gateways-storage-example.sqlite"); + + let mut conn = SqliteConnection::connect(&format!("sqlite://{database_path}?mode=rwc")) + .await + .expect("Failed to create SQLx database connection"); + + sqlx::migrate!("./fs_gateways_migrations") + .run(&mut conn) + .await + .expect("Failed to perform SQLx migrations"); + + #[cfg(target_family = "unix")] + println!("cargo:rustc-env=DATABASE_URL=sqlite://{}", &database_path); + + #[cfg(target_family = "windows")] + // for some strange reason we need to add a leading `/` to the windows path even though it's + // not a valid windows path... but hey, it works... + println!("cargo:rustc-env=DATABASE_URL=sqlite:///{}", &database_path); + } +} diff --git a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql new file mode 100644 index 0000000000..95f347024c --- /dev/null +++ b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql @@ -0,0 +1,31 @@ +/* + * Copyright 2024 - Nym Technologies SA + * SPDX-License-Identifier: Apache-2.0 + */ + +CREATE TABLE active_gateway +( + id INTEGER PRIMARY KEY CHECK (id = 0), + active_gateway_id_bs58 TEXT REFERENCES registered_gateway (gateway_id_bs58) +); + +CREATE TABLE registered_gateway +( + gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY, + gateway_type TEXT CHECK ( gateway_type IN ('remote', 'custom') ) NOT NULL DEFAULT 'remote' +); + +CREATE TABLE remote_gateway_details +( + gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58), + derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL, + gateway_owner_address TEXT NOT NULL, + gateway_listener TEXT NOT NULL +); + +CREATE TABLE custom_gateway_details +( + gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58), + data BLOB +); + diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs new file mode 100644 index 0000000000..7d12d9af81 --- /dev/null +++ b/common/client-core/gateways-storage/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} From 4c9de843c556190483cf905f768aed6bc94244b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 4 Mar 2024 14:56:56 +0000 Subject: [PATCH 03/56] types --- Cargo.lock | 22 ++- Cargo.toml | 1 + common/client-core/Cargo.toml | 1 + .../client-core/gateways-storage/Cargo.toml | 7 + .../client-core/gateways-storage/src/error.rs | 50 +++++ .../client-core/gateways-storage/src/lib.rs | 32 ++-- .../gateways-storage/src/models.rs | 172 ++++++++++++++++++ .../src/registration/handshake/shared_key.rs | 2 +- 8 files changed, 271 insertions(+), 16 deletions(-) create mode 100644 common/client-core/gateways-storage/src/error.rs create mode 100644 common/client-core/gateways-storage/src/models.rs diff --git a/Cargo.lock b/Cargo.lock index 89f8e79715..b61fc7884b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5232,8 +5232,6 @@ dependencies = [ "base64 0.21.4", "cfg-if", "clap 4.4.7", - "dashmap", - "dirs 4.0.0", "futures", "gloo-timers", "http-body-util", @@ -5242,6 +5240,7 @@ dependencies = [ "hyper-util", "log", "nym-bandwidth-controller", + "nym-client-core-gateways-storage", "nym-client-core-surb-storage", "nym-config", "nym-credential-storage", @@ -5258,12 +5257,10 @@ dependencies = [ "nym-topology", "nym-validator-client", "rand 0.7.3", - "reqwest", "serde", "serde_json", "sha2 0.10.8", "si-scale", - "sqlx", "tap", "tempfile", "thiserror", @@ -5280,6 +5277,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nym-client-core-gateways-storage" +version = "0.1.0" +dependencies = [ + "async-trait", + "cosmrs 0.15.0 (git+https://github.com/jstuczyn/cosmos-rust?branch=nym-temp/all-validator-features)", + "log", + "nym-crypto", + "nym-gateway-requests", + "serde", + "sqlx", + "thiserror", + "tokio", + "url", + "zeroize", +] + [[package]] name = "nym-client-core-surb-storage" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 13359ec2db..f7a7982019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ members = [ "common/bin-common", "common/client-core", "common/client-core/surb-storage", + "common/client-core/gateways-storage", "common/client-libs/gateway-client", "common/client-libs/mixnet-client", "common/client-libs/validator-client", diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index 9052001f15..b2643888c5 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -46,6 +46,7 @@ nym-task = { path = "../task" } nym-credential-storage = { path = "../credential-storage" } nym-network-defaults = { path = "../network-defaults" } nym-client-core-surb-storage = { path = "./surb-storage" } +nym-client-core-gateways-storage = { path = "./gateways-storage" } ### For serving prometheus metrics [target."cfg(not(target_arch = \"wasm32\"))".dependencies.hyper] diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index f51396a354..04f6146f09 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -7,8 +7,15 @@ edition = "2021" [dependencies] async-trait.workspace = true +cosmrs.workspace = true log.workspace = true +serde = { workspace = true, features = ["derive"] } thiserror.workspace = true +url.workspace = true +zeroize = { workspace = true, features = ["zeroize_derive"] } + +nym-crypto = { path = "../../crypto", features = ["asymmetric"] } +nym-gateway-requests = { path = "../../../gateway/gateway-requests" } [target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] workspace = true diff --git a/common/client-core/gateways-storage/src/error.rs b/common/client-core/gateways-storage/src/error.rs new file mode 100644 index 0000000000..287ffb4567 --- /dev/null +++ b/common/client-core/gateways-storage/src/error.rs @@ -0,0 +1,50 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use nym_crypto::asymmetric::identity::Ed25519RecoveryError; +use nym_gateway_requests::registration::handshake::shared_key::SharedKeyConversionError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum GatewaysStorageError { + #[error("{typ} is not a valid gateway type")] + InvalidGatewayType { typ: String }, + + #[error("the provided gateway identity {gateway_id} is malformed: {source}")] + MalformedGatewayIdentity { + gateway_id: String, + + #[source] + source: Ed25519RecoveryError, + }, + + #[error("the account owner of gateway {gateway_id} ({raw_owner}) is malformed: {source}")] + MalformedGatewayOwnerAccountAddress { + gateway_id: String, + + raw_owner: String, + + #[source] + source: cosmrs::ErrorReport, + }, + + #[error("the shared keys provided for gateway {gateway_id} are malformed: {source}")] + MalformedSharedKeys { + gateway_id: String, + + #[source] + source: SharedKeyConversionError, + }, + + #[error( + "the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}" + )] + MalformedListener { + gateway_id: String, + + raw_listener: String, + + #[source] + source: url::ParseError, + }, +} diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 7d12d9af81..358a293930 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -1,14 +1,24 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 -#[cfg(test)] -mod tests { - use super::*; +use async_trait::async_trait; +use std::error::Error; - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } +pub mod error; +pub mod models; + +pub use error::GatewaysStorageError; + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +pub trait GatewayDetailsStore { + type StorageError: Error; + + async fn active_gateway(&self) -> Result, Self::StorageError>; + + async fn all_gateways(&self) -> Result, Self::StorageError>; + + async fn load_gateway_details(&self) -> Result<(), Self::StorageError>; + + async fn store_gateway_details(&self) -> Result<(), Self::StorageError>; } diff --git a/common/client-core/gateways-storage/src/models.rs b/common/client-core/gateways-storage/src/models.rs new file mode 100644 index 0000000000..c78156ef73 --- /dev/null +++ b/common/client-core/gateways-storage/src/models.rs @@ -0,0 +1,172 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::GatewaysStorageError; +use cosmrs::AccountId; +use nym_crypto::asymmetric::identity; +use nym_gateway_requests::registration::handshake::SharedKeys; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; +use url::Url; +use zeroize::{Zeroize, ZeroizeOnDrop}; + +pub const REMOTE_GATEWAY_TYPE: &str = "remote"; +pub const CUSTOM_GATEWAY_TYPE: &str = "custom"; + +#[derive(Debug, Copy, Clone, Default)] +pub enum GatewayType { + #[default] + Remote, + + Custom, +} + +impl FromStr for GatewayType { + type Err = GatewaysStorageError; + + fn from_str(s: &str) -> Result { + match s { + REMOTE_GATEWAY_TYPE => Ok(GatewayType::Remote), + CUSTOM_GATEWAY_TYPE => Ok(GatewayType::Custom), + other => Err(GatewaysStorageError::InvalidGatewayType { + typ: other.to_string(), + }), + } + } +} + +impl Display for GatewayType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + GatewayType::Remote => REMOTE_GATEWAY_TYPE.fmt(f), + GatewayType::Custom => CUSTOM_GATEWAY_TYPE.fmt(f), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct RawRegisteredGateway { + pub gateway_id_bs58: String, + pub gateway_type: String, +} + +#[derive(Debug, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct RawRemoteGatewayDetails { + pub gateway_id_bs58: String, + pub derived_aes128_ctr_blake3_hmac_keys_bs58: String, + pub gateway_owner_address: String, + pub gateway_listener: String, +} + +impl TryFrom for RemoteGatewayDetails { + type Error = GatewaysStorageError; + + fn try_from(value: RawRemoteGatewayDetails) -> Result { + let gateway_id = + identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| { + GatewaysStorageError::MalformedGatewayIdentity { + gateway_id: value.gateway_id_bs58.clone(), + source, + } + })?; + + let derived_aes128_ctr_blake3_hmac_keys = + SharedKeys::try_from_base58_string(&value.derived_aes128_ctr_blake3_hmac_keys_bs58) + .map_err(|source| GatewaysStorageError::MalformedSharedKeys { + gateway_id: value.gateway_id_bs58.clone(), + source, + })?; + + let gateway_owner_address = + AccountId::from_str(&value.gateway_owner_address).map_err(|source| { + GatewaysStorageError::MalformedGatewayOwnerAccountAddress { + gateway_id: value.gateway_id_bs58.clone(), + raw_owner: value.gateway_owner_address.clone(), + source, + } + })?; + + let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| { + GatewaysStorageError::MalformedListener { + gateway_id: value.gateway_id_bs58.clone(), + raw_listener: value.gateway_listener.clone(), + source, + } + })?; + + Ok(RemoteGatewayDetails { + gateway_id, + derived_aes128_ctr_blake3_hmac_keys, + gateway_owner_address, + gateway_listener, + }) + } +} + +impl From for RawRemoteGatewayDetails { + fn from(value: RemoteGatewayDetails) -> Self { + RawRemoteGatewayDetails { + gateway_id_bs58: value.gateway_id.to_base58_string(), + derived_aes128_ctr_blake3_hmac_keys_bs58: value + .derived_aes128_ctr_blake3_hmac_keys + .to_base58_string(), + gateway_owner_address: value.gateway_owner_address.to_string(), + gateway_listener: value.gateway_listener.to_string(), + } + } +} + +#[derive(Debug, Zeroize, ZeroizeOnDrop)] +pub struct RemoteGatewayDetails { + #[zeroize(skip)] + pub gateway_id: identity::PublicKey, + pub derived_aes128_ctr_blake3_hmac_keys: SharedKeys, + #[zeroize(skip)] + pub gateway_owner_address: AccountId, + #[zeroize(skip)] + pub gateway_listener: Url, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct RawCustomGatewayDetails { + pub gateway_id_bs58: String, + pub data: Option>, +} + +impl TryFrom for CustomGatewayDetails { + type Error = GatewaysStorageError; + + fn try_from(value: RawCustomGatewayDetails) -> Result { + let gateway_id = + identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| { + GatewaysStorageError::MalformedGatewayIdentity { + gateway_id: value.gateway_id_bs58.clone(), + source, + } + })?; + + Ok(CustomGatewayDetails { + gateway_id, + data: value.data, + }) + } +} + +impl From for RawCustomGatewayDetails { + fn from(value: CustomGatewayDetails) -> Self { + RawCustomGatewayDetails { + gateway_id_bs58: value.gateway_id.to_base58_string(), + data: value.data, + } + } +} + +#[derive(Debug)] +pub struct CustomGatewayDetails { + pub gateway_id: identity::PublicKey, + pub data: Option>, +} diff --git a/gateway/gateway-requests/src/registration/handshake/shared_key.rs b/gateway/gateway-requests/src/registration/handshake/shared_key.rs index d3101017a4..4d4dce6e7f 100644 --- a/gateway/gateway-requests/src/registration/handshake/shared_key.rs +++ b/gateway/gateway-requests/src/registration/handshake/shared_key.rs @@ -30,7 +30,7 @@ pub struct SharedKeys { mac_key: MacKey, } -#[derive(Debug, Error)] +#[derive(Debug, Clone, Copy, Error)] pub enum SharedKeyConversionError { #[error("the string representation of the shared keys was malformed - {0}")] DecodeError(#[from] bs58::decode::Error), From 84a36c00b4a3387973fe0f122383b2e146c0dd1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 5 Mar 2024 09:35:47 +0000 Subject: [PATCH 04/56] added registration timestamp --- common/client-core/gateways-storage/Cargo.toml | 1 + .../20240304120000_create_initial_tables.sql | 5 +++-- common/client-core/gateways-storage/src/lib.rs | 4 ++++ common/client-core/gateways-storage/src/models.rs | 5 +++++ 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index 04f6146f09..a4c3f44fa4 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -11,6 +11,7 @@ cosmrs.workspace = true log.workspace = true serde = { workspace = true, features = ["derive"] } thiserror.workspace = true +time.workspace = true url.workspace = true zeroize = { workspace = true, features = ["zeroize_derive"] } diff --git a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql index 95f347024c..6df9d40a1a 100644 --- a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql +++ b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql @@ -11,8 +11,9 @@ CREATE TABLE active_gateway CREATE TABLE registered_gateway ( - gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY, - gateway_type TEXT CHECK ( gateway_type IN ('remote', 'custom') ) NOT NULL DEFAULT 'remote' + gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY, + registration_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL, + gateway_type TEXT CHECK ( gateway_type IN ('remote', 'custom') ) NOT NULL DEFAULT 'remote' ); CREATE TABLE remote_gateway_details diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 358a293930..adda95c055 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -14,11 +14,15 @@ pub use error::GatewaysStorageError; pub trait GatewayDetailsStore { type StorageError: Error; + /// Returns details of the currently active gateway, if available. async fn active_gateway(&self) -> Result, Self::StorageError>; + /// Returns details of all registered gateways. async fn all_gateways(&self) -> Result, Self::StorageError>; + /// Returns details of the particular gateway. async fn load_gateway_details(&self) -> Result<(), Self::StorageError>; + /// Store the provided gateway details. async fn store_gateway_details(&self) -> Result<(), Self::StorageError>; } diff --git a/common/client-core/gateways-storage/src/models.rs b/common/client-core/gateways-storage/src/models.rs index c78156ef73..ac8f884dd5 100644 --- a/common/client-core/gateways-storage/src/models.rs +++ b/common/client-core/gateways-storage/src/models.rs @@ -8,6 +8,7 @@ use nym_gateway_requests::registration::handshake::SharedKeys; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; use std::str::FromStr; +use time::OffsetDateTime; use url::Url; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -49,6 +50,10 @@ impl Display for GatewayType { #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct RawRegisteredGateway { pub gateway_id_bs58: String, + + // not necessarily needed but is nice for display purposes + pub registration_timestamp: OffsetDateTime, + pub gateway_type: String, } From fe2edd56a8b1fbd73bf81d647b833c2409faf01b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 5 Mar 2024 15:39:56 +0000 Subject: [PATCH 05/56] adjusting the trait --- .../client-core/gateways-storage/Cargo.toml | 1 + .../src/backend/fs_backend/error.rs | 38 +++++++++ .../src/backend/fs_backend/manager.rs | 53 +++++++++++++ .../src/backend/fs_backend/mod.rs | 46 +++++++++++ .../src/backend/fs_backend/models.rs | 2 + .../src/backend/mem_backend.rs | 69 ++++++++++++++++ .../gateways-storage/src/backend/mod.rs | 7 ++ .../client-core/gateways-storage/src/error.rs | 2 +- .../client-core/gateways-storage/src/lib.rs | 28 +++++-- .../src/{models.rs => types.rs} | 78 +++++++++++++++---- .../src/backend/fs_backend/error.rs | 2 +- 11 files changed, 300 insertions(+), 26 deletions(-) create mode 100644 common/client-core/gateways-storage/src/backend/fs_backend/error.rs create mode 100644 common/client-core/gateways-storage/src/backend/fs_backend/manager.rs create mode 100644 common/client-core/gateways-storage/src/backend/fs_backend/mod.rs create mode 100644 common/client-core/gateways-storage/src/backend/fs_backend/models.rs create mode 100644 common/client-core/gateways-storage/src/backend/mem_backend.rs create mode 100644 common/client-core/gateways-storage/src/backend/mod.rs rename common/client-core/gateways-storage/src/{models.rs => types.rs} (72%) diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index a4c3f44fa4..3968df079e 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -12,6 +12,7 @@ log.workspace = true serde = { workspace = true, features = ["derive"] } thiserror.workspace = true time.workspace = true +tokio = { workspace = true, features = ["sync"] } url.workspace = true zeroize = { workspace = true, features = ["zeroize_derive"] } diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/error.rs b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs new file mode 100644 index 0000000000..0a39dbbe06 --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs @@ -0,0 +1,38 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use std::io; +use std::path::PathBuf; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum StorageError { + #[error("the provided database path doesn't have a filename defined")] + DatabasePathWithoutFilename { provided_path: PathBuf }, + + #[error("unable to create the directory for the database at {}: {source}", provided_path.display())] + DatabasePathUnableToCreateParentDirectory { + provided_path: PathBuf, + source: io::Error, + }, + + #[error("failed to perform sqlx migration: {source}")] + MigrationError { + #[source] + #[from] + source: sqlx::migrate::MigrateError, + }, + + #[error("failed to connect to the underlying connection pool: {source}")] + DatabaseConnectionError { + #[source] + source: sqlx::error::Error, + }, + + #[error("failed to run the SQL query: {source}")] + QueryError { + #[source] + #[from] + source: sqlx::error::Error, + }, +} diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs new file mode 100644 index 0000000000..299b16ea8b --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -0,0 +1,53 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::backend::fs_backend::error::StorageError; +use crate::backend::fs_backend::models::{ + ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender, +}; +use log::{error, info}; +use sqlx::ConnectOptions; +use std::path::Path; + +#[derive(Debug, Clone)] +pub struct StorageManager { + pub connection_pool: sqlx::SqlitePool, +} + +// all SQL goes here +impl StorageManager { + pub async fn init>(database_path: P, fresh: bool) -> Result { + // ensure the whole directory structure exists + if let Some(parent_dir) = database_path.as_ref().parent() { + std::fs::create_dir_all(parent_dir).map_err(|source| { + StorageError::DatabasePathUnableToCreateParentDirectory { + provided_path: database_path.as_ref().to_path_buf(), + source, + } + })?; + } + + let mut opts = sqlx::sqlite::SqliteConnectOptions::new() + .filename(database_path) + .create_if_missing(fresh); + + opts.disable_statement_logging(); + + let connection_pool = sqlx::SqlitePool::connect_with(opts) + .await + .map_err(|source| { + error!("Failed to connect to SQLx database: {err}"); + StorageError::DatabaseConnectionError { source } + })?; + + sqlx::migrate!("./fs_gateways_migrations") + .run(&connection_pool) + .await + .inspect_err(|err| { + error!("Failed to initialize SQLx database: {err}"); + })?; + + info!("Database migration finished!"); + Ok(StorageManager { connection_pool }) + } +} diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs new file mode 100644 index 0000000000..e8ddc05d83 --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -0,0 +1,46 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::types::GatewayDetails; +use crate::GatewayDetailsStore; +use async_trait::async_trait; +use manager::StorageManager; + +mod error; +mod manager; +mod models; + +pub struct OnDiskGatewayDetails { + manager: StorageManager, +} + +#[async_trait] +impl GatewayDetailsStore for OnDiskGatewayDetails { + type StorageError = error::StorageError; + + async fn active_gateway(&self) -> Result, Self::StorageError> { + todo!() + } + + async fn all_gateways(&self) -> Result, Self::StorageError> { + todo!() + } + + async fn load_gateway_details( + &self, + gateway_id: &str, + ) -> Result { + todo!() + } + + async fn store_gateway_details( + &self, + details: GatewayDetails, + ) -> Result<(), Self::StorageError> { + todo!() + } + + async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + todo!() + } +} diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/models.rs b/common/client-core/gateways-storage/src/backend/fs_backend/models.rs new file mode 100644 index 0000000000..755fb6cc8b --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/fs_backend/models.rs @@ -0,0 +1,2 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs new file mode 100644 index 0000000000..53afb6007b --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -0,0 +1,69 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::types::GatewayDetails; +use crate::{BadGateway, GatewayDetailsStore}; +use async_trait::async_trait; +use std::collections::HashMap; +use std::sync::Arc; +use thiserror::Error; +use tokio::sync::RwLock; + +#[derive(Debug, Error)] +pub enum InMemStorageError { + #[error("gateway {gateway_id} does not exist")] + GatewayDoesNotExist { gateway_id: String }, + + #[error(transparent)] + MalformedGateway(#[from] BadGateway), +} + +pub struct InMemStorage { + inner: Arc>, +} + +struct InMemStorageInner { + active_gateway: Option, + gateways: HashMap, +} + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +impl GatewayDetailsStore for InMemStorage { + type StorageError = InMemStorageError; + + async fn active_gateway(&self) -> Result, 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 all_gateways(&self) -> Result, Self::StorageError> { + todo!() + } + + async fn load_gateway_details( + &self, + gateway_id: &str, + ) -> Result { + todo!() + } + + async fn store_gateway_details( + &self, + details: GatewayDetails, + ) -> Result<(), Self::StorageError> { + todo!() + } + + async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + todo!() + } +} diff --git a/common/client-core/gateways-storage/src/backend/mod.rs b/common/client-core/gateways-storage/src/backend/mod.rs new file mode 100644 index 0000000000..9414bb4f14 --- /dev/null +++ b/common/client-core/gateways-storage/src/backend/mod.rs @@ -0,0 +1,7 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] +pub mod fs_backend; + +pub mod mem_backend; diff --git a/common/client-core/gateways-storage/src/error.rs b/common/client-core/gateways-storage/src/error.rs index 287ffb4567..f547164022 100644 --- a/common/client-core/gateways-storage/src/error.rs +++ b/common/client-core/gateways-storage/src/error.rs @@ -6,7 +6,7 @@ use nym_gateway_requests::registration::handshake::shared_key::SharedKeyConversi use thiserror::Error; #[derive(Debug, Error)] -pub enum GatewaysStorageError { +pub enum BadGateway { #[error("{typ} is not a valid gateway type")] InvalidGatewayType { typ: String }, diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index adda95c055..393e6438ff 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -1,28 +1,42 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +#![warn(clippy::expect_used)] +#![warn(clippy::unwrap_used)] + use async_trait::async_trait; use std::error::Error; +mod backend; pub mod error; -pub mod models; +pub mod types; -pub use error::GatewaysStorageError; +use crate::types::GatewayDetails; +pub use error::BadGateway; #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] pub trait GatewayDetailsStore { - type StorageError: Error; + type StorageError: Error + From; /// Returns details of the currently active gateway, if available. - async fn active_gateway(&self) -> Result, Self::StorageError>; + async fn active_gateway(&self) -> Result, Self::StorageError>; /// Returns details of all registered gateways. - async fn all_gateways(&self) -> Result, Self::StorageError>; + async fn all_gateways(&self) -> Result, Self::StorageError>; /// Returns details of the particular gateway. - async fn load_gateway_details(&self) -> Result<(), Self::StorageError>; + async fn load_gateway_details( + &self, + gateway_id: &str, + ) -> Result; /// Store the provided gateway details. - async fn store_gateway_details(&self) -> Result<(), Self::StorageError>; + async fn store_gateway_details( + &self, + details: GatewayDetails, + ) -> Result<(), Self::StorageError>; + + /// Remove given gateway details from the underlying store. + async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError>; } diff --git a/common/client-core/gateways-storage/src/models.rs b/common/client-core/gateways-storage/src/types.rs similarity index 72% rename from common/client-core/gateways-storage/src/models.rs rename to common/client-core/gateways-storage/src/types.rs index ac8f884dd5..383500284f 100644 --- a/common/client-core/gateways-storage/src/models.rs +++ b/common/client-core/gateways-storage/src/types.rs @@ -1,13 +1,14 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::GatewaysStorageError; +use crate::BadGateway; use cosmrs::AccountId; use nym_crypto::asymmetric::identity; use nym_gateway_requests::registration::handshake::SharedKeys; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; use std::str::FromStr; +use std::sync::Arc; use time::OffsetDateTime; use url::Url; use zeroize::{Zeroize, ZeroizeOnDrop}; @@ -15,6 +16,37 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub const REMOTE_GATEWAY_TYPE: &str = "remote"; pub const CUSTOM_GATEWAY_TYPE: &str = "custom"; +#[derive(Debug)] +pub struct GatewayRegistration { + pub details: GatewayDetails, + pub registration_timestamp: OffsetDateTime, +} + +#[derive(Debug)] +pub enum GatewayDetails { + /// Standard details of a remote gateway + Remote(RemoteGatewayDetails), + + /// Custom gateway setup, such as for a client embedded inside gateway itself + Custom(CustomGatewayDetails), +} + +impl GatewayDetails { + pub fn gateway_id(&self) -> identity::PublicKey { + match self { + GatewayDetails::Remote(details) => details.gateway_id, + GatewayDetails::Custom(details) => details.gateway_id, + } + } + + pub fn shared_key(&self) -> Option<&SharedKeys> { + match self { + GatewayDetails::Remote(details) => Some(&details.derived_aes128_ctr_blake3_hmac_keys), + GatewayDetails::Custom(_) => None, + } + } +} + #[derive(Debug, Copy, Clone, Default)] pub enum GatewayType { #[default] @@ -24,13 +56,13 @@ pub enum GatewayType { } impl FromStr for GatewayType { - type Err = GatewaysStorageError; + type Err = BadGateway; fn from_str(s: &str) -> Result { match s { REMOTE_GATEWAY_TYPE => Ok(GatewayType::Remote), CUSTOM_GATEWAY_TYPE => Ok(GatewayType::Custom), - other => Err(GatewaysStorageError::InvalidGatewayType { + other => Err(BadGateway::InvalidGatewayType { typ: other.to_string(), }), } @@ -57,6 +89,15 @@ pub struct RawRegisteredGateway { pub gateway_type: String, } +#[derive(Debug, Clone, Copy)] +pub struct RegisteredGateway { + pub gateway_id: identity::PublicKey, + + pub registration_timestamp: OffsetDateTime, + + pub gateway_type: GatewayType, +} + #[derive(Debug, Zeroize, ZeroizeOnDrop, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct RawRemoteGatewayDetails { @@ -67,27 +108,28 @@ pub struct RawRemoteGatewayDetails { } impl TryFrom for RemoteGatewayDetails { - type Error = GatewaysStorageError; + type Error = BadGateway; fn try_from(value: RawRemoteGatewayDetails) -> Result { let gateway_id = identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| { - GatewaysStorageError::MalformedGatewayIdentity { + BadGateway::MalformedGatewayIdentity { gateway_id: value.gateway_id_bs58.clone(), source, } })?; - let derived_aes128_ctr_blake3_hmac_keys = + let derived_aes128_ctr_blake3_hmac_keys = Arc::new( SharedKeys::try_from_base58_string(&value.derived_aes128_ctr_blake3_hmac_keys_bs58) - .map_err(|source| GatewaysStorageError::MalformedSharedKeys { + .map_err(|source| BadGateway::MalformedSharedKeys { gateway_id: value.gateway_id_bs58.clone(), source, - })?; + })?, + ); let gateway_owner_address = AccountId::from_str(&value.gateway_owner_address).map_err(|source| { - GatewaysStorageError::MalformedGatewayOwnerAccountAddress { + BadGateway::MalformedGatewayOwnerAccountAddress { gateway_id: value.gateway_id_bs58.clone(), raw_owner: value.gateway_owner_address.clone(), source, @@ -95,7 +137,7 @@ impl TryFrom for RemoteGatewayDetails { })?; let gateway_listener = Url::parse(&value.gateway_listener).map_err(|source| { - GatewaysStorageError::MalformedListener { + BadGateway::MalformedListener { gateway_id: value.gateway_id_bs58.clone(), raw_listener: value.gateway_listener.clone(), source, @@ -124,14 +166,16 @@ impl From for RawRemoteGatewayDetails { } } -#[derive(Debug, Zeroize, ZeroizeOnDrop)] +#[derive(Debug)] pub struct RemoteGatewayDetails { - #[zeroize(skip)] pub gateway_id: identity::PublicKey, - pub derived_aes128_ctr_blake3_hmac_keys: SharedKeys, - #[zeroize(skip)] + + // note: `SharedKeys` implement ZeroizeOnDrop, meaning when `RemoteGatewayDetails` is dropped, + // the keys will be zeroized + pub derived_aes128_ctr_blake3_hmac_keys: Arc, + pub gateway_owner_address: AccountId, - #[zeroize(skip)] + pub gateway_listener: Url, } @@ -143,12 +187,12 @@ pub struct RawCustomGatewayDetails { } impl TryFrom for CustomGatewayDetails { - type Error = GatewaysStorageError; + type Error = BadGateway; fn try_from(value: RawCustomGatewayDetails) -> Result { let gateway_id = identity::PublicKey::from_base58_string(&value.gateway_id_bs58).map_err(|source| { - GatewaysStorageError::MalformedGatewayIdentity { + BadGateway::MalformedGatewayIdentity { gateway_id: value.gateway_id_bs58.clone(), source, } diff --git a/common/client-core/surb-storage/src/backend/fs_backend/error.rs b/common/client-core/surb-storage/src/backend/fs_backend/error.rs index 84cac2f7ec..02742758ae 100644 --- a/common/client-core/surb-storage/src/backend/fs_backend/error.rs +++ b/common/client-core/surb-storage/src/backend/fs_backend/error.rs @@ -10,7 +10,7 @@ pub enum StorageError { #[error("the provided database path doesn't have a filename defined")] DatabasePathWithoutFilename { provided_path: PathBuf }, - #[error("unable to create the directory for the database")] + #[error("unable to create the directory for the database at {}: {source}", provided_path.display())] DatabasePathUnableToCreateParentDirectory { provided_path: PathBuf, source: io::Error, From c80c0b88bf3e08130811cc676ddc38352312df56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 5 Mar 2024 16:59:54 +0000 Subject: [PATCH 06/56] starting to weave in new storage trait --- clients/native/Cargo.toml | 2 +- clients/socks5/Cargo.toml | 2 +- common/client-core/Cargo.toml | 1 + .../src/backend/fs_backend/error.rs | 4 + .../src/backend/fs_backend/manager.rs | 9 +- .../src/backend/fs_backend/mod.rs | 17 +- .../src/backend/mem_backend.rs | 8 +- .../client-core/gateways-storage/src/lib.rs | 11 +- .../src/cli_helpers/client_init.rs | 162 +++++++++--------- .../client-core/src/client/base_client/mod.rs | 14 +- .../client/base_client/non_wasm_helpers.rs | 12 ++ .../src/client/base_client/storage/mod.rs | 65 ++++--- .../src/config/disk_persistence/mod.rs | 7 + .../config/disk_persistence/old_v1_1_20_2.rs | 13 +- .../config/disk_persistence/old_v1_1_33.rs | 2 + common/client-core/src/init/mod.rs | 50 +++--- common/client-core/src/init/types.rs | 42 ++--- common/client-core/src/lib.rs | 6 +- common/socks5-client-core/Cargo.toml | 2 +- common/socks5-client-core/src/lib.rs | 4 +- .../src/storage/core_client_traits.rs | 4 +- sdk/lib/socks5-listener/src/persistence.rs | 4 +- sdk/rust/nym-sdk/Cargo.toml | 2 +- .../examples/manually_handle_storage.rs | 4 +- sdk/rust/nym-sdk/src/mixnet/client.rs | 4 +- 25 files changed, 266 insertions(+), 185 deletions(-) create mode 100644 common/client-core/src/config/disk_persistence/old_v1_1_33.rs diff --git a/clients/native/Cargo.toml b/clients/native/Cargo.toml index a85b73e5a4..2e49dd8261 100644 --- a/clients/native/Cargo.toml +++ b/clients/native/Cargo.toml @@ -38,7 +38,7 @@ zeroize = { workspace = true } ## internal nym-bandwidth-controller = { path = "../../common/bandwidth-controller" } nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } -nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] } +nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] } nym-config = { path = "../../common/config" } nym-credential-storage = { path = "../../common/credential-storage" } nym-credentials = { path = "../../common/credentials" } diff --git a/clients/socks5/Cargo.toml b/clients/socks5/Cargo.toml index 2665f6355c..66fbc64e5a 100644 --- a/clients/socks5/Cargo.toml +++ b/clients/socks5/Cargo.toml @@ -23,7 +23,7 @@ zeroize = { workspace = true } # internal nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } -nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "cli"] } +nym-client-core = { path = "../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage", "cli"] } nym-config = { path = "../../common/config" } nym-credentials = { path = "../../common/credentials" } nym-crypto = { path = "../../common/crypto" } diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index b2643888c5..f144aa4373 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -102,5 +102,6 @@ tempfile = "3.1.0" default = [] cli = ["clap"] fs-surb-storage = ["nym-client-core-surb-storage/fs-surb-storage"] +fs-gateways-storage = ["nym-client-core-gateways-storage/fs-gateways-storage"] wasm = ["nym-gateway-client/wasm"] metrics-server = [] diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/error.rs b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs index 0a39dbbe06..44cab38a8c 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/error.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs @@ -1,6 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::BadGateway; use std::io; use std::path::PathBuf; use thiserror::Error; @@ -35,4 +36,7 @@ pub enum StorageError { #[from] source: sqlx::error::Error, }, + + #[error(transparent)] + MalformedGateway(#[from] BadGateway), } diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs index 299b16ea8b..5447c6c9ab 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -2,9 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 use crate::backend::fs_backend::error::StorageError; -use crate::backend::fs_backend::models::{ - ReplySurbStorageMetadata, StoredReplyKey, StoredReplySurb, StoredSenderTag, StoredSurbSender, -}; use log::{error, info}; use sqlx::ConnectOptions; use std::path::Path; @@ -16,7 +13,7 @@ pub struct StorageManager { // all SQL goes here impl StorageManager { - pub async fn init>(database_path: P, fresh: bool) -> Result { + pub async fn init>(database_path: P) -> Result { // ensure the whole directory structure exists if let Some(parent_dir) = database_path.as_ref().parent() { std::fs::create_dir_all(parent_dir).map_err(|source| { @@ -29,14 +26,14 @@ impl StorageManager { let mut opts = sqlx::sqlite::SqliteConnectOptions::new() .filename(database_path) - .create_if_missing(fresh); + .create_if_missing(true); opts.disable_statement_logging(); let connection_pool = sqlx::SqlitePool::connect_with(opts) .await .map_err(|source| { - error!("Failed to connect to SQLx database: {err}"); + error!("Failed to connect to SQLx database: {source}"); StorageError::DatabaseConnectionError { source } })?; diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index e8ddc05d83..76d21c177b 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -2,20 +2,29 @@ // SPDX-License-Identifier: Apache-2.0 use crate::types::GatewayDetails; -use crate::GatewayDetailsStore; +use crate::{GatewaysDetailsStore, StorageError}; use async_trait::async_trait; use manager::StorageManager; +use std::path::Path; -mod error; +pub mod error; mod manager; mod models; -pub struct OnDiskGatewayDetails { +pub struct OnDiskGatewaysDetails { manager: StorageManager, } +impl OnDiskGatewaysDetails { + pub async fn init>(database_path: P) -> Result { + Ok(OnDiskGatewaysDetails { + manager: StorageManager::init(database_path).await?, + }) + } +} + #[async_trait] -impl GatewayDetailsStore for OnDiskGatewayDetails { +impl GatewaysDetailsStore for OnDiskGatewaysDetails { type StorageError = error::StorageError; async fn active_gateway(&self) -> Result, Self::StorageError> { diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 53afb6007b..986ffef2de 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::types::GatewayDetails; -use crate::{BadGateway, GatewayDetailsStore}; +use crate::{BadGateway, GatewaysDetailsStore}; use async_trait::async_trait; use std::collections::HashMap; use std::sync::Arc; @@ -18,10 +18,12 @@ pub enum InMemStorageError { MalformedGateway(#[from] BadGateway), } -pub struct InMemStorage { +#[derive(Debug, Default)] +pub struct InMemGatewaysDetails { inner: Arc>, } +#[derive(Debug, Default)] struct InMemStorageInner { active_gateway: Option, gateways: HashMap, @@ -29,7 +31,7 @@ struct InMemStorageInner { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl GatewayDetailsStore for InMemStorage { +impl GatewaysDetailsStore for InMemGatewaysDetails { type StorageError = InMemStorageError; async fn active_gateway(&self) -> Result, Self::StorageError> { diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 393e6438ff..17c3f60dd8 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -7,16 +7,21 @@ use async_trait::async_trait; use std::error::Error; -mod backend; +pub mod backend; pub mod error; pub mod types; -use crate::types::GatewayDetails; +// todo: export port types +pub use crate::types::GatewayDetails; +pub use backend::mem_backend::{InMemGatewaysDetails, InMemStorageError}; pub use error::BadGateway; +#[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] +pub use backend::fs_backend::{error::StorageError, OnDiskGatewaysDetails}; + #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait GatewayDetailsStore { +pub trait GatewaysDetailsStore { type StorageError: Error + From; /// Returns details of the currently active gateway, if available. diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 9550cffdb2..e7fb8e6ba0 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -5,7 +5,7 @@ use crate::config::disk_persistence::CommonClientPaths; use crate::error::ClientCoreError; use crate::{ client::{ - base_client::storage::gateway_details::OnDiskGatewayDetails, + base_client::non_wasm_helpers::setup_fs_gateways_storage, key_manager::persistence::OnDiskKeys, }, init::types::{GatewayDetails, GatewaySelectionSpecification, GatewaySetup, InitResults}, @@ -144,84 +144,86 @@ where let user_chosen_gateway_id = common_args.gateway; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); - let selection_spec = GatewaySelectionSpecification::new( - user_chosen_gateway_id.map(|id| id.to_base58_string()), - Some(common_args.latency_based_selection), - false, - ); - log::debug!("Gateway selection specification: {selection_spec:?}"); + todo!() - // Load and potentially override config - log::debug!("Init arguments: {init_args:#?}"); - let config = C::construct_config(&init_args); - log::debug!("Constructed config: {config:#?}"); - let paths = config.common_paths(); - let core = config.core_config(); - - log::info!( - "Using nym-api: {}", - core.client - .nym_api_urls - .iter() - .map(|url| url.as_str()) - .collect::>() - .join(",") - ); - - // Setup gateway by either registering a new one, or creating a new config from the selected - // one but with keys kept, or reusing the gateway configuration. - let key_store = OnDiskKeys::new(paths.keys.clone()); - let details_store = OnDiskGatewayDetails::new(&paths.gateway_details); - - let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { - let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { - ClientCoreError::CustomTopologyLoadFailure { - file_path: custom_mixnet.clone(), - source, - } - })?; - hardcoded_topology.get_gateways() - } else { - let mut rng = rand::thread_rng(); - crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? - }; - - let gateway_setup = GatewaySetup::New { - specification: selection_spec, - available_gateways, - overwrite_data: register_gateway, - }; - - let init_details = - crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; - - // TODO: ask the service provider we specified for its interface version and set it in the config - - let config_save_location = config.default_store_location(); - if let Err(err) = config.save_to(&config_save_location) { - return Err(ClientCoreError::ConfigSaveFailure { - typ: C::NAME.to_string(), - id: id.to_string(), - path: config_save_location, - source: err, - } - .into()); - } - - eprintln!( - "Saved configuration file to {}", - config_save_location.display() - ); - - let address = init_details.client_address()?; - - let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else { - return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; - }; - let init_results = InitResults::new(config.core_config(), address, &gateway_details); - - Ok(InitResultsWithConfig { - config, - init_results, - }) + // let selection_spec = GatewaySelectionSpecification::new( + // user_chosen_gateway_id.map(|id| id.to_base58_string()), + // Some(common_args.latency_based_selection), + // false, + // ); + // log::debug!("Gateway selection specification: {selection_spec:?}"); + // + // // Load and potentially override config + // log::debug!("Init arguments: {init_args:#?}"); + // let config = C::construct_config(&init_args); + // log::debug!("Constructed config: {config:#?}"); + // let paths = config.common_paths(); + // let core = config.core_config(); + // + // log::info!( + // "Using nym-api: {}", + // core.client + // .nym_api_urls + // .iter() + // .map(|url| url.as_str()) + // .collect::>() + // .join(",") + // ); + // + // // Setup gateway by either registering a new one, or creating a new config from the selected + // // one but with keys kept, or reusing the gateway configuration. + // let key_store = OnDiskKeys::new(paths.keys.clone()); + // let details_store = setup_fs_gateways_storage(&paths.gateway_details).await?; + // + // let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { + // let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { + // ClientCoreError::CustomTopologyLoadFailure { + // file_path: custom_mixnet.clone(), + // source, + // } + // })?; + // hardcoded_topology.get_gateways() + // } else { + // let mut rng = rand::thread_rng(); + // crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? + // }; + // + // let gateway_setup = GatewaySetup::New { + // specification: selection_spec, + // available_gateways, + // overwrite_data: register_gateway, + // }; + // + // let init_details = + // crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; + // + // // TODO: ask the service provider we specified for its interface version and set it in the config + // + // let config_save_location = config.default_store_location(); + // if let Err(err) = config.save_to(&config_save_location) { + // return Err(ClientCoreError::ConfigSaveFailure { + // typ: C::NAME.to_string(), + // id: id.to_string(), + // path: config_save_location, + // source: err, + // } + // .into()); + // } + // + // eprintln!( + // "Saved configuration file to {}", + // config_save_location.display() + // ); + // + // let address = init_details.client_address()?; + // + // let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else { + // return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; + // }; + // let init_results = InitResults::new(config.core_config(), address, &gateway_details); + // + // Ok(InitResultsWithConfig { + // config, + // init_results, + // }) } diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index c2632f73ad..41c9a3f01b 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -4,7 +4,6 @@ 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::gateway_details::GatewayDetailsStore; use crate::client::base_client::storage::MixnetClientStorage; use crate::client::cover_traffic_stream::LoopCoverTrafficStream; use crate::client::inbound_messages::{InputMessage, InputMessageReceiver, InputMessageSender}; @@ -36,6 +35,7 @@ use crate::{config, spawn_future}; use futures::channel::mpsc; use log::{debug, error, info}; use nym_bandwidth_controller::BandwidthController; +use nym_client_core_gateways_storage::GatewaysDetailsStore; use nym_credential_storage::storage::Storage as CredentialStorage; use nym_crypto::asymmetric::encryption; use nym_gateway_client::{ @@ -57,7 +57,11 @@ use std::path::Path; use std::sync::Arc; use url::Url; -#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] pub mod non_wasm_helpers; pub mod helpers; @@ -569,11 +573,11 @@ where async fn initialise_keys_and_gateway( setup_method: GatewaySetup, key_store: &S::KeyStore, - details_store: &S::GatewayDetailsStore, + details_store: &S::GatewaysDetailsStore, ) -> Result where ::StorageError: Sync + Send, - ::StorageError: Sync + Send, + ::StorageError: Sync + Send, { setup_gateway(setup_method, key_store, details_store).await } @@ -584,7 +588,7 @@ where ::StorageError: Send + Sync, ::StorageError: Sync + Send, ::StorageError: Send + Sync + 'static, - ::StorageError: Sync + Send, + ::StorageError: Sync + Send, { info!("Starting nym client"); diff --git a/common/client-core/src/client/base_client/non_wasm_helpers.rs b/common/client-core/src/client/base_client/non_wasm_helpers.rs index d0d2d5a058..70ad8358e6 100644 --- a/common/client-core/src/client/base_client/non_wasm_helpers.rs +++ b/common/client-core/src/client/base_client/non_wasm_helpers.rs @@ -9,6 +9,7 @@ use crate::config::Config; use crate::error::ClientCoreError; use log::{error, info}; use nym_bandwidth_controller::BandwidthController; +use nym_client_core_gateways_storage::OnDiskGatewaysDetails; use nym_credential_storage::storage::Storage as CredentialStorage; use nym_validator_client::nyxd; use nym_validator_client::QueryHttpRpcNyxdClient; @@ -101,6 +102,17 @@ pub async fn setup_fs_reply_surb_backend>( } } +pub async fn setup_fs_gateways_storage>( + db_path: P, +) -> Result { + info!("setting up gateways details storage"); + OnDiskGatewaysDetails::init(db_path) + .await + .map_err(|source| ClientCoreError::GatewayDetailsStoreError { + source: Box::new(source), + }) +} + pub fn create_bandwidth_controller( config: &Config, storage: St, diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 60e3ff9a73..969b60d617 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -4,20 +4,24 @@ // 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::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; use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage; -#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +#[cfg(all( + not(target_arch = "wasm32"), + 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(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +// #[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; @@ -28,22 +32,30 @@ use crate::error::ClientCoreError; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; +// fs-gateways + +#[deprecated] pub mod gateway_details; +pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; + +#[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] +pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; + // TODO: ideally this should be changed into // `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewayDetailsStore` pub trait MixnetClientStorage { type KeyStore: KeyStore; type ReplyStore: ReplyStorageBackend; type CredentialStore: CredentialStorage; - type GatewayDetailsStore: GatewayDetailsStore; + type GatewaysDetailsStore: GatewaysDetailsStore; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore); fn key_store(&self) -> &Self::KeyStore; fn reply_store(&self) -> &Self::ReplyStore; fn credential_store(&self) -> &Self::CredentialStore; - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore; + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore; } #[derive(Default)] @@ -51,7 +63,7 @@ pub struct Ephemeral { key_store: InMemEphemeralKeys, reply_store: reply_storage::Empty, credential_store: EphemeralCredentialStorage, - gateway_details_store: InMemGatewayDetails, + gateway_details_store: InMemGatewaysDetails, } impl Ephemeral { @@ -64,7 +76,7 @@ impl MixnetClientStorage for Ephemeral { type KeyStore = InMemEphemeralKeys; type ReplyStore = reply_storage::Empty; type CredentialStore = EphemeralCredentialStorage; - type GatewayDetailsStore = InMemGatewayDetails; + type GatewaysDetailsStore = InMemGatewaysDetails; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_store, self.credential_store) @@ -82,26 +94,34 @@ impl MixnetClientStorage for Ephemeral { &self.credential_store } - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore { + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore { &self.gateway_details_store } } -#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] pub struct OnDiskPersistent { pub(crate) key_store: OnDiskKeys, pub(crate) reply_store: fs_backend::Backend, pub(crate) credential_store: PersistentCredentialStorage, - pub(crate) gateway_details_store: OnDiskGatewayDetails, + pub(crate) gateway_details_store: OnDiskGatewaysDetails, } -#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] impl OnDiskPersistent { pub fn new( key_store: OnDiskKeys, reply_store: fs_backend::Backend, credential_store: PersistentCredentialStorage, - gateway_details_store: OnDiskGatewayDetails, + gateway_details_store: OnDiskGatewaysDetails, ) -> Self { Self { key_store, @@ -126,7 +146,8 @@ impl OnDiskPersistent { let credential_store = nym_credential_storage::initialise_persistent_storage(paths.credentials_database).await; - let gateway_details_store = OnDiskGatewayDetails::new(paths.gateway_details); + let gateway_details_store = + non_wasm_helpers::setup_fs_gateways_storage(paths.gateway_registrations).await?; Ok(OnDiskPersistent { key_store, @@ -137,12 +158,16 @@ impl OnDiskPersistent { } } -#[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] impl MixnetClientStorage for OnDiskPersistent { type KeyStore = OnDiskKeys; type ReplyStore = fs_backend::Backend; type CredentialStore = PersistentCredentialStorage; - type GatewayDetailsStore = OnDiskGatewayDetails; + type GatewaysDetailsStore = OnDiskGatewaysDetails; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_store, self.credential_store) @@ -160,7 +185,7 @@ impl MixnetClientStorage for OnDiskPersistent { &self.credential_store } - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore { + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore { &self.gateway_details_store } } diff --git a/common/client-core/src/config/disk_persistence/mod.rs b/common/client-core/src/config/disk_persistence/mod.rs index b323d059dc..7272f9edaf 100644 --- a/common/client-core/src/config/disk_persistence/mod.rs +++ b/common/client-core/src/config/disk_persistence/mod.rs @@ -7,10 +7,12 @@ use std::path::{Path, PathBuf}; pub mod keys_paths; pub mod old_v1_1_20_2; +mod old_v1_1_33; pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json"; pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite"; pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db"; +pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.db"; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] @@ -19,8 +21,12 @@ pub struct CommonClientPaths { /// Path to the file containing information about gateway used by this client, /// i.e. details such as its public key, owner address or the network information. + #[deprecated] pub gateway_details: PathBuf, + // TODO: + pub gateway_registrations: PathBuf, + /// Path to the database containing bandwidth credentials of this client. pub credentials_database: PathBuf, @@ -36,6 +42,7 @@ impl CommonClientPaths { credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME), reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME), gateway_details: base_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), + gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME), keys: ClientKeysPaths::new_base(base_data_directory), } } diff --git a/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs b/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs index d26cf1461c..24496f1497 100644 --- a/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs +++ b/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs @@ -22,11 +22,12 @@ impl CommonClientPathsV1_1_20_2 { new_version: "1.1.20-2".to_string(), } })?; - Ok(CommonClientPaths { - keys: self.keys, - gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), - credentials_database: self.credentials_database, - reply_surb_database: self.reply_surb_database, - }) + todo!() + // Ok(CommonClientPaths { + // keys: self.keys, + // gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), + // credentials_database: self.credentials_database, + // reply_surb_database: self.reply_surb_database, + // }) } } diff --git a/common/client-core/src/config/disk_persistence/old_v1_1_33.rs b/common/client-core/src/config/disk_persistence/old_v1_1_33.rs new file mode 100644 index 0000000000..755fb6cc8b --- /dev/null +++ b/common/client-core/src/config/disk_persistence/old_v1_1_33.rs @@ -0,0 +1,2 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 13129bf5f5..7765c09f0c 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -3,9 +3,7 @@ //! Collection of initialization steps used by client implementations -use crate::client::base_client::storage::gateway_details::{ - GatewayDetailsStore, PersistedGatewayDetails, -}; +use crate::client::base_client::storage::gateway_details::PersistedGatewayDetails; use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::ManagedKeys; use crate::config::GatewayEndpointConfig; @@ -17,6 +15,7 @@ use crate::init::types::{ CustomGatewayDetails, GatewayDetails, GatewaySelectionSpecification, GatewaySetup, InitialisationResult, }; +use nym_client_core_gateways_storage::GatewaysDetailsStore; use nym_gateway_client::client::InitGatewayClient; use nym_topology::gateway; use rand::rngs::OsRng; @@ -33,32 +32,34 @@ async fn _store_gateway_details( details: &PersistedGatewayDetails, ) -> Result<(), ClientCoreError> where - D: GatewayDetailsStore, + D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, T: Serialize + Send + Sync, { - details_store - .store_gateway_details(details) - .await - .map_err(|source| ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - }) + todo!() + // details_store + // .store_gateway_details(details) + // .await + // .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + // source: Box::new(source), + // }) } async fn _load_gateway_details( details_store: &D, ) -> Result, ClientCoreError> where - D: GatewayDetailsStore, + D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Send + Sync, { - details_store - .load_gateway_details() - .await - .map_err(|source| ClientCoreError::UnavailableGatewayDetails { - source: Box::new(source), - }) + todo!() + // details_store + // .load_gateway_details() + // .await + // .map_err(|source| ClientCoreError::UnavailableGatewayDetails { + // source: Box::new(source), + // }) } async fn _load_managed_keys(key_store: &K) -> Result @@ -89,7 +90,7 @@ async fn setup_new_gateway( ) -> Result, ClientCoreError> where K: KeyStore, - D: GatewayDetailsStore, + D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Serialize + Send + Sync, @@ -98,9 +99,12 @@ where // if we're setting up new gateway, failing to load existing information is fine. // as a matter of fact, it's only potentially a problem if we DO succeed - if _load_gateway_details(details_store).await.is_ok() && !overwrite_data { - return Err(ClientCoreError::ForbiddenKeyOverwrite); - } + + todo!("check gateway details (maybe not even needed anymore, idk)"); + // if _load_gateway_details(details_store).await.is_ok() && !overwrite_data { + // return Err(ClientCoreError::ForbiddenKeyOverwrite); + // } + if _load_managed_keys(key_store).await.is_ok() && !overwrite_data { return Err(ClientCoreError::ForbiddenKeyOverwrite); } @@ -171,7 +175,7 @@ async fn use_loaded_gateway_details( ) -> Result, ClientCoreError> where K: KeyStore, - D: GatewayDetailsStore, + D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Send + Sync, @@ -207,7 +211,7 @@ pub async fn setup_gateway( ) -> Result, ClientCoreError> where K: KeyStore, - D: GatewayDetailsStore, + D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Serialize + Send + Sync, diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 141bf8dd2d..4d90cd1f53 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -56,25 +56,26 @@ impl InitialisationResult { D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Send + Sync, { - let loaded_details = _load_gateway_details(details_store).await?; - let loaded_keys = _load_managed_keys(key_store).await?; - - match &loaded_details { - PersistedGatewayDetails::Default(loaded_default) => { - if !loaded_default.verify(&loaded_keys.must_get_gateway_shared_key()) { - return Err(ClientCoreError::MismatchedGatewayDetails { - gateway_id: loaded_default.details.gateway_id.clone(), - }); - } - } - PersistedGatewayDetails::Custom(_) => {} - } - - Ok(InitialisationResult { - gateway_details: loaded_details.into(), - managed_keys: loaded_keys, - authenticated_ephemeral_client: None, - }) + todo!() + // let loaded_details = _load_gateway_details(details_store).await?; + // let loaded_keys = _load_managed_keys(key_store).await?; + // + // match &loaded_details { + // PersistedGatewayDetails::Default(loaded_default) => { + // if !loaded_default.verify(&loaded_keys.must_get_gateway_shared_key()) { + // return Err(ClientCoreError::MismatchedGatewayDetails { + // gateway_id: loaded_default.details.gateway_id.clone(), + // }); + // } + // } + // PersistedGatewayDetails::Custom(_) => {} + // } + // + // Ok(InitialisationResult { + // gateway_details: loaded_details.into(), + // managed_keys: loaded_keys, + // authenticated_ephemeral_client: None, + // }) } pub fn client_address(&self) -> Result { @@ -281,7 +282,8 @@ impl GatewaySetup { D::StorageError: Send + Sync + 'static, T: DeserializeOwned + Serialize + Send + Sync, { - setup_gateway(self, key_store, details_store).await + todo!() + // setup_gateway(self, key_store, details_store).await } pub fn is_must_load(&self) -> bool { diff --git a/common/client-core/src/lib.rs b/common/client-core/src/lib.rs index 0b401f4e02..1eb90ddcf7 100644 --- a/common/client-core/src/lib.rs +++ b/common/client-core/src/lib.rs @@ -1,6 +1,10 @@ use std::future::Future; -#[cfg(not(target_arch = "wasm32"))] +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] pub mod cli_helpers; pub mod client; pub mod config; diff --git a/common/socks5-client-core/Cargo.toml b/common/socks5-client-core/Cargo.toml index 80aefcf934..52fc4d6d0b 100644 --- a/common/socks5-client-core/Cargo.toml +++ b/common/socks5-client-core/Cargo.toml @@ -22,7 +22,7 @@ tokio = { version = "1.24.1", features = ["rt-multi-thread", "net", "signal"] } url = { workspace = true } nym-bandwidth-controller = { path = "../../common/bandwidth-controller" } -nym-client-core = { path = "../client-core", features = ["fs-surb-storage"] } +nym-client-core = { path = "../client-core", features = ["fs-surb-storage", "fs-gateways-storage"] } nym-config = { path = "../config" } nym-contracts-common = { path = "../cosmwasm-smart-contracts/contracts-common" } nym-credential-storage = { path = "../credential-storage" } diff --git a/common/socks5-client-core/src/lib.rs b/common/socks5-client-core/src/lib.rs index ecef31354f..d9d036d1a8 100644 --- a/common/socks5-client-core/src/lib.rs +++ b/common/socks5-client-core/src/lib.rs @@ -11,7 +11,7 @@ use futures::channel::mpsc; use futures::StreamExt; use log::*; use nym_client_core::client::base_client::non_wasm_helpers::default_query_dkg_client_from_config; -use nym_client_core::client::base_client::storage::gateway_details::GatewayDetailsStore; +use nym_client_core::client::base_client::storage::GatewaysDetailsStore; use nym_client_core::client::base_client::storage::MixnetClientStorage; use nym_client_core::client::base_client::{ BaseClientBuilder, ClientInput, ClientOutput, ClientState, @@ -71,7 +71,7 @@ where S::ReplyStore: Send + Sync, ::StorageError: Sync + Send, ::StorageError: Send + Sync, - ::StorageError: Sync + Send, + ::StorageError: Sync + Send, ::StorageError: Send + Sync, { pub fn new(config: Config, storage: S, custom_mixnet: Option) -> Self { diff --git a/common/wasm/client-core/src/storage/core_client_traits.rs b/common/wasm/client-core/src/storage/core_client_traits.rs index b017bb3914..7e4ae13e03 100644 --- a/common/wasm/client-core/src/storage/core_client_traits.rs +++ b/common/wasm/client-core/src/storage/core_client_traits.rs @@ -41,7 +41,7 @@ impl MixnetClientStorage for FullWasmClientStorage { type ReplyStore = browser_backend::Backend; type CredentialStore = EphemeralCredentialStorage; - type GatewayDetailsStore = ClientStorage; + type GatewaysDetailsStore = ClientStorage; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_storage, self.credential_storage) @@ -59,7 +59,7 @@ impl MixnetClientStorage for FullWasmClientStorage { &self.credential_storage } - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore { + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore { &self.keys_and_gateway_store } } diff --git a/sdk/lib/socks5-listener/src/persistence.rs b/sdk/lib/socks5-listener/src/persistence.rs index 68455fad27..93916feb42 100644 --- a/sdk/lib/socks5-listener/src/persistence.rs +++ b/sdk/lib/socks5-listener/src/persistence.rs @@ -21,7 +21,7 @@ impl MixnetClientStorage for MobileClientStorage { type KeyStore = InMemEphemeralKeys; type ReplyStore = reply_storage::Empty; type CredentialStore = EphemeralCredentialStorage; - type GatewayDetailsStore = InMemGatewayDetails; + type GatewaysDetailsStore = InMemGatewayDetails; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_store, self.credential_store) @@ -39,7 +39,7 @@ impl MixnetClientStorage for MobileClientStorage { &self.credential_store } - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore { + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore { &self.gateway_details_store } } diff --git a/sdk/rust/nym-sdk/Cargo.toml b/sdk/rust/nym-sdk/Cargo.toml index c0a0960f79..4948f230f5 100644 --- a/sdk/rust/nym-sdk/Cargo.toml +++ b/sdk/rust/nym-sdk/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [dependencies] async-trait = { workspace = true } bip39 = { workspace = true } -nym-client-core = { path = "../../../common/client-core", features = ["fs-surb-storage"]} +nym-client-core = { path = "../../../common/client-core", features = ["fs-surb-storage", "fs-gateways-storage"]} nym-crypto = { path = "../../../common/crypto" } nym-gateway-requests = { path = "../../../gateway/gateway-requests" } nym-bandwidth-controller = { path = "../../../common/bandwidth-controller" } diff --git a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs index dd650b1e2a..b4844005bf 100644 --- a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs +++ b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs @@ -64,7 +64,7 @@ impl MixnetClientStorage for MockClientStorage { type KeyStore = MockKeyStore; type ReplyStore = EmptyReplyStorage; type CredentialStore = EphemeralCredentialStorage; - type GatewayDetailsStore = MockGatewayDetailsStore; + type GatewaysDetailsStore = MockGatewayDetailsStore; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_store, self.credential_store) @@ -82,7 +82,7 @@ impl MixnetClientStorage for MockClientStorage { &self.credential_store } - fn gateway_details_store(&self) -> &Self::GatewayDetailsStore { + fn gateway_details_store(&self) -> &Self::GatewaysDetailsStore { &self.gateway_details_store } } diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index 69995214b8..942e192882 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -104,7 +104,7 @@ where ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, - ::StorageError: Send + Sync, + ::StorageError: Send + Sync, { /// Creates a client builder with the provided client storage implementation. #[must_use] @@ -309,7 +309,7 @@ where ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, - ::StorageError: Send + Sync, + ::StorageError: Send + Sync, { /// Create a new mixnet client in a disconnected state. The default configuration, /// creates a new mainnet client with ephemeral keys stored in RAM, which will be discarded at From 6915fef99f190adf3572f54b054105e5da52b9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 09:07:10 +0000 Subject: [PATCH 07/56] removing generics from 'GatewaySelectionSpecification' --- Cargo.lock | 1 + .../base_client/storage/gateway_details.rs | 51 ++++------- .../src/config/disk_persistence/mod.rs | 2 +- common/client-core/src/init/mod.rs | 39 ++++---- common/client-core/src/init/types.rs | 67 ++++++-------- gateway/src/commands/helpers.rs | 7 +- nym-connect/desktop/Cargo.lock | 40 +++++++- sdk/rust/nym-sdk/src/mixnet/client.rs | 91 ++++++++++--------- sdk/rust/nym-sdk/src/mixnet/paths.rs | 18 +++- .../network-requester/Cargo.toml | 2 +- .../network-requester/src/lib.rs | 5 +- 11 files changed, 172 insertions(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b61fc7884b..d136c0c614 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5289,6 +5289,7 @@ dependencies = [ "serde", "sqlx", "thiserror", + "time", "tokio", "url", "zeroize", diff --git a/common/client-core/src/client/base_client/storage/gateway_details.rs b/common/client-core/src/client/base_client/storage/gateway_details.rs index d9eaddfa87..152ef96283 100644 --- a/common/client-core/src/client/base_client/storage/gateway_details.rs +++ b/common/client-core/src/client/base_client/storage/gateway_details.rs @@ -3,7 +3,7 @@ use crate::config::GatewayEndpointConfig; use crate::error::ClientCoreError; -use crate::init::types::{EmptyCustomDetails, GatewayDetails}; +use crate::init::types::GatewayDetails; use async_trait::async_trait; use log::error; use nym_gateway_requests::registration::handshake::SharedKeys; @@ -17,32 +17,28 @@ use zeroize::Zeroizing; #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait GatewayDetailsStore { +pub trait GatewayDetailsStore { type StorageError: Error; - async fn load_gateway_details(&self) -> Result, Self::StorageError> - where - T: DeserializeOwned + Send + Sync; + async fn load_gateway_details(&self) -> Result; async fn store_gateway_details( &self, - details: &PersistedGatewayDetails, - ) -> Result<(), Self::StorageError> - where - T: Serialize + Send + Sync; + details: &PersistedGatewayDetails, + ) -> Result<(), Self::StorageError>; } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] -pub enum PersistedGatewayDetails { +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), + Custom(PersistedCustomGatewayDetails), } -impl PersistedGatewayDetails { +impl PersistedGatewayDetails { // TODO: this should probably allow for custom verification over T pub fn validate(&self, shared_key: Option<&SharedKeys>) -> Result<(), ClientCoreError> { match self { @@ -81,12 +77,12 @@ pub struct PersistedGatewayConfig { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PersistedCustomGatewayDetails { +pub struct PersistedCustomGatewayDetails { // whatever custom method is used, gateway's identity must be known pub gateway_id: String, #[serde(flatten)] - pub additional_data: T, + pub additional_data: Vec, } impl PersistedGatewayConfig { @@ -111,9 +107,9 @@ impl PersistedGatewayConfig { } } -impl PersistedGatewayDetails { +impl PersistedGatewayDetails { pub fn new( - details: GatewayDetails, + details: GatewayDetails, shared_key: Option<&SharedKeys>, ) -> Result { match details { @@ -131,10 +127,7 @@ impl PersistedGatewayDetails { matches!(self, PersistedGatewayDetails::Custom(..)) } - pub fn matches(&self, other: &GatewayDetails) -> bool - where - T: PartialEq, - { + pub fn matches(&self, other: &GatewayDetails) -> bool { match self { PersistedGatewayDetails::Default(default) => { if let GatewayDetails::Configured(other_configured) = other { @@ -205,10 +198,7 @@ impl OnDiskGatewayDetails { } } - pub fn load_from_disk(&self) -> Result, OnDiskGatewayDetailsError> - where - T: DeserializeOwned, - { + pub fn load_from_disk(&self) -> Result { let file = std::fs::File::open(&self.file_location).map_err(|err| { OnDiskGatewayDetailsError::LoadFailure { path: self.file_location.display().to_string(), @@ -219,13 +209,10 @@ impl OnDiskGatewayDetails { Ok(serde_json::from_reader(file)?) } - pub fn store_to_disk( + pub fn store_to_disk( &self, - details: &PersistedGatewayDetails, - ) -> Result<(), OnDiskGatewayDetailsError> - where - T: Serialize, - { + 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| { @@ -265,8 +252,8 @@ impl GatewayDetailsStore for OnDiskGatewayDetails { } #[derive(Default)] -pub struct InMemGatewayDetails { - details: Mutex>>, +pub struct InMemGatewayDetails { + details: Mutex>, } #[derive(Debug, thiserror::Error)] diff --git a/common/client-core/src/config/disk_persistence/mod.rs b/common/client-core/src/config/disk_persistence/mod.rs index 7272f9edaf..b52b261bff 100644 --- a/common/client-core/src/config/disk_persistence/mod.rs +++ b/common/client-core/src/config/disk_persistence/mod.rs @@ -12,7 +12,7 @@ mod old_v1_1_33; pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json"; pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite"; pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db"; -pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.db"; +pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite"; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 7765c09f0c..72b6f67996 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -27,14 +27,13 @@ pub mod helpers; pub mod types; // helpers for error wrapping -async fn _store_gateway_details( +async fn _store_gateway_details( details_store: &D, - details: &PersistedGatewayDetails, + details: &PersistedGatewayDetails, ) -> Result<(), ClientCoreError> where D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, - T: Serialize + Send + Sync, { todo!() // details_store @@ -45,13 +44,12 @@ where // }) } -async fn _load_gateway_details( +async fn _load_gateway_details( details_store: &D, -) -> Result, ClientCoreError> +) -> Result where D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Send + Sync, { todo!() // details_store @@ -74,26 +72,25 @@ where }) } -fn ensure_valid_details( - details: &PersistedGatewayDetails, +fn ensure_valid_details( + details: &PersistedGatewayDetails, loaded_keys: &ManagedKeys, ) -> Result<(), ClientCoreError> { details.validate(loaded_keys.gateway_shared_key().as_deref()) } -async fn setup_new_gateway( +async fn setup_new_gateway( key_store: &K, details_store: &D, overwrite_data: bool, - selection_specification: GatewaySelectionSpecification, + selection_specification: GatewaySelectionSpecification, available_gateways: Vec, -) -> Result, ClientCoreError> +) -> Result where K: KeyStore, D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Serialize + Send + Sync, { log::trace!("Setting up new gateway"); @@ -169,16 +166,15 @@ where }) } -async fn use_loaded_gateway_details( +async fn use_loaded_gateway_details( key_store: &K, details_store: &D, -) -> Result, ClientCoreError> +) -> Result where K: KeyStore, D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Send + Sync, { let loaded_details = _load_gateway_details(details_store).await?; let loaded_keys = _load_managed_keys(key_store).await?; @@ -192,11 +188,11 @@ where )) } -fn reuse_gateway_connection( +fn reuse_gateway_connection( authenticated_ephemeral_client: InitGatewayClient, - gateway_details: GatewayDetails, + gateway_details: GatewayDetails, managed_keys: ManagedKeys, -) -> InitialisationResult { +) -> InitialisationResult { InitialisationResult { gateway_details, managed_keys, @@ -204,17 +200,16 @@ fn reuse_gateway_connection( } } -pub async fn setup_gateway( - setup: GatewaySetup, +pub async fn setup_gateway( + setup: GatewaySetup, key_store: &K, details_store: &D, -) -> Result, ClientCoreError> +) -> Result where K: KeyStore, D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Serialize + Send + Sync, { log::debug!("Setting up gateway"); match setup { diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 4d90cd1f53..9863fc7c07 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -33,14 +33,14 @@ pub struct RegistrationResult { /// - all loaded (or derived) keys /// - an optional authenticated handle of an ephemeral gateway handle created for the purposes of registration, /// if this was the first time this client registered -pub struct InitialisationResult { - pub gateway_details: GatewayDetails, +pub struct InitialisationResult { + pub gateway_details: GatewayDetails, pub managed_keys: ManagedKeys, pub authenticated_ephemeral_client: Option, } -impl InitialisationResult { - pub fn new_loaded(gateway_details: GatewayDetails, managed_keys: ManagedKeys) -> Self { +impl InitialisationResult { + pub fn new_loaded(gateway_details: GatewayDetails, managed_keys: ManagedKeys) -> Self { InitialisationResult { gateway_details, managed_keys, @@ -51,10 +51,9 @@ impl InitialisationResult { pub async fn try_load(key_store: &K, details_store: &D) -> Result where K: KeyStore, - D: GatewayDetailsStore, + D: GatewayDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Send + Sync, { todo!() // let loaded_details = _load_gateway_details(details_store).await?; @@ -93,29 +92,24 @@ impl InitialisationResult { /// Details of particular gateway client got registered with #[derive(Debug, Clone)] -pub enum GatewayDetails { +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), + Custom(CustomGatewayDetails), } -#[derive(Debug, Default, Copy, Clone, Serialize, Deserialize, Eq, PartialEq)] -#[serde(rename_all = "snake_case")] -pub struct EmptyCustomDetails {} - #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CustomGatewayDetails { +pub struct CustomGatewayDetails { // whatever custom method is used, gateway's identity must be known pub gateway_id: String, - #[serde(flatten)] - pub additional_data: T, + pub additional_data: Vec, } -impl CustomGatewayDetails { - pub fn new(gateway_id: String, additional_data: T) -> Self { +impl CustomGatewayDetails { + pub fn new(gateway_id: String, additional_data: Vec) -> Self { Self { gateway_id, additional_data, @@ -123,7 +117,7 @@ impl CustomGatewayDetails { } } -impl GatewayDetails { +impl GatewayDetails { pub fn try_get_configured_endpoint(&self) -> Option<&GatewayEndpointConfig> { if let GatewayDetails::Configured(endpoint) = &self { Some(endpoint) @@ -150,8 +144,8 @@ impl From for GatewayDetails { } } -impl From> for CustomGatewayDetails { - fn from(value: PersistedCustomGatewayDetails) -> Self { +impl From for CustomGatewayDetails { + fn from(value: PersistedCustomGatewayDetails) -> Self { CustomGatewayDetails { gateway_id: value.gateway_id, additional_data: value.additional_data, @@ -159,8 +153,8 @@ impl From> for CustomGatewayDetails { } } -impl From> for PersistedCustomGatewayDetails { - fn from(value: CustomGatewayDetails) -> Self { +impl From for PersistedCustomGatewayDetails { + fn from(value: CustomGatewayDetails) -> Self { PersistedCustomGatewayDetails { gateway_id: value.gateway_id, additional_data: value.additional_data, @@ -168,8 +162,8 @@ impl From> for PersistedCustomGatewayDetails { } } -impl From> for GatewayDetails { - fn from(value: PersistedGatewayDetails) -> Self { +impl From for GatewayDetails { + fn from(value: PersistedGatewayDetails) -> Self { match value { PersistedGatewayDetails::Default(default) => { GatewayDetails::Configured(default.details) @@ -180,7 +174,7 @@ impl From> for GatewayDetails { } #[derive(Clone, Debug)] -pub enum GatewaySelectionSpecification { +pub enum GatewaySelectionSpecification { /// Uniformly choose a random remote gateway. UniformRemote { must_use_tls: bool }, @@ -198,11 +192,11 @@ pub enum GatewaySelectionSpecification { /// This client has handled the selection by itself Custom { gateway_identity: String, - additional_data: T, + additional_data: Vec, }, } -impl Default for GatewaySelectionSpecification { +impl Default for GatewaySelectionSpecification { fn default() -> Self { GatewaySelectionSpecification::UniformRemote { must_use_tls: false, @@ -210,7 +204,7 @@ impl Default for GatewaySelectionSpecification { } } -impl GatewaySelectionSpecification { +impl GatewaySelectionSpecification { pub fn new( gateway_identity: Option, latency_based_selection: Option, @@ -229,13 +223,13 @@ impl GatewaySelectionSpecification { } } -pub enum GatewaySetup { +pub enum GatewaySetup { /// The gateway specification (details + keys) MUST BE loaded from the underlying storage. MustLoad, /// Specifies usage of a new gateway New { - specification: GatewaySelectionSpecification, + specification: GatewaySelectionSpecification, // TODO: seems to be a bit inefficient to pass them by value available_gateways: Vec, @@ -249,16 +243,14 @@ pub enum GatewaySetup { authenticated_ephemeral_client: InitGatewayClient, // Details of this pre-initialised client (i.e. gateway and keys) - gateway_details: GatewayDetails, + gateway_details: GatewayDetails, managed_keys: ManagedKeys, }, } -impl GatewaySetup { - pub fn try_reuse_connection( - init_res: InitialisationResult, - ) -> Result { +impl GatewaySetup { + pub fn try_reuse_connection(init_res: InitialisationResult) -> Result { if let Some(authenticated_ephemeral_client) = init_res.authenticated_ephemeral_client { Ok(GatewaySetup::ReuseConnection { authenticated_ephemeral_client, @@ -274,13 +266,12 @@ impl GatewaySetup { self, key_store: &K, details_store: &D, - ) -> Result, ClientCoreError> + ) -> Result where K: KeyStore, - D: GatewayDetailsStore, + D: GatewayDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, - T: DeserializeOwned + Serialize + Send + Sync, { todo!() // setup_gateway(self, key_store, details_store).await diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index 043288db42..956c78834f 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -17,7 +17,8 @@ use nym_network_defaults::var_names::NYXD; use nym_network_defaults::var_names::{BECH32_PREFIX, NYM_API, STATISTICS_SERVICE_DOMAIN_ADDRESS}; use nym_network_requester::config::BaseClientConfig; use nym_network_requester::{ - setup_gateway, GatewaySelectionSpecification, GatewaySetup, OnDiskGatewayDetails, OnDiskKeys, + setup_fs_gateways_storage, setup_gateway, GatewaySelectionSpecification, GatewaySetup, + OnDiskKeys, }; use nym_types::gateway::{GatewayIpPacketRouterDetails, GatewayNetworkRequesterDetails}; use nym_validator_client::nyxd::AccountId; @@ -275,7 +276,7 @@ pub(crate) async fn initialise_local_network_requester( let key_store = OnDiskKeys::new(nr_cfg.storage_paths.common_paths.keys.clone()); let details_store = - OnDiskGatewayDetails::new(&nr_cfg.storage_paths.common_paths.gateway_details); + setup_fs_gateways_storage(&nr_cfg.storage_paths.common_paths.gateway_registrations).await?; // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( @@ -348,7 +349,7 @@ pub(crate) async fn initialise_local_ip_packet_router( let key_store = OnDiskKeys::new(ip_cfg.storage_paths.common_paths.keys.clone()); let details_store = - OnDiskGatewayDetails::new(&ip_cfg.storage_paths.common_paths.gateway_details); + setup_fs_gateways_storage(&ip_cfg.storage_paths.common_paths.gateway_registrations).await?; // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 8a87804f61..86afcd16e4 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -3805,8 +3805,6 @@ dependencies = [ "async-trait", "base64 0.21.4", "cfg-if", - "dashmap", - "dirs 4.0.0", "futures", "gloo-timers", "http-body-util", @@ -3815,6 +3813,8 @@ dependencies = [ "hyper-util", "log", "nym-bandwidth-controller", + "nym-client-core-gateways-storage", + "nym-client-core-surb-storage", "nym-config", "nym-credential-storage", "nym-crypto", @@ -3830,12 +3830,10 @@ dependencies = [ "nym-topology", "nym-validator-client", "rand 0.7.3", - "reqwest", "serde", "serde_json", "sha2 0.10.8", "si-scale", - "sqlx", "tap", "thiserror", "time", @@ -3851,6 +3849,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "nym-client-core-gateways-storage" +version = "0.1.0" +dependencies = [ + "async-trait", + "cosmrs", + "log", + "nym-crypto", + "nym-gateway-requests", + "serde", + "sqlx", + "thiserror", + "time", + "tokio", + "url", + "zeroize", +] + +[[package]] +name = "nym-client-core-surb-storage" +version = "0.1.0" +dependencies = [ + "async-trait", + "dashmap", + "log", + "nym-crypto", + "nym-sphinx", + "nym-task", + "sqlx", + "thiserror", + "time", + "tokio", +] + [[package]] name = "nym-coconut" version = "0.5.0" diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index 942e192882..c075acdfef 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -15,7 +15,7 @@ use nym_client_core::client::base_client::storage::gateway_details::{ GatewayDetailsStore, PersistedGatewayDetails, }; use nym_client_core::client::base_client::storage::{ - Ephemeral, MixnetClientStorage, OnDiskPersistent, + Ephemeral, GatewaysDetailsStore, MixnetClientStorage, OnDiskPersistent, }; use nym_client_core::client::base_client::BaseClient; use nym_client_core::client::key_manager::persistence::KeyStore; @@ -104,7 +104,7 @@ where ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, - ::StorageError: Send + Sync, + ::StorageError: Send + Sync, { /// Creates a client builder with the provided client storage implementation. #[must_use] @@ -309,7 +309,7 @@ where ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, - ::StorageError: Send + Sync, + ::StorageError: Send + Sync, { /// Create a new mixnet client in a disconnected state. The default configuration, /// creates a new mainnet client with ephemeral keys stored in RAM, which will be discarded at @@ -426,25 +426,27 @@ where } }; - let gateway_details = match self - .storage - .gateway_details_store() - .load_gateway_details() - .await - { - Ok(details) => details, - Err(err) => { - warn!("failed to load stored gateway details: {err}"); - return false; - } - }; + todo!() - if let Err(err) = gateway_details.validate(keys.gateway_shared_key().as_deref()) { - warn!("stored key verification failure: {err}"); - return false; - } - - true + // let gateway_details = match self + // .storage + // .gateway_details_store() + // .load_gateway_details() + // .await + // { + // Ok(details) => details, + // Err(err) => { + // warn!("failed to load stored gateway details: {err}"); + // return false; + // } + // }; + // + // if let Err(err) = gateway_details.validate(keys.gateway_shared_key().as_deref()) { + // warn!("stored key verification failure: {err}"); + // return false; + // } + // + // true } /// Register with a gateway. If a gateway is provided in the config then that will try to be @@ -552,29 +554,30 @@ where .with_wait_for_gateway(self.wait_for_gateway) .with_gateway_setup(setup) } else if self.wireguard_mode { - if let Ok(PersistedGatewayDetails::Default(mut config)) = self - .storage - .gateway_details_store() - .load_gateway_details() - .await - { - config.details.gateway_listener = format!( - "ws://{}:{}", - WG_TUN_DEVICE_ADDRESS, DEFAULT_CLIENT_LISTENING_PORT - ); - if let Err(e) = self - .storage - .gateway_details_store() - .store_gateway_details(&PersistedGatewayDetails::Default(config)) - .await - { - warn!("Could not switch to using wireguard mode - {:?}", e); - } - } else { - warn!("Storage type not supported with wireguard mode"); - } - BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) - .with_wait_for_gateway(self.wait_for_gateway) + todo!() + // if let Ok(PersistedGatewayDetails::Default(mut config)) = self + // .storage + // .gateway_details_store() + // .load_gateway_details() + // .await + // { + // config.details.gateway_listener = format!( + // "ws://{}:{}", + // WG_TUN_DEVICE_ADDRESS, DEFAULT_CLIENT_LISTENING_PORT + // ); + // if let Err(e) = self + // .storage + // .gateway_details_store() + // .store_gateway_details(&PersistedGatewayDetails::Default(config)) + // .await + // { + // warn!("Could not switch to using wireguard mode - {:?}", e); + // } + // } else { + // warn!("Storage type not supported with wireguard mode"); + // } + // BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) + // .with_wait_for_gateway(self.wait_for_gateway) } else { BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) .with_wait_for_gateway(self.wait_for_gateway) diff --git a/sdk/rust/nym-sdk/src/mixnet/paths.rs b/sdk/rust/nym-sdk/src/mixnet/paths.rs index 288218f5c5..88ae655d6a 100644 --- a/sdk/rust/nym-sdk/src/mixnet/paths.rs +++ b/sdk/rust/nym-sdk/src/mixnet/paths.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::{Error, Result}; -use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails; +use nym_client_core::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; +use nym_client_core::client::base_client::storage::OnDiskGatewaysDetails; use nym_client_core::client::base_client::{non_wasm_helpers, storage}; use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::client::replies::reply_storage::fs_backend; @@ -32,6 +33,7 @@ pub struct StoragePaths { pub ack_key: PathBuf, /// Key setup after authenticating with a gateway + #[deprecated] pub gateway_shared_key: PathBuf, /// The database containing credentials @@ -41,7 +43,10 @@ pub struct StoragePaths { pub reply_surb_database_path: PathBuf, /// Details of the used gateway + #[deprecated] pub gateway_details_path: PathBuf, + + pub gateway_registrations: PathBuf, } impl StoragePaths { @@ -67,6 +72,7 @@ impl StoragePaths { credential_database_path: dir.join("db.sqlite"), reply_surb_database_path: dir.join("persistent_reply_store.sqlite"), gateway_details_path: dir.join("gateway_details.json"), + gateway_registrations: dir.join("gateways_registrations.sqlite"), }) } @@ -78,7 +84,7 @@ impl StoragePaths { self.on_disk_key_storage_spec(), self.default_persistent_fs_reply_backend().await?, self.persistent_credential_storage().await?, - self.on_disk_gateway_details_storage(), + self.on_disk_gateway_details_storage().await?, )) } @@ -92,7 +98,7 @@ impl StoragePaths { self.persistent_fs_reply_backend(&config.reply_surbs) .await?, self.persistent_credential_storage().await?, - self.on_disk_gateway_details_storage(), + self.on_disk_gateway_details_storage().await?, )) } @@ -129,8 +135,8 @@ impl StoragePaths { OnDiskKeys::new(self.client_keys_paths()) } - pub fn on_disk_gateway_details_storage(&self) -> OnDiskGatewayDetails { - OnDiskGatewayDetails::new(&self.gateway_details_path) + pub async fn on_disk_gateway_details_storage(&self) -> Result { + Ok(non_wasm_helpers::setup_fs_gateways_storage(&self.gateway_registrations).await?) } fn client_keys_paths(&self) -> ClientKeysPaths { @@ -157,6 +163,7 @@ impl From for CommonClientPaths { ack_key_file: value.ack_key, }, gateway_details: value.gateway_details_path, + gateway_registrations: value.gateway_registrations, credentials_database: value.credential_database_path, reply_surb_database: value.reply_surb_database_path, } @@ -175,6 +182,7 @@ impl From for StoragePaths { credential_database_path: value.credentials_database, reply_surb_database_path: value.reply_surb_database, gateway_details_path: value.gateway_details, + gateway_registrations: value.gateway_registrations, } } } diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index 03923f46ad..e0aa58d955 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -44,7 +44,7 @@ zeroize = "1.6.0" # internal nym-async-file-watcher = { path = "../../common/async-file-watcher" } nym-bin-common = { path = "../../common/bin-common", features = ["output_format"] } -nym-client-core = { path = "../../common/client-core", features = ["cli"] } +nym-client-core = { path = "../../common/client-core", features = ["cli", "fs-gateways-storage", "fs-surb-storage"] } nym-client-websocket-requests = { path = "../../clients/native/websocket-requests" } nym-config = { path = "../../common/config" } nym-credentials = { path = "../../common/credentials" } diff --git a/service-providers/network-requester/src/lib.rs b/service-providers/network-requester/src/lib.rs index a8e54ad19f..f8d783b13d 100644 --- a/service-providers/network-requester/src/lib.rs +++ b/service-providers/network-requester/src/lib.rs @@ -13,7 +13,10 @@ pub use crate::core::{NRServiceProvider, NRServiceProviderBuilder}; pub use config::Config; pub use nym_client_core::{ client::{ - base_client::storage::{gateway_details::OnDiskGatewayDetails, OnDiskPersistent}, + base_client::{ + non_wasm_helpers::{setup_fs_gateways_storage, setup_fs_reply_surb_backend}, + storage::{GatewaysDetailsStore, OnDiskGatewaysDetails, OnDiskPersistent}, + }, key_manager::persistence::OnDiskKeys, mix_traffic::transceiver::*, }, From bf4f16c7b919bb5ee67693dab6370ceb9398e916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 09:29:07 +0000 Subject: [PATCH 08/56] adding additional methods to the trait --- .../src/backend/fs_backend/mod.rs | 4 + .../src/backend/mem_backend.rs | 4 + .../client-core/gateways-storage/src/lib.rs | 3 + .../src/cli_helpers/client_init.rs | 172 +++++++++--------- 4 files changed, 102 insertions(+), 81 deletions(-) diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 76d21c177b..6364bd376b 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -31,6 +31,10 @@ impl GatewaysDetailsStore for OnDiskGatewaysDetails { todo!() } + async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + todo!() + } + async fn all_gateways(&self) -> Result, Self::StorageError> { todo!() } diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 986ffef2de..2d955f6c20 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -47,6 +47,10 @@ impl GatewaysDetailsStore for InMemGatewaysDetails { // foo.cloned() } + async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + todo!() + } + async fn all_gateways(&self) -> Result, Self::StorageError> { todo!() } diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 17c3f60dd8..4a64ab354c 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -27,6 +27,9 @@ pub trait GatewaysDetailsStore { /// Returns details of the currently active gateway, if available. async fn active_gateway(&self) -> Result, Self::StorageError>; + /// Set the provided gateway as the currently active gateway. + async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError>; + /// Returns details of all registered gateways. async fn all_gateways(&self) -> Result, Self::StorageError>; diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index e7fb8e6ba0..e147dd632c 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -51,6 +51,10 @@ pub struct CommonClientInitArgs { #[cfg_attr(feature = "cli", clap(long))] pub gateway: Option, + /// Specifies whether the client will attempt to enforce tls connection to the desired gateway. + #[cfg_attr(feature = "cli", clap(long))] + pub force_tls_gateway: bool, + /// Specifies whether the new gateway should be determined based by latency as opposed to being chosen /// uniformly. #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))] @@ -61,6 +65,11 @@ pub struct CommonClientInitArgs { #[cfg_attr(feature = "cli", clap(long))] pub force_register_gateway: bool, + /// If the registration is happening against new gateway, + /// specify whether it should be set as the currently active gateway + #[cfg_attr(feature = "cli", clap(long, default_value_t = true))] + pub set_active: bool, + /// Comma separated list of rest endpoints of the nyxd validators #[cfg_attr( feature = "cli", @@ -135,6 +144,9 @@ where eprintln!("Instructed to force registering gateway. This might overwrite keys!"); } + // TODO: look at the registration logic due to being able to store multiple gws now + let unused_variable = 42; + // If the client was already initialized, don't generate new keys and don't re-register with // the gateway (because this would create a new shared key). // Unless the user really wants to. @@ -144,86 +156,84 @@ where let user_chosen_gateway_id = common_args.gateway; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); - todo!() + let selection_spec = GatewaySelectionSpecification::new( + user_chosen_gateway_id.map(|id| id.to_base58_string()), + Some(common_args.latency_based_selection), + common_args.force_tls_gateway, + ); + log::debug!("Gateway selection specification: {selection_spec:?}"); - // let selection_spec = GatewaySelectionSpecification::new( - // user_chosen_gateway_id.map(|id| id.to_base58_string()), - // Some(common_args.latency_based_selection), - // false, - // ); - // log::debug!("Gateway selection specification: {selection_spec:?}"); - // - // // Load and potentially override config - // log::debug!("Init arguments: {init_args:#?}"); - // let config = C::construct_config(&init_args); - // log::debug!("Constructed config: {config:#?}"); - // let paths = config.common_paths(); - // let core = config.core_config(); - // - // log::info!( - // "Using nym-api: {}", - // core.client - // .nym_api_urls - // .iter() - // .map(|url| url.as_str()) - // .collect::>() - // .join(",") - // ); - // - // // Setup gateway by either registering a new one, or creating a new config from the selected - // // one but with keys kept, or reusing the gateway configuration. - // let key_store = OnDiskKeys::new(paths.keys.clone()); - // let details_store = setup_fs_gateways_storage(&paths.gateway_details).await?; - // - // let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { - // let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { - // ClientCoreError::CustomTopologyLoadFailure { - // file_path: custom_mixnet.clone(), - // source, - // } - // })?; - // hardcoded_topology.get_gateways() - // } else { - // let mut rng = rand::thread_rng(); - // crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? - // }; - // - // let gateway_setup = GatewaySetup::New { - // specification: selection_spec, - // available_gateways, - // overwrite_data: register_gateway, - // }; - // - // let init_details = - // crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; - // - // // TODO: ask the service provider we specified for its interface version and set it in the config - // - // let config_save_location = config.default_store_location(); - // if let Err(err) = config.save_to(&config_save_location) { - // return Err(ClientCoreError::ConfigSaveFailure { - // typ: C::NAME.to_string(), - // id: id.to_string(), - // path: config_save_location, - // source: err, - // } - // .into()); - // } - // - // eprintln!( - // "Saved configuration file to {}", - // config_save_location.display() - // ); - // - // let address = init_details.client_address()?; - // - // let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else { - // return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; - // }; - // let init_results = InitResults::new(config.core_config(), address, &gateway_details); - // - // Ok(InitResultsWithConfig { - // config, - // init_results, - // }) + // Load and potentially override config + log::debug!("Init arguments: {init_args:#?}"); + let config = C::construct_config(&init_args); + log::debug!("Constructed config: {config:#?}"); + let paths = config.common_paths(); + let core = config.core_config(); + + log::info!( + "Using nym-api: {}", + core.client + .nym_api_urls + .iter() + .map(|url| url.as_str()) + .collect::>() + .join(",") + ); + + // Setup gateway by either registering a new one, or creating a new config from the selected + // one but with keys kept, or reusing the gateway configuration. + let key_store = OnDiskKeys::new(paths.keys.clone()); + let details_store = setup_fs_gateways_storage(&paths.gateway_details).await?; + + let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { + let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { + ClientCoreError::CustomTopologyLoadFailure { + file_path: custom_mixnet.clone(), + source, + } + })?; + hardcoded_topology.get_gateways() + } else { + let mut rng = rand::thread_rng(); + crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? + }; + + let gateway_setup = GatewaySetup::New { + specification: selection_spec, + available_gateways, + overwrite_data: register_gateway, + }; + + let init_details = + crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; + + // TODO: ask the service provider we specified for its interface version and set it in the config + + let config_save_location = config.default_store_location(); + if let Err(err) = config.save_to(&config_save_location) { + return Err(ClientCoreError::ConfigSaveFailure { + typ: C::NAME.to_string(), + id: id.to_string(), + path: config_save_location, + source: err, + } + .into()); + } + + eprintln!( + "Saved configuration file to {}", + config_save_location.display() + ); + + let address = init_details.client_address()?; + + let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else { + return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; + }; + let init_results = InitResults::new(config.core_config(), address, &gateway_details); + + Ok(InitResultsWithConfig { + config, + init_results, + }) } From 0e09826140d5a8636cb3fe59d9b2c5bc3c1ea750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 11:12:43 +0000 Subject: [PATCH 09/56] initial work on client config migration --- clients/native/src/client/config/mod.rs | 1 + .../src/client/config/old_config_v1_1_20.rs | 4 +- .../src/client/config/old_config_v1_1_20_2.rs | 25 +- .../src/client/config/old_config_v1_1_33.rs | 99 ++++ .../native/src/client/config/persistence.rs | 2 + clients/native/src/commands/mod.rs | 85 +++- .../20240304120000_create_initial_tables.sql | 3 + .../src/cli_helpers/client_init.rs | 2 +- .../src/client/key_manager/persistence.rs | 21 +- .../src/config/disk_persistence/keys_paths.rs | 16 - .../src/config/disk_persistence/mod.rs | 12 +- .../config/disk_persistence/old_v1_1_20_2.rs | 26 +- .../config/disk_persistence/old_v1_1_33.rs | 78 +++ common/client-core/src/config/mod.rs | 1 + .../src/config/old_config_v1_1_30.rs | 42 +- .../src/config/old_config_v1_1_33.rs | 478 ++++++++++++++++++ common/client-core/src/error.rs | 3 + 17 files changed, 782 insertions(+), 116 deletions(-) create mode 100644 clients/native/src/client/config/old_config_v1_1_33.rs create mode 100644 common/client-core/src/config/old_config_v1_1_33.rs diff --git a/clients/native/src/client/config/mod.rs b/clients/native/src/client/config/mod.rs index 7fa28c8ab4..5c0d156bd5 100644 --- a/clients/native/src/client/config/mod.rs +++ b/clients/native/src/client/config/mod.rs @@ -24,6 +24,7 @@ pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig}; pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; +pub mod old_config_v1_1_33; mod persistence; mod template; diff --git a/clients/native/src/client/config/old_config_v1_1_20.rs b/clients/native/src/client/config/old_config_v1_1_20.rs index 8c2452d3e1..77ca8f5ca1 100644 --- a/clients/native/src/client/config/old_config_v1_1_20.rs +++ b/clients/native/src/client/config/old_config_v1_1_20.rs @@ -5,8 +5,8 @@ use crate::client::config::old_config_v1_1_20_2::{ ClientPathsV1_1_20_2, ConfigV1_1_20_2, SocketTypeV1_1_20_2, SocketV1_1_20_2, }; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; +use nym_client_core::config::disk_persistence::old_v1_1_33::ClientKeysPathsV1_1_33; use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20; use nym_client_core::config::old_config_v1_1_20_2::{ ClientV1_1_20_2, ConfigV1_1_20_2 as BaseConfigV1_1_20_2, @@ -60,7 +60,7 @@ impl From for ConfigV1_1_20_2 { socket: value.socket.into(), storage_paths: ClientPathsV1_1_20_2 { common_paths: CommonClientPathsV1_1_20_2 { - keys: ClientKeysPaths { + keys: ClientKeysPathsV1_1_33 { private_identity_key_file: value.base.client.private_identity_key_file, public_identity_key_file: value.base.client.public_identity_key_file, private_encryption_key_file: value.base.client.private_encryption_key_file, diff --git a/clients/native/src/client/config/old_config_v1_1_20_2.rs b/clients/native/src/client/config/old_config_v1_1_20_2.rs index 8e50fe0047..b6d9703a92 100644 --- a/clients/native/src/client/config/old_config_v1_1_20_2.rs +++ b/clients/native/src/client/config/old_config_v1_1_20_2.rs @@ -1,13 +1,10 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::{ - client::config::{ - default_config_filepath, persistence::ClientPaths, Config, Socket, SocketType, - }, - error::ClientError, +use crate::client::config::old_config_v1_1_33::{ + ClientPathsV1_1_33, ConfigV1_1_33, SocketTypeV1_1_33, SocketV1_1_33, }; - +use crate::{client::config::default_config_filepath, error::ClientError}; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2; @@ -49,12 +46,12 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), ClientError> { + pub fn upgrade(self) -> Result<(ConfigV1_1_33, GatewayEndpointConfig), ClientError> { let gateway_details = self.base.client.gateway_endpoint.clone().into(); - let config = Config { + let config = ConfigV1_1_33 { base: BaseConfigV1_1_30::from(self.base).into(), socket: self.socket.into(), - storage_paths: ClientPaths { + storage_paths: ClientPathsV1_1_33 { common_paths: self.storage_paths.common_paths.upgrade_default()?, }, logging: self.logging, @@ -71,11 +68,11 @@ pub enum SocketTypeV1_1_20_2 { None, } -impl From for SocketType { +impl From for SocketTypeV1_1_33 { fn from(value: SocketTypeV1_1_20_2) -> Self { match value { - SocketTypeV1_1_20_2::WebSocket => SocketType::WebSocket, - SocketTypeV1_1_20_2::None => SocketType::None, + SocketTypeV1_1_20_2::WebSocket => SocketTypeV1_1_33::WebSocket, + SocketTypeV1_1_20_2::None => SocketTypeV1_1_33::None, } } } @@ -88,9 +85,9 @@ pub struct SocketV1_1_20_2 { pub listening_port: u16, } -impl From for Socket { +impl From for SocketV1_1_33 { fn from(value: SocketV1_1_20_2) -> Self { - Socket { + SocketV1_1_33 { socket_type: value.socket_type.into(), host: value.host, listening_port: value.listening_port, diff --git a/clients/native/src/client/config/old_config_v1_1_33.rs b/clients/native/src/client/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..02ed7218d1 --- /dev/null +++ b/clients/native/src/client/config/old_config_v1_1_33.rs @@ -0,0 +1,99 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::client::config::persistence::ClientPaths; +use crate::client::config::{default_config_filepath, Config, Socket, SocketType}; +use crate::error::ClientError; +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; +use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseConfigV1_1_33; +use nym_config::read_config_from_toml_file; +use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; +use serde::{Deserialize, Serialize}; +use std::io; +use std::net::{IpAddr, Ipv4Addr}; +use std::path::Path; + +#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] +pub struct ClientPathsV1_1_33 { + #[serde(flatten)] + pub common_paths: CommonClientPathsV1_1_33, +} + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct ConfigV1_1_33 { + #[serde(flatten)] + pub base: BaseConfigV1_1_33, + + pub socket: SocketV1_1_33, + + // \/ CHANGED + pub storage_paths: ClientPathsV1_1_33, + // /\ CHANGED + pub logging: LoggingSettings, +} + +impl ConfigV1_1_33 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + socket: self.socket.into(), + storage_paths: ClientPaths { + common_paths: self.storage_paths.common_paths.upgrade_default()?, + }, + logging: self.logging, + }) + } +} + +#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone, Copy)] +#[serde(deny_unknown_fields)] +pub enum SocketTypeV1_1_33 { + WebSocket, + None, +} + +impl From for SocketType { + fn from(value: SocketTypeV1_1_33) -> Self { + match value { + SocketTypeV1_1_33::WebSocket => SocketType::WebSocket, + SocketTypeV1_1_33::None => SocketType::None, + } + } +} + +#[derive(Debug, Deserialize, PartialEq, Eq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct SocketV1_1_33 { + pub socket_type: SocketTypeV1_1_33, + pub host: IpAddr, + pub listening_port: u16, +} + +impl From for Socket { + fn from(value: SocketV1_1_33) -> Self { + Socket { + socket_type: value.socket_type.into(), + host: value.host, + listening_port: value.listening_port, + } + } +} + +impl Default for SocketV1_1_33 { + fn default() -> Self { + SocketV1_1_33 { + socket_type: SocketTypeV1_1_33::WebSocket, + host: IpAddr::V4(Ipv4Addr::LOCALHOST), + listening_port: DEFAULT_WEBSOCKET_LISTENING_PORT, + } + } +} diff --git a/clients/native/src/client/config/persistence.rs b/clients/native/src/client/config/persistence.rs index a61913a2f7..bdd3cd6a65 100644 --- a/clients/native/src/client/config/persistence.rs +++ b/clients/native/src/client/config/persistence.rs @@ -5,6 +5,8 @@ use nym_client_core::config::disk_persistence::CommonClientPaths; use serde::{Deserialize, Serialize}; use std::path::Path; + + #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] pub struct ClientPaths { #[serde(flatten)] diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index ff1b8087fd..39ab24913f 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -4,6 +4,7 @@ use crate::client::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::client::config::old_config_v1_1_20::ConfigV1_1_20; use crate::client::config::old_config_v1_1_20_2::ConfigV1_1_20_2; +use crate::client::config::old_config_v1_1_33::ConfigV1_1_33; use crate::client::config::{BaseClientConfig, Config}; use crate::error::ClientError; use clap::CommandFactory; @@ -14,6 +15,7 @@ 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; use nym_client_core::error::ClientCoreError; @@ -126,22 +128,34 @@ fn persist_gateway_details( config: &Config, details: GatewayEndpointConfig, ) -> Result<(), ClientError> { - let details_store = - OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - ClientError::ClientCoreError(ClientCoreError::KeyStoreError { - source: Box::new(source), - }) - })?; - let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - details_store - .store_to_disk(&persisted_details) - .map_err(|source| { - ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - }) - }) + todo!() + // let details_store = + // OnDiskGatewaysDetails::new(&config.storage_paths.common_paths.gateway_details); + // let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); + // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { + // ClientError::ClientCoreError(ClientCoreError::KeyStoreError { + // source: Box::new(source), + // }) + // })?; + // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; + // details_store + // .store_to_disk(&persisted_details) + // .map_err(|source| { + // ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { + // source: Box::new(source), + // }) + // }) +} + +fn migrate_gateway_details( + config: &Config, + old_details: Option, +) -> Result<(), ClientError> { + todo!() +} + +fn extract_gateway_details(config: &ConfigV1_1_33) -> Result<(), ClientError> { + todo!() } fn try_upgrade_v1_1_13_config(id: &str) -> Result { @@ -158,8 +172,10 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); - let (updated, gateway_config) = updated_step2.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let updated = updated_step3.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; updated.save_to_default_location()?; Ok(true) @@ -178,8 +194,10 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let updated_step1: ConfigV1_1_20_2 = old_config.into(); - let (updated, gateway_config) = updated_step1.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let updated = updated_step2.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; updated.save_to_default_location()?; Ok(true) @@ -195,8 +213,28 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.20_2 config template."); info!("It is going to get updated to the current specification."); - let (updated, gateway_config) = old_config.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step1, gateway_config) = old_config.upgrade()?; + let updated = updated_step1.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; + + updated.save_to_default_location()?; + Ok(true) +} + +fn try_upgrade_v1_1_33_config(id: &str) -> Result { + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) + let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.33 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + + migrate_gateway_details(&updated, None)?; updated.save_to_default_location()?; Ok(true) @@ -212,6 +250,9 @@ fn try_upgrade_config(id: &str) -> Result<(), ClientError> { if try_upgrade_v1_1_20_2_config(id)? { return Ok(()); } + if try_upgrade_v1_1_33_config(id)? { + return Ok(()); + } Ok(()) } diff --git a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql index 6df9d40a1a..bb4d59f7a1 100644 --- a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql +++ b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql @@ -16,6 +16,9 @@ CREATE TABLE registered_gateway gateway_type TEXT CHECK ( gateway_type IN ('remote', 'custom') ) NOT NULL DEFAULT 'remote' ); +-- TODO: perhaps keep additional metadata such as bandwidth, credential usage, etc + + CREATE TABLE remote_gateway_details ( gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58), diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index e147dd632c..3317aa4df7 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -183,7 +183,7 @@ where // Setup gateway by either registering a new one, or creating a new config from the selected // one but with keys kept, or reusing the gateway configuration. let key_store = OnDiskKeys::new(paths.keys.clone()); - let details_store = setup_fs_gateways_storage(&paths.gateway_details).await?; + let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { diff --git a/common/client-core/src/client/key_manager/persistence.rs b/common/client-core/src/client/key_manager/persistence.rs index 984019eb93..00041206db 100644 --- a/common/client-core/src/client/key_manager/persistence.rs +++ b/common/client-core/src/client/key_manager/persistence.rs @@ -84,14 +84,6 @@ impl OnDiskKeys { OnDiskKeys { paths } } - #[doc(hidden)] - pub fn ephemeral_load_gateway_keys( - &self, - ) -> Result, OnDiskKeysError> { - self.load_key(self.paths.gateway_shared_key(), "gateway shared") - .map(zeroize::Zeroizing::new) - } - #[doc(hidden)] pub fn load_encryption_keypair(&self) -> Result { let encryption_paths = self.paths.encryption_key_pair_path(); @@ -161,14 +153,11 @@ impl OnDiskKeys { let encryption_keypair = self.load_encryption_keypair()?; let ack_key: AckKey = self.load_key(self.paths.ack_key(), "ack key")?; - let gateway_shared_key: Option = self - .load_key(self.paths.gateway_shared_key(), "gateway shared keys") - .ok(); Ok(KeyManager::from_keys( identity_keypair, encryption_keypair, - gateway_shared_key, + None, ack_key, )) } @@ -192,14 +181,6 @@ impl OnDiskKeys { self.store_key(keys.ack_key.as_ref(), self.paths.ack_key(), "ack key")?; - if let Some(shared_keys) = &keys.gateway_shared_key { - self.store_key( - shared_keys.deref(), - self.paths.gateway_shared_key(), - "gateway shared keys", - )?; - } - Ok(()) } } diff --git a/common/client-core/src/config/disk_persistence/keys_paths.rs b/common/client-core/src/config/disk_persistence/keys_paths.rs index aeab0359ea..cdffebe1e2 100644 --- a/common/client-core/src/config/disk_persistence/keys_paths.rs +++ b/common/client-core/src/config/disk_persistence/keys_paths.rs @@ -8,7 +8,6 @@ pub const DEFAULT_PRIVATE_IDENTITY_KEY_FILENAME: &str = "private_identity.pem"; pub const DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME: &str = "public_identity.pem"; pub const DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME: &str = "private_encryption.pem"; pub const DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME: &str = "public_encryption.pem"; -pub const DEFAULT_GATEWAY_SHARED_KEY_FILENAME: &str = "gateway_shared.pem"; pub const DEFAULT_ACK_KEY_FILENAME: &str = "ack_key.pem"; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] @@ -25,10 +24,6 @@ pub struct ClientKeysPaths { /// Path to file containing public encryption key. pub public_encryption_key_file: PathBuf, - /// Path to file containing shared key derived with the specified gateway that is used - /// for all communication with it. - pub gateway_shared_key_file: PathBuf, - /// Path to file containing key used for encrypting and decrypting the content of an /// acknowledgement so that nobody besides the client knows which packet it refers to. pub ack_key_file: PathBuf, @@ -43,7 +38,6 @@ impl ClientKeysPaths { public_identity_key_file: base_dir.join(DEFAULT_PUBLIC_IDENTITY_KEY_FILENAME), private_encryption_key_file: base_dir.join(DEFAULT_PRIVATE_ENCRYPTION_KEY_FILENAME), public_encryption_key_file: base_dir.join(DEFAULT_PUBLIC_ENCRYPTION_KEY_FILENAME), - gateway_shared_key_file: base_dir.join(DEFAULT_GATEWAY_SHARED_KEY_FILENAME), ack_key_file: base_dir.join(DEFAULT_ACK_KEY_FILENAME), } } @@ -67,7 +61,6 @@ impl ClientKeysPaths { || matches!(self.private_identity_key_file.try_exists(), Ok(true)) || matches!(self.public_encryption_key_file.try_exists(), Ok(true)) || matches!(self.private_encryption_key_file.try_exists(), Ok(true)) - || matches!(self.gateway_shared_key_file.try_exists(), Ok(true)) || matches!(self.ack_key_file.try_exists(), Ok(true)) } @@ -76,14 +69,9 @@ impl ClientKeysPaths { .or_else(|| file_exists(&self.private_identity_key_file)) .or_else(|| file_exists(&self.public_encryption_key_file)) .or_else(|| file_exists(&self.private_encryption_key_file)) - .or_else(|| file_exists(&self.gateway_shared_key_file)) .or_else(|| file_exists(&self.ack_key_file)) } - pub fn gateway_key_file_exists(&self) -> bool { - matches!(self.gateway_shared_key_file.try_exists(), Ok(true)) - } - pub fn private_identity_key(&self) -> &Path { &self.private_identity_key_file } @@ -100,10 +88,6 @@ impl ClientKeysPaths { &self.public_encryption_key_file } - pub fn gateway_shared_key(&self) -> &Path { - &self.gateway_shared_key_file - } - pub fn ack_key(&self) -> &Path { &self.ack_key_file } diff --git a/common/client-core/src/config/disk_persistence/mod.rs b/common/client-core/src/config/disk_persistence/mod.rs index b52b261bff..c086696a4b 100644 --- a/common/client-core/src/config/disk_persistence/mod.rs +++ b/common/client-core/src/config/disk_persistence/mod.rs @@ -7,9 +7,8 @@ use std::path::{Path, PathBuf}; pub mod keys_paths; pub mod old_v1_1_20_2; -mod old_v1_1_33; +pub mod old_v1_1_33; -pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json"; pub const DEFAULT_REPLY_SURB_DB_FILENAME: &str = "persistent_reply_store.sqlite"; pub const DEFAULT_CREDENTIALS_DB_FILENAME: &str = "credentials_database.db"; pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.sqlite"; @@ -19,12 +18,8 @@ pub const DEFAULT_GATEWAYS_DETAILS_DB_FILENAME: &str = "gateways_registrations.s pub struct CommonClientPaths { pub keys: ClientKeysPaths, - /// Path to the file containing information about gateway used by this client, - /// i.e. details such as its public key, owner address or the network information. - #[deprecated] - pub gateway_details: PathBuf, - - // TODO: + /// Path to the file containing information about gateways used by this client, + /// i.e. details such as their public keys, owner addresses or the network information. pub gateway_registrations: PathBuf, /// Path to the database containing bandwidth credentials of this client. @@ -41,7 +36,6 @@ impl CommonClientPaths { CommonClientPaths { credentials_database: base_dir.join(DEFAULT_CREDENTIALS_DB_FILENAME), reply_surb_database: base_dir.join(DEFAULT_REPLY_SURB_DB_FILENAME), - gateway_details: base_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), gateway_registrations: base_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME), keys: ClientKeysPaths::new_base(base_data_directory), } diff --git a/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs b/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs index 24496f1497..e1863bb567 100644 --- a/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs +++ b/common/client-core/src/config/disk_persistence/old_v1_1_20_2.rs @@ -1,8 +1,9 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::disk_persistence::keys_paths::ClientKeysPaths; -use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAY_DETAILS_FILENAME}; +use crate::config::disk_persistence::old_v1_1_33::{ + ClientKeysPathsV1_1_33, CommonClientPathsV1_1_33, DEFAULT_GATEWAY_DETAILS_FILENAME, +}; use crate::error::ClientCoreError; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -10,24 +11,23 @@ use std::path::PathBuf; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] pub struct CommonClientPathsV1_1_20_2 { - pub keys: ClientKeysPaths, + pub keys: ClientKeysPathsV1_1_33, pub credentials_database: PathBuf, pub reply_surb_database: PathBuf, } impl CommonClientPathsV1_1_20_2 { - pub fn upgrade_default(self) -> Result { + pub fn upgrade_default(self) -> Result { let data_dir = self.reply_surb_database.parent().ok_or_else(|| { - ClientCoreError::UnableToUpgradeConfigFile { - new_version: "1.1.20-2".to_string(), + ClientCoreError::ConfigFileUpgradeFailure { + current_version: "1.1.20-2".to_string(), } })?; - todo!() - // Ok(CommonClientPaths { - // keys: self.keys, - // gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), - // credentials_database: self.credentials_database, - // reply_surb_database: self.reply_surb_database, - // }) + Ok(CommonClientPathsV1_1_33 { + keys: self.keys, + gateway_details: data_dir.join(DEFAULT_GATEWAY_DETAILS_FILENAME), + credentials_database: self.credentials_database, + reply_surb_database: self.reply_surb_database, + }) } } diff --git a/common/client-core/src/config/disk_persistence/old_v1_1_33.rs b/common/client-core/src/config/disk_persistence/old_v1_1_33.rs index 755fb6cc8b..f453b5e01a 100644 --- a/common/client-core/src/config/disk_persistence/old_v1_1_33.rs +++ b/common/client-core/src/config/disk_persistence/old_v1_1_33.rs @@ -1,2 +1,80 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use crate::config::disk_persistence::keys_paths::ClientKeysPaths; +use crate::config::disk_persistence::{CommonClientPaths, DEFAULT_GATEWAYS_DETAILS_DB_FILENAME}; +use crate::error::ClientCoreError; +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +pub const DEFAULT_GATEWAY_DETAILS_FILENAME: &str = "gateway_details.json"; + +#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] +pub struct ClientKeysPathsV1_1_33 { + /// Path to file containing private identity key. + pub private_identity_key_file: PathBuf, + + /// Path to file containing public identity key. + pub public_identity_key_file: PathBuf, + + /// Path to file containing private encryption key. + pub private_encryption_key_file: PathBuf, + + /// Path to file containing public encryption key. + pub public_encryption_key_file: PathBuf, + + /// Path to file containing shared key derived with the specified gateway that is used + /// for all communication with it. + pub gateway_shared_key_file: PathBuf, + + /// Path to file containing key used for encrypting and decrypting the content of an + /// acknowledgement so that nobody besides the client knows which packet it refers to. + pub ack_key_file: PathBuf, +} + +impl ClientKeysPathsV1_1_33 { + pub fn upgrade(self) -> ClientKeysPaths { + ClientKeysPaths { + private_identity_key_file: self.private_identity_key_file, + public_identity_key_file: self.public_identity_key_file, + private_encryption_key_file: self.private_encryption_key_file, + public_encryption_key_file: self.public_encryption_key_file, + ack_key_file: self.ack_key_file, + } + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct CommonClientPathsV1_1_33 { + pub keys: ClientKeysPathsV1_1_33, + + /// Path to the file containing information about gateway used by this client, + /// i.e. details such as its public key, owner address or the network information. + pub gateway_details: PathBuf, + + /// Path to the database containing bandwidth credentials of this client. + pub credentials_database: PathBuf, + + /// Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. + pub reply_surb_database: PathBuf, +} + +impl CommonClientPathsV1_1_33 { + // note that during the upgrade process, the caller will need to extract the key and gateway details + // manually and resave them in the new database + pub fn upgrade_default(self) -> Result { + let data_dir = self.gateway_details.parent().ok_or_else(|| { + ClientCoreError::ConfigFileUpgradeFailure { + current_version: "1.1.33".to_string(), + } + })?; + + Ok(CommonClientPaths { + keys: self.keys.upgrade(), + gateway_registrations: data_dir.join(DEFAULT_GATEWAYS_DETAILS_DB_FILENAME), + credentials_database: self.credentials_database, + reply_surb_database: self.reply_surb_database, + }) + } +} diff --git a/common/client-core/src/config/mod.rs b/common/client-core/src/config/mod.rs index 3f4bbb4efe..96615d3be4 100644 --- a/common/client-core/src/config/mod.rs +++ b/common/client-core/src/config/mod.rs @@ -21,6 +21,7 @@ pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_30; +pub mod old_config_v1_1_33; // 'DEBUG' const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; diff --git a/common/client-core/src/config/old_config_v1_1_30.rs b/common/client-core/src/config/old_config_v1_1_30.rs index 87dae0eb3f..17aeba6bfd 100644 --- a/common/client-core/src/config/old_config_v1_1_30.rs +++ b/common/client-core/src/config/old_config_v1_1_30.rs @@ -2,9 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 use crate::client::topology_control::geo_aware_provider::CountryGroup; -use crate::config::{ - Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, GroupBy, - ReplySurbs, Topology, TopologyStructure, Traffic, +use crate::config::old_config_v1_1_33::{ + AcknowledgementsV1_1_33, ClientV1_1_33, ConfigV1_1_33, CoverTrafficV1_1_33, DebugConfigV1_1_33, + GatewayConnectionV1_1_33, GroupByV1_1_33, ReplySurbsV1_1_33, TopologyStructureV1_1_33, + TopologyV1_1_33, TrafficV1_1_33, }; use nym_sphinx::{ addressing::clients::Recipient, @@ -64,18 +65,18 @@ pub struct ConfigV1_1_30 { pub debug: DebugConfigV1_1_30, } -impl From for Config { +impl From for ConfigV1_1_33 { fn from(value: ConfigV1_1_30) -> Self { - Config { - client: Client { + ConfigV1_1_33 { + client: ClientV1_1_33 { version: value.client.version, id: value.client.id, disabled_credentials_mode: value.client.disabled_credentials_mode, nyxd_urls: value.client.nyxd_urls, nym_api_urls: value.client.nym_api_urls, }, - debug: DebugConfig { - traffic: Traffic { + debug: DebugConfigV1_1_33 { + traffic: TrafficV1_1_33 { average_packet_delay: value.debug.traffic.average_packet_delay, message_sending_average_delay: value .debug @@ -89,7 +90,7 @@ impl From for Config { secondary_packet_size: value.debug.traffic.secondary_packet_size, packet_type: value.debug.traffic.packet_type, }, - cover_traffic: CoverTraffic { + cover_traffic: CoverTrafficV1_1_33 { loop_cover_traffic_average_delay: value .debug .cover_traffic @@ -103,18 +104,18 @@ impl From for Config { .cover_traffic .disable_loop_cover_traffic_stream, }, - gateway_connection: GatewayConnection { + gateway_connection: GatewayConnectionV1_1_33 { gateway_response_timeout: value .debug .gateway_connection .gateway_response_timeout, }, - acknowledgements: Acknowledgements { + acknowledgements: AcknowledgementsV1_1_33 { average_ack_delay: value.debug.acknowledgements.average_ack_delay, ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier, ack_wait_addition: value.debug.acknowledgements.ack_wait_addition, }, - topology: Topology { + topology: TopologyV1_1_33 { topology_refresh_rate: value.debug.topology.topology_refresh_rate, topology_resolution_timeout: value.debug.topology.topology_resolution_timeout, disable_refreshing: value.debug.topology.disable_refreshing, @@ -124,7 +125,7 @@ impl From for Config { .max_startup_gateway_waiting_period, topology_structure: value.debug.topology.topology_structure.into(), }, - reply_surbs: ReplySurbs { + reply_surbs: ReplySurbsV1_1_33 { minimum_reply_surb_storage_threshold: value .debug .reply_surbs @@ -155,7 +156,10 @@ impl From for Config { .maximum_reply_surb_drop_waiting_period, maximum_reply_surb_age: value.debug.reply_surbs.maximum_reply_surb_age, maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age, + + // \/ ADDED surb_mix_hops: None, + // /\ ADDED }, }, } @@ -345,12 +349,12 @@ pub enum TopologyStructureV1_1_30 { GeoAware(GroupByV1_1_30), } -impl From for TopologyStructure { +impl From for TopologyStructureV1_1_33 { fn from(value: TopologyStructureV1_1_30) -> Self { match value { - TopologyStructureV1_1_30::NymApi => TopologyStructure::NymApi, + TopologyStructureV1_1_30::NymApi => TopologyStructureV1_1_33::NymApi, TopologyStructureV1_1_30::GeoAware(group_by) => { - TopologyStructure::GeoAware(group_by.into()) + TopologyStructureV1_1_33::GeoAware(group_by.into()) } } } @@ -363,11 +367,11 @@ pub enum GroupByV1_1_30 { NymAddress(Recipient), } -impl From for GroupBy { +impl From for GroupByV1_1_33 { fn from(value: GroupByV1_1_30) -> Self { match value { - GroupByV1_1_30::CountryGroup(country) => GroupBy::CountryGroup(country), - GroupByV1_1_30::NymAddress(addr) => GroupBy::NymAddress(addr), + GroupByV1_1_30::CountryGroup(country) => GroupByV1_1_33::CountryGroup(country), + GroupByV1_1_30::NymAddress(addr) => GroupByV1_1_33::NymAddress(addr), } } } diff --git a/common/client-core/src/config/old_config_v1_1_33.rs b/common/client-core/src/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..0d47b95361 --- /dev/null +++ b/common/client-core/src/config/old_config_v1_1_33.rs @@ -0,0 +1,478 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::client::topology_control::geo_aware_provider::CountryGroup; +use crate::config::{ + Acknowledgements, Client, Config, CoverTraffic, DebugConfig, GatewayConnection, GroupBy, + ReplySurbs, Topology, TopologyStructure, Traffic, +}; +use nym_sphinx::{ + addressing::clients::Recipient, + params::{PacketSize, PacketType}, +}; +use serde::{Deserialize, Serialize}; +use std::time::Duration; +use url::Url; + +// 'DEBUG' +const DEFAULT_ACK_WAIT_MULTIPLIER: f64 = 1.5; + +const DEFAULT_ACK_WAIT_ADDITION: Duration = Duration::from_millis(1_500); +const DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(200); +const DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY: Duration = Duration::from_millis(20); +const DEFAULT_AVERAGE_PACKET_DELAY: Duration = Duration::from_millis(50); +const DEFAULT_TOPOLOGY_REFRESH_RATE: Duration = Duration::from_secs(5 * 60); // every 5min +const DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT: Duration = Duration::from_millis(5_000); +const DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD: Duration = Duration::from_secs(70 * 60); // 70min -> full epoch (1h) + a bit of overhead + +// Set this to a high value for now, so that we don't risk sporadic timeouts that might cause +// bought bandwidth tokens to not have time to be spent; Once we remove the gateway from the +// bandwidth bridging protocol, we can come back to a smaller timeout value +const DEFAULT_GATEWAY_RESPONSE_TIMEOUT: Duration = Duration::from_secs(5 * 60); + +const DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO: f64 = 0.70; + +// reply-surbs related: + +// define when to request +// clients/client-core/src/client/replies/reply_storage/surb_storage.rs +const DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 10; +const DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD: usize = 200; + +// define how much to request at once +// clients/client-core/src/client/replies/reply_controller.rs +const DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 10; +const DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE: u32 = 100; + +const DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE: u32 = 500; + +const DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD: Duration = Duration::from_secs(10); +const DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD: Duration = Duration::from_secs(5 * 60); + +// 12 hours +const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 60); + +// 24 hours +const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_33 { + pub client: ClientV1_1_33, + + #[serde(default)] + pub debug: DebugConfigV1_1_33, +} + +impl From for Config { + fn from(value: ConfigV1_1_33) -> Self { + Config { + client: Client { + version: value.client.version, + id: value.client.id, + disabled_credentials_mode: value.client.disabled_credentials_mode, + nyxd_urls: value.client.nyxd_urls, + nym_api_urls: value.client.nym_api_urls, + }, + debug: DebugConfig { + traffic: Traffic { + average_packet_delay: value.debug.traffic.average_packet_delay, + message_sending_average_delay: value + .debug + .traffic + .message_sending_average_delay, + disable_main_poisson_packet_distribution: value + .debug + .traffic + .disable_main_poisson_packet_distribution, + primary_packet_size: value.debug.traffic.primary_packet_size, + secondary_packet_size: value.debug.traffic.secondary_packet_size, + packet_type: value.debug.traffic.packet_type, + }, + cover_traffic: CoverTraffic { + loop_cover_traffic_average_delay: value + .debug + .cover_traffic + .loop_cover_traffic_average_delay, + cover_traffic_primary_size_ratio: value + .debug + .cover_traffic + .cover_traffic_primary_size_ratio, + disable_loop_cover_traffic_stream: value + .debug + .cover_traffic + .disable_loop_cover_traffic_stream, + }, + gateway_connection: GatewayConnection { + gateway_response_timeout: value + .debug + .gateway_connection + .gateway_response_timeout, + }, + acknowledgements: Acknowledgements { + average_ack_delay: value.debug.acknowledgements.average_ack_delay, + ack_wait_multiplier: value.debug.acknowledgements.ack_wait_multiplier, + ack_wait_addition: value.debug.acknowledgements.ack_wait_addition, + }, + topology: Topology { + topology_refresh_rate: value.debug.topology.topology_refresh_rate, + topology_resolution_timeout: value.debug.topology.topology_resolution_timeout, + disable_refreshing: value.debug.topology.disable_refreshing, + max_startup_gateway_waiting_period: value + .debug + .topology + .max_startup_gateway_waiting_period, + topology_structure: value.debug.topology.topology_structure.into(), + }, + reply_surbs: ReplySurbs { + minimum_reply_surb_storage_threshold: value + .debug + .reply_surbs + .minimum_reply_surb_storage_threshold, + maximum_reply_surb_storage_threshold: value + .debug + .reply_surbs + .maximum_reply_surb_storage_threshold, + minimum_reply_surb_request_size: value + .debug + .reply_surbs + .minimum_reply_surb_request_size, + maximum_reply_surb_request_size: value + .debug + .reply_surbs + .maximum_reply_surb_request_size, + maximum_allowed_reply_surb_request_size: value + .debug + .reply_surbs + .maximum_allowed_reply_surb_request_size, + maximum_reply_surb_rerequest_waiting_period: value + .debug + .reply_surbs + .maximum_reply_surb_rerequest_waiting_period, + maximum_reply_surb_drop_waiting_period: value + .debug + .reply_surbs + .maximum_reply_surb_drop_waiting_period, + maximum_reply_surb_age: value.debug.reply_surbs.maximum_reply_surb_age, + maximum_reply_key_age: value.debug.reply_surbs.maximum_reply_key_age, + surb_mix_hops: value.debug.reply_surbs.surb_mix_hops, + }, + }, + } + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] +// note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2 +#[serde(deny_unknown_fields)] +pub struct ClientV1_1_33 { + /// Version of the client for which this configuration was created. + pub version: String, + + /// ID specifies the human readable ID of this particular client. + pub id: String, + + /// Indicates whether this client is running in a disabled credentials mode, thus attempting + /// to claim bandwidth without presenting bandwidth credentials. + // TODO: this should be moved to `debug.gateway_connection` + #[serde(default)] + pub disabled_credentials_mode: bool, + + /// Addresses to nyxd validators via which the client can communicate with the chain. + #[serde(alias = "validator_urls")] + pub nyxd_urls: Vec, + + /// Addresses to APIs running on validator from which the client gets the view of the network. + #[serde(alias = "validator_api_urls")] + pub nym_api_urls: Vec, +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct TrafficV1_1_33 { + /// The parameter of Poisson distribution determining how long, on average, + /// sent packet is going to be delayed at any given mix node. + /// So for a packet going through three mix nodes, on average, it will take three times this value + /// until the packet reaches its destination. + #[serde(with = "humantime_serde")] + pub average_packet_delay: Duration, + + /// The parameter of Poisson distribution determining how long, on average, + /// it is going to take another 'real traffic stream' message to be sent. + /// If no real packets are available and cover traffic is enabled, + /// a loop cover message is sent instead in order to preserve the rate. + #[serde(with = "humantime_serde")] + pub message_sending_average_delay: Duration, + + /// Controls whether the main packet stream constantly produces packets according to the predefined + /// poisson distribution. + pub disable_main_poisson_packet_distribution: bool, + + /// Specifies the packet size used for sent messages. + /// Do not override it unless you understand the consequences of that change. + pub primary_packet_size: PacketSize, + + /// Specifies the optional auxiliary packet size for optimizing message streams. + /// Note that its use decreases overall anonymity. + /// Do not set it it unless you understand the consequences of that change. + pub secondary_packet_size: Option, + + pub packet_type: PacketType, +} + +impl Default for TrafficV1_1_33 { + fn default() -> Self { + TrafficV1_1_33 { + average_packet_delay: DEFAULT_AVERAGE_PACKET_DELAY, + message_sending_average_delay: DEFAULT_MESSAGE_STREAM_AVERAGE_DELAY, + disable_main_poisson_packet_distribution: false, + primary_packet_size: PacketSize::RegularPacket, + secondary_packet_size: None, + packet_type: PacketType::Mix, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct CoverTrafficV1_1_33 { + /// The parameter of Poisson distribution determining how long, on average, + /// it is going to take for another loop cover traffic message to be sent. + #[serde(with = "humantime_serde")] + pub loop_cover_traffic_average_delay: Duration, + + /// Specifies the ratio of `primary_packet_size` to `secondary_packet_size` used in cover traffic. + /// Only applicable if `secondary_packet_size` is enabled. + pub cover_traffic_primary_size_ratio: f64, + + /// Controls whether the dedicated loop cover traffic stream should be enabled. + /// (and sending packets, on average, every [Self::loop_cover_traffic_average_delay]) + pub disable_loop_cover_traffic_stream: bool, +} + +impl Default for CoverTrafficV1_1_33 { + fn default() -> Self { + CoverTrafficV1_1_33 { + loop_cover_traffic_average_delay: DEFAULT_LOOP_COVER_STREAM_AVERAGE_DELAY, + cover_traffic_primary_size_ratio: DEFAULT_COVER_TRAFFIC_PRIMARY_SIZE_RATIO, + disable_loop_cover_traffic_stream: false, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct GatewayConnectionV1_1_33 { + /// How long we're willing to wait for a response to a message sent to the gateway, + /// before giving up on it. + #[serde(with = "humantime_serde")] + pub gateway_response_timeout: Duration, +} + +impl Default for GatewayConnectionV1_1_33 { + fn default() -> Self { + GatewayConnectionV1_1_33 { + gateway_response_timeout: DEFAULT_GATEWAY_RESPONSE_TIMEOUT, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct AcknowledgementsV1_1_33 { + /// The parameter of Poisson distribution determining how long, on average, + /// sent acknowledgement is going to be delayed at any given mix node. + /// So for an ack going through three mix nodes, on average, it will take three times this value + /// until the packet reaches its destination. + #[serde(with = "humantime_serde")] + pub average_ack_delay: Duration, + + /// Value multiplied with the expected round trip time of an acknowledgement packet before + /// it is assumed it was lost and retransmission of the data packet happens. + /// In an ideal network with 0 latency, this value would have been 1. + pub ack_wait_multiplier: f64, + + /// Value added to the expected round trip time of an acknowledgement packet before + /// it is assumed it was lost and retransmission of the data packet happens. + /// In an ideal network with 0 latency, this value would have been 0. + #[serde(with = "humantime_serde")] + pub ack_wait_addition: Duration, +} + +impl Default for AcknowledgementsV1_1_33 { + fn default() -> Self { + AcknowledgementsV1_1_33 { + average_ack_delay: DEFAULT_AVERAGE_PACKET_DELAY, + ack_wait_multiplier: DEFAULT_ACK_WAIT_MULTIPLIER, + ack_wait_addition: DEFAULT_ACK_WAIT_ADDITION, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct TopologyV1_1_33 { + /// The uniform delay every which clients are querying the directory server + /// to try to obtain a compatible network topology to send sphinx packets through. + #[serde(with = "humantime_serde")] + pub topology_refresh_rate: Duration, + + /// During topology refresh, test packets are sent through every single possible network + /// path. This timeout determines waiting period until it is decided that the packet + /// did not reach its destination. + #[serde(with = "humantime_serde")] + pub topology_resolution_timeout: Duration, + + /// Specifies whether the client should not refresh the network topology after obtaining + /// the first valid instance. + /// Supersedes `topology_refresh_rate_ms`. + pub disable_refreshing: bool, + + /// Defines how long the client is going to wait on startup for its gateway to come online, + /// before abandoning the procedure. + #[serde(with = "humantime_serde")] + pub max_startup_gateway_waiting_period: Duration, + + /// Specifies the mixnode topology to be used for sending packets. + pub topology_structure: TopologyStructureV1_1_33, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Default, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum TopologyStructureV1_1_33 { + #[default] + NymApi, + GeoAware(GroupByV1_1_33), +} + +impl From for TopologyStructure { + fn from(value: TopologyStructureV1_1_33) -> Self { + match value { + TopologyStructureV1_1_33::NymApi => TopologyStructure::NymApi, + TopologyStructureV1_1_33::GeoAware(group_by) => { + TopologyStructure::GeoAware(group_by.into()) + } + } + } +} + +#[allow(clippy::large_enum_variant)] +#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum GroupByV1_1_33 { + CountryGroup(CountryGroup), + NymAddress(Recipient), +} + +impl From for GroupBy { + fn from(value: GroupByV1_1_33) -> Self { + match value { + GroupByV1_1_33::CountryGroup(country) => GroupBy::CountryGroup(country), + GroupByV1_1_33::NymAddress(addr) => GroupBy::NymAddress(addr), + } + } +} + +impl std::fmt::Display for GroupByV1_1_33 { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + GroupByV1_1_33::CountryGroup(group) => write!(f, "group: {}", group), + GroupByV1_1_33::NymAddress(address) => write!(f, "address: {}", address), + } + } +} + +impl Default for TopologyV1_1_33 { + fn default() -> Self { + TopologyV1_1_33 { + topology_refresh_rate: DEFAULT_TOPOLOGY_REFRESH_RATE, + topology_resolution_timeout: DEFAULT_TOPOLOGY_RESOLUTION_TIMEOUT, + disable_refreshing: false, + max_startup_gateway_waiting_period: DEFAULT_MAX_STARTUP_GATEWAY_WAITING_PERIOD, + topology_structure: TopologyStructureV1_1_33::default(), + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct ReplySurbsV1_1_33 { + /// Defines the minimum number of reply surbs the client wants to keep in its storage at all times. + /// It can only allow to go below that value if its to request additional reply surbs. + pub minimum_reply_surb_storage_threshold: usize, + + /// Defines the maximum number of reply surbs the client wants to keep in its storage at any times. + pub maximum_reply_surb_storage_threshold: usize, + + /// Defines the minimum number of reply surbs the client would request. + pub minimum_reply_surb_request_size: u32, + + /// Defines the maximum number of reply surbs the client would request. + pub maximum_reply_surb_request_size: u32, + + /// Defines the maximum number of reply surbs a remote party is allowed to request from this client at once. + pub maximum_allowed_reply_surb_request_size: u32, + + /// Defines maximum amount of time the client is going to wait for reply surbs before explicitly asking + /// for more even though in theory they wouldn't need to. + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_rerequest_waiting_period: Duration, + + /// Defines maximum amount of time the client is going to wait for reply surbs before + /// deciding it's never going to get them and would drop all pending messages + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_drop_waiting_period: Duration, + + /// Defines maximum amount of time given reply surb is going to be valid for. + /// This is going to be superseded by key rotation once implemented. + #[serde(with = "humantime_serde")] + pub maximum_reply_surb_age: Duration, + + /// Defines maximum amount of time given reply key is going to be valid for. + /// This is going to be superseded by key rotation once implemented. + #[serde(with = "humantime_serde")] + pub maximum_reply_key_age: Duration, + + /// Specifies the number of mixnet hops the packet should go through. If not specified, then + /// the default value is used. + pub surb_mix_hops: Option, +} + +impl Default for ReplySurbsV1_1_33 { + fn default() -> Self { + ReplySurbsV1_1_33 { + minimum_reply_surb_storage_threshold: DEFAULT_MINIMUM_REPLY_SURB_STORAGE_THRESHOLD, + maximum_reply_surb_storage_threshold: DEFAULT_MAXIMUM_REPLY_SURB_STORAGE_THRESHOLD, + minimum_reply_surb_request_size: DEFAULT_MINIMUM_REPLY_SURB_REQUEST_SIZE, + maximum_reply_surb_request_size: DEFAULT_MAXIMUM_REPLY_SURB_REQUEST_SIZE, + maximum_allowed_reply_surb_request_size: DEFAULT_MAXIMUM_ALLOWED_SURB_REQUEST_SIZE, + maximum_reply_surb_rerequest_waiting_period: + DEFAULT_MAXIMUM_REPLY_SURB_REREQUEST_WAITING_PERIOD, + maximum_reply_surb_drop_waiting_period: DEFAULT_MAXIMUM_REPLY_SURB_DROP_WAITING_PERIOD, + maximum_reply_surb_age: DEFAULT_MAXIMUM_REPLY_SURB_AGE, + maximum_reply_key_age: DEFAULT_MAXIMUM_REPLY_KEY_AGE, + surb_mix_hops: None, + } + } +} + +#[derive(Debug, Default, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct DebugConfigV1_1_33 { + /// Defines all configuration options related to traffic streams. + pub traffic: TrafficV1_1_33, + + /// Defines all configuration options related to cover traffic stream(s). + pub cover_traffic: CoverTrafficV1_1_33, + + /// Defines all configuration options related to the gateway connection. + pub gateway_connection: GatewayConnectionV1_1_33, + + /// Defines all configuration options related to acknowledgements, such as delays or wait timeouts. + pub acknowledgements: AcknowledgementsV1_1_33, + + /// Defines all configuration options related topology, such as refresh rates or timeouts. + pub topology: TopologyV1_1_33, + + /// Defines all configuration options related to reply SURBs. + pub reply_surbs: ReplySurbsV1_1_33, +} diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index e4496e461a..3d931bf3ce 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -113,6 +113,9 @@ pub enum ClientCoreError { #[error("the provided gateway details (for gateway {gateway_id}) do not correspond to the shared keys")] MismatchedGatewayDetails { gateway_id: String }, + #[error("unable to upgrade config file from `{current_version}`")] + ConfigFileUpgradeFailure { current_version: String }, + #[error("unable to upgrade config file to `{new_version}`")] UnableToUpgradeConfigFile { new_version: String }, From a3132b907ada02c7c8d470a174cf400102df7964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 16:12:03 +0000 Subject: [PATCH 10/56] further propagation of new gateway/key types --- .../src/backend/fs_backend/mod.rs | 12 +- .../src/backend/mem_backend.rs | 12 +- .../client-core/gateways-storage/src/lib.rs | 14 +- .../client-core/gateways-storage/src/types.rs | 31 ++ .../src/cli_helpers/client_init.rs | 40 +- .../client-core/src/client/base_client/mod.rs | 46 +- .../base_client/storage/gateway_details.rs | 77 ++- .../src/client/base_client/storage/mod.rs | 3 +- .../client-core/src/client/key_manager/mod.rs | 500 +++++++++--------- .../src/client/key_manager/persistence.rs | 4 - common/client-core/src/config/mod.rs | 3 + common/client-core/src/error.rs | 41 +- common/client-core/src/init/helpers.rs | 15 +- common/client-core/src/init/mod.rs | 206 +++++--- common/client-core/src/init/types.rs | 346 +++++++----- .../client-libs/gateway-client/src/client.rs | 25 +- .../crypto/src/asymmetric/encryption/mod.rs | 15 + common/crypto/src/asymmetric/identity/mod.rs | 15 + common/nymsphinx/acknowledgements/src/key.rs | 15 + 19 files changed, 858 insertions(+), 562 deletions(-) diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 6364bd376b..8aa5c3ff9d 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::GatewayDetails; +use crate::types::{GatewayDetails, GatewayRegistration}; use crate::{GatewaysDetailsStore, StorageError}; use async_trait::async_trait; use manager::StorageManager; @@ -26,8 +26,10 @@ impl OnDiskGatewaysDetails { #[async_trait] impl GatewaysDetailsStore for OnDiskGatewaysDetails { type StorageError = error::StorageError; - - async fn active_gateway(&self) -> Result, Self::StorageError> { + async fn has_gateway_details(&self, gateway_id: &str) -> Result { + todo!() + } + async fn active_gateway(&self) -> Result, Self::StorageError> { todo!() } @@ -35,14 +37,14 @@ impl GatewaysDetailsStore for OnDiskGatewaysDetails { todo!() } - async fn all_gateways(&self) -> Result, Self::StorageError> { + async fn all_gateways(&self) -> Result, Self::StorageError> { todo!() } async fn load_gateway_details( &self, gateway_id: &str, - ) -> Result { + ) -> Result { todo!() } diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 2d955f6c20..003284622e 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::GatewayDetails; +use crate::types::{GatewayDetails, GatewayRegistration}; use crate::{BadGateway, GatewaysDetailsStore}; use async_trait::async_trait; use std::collections::HashMap; @@ -33,8 +33,10 @@ struct InMemStorageInner { #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl GatewaysDetailsStore for InMemGatewaysDetails { type StorageError = InMemStorageError; - - async fn active_gateway(&self) -> Result, Self::StorageError> { + async fn has_gateway_details(&self, gateway_id: &str) -> Result { + todo!() + } + async fn active_gateway(&self) -> Result, Self::StorageError> { // let guard = self.inner.read().await; // // let foo = guard.active_gateway.map(|id| { @@ -51,14 +53,14 @@ impl GatewaysDetailsStore for InMemGatewaysDetails { todo!() } - async fn all_gateways(&self) -> Result, Self::StorageError> { + async fn all_gateways(&self) -> Result, Self::StorageError> { todo!() } async fn load_gateway_details( &self, gateway_id: &str, - ) -> Result { + ) -> Result { todo!() } diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 4a64ab354c..0c11b51f52 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -12,7 +12,10 @@ pub mod error; pub mod types; // todo: export port types -pub use crate::types::GatewayDetails; +pub use crate::types::{ + CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, RegisteredGateway, + RemoteGatewayDetails, +}; pub use backend::mem_backend::{InMemGatewaysDetails, InMemStorageError}; pub use error::BadGateway; @@ -25,19 +28,22 @@ pub trait GatewaysDetailsStore { type StorageError: Error + From; /// Returns details of the currently active gateway, if available. - async fn active_gateway(&self) -> Result, Self::StorageError>; + async fn active_gateway(&self) -> Result, Self::StorageError>; /// Set the provided gateway as the currently active gateway. async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError>; /// Returns details of all registered gateways. - async fn all_gateways(&self) -> Result, Self::StorageError>; + async fn all_gateways(&self) -> Result, Self::StorageError>; + + /// Check if the gateway with the provided id already exists in the store. + async fn has_gateway_details(&self, gateway_id: &str) -> Result; /// Returns details of the particular gateway. async fn load_gateway_details( &self, gateway_id: &str, - ) -> Result; + ) -> Result; /// Store the provided gateway details. async fn store_gateway_details( diff --git a/common/client-core/gateways-storage/src/types.rs b/common/client-core/gateways-storage/src/types.rs index 383500284f..abb20708a3 100644 --- a/common/client-core/gateways-storage/src/types.rs +++ b/common/client-core/gateways-storage/src/types.rs @@ -31,7 +31,34 @@ pub enum GatewayDetails { Custom(CustomGatewayDetails), } +impl From for GatewayRegistration { + fn from(details: GatewayDetails) -> Self { + GatewayRegistration { + details, + registration_timestamp: OffsetDateTime::now_utc(), + } + } +} + impl GatewayDetails { + pub fn new_remote( + gateway_id: identity::PublicKey, + derived_aes128_ctr_blake3_hmac_keys: Arc, + gateway_owner_address: AccountId, + gateway_listener: Url, + ) -> Self { + GatewayDetails::Remote(RemoteGatewayDetails { + gateway_id, + derived_aes128_ctr_blake3_hmac_keys, + gateway_owner_address, + gateway_listener, + }) + } + + pub fn new_custom(gateway_id: identity::PublicKey, data: Option>) -> Self { + GatewayDetails::Custom(CustomGatewayDetails { gateway_id, data }) + } + pub fn gateway_id(&self) -> identity::PublicKey { match self { GatewayDetails::Remote(details) => details.gateway_id, @@ -45,6 +72,10 @@ impl GatewayDetails { GatewayDetails::Custom(_) => None, } } + + pub fn is_custom(&self) -> bool { + matches!(self, GatewayDetails::Custom(..)) + } } #[derive(Debug, Copy, Clone, Default)] diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 3317aa4df7..9c93cd1729 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -8,11 +8,13 @@ use crate::{ base_client::non_wasm_helpers::setup_fs_gateways_storage, key_manager::persistence::OnDiskKeys, }, - init::types::{GatewayDetails, GatewaySelectionSpecification, GatewaySetup, InitResults}, + init::types::{GatewaySelectionSpecification, GatewaySetup, InitResults}, }; use log::info; +use nym_client_core_gateways_storage::GatewayDetails; use nym_crypto::asymmetric::identity; use nym_topology::NymTopology; +use rand::rngs::OsRng; use std::path::{Path, PathBuf}; pub trait InitialisableClient { @@ -133,6 +135,10 @@ where eprintln!("{} client \"{id}\" was already initialised before", C::NAME); true } else { + info!( + "{} client {id:?} hasn't been initialised before - new keys are going to be generated", + C::NAME + ); C::initialise_storage_paths(id)?; false }; @@ -144,14 +150,6 @@ where eprintln!("Instructed to force registering gateway. This might overwrite keys!"); } - // TODO: look at the registration logic due to being able to store multiple gws now - let unused_variable = 42; - - // If the client was already initialized, don't generate new keys and don't re-register with - // the gateway (because this would create a new shared key). - // Unless the user really wants to. - let register_gateway = !already_init || user_wants_force_register; - // Attempt to use a user-provided gateway, if possible let user_chosen_gateway_id = common_args.gateway; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); @@ -180,9 +178,16 @@ where .join(",") ); + let key_store = OnDiskKeys::new(paths.keys.clone()); + + // if this is a first time client with this particular id is initialised, generated long-term keys + if !already_init { + let mut rng = OsRng; + crate::init::generate_new_client_keys(&mut rng, &key_store).await?; + } + // Setup gateway by either registering a new one, or creating a new config from the selected // one but with keys kept, or reusing the gateway configuration. - let key_store = OnDiskKeys::new(paths.keys.clone()); let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { @@ -198,10 +203,12 @@ where crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? }; + todo!("remove registered gateways from the list"); + let gateway_setup = GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: register_gateway, + overwrite_data: common_args.force_register_gateway, }; let init_details = @@ -225,12 +232,17 @@ where config_save_location.display() ); - let address = init_details.client_address()?; + let address = init_details.client_address(); - let GatewayDetails::Configured(gateway_details) = init_details.gateway_details else { + let GatewayDetails::Remote(gateway_details) = init_details.gateway_registration.details else { return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; }; - let init_results = InitResults::new(config.core_config(), address, &gateway_details); + let init_results = InitResults::new( + config.core_config(), + address, + &gateway_details, + init_details.gateway_registration.registration_timestamp, + ); Ok(InitResultsWithConfig { config, diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index 41c9a3f01b..c2400a7dc5 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -29,17 +29,17 @@ use crate::config::{Config, DebugConfig}; use crate::error::ClientCoreError; use crate::init::{ setup_gateway, - types::{GatewayDetails, GatewaySetup, InitialisationResult}, + types::{GatewaySetup, InitialisationResult}, }; use crate::{config, spawn_future}; use futures::channel::mpsc; use log::{debug, error, info}; use nym_bandwidth_controller::BandwidthController; -use nym_client_core_gateways_storage::GatewaysDetailsStore; +use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore}; use nym_credential_storage::storage::Storage as CredentialStorage; use nym_crypto::asymmetric::encryption; use nym_gateway_client::{ - AcknowledgementReceiver, GatewayClient, MixnetMessageReceiver, PacketRouter, + AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter, }; use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::addressing::clients::Recipient; @@ -201,7 +201,7 @@ where custom_topology_provider: None, custom_gateway_transceiver: None, shutdown: None, - setup_method: GatewaySetup::MustLoad, + setup_method: GatewaySetup::MustLoad { gateway_id: None }, } } @@ -250,13 +250,7 @@ where // note: do **NOT** make this method public as its only valid usage is from within `start_base` // because it relies on the crypto keys being already loaded fn mix_address(details: &InitialisationResult) -> Recipient { - Recipient::new( - *details.managed_keys.identity_public_key(), - *details.managed_keys.encryption_public_key(), - // TODO: below only works under assumption that gateway address == gateway id - // (which currently is true) - NodeIdentity::from_base58_string(details.gateway_details.gateway_id()).unwrap(), - ) + details.client_address() } // future constantly pumping loop cover traffic at some specified average rate @@ -355,8 +349,8 @@ where ::StorageError: Send + Sync + 'static, ::StorageError: Send + Sync + 'static, { - let managed_keys = initialisation_result.managed_keys; - let GatewayDetails::Configured(gateway_config) = initialisation_result.gateway_details + let managed_keys = initialisation_result.client_keys; + let GatewayDetails::Remote(details) = initialisation_result.gateway_registration.details else { return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails); }; @@ -365,11 +359,15 @@ where if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client { existing_client.upgrade(packet_router, bandwidth_controller, shutdown) } else { - let cfg = gateway_config.try_into()?; + let cfg = GatewayConfig::new( + details.gateway_id, + Some(details.gateway_owner_address.to_string()), + details.gateway_listener.to_string(), + ); GatewayClient::new( cfg, managed_keys.identity_keypair(), - Some(managed_keys.must_get_gateway_shared_key()), + Some(details.derived_aes128_ctr_blake3_hmac_keys), packet_router, bandwidth_controller, shutdown, @@ -378,21 +376,17 @@ where .with_response_timeout(config.debug.gateway_connection.gateway_response_timeout) }; - let gateway_id = gateway_client.gateway_identity(); - - let shared_key = gateway_client + gateway_client .authenticate_and_start() .await .map_err(|err| { log::error!("Could not authenticate and start up the gateway connection - {err}"); ClientCoreError::GatewayClientError { - gateway_id: gateway_id.to_base58_string(), + gateway_id: details.gateway_id.to_base58_string(), source: err, } })?; - managed_keys.ensure_gateway_key(Some(shared_key)); - Ok(gateway_client) } @@ -410,7 +404,11 @@ where { // if we have setup custom gateway sender and persisted details agree with it, return it if let Some(mut custom_gateway_transceiver) = custom_gateway_transceiver { - return if !initialisation_result.gateway_details.is_custom() { + return if !initialisation_result + .gateway_registration + .details + .is_custom() + { Err(ClientCoreError::CustomGatewaySelectionExpected) } else { // and make sure to invalidate the task client so we wouldn't cause premature shutdown @@ -633,8 +631,8 @@ where reply_controller::requests::new_control_channels(); let self_address = Self::mix_address(&init_res); - let ack_key = init_res.managed_keys.ack_key(); - let encryption_keys = init_res.managed_keys.encryption_keypair(); + let ack_key = init_res.client_keys.ack_key(); + let encryption_keys = init_res.client_keys.encryption_keypair(); // the components are started in very specific order. Unless you know what you are doing, // do not change that. diff --git a/common/client-core/src/client/base_client/storage/gateway_details.rs b/common/client-core/src/client/base_client/storage/gateway_details.rs index 152ef96283..552de2dbbd 100644 --- a/common/client-core/src/client/base_client/storage/gateway_details.rs +++ b/common/client-core/src/client/base_client/storage/gateway_details.rs @@ -3,7 +3,6 @@ use crate::config::GatewayEndpointConfig; use crate::error::ClientCoreError; -use crate::init::types::GatewayDetails; use async_trait::async_trait; use log::error; use nym_gateway_requests::registration::handshake::SharedKeys; @@ -108,44 +107,44 @@ impl PersistedGatewayConfig { } impl PersistedGatewayDetails { - pub fn new( - details: GatewayDetails, - shared_key: Option<&SharedKeys>, - ) -> Result { - 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 - } - } - } - } + // pub fn new( + // details: GatewayDetails, + // shared_key: Option<&SharedKeys>, + // ) -> Result { + // 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 serialization use base64 representation to make it human readable diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 969b60d617..86180b99eb 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -10,6 +10,7 @@ use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore}; use crate::client::replies::reply_storage; use crate::client::replies::reply_storage::ReplyStorageBackend; +use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage; @@ -37,8 +38,6 @@ use nym_credential_storage::persistent_storage::PersistentStorage as PersistentC #[deprecated] pub mod gateway_details; -pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; - #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; diff --git a/common/client-core/src/client/key_manager/mod.rs b/common/client-core/src/client/key_manager/mod.rs index f01f8e2fbb..b15ca52f44 100644 --- a/common/client-core/src/client/key_manager/mod.rs +++ b/common/client-core/src/client/key_manager/mod.rs @@ -12,218 +12,223 @@ use zeroize::ZeroizeOnDrop; pub mod persistence; -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, +pub struct ManagedKeys { + client_keys: KeyManager, + active_gateway_keys: Option>, } - -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 for ManagedKeys { - fn from(value: KeyManagerBuilder) -> Self { - ManagedKeys::Initial(value) - } -} - -impl From for ManagedKeys { - fn from(value: KeyManager) -> Self { - ManagedKeys::FullyDerived(value) - } -} - +// +// 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 for ManagedKeys { +// fn from(value: KeyManagerBuilder) -> Self { +// ManagedKeys::Initial(value) +// } +// } +// +// impl From 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(key_store: &S) -> Result { - Ok(ManagedKeys::FullyDerived( - KeyManager::load_keys(key_store).await?, - )) - } - - pub fn generate_new(rng: &mut R) -> Self - where - R: RngCore + CryptoRng, - { - ManagedKeys::Initial(KeyManagerBuilder::new(rng)) - } - - pub async fn load_or_generate(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 { - 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 { - 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 { - 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 { - self.gateway_shared_key() - .expect("failed to extract gateway shared key") - } - - pub fn gateway_shared_key(&self) -> Option> { - 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>) { - 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( - &mut self, - gateway_shared_key: Option>, - 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, - - /// encryption key associated with the client instance. - encryption_keypair: Arc, - - /// key used for producing and processing acknowledgement packets. - ack_key: Arc, -} - -impl KeyManagerBuilder { - /// Creates new instance of a [`KeyManager`] - pub fn new(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>, - ) -> 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 { - Arc::clone(&self.identity_keypair) - } - - pub fn encryption_keypair(&self) -> Arc { - Arc::clone(&self.encryption_keypair) - } - - pub fn ack_key(&self) -> Arc { - Arc::clone(&self.ack_key) - } + // pub fn is_valid(&self) -> bool { + // !matches!(self, ManagedKeys::Invalidated) + // } + // + // pub async fn try_load(key_store: &S) -> Result { + // Ok(ManagedKeys::FullyDerived( + // KeyManager::load_keys(key_store).await?, + // )) + // } + // + // pub fn generate_new(rng: &mut R) -> Self + // where + // R: RngCore + CryptoRng, + // { + // ManagedKeys::Initial(KeyManagerBuilder::new(rng)) + // } + // + // pub async fn load_or_generate(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 { + // 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 { + // 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 { + // 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 { + // self.gateway_shared_key() + // .expect("failed to extract gateway shared key") + // } + // + // pub fn gateway_shared_key(&self) -> Option> { + // 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>) { + // 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( + // &mut self, + // gateway_shared_key: Option>, + // 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, +// +// /// encryption key associated with the client instance. +// encryption_keypair: Arc, +// +// /// key used for producing and processing acknowledgement packets. +// ack_key: Arc, +// } +// +// impl KeyManagerBuilder { +// /// Creates new instance of a [`KeyManager`] +// pub fn new(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>, +// ) -> 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 { +// Arc::clone(&self.identity_keypair) +// } +// +// pub fn encryption_keypair(&self) -> Arc { +// Arc::clone(&self.encryption_keypair) +// } +// +// pub fn ack_key(&self) -> Arc { +// 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 @@ -240,28 +245,39 @@ pub struct KeyManager { /// encryption key associated with the client instance. encryption_keypair: Arc, - /// 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>, - + // /// 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>, /// key used for producing and processing acknowledgement packets. ack_key: Arc, } impl KeyManager { + /// Creates new instance of a [`KeyManager`] + pub fn generate_new(rng: &mut R) -> Self + where + R: RngCore + CryptoRng, + { + KeyManager { + 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 from_keys( id_keypair: identity::KeyPair, enc_keypair: encryption::KeyPair, - gateway_shared_key: Option, + // gateway_shared_key: Option, 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), + // gateway_shared_key: gateway_shared_key.map(Arc::new), ack_key: Arc::new(ack_key), } } @@ -288,31 +304,31 @@ impl KeyManager { Arc::clone(&self.ack_key) } - fn must_get_gateway_shared_key(&self) -> &Arc { - self.gateway_shared_key - .as_ref() - .expect("gateway shared key is unavailable") - } + // fn must_get_gateway_shared_key(&self) -> &Arc { + // 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> { + // self.gateway_shared_key.as_ref().map(Arc::clone) + // } - 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> { - self.gateway_shared_key.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, - } - } + // 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() { diff --git a/common/client-core/src/client/key_manager/persistence.rs b/common/client-core/src/client/key_manager/persistence.rs index 00041206db..a7a4196d30 100644 --- a/common/client-core/src/client/key_manager/persistence.rs +++ b/common/client-core/src/client/key_manager/persistence.rs @@ -151,20 +151,16 @@ impl OnDiskKeys { fn load_keys(&self) -> Result { 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( identity_keypair, encryption_keypair, - None, ack_key, )) } fn store_keys(&self, keys: &KeyManager) -> Result<(), OnDiskKeysError> { - use std::ops::Deref; - let identity_paths = self.paths.identity_key_pair_path(); let encryption_paths = self.paths.encryption_key_pair_path(); diff --git a/common/client-core/src/config/mod.rs b/common/client-core/src/config/mod.rs index 96615d3be4..1fd2cf26f3 100644 --- a/common/client-core/src/config/mod.rs +++ b/common/client-core/src/config/mod.rs @@ -232,6 +232,7 @@ impl Config { } } +#[deprecated] #[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen(getter_with_clone))] pub struct GatewayEndpointConfig { @@ -259,6 +260,7 @@ impl TryFrom for GatewayConfig { } } +#[deprecated] #[cfg_attr(target_arch = "wasm32", wasm_bindgen)] impl GatewayEndpointConfig { #[cfg_attr(target_arch = "wasm32", wasm_bindgen(constructor))] @@ -276,6 +278,7 @@ impl GatewayEndpointConfig { } // separate block so it wouldn't be exported via wasm bindgen +#[deprecated] impl GatewayEndpointConfig { pub fn try_get_gateway_identity_key(&self) -> Result { identity::PublicKey::from_base58_string(&self.gateway_id) diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index 3d931bf3ce..72fcf7762e 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -4,6 +4,7 @@ use crate::client::mix_traffic::transceiver::ErasedGatewayError; use nym_crypto::asymmetric::identity::Ed25519RecoveryError; use nym_gateway_client::error::GatewayClientError; +use nym_gateway_requests::registration::handshake::shared_key::SharedKeyConversionError; use nym_topology::gateway::GatewayConversionError; use nym_topology::NymTopologyError; use nym_validator_client::ValidatorClientError; @@ -94,13 +95,21 @@ pub enum ClientCoreError { #[error("unexpected exit")] UnexpectedExit, + #[error("this operation would have resulted in the gateway {gateway_id:?} key being overwritten without permission")] + ForbiddenGatewayKeyOverwrite { gateway_id: String }, + #[error( "this operation would have resulted in clients keys being overwritten without permission" )] ForbiddenKeyOverwrite, - #[error("gateway details are unavailable")] + #[error("the client doesn't have any gateway set as active")] + NoActiveGatewaySet, + + #[error("gateway details for gateway {gateway_id:?} are unavailable")] UnavailableGatewayDetails { + gateway_id: String, + #[source] source: Box, }, @@ -156,6 +165,36 @@ pub enum ClientCoreError { #[source] source: std::io::Error, }, + + #[error("the provided gateway identity {gateway_id} is malformed: {source}")] + MalformedGatewayIdentity { + gateway_id: String, + + #[source] + source: Ed25519RecoveryError, + }, + + #[error("the account owner of gateway {gateway_id} ({raw_owner}) is malformed: {err}")] + MalformedGatewayOwnerAccountAddress { + gateway_id: String, + + raw_owner: String, + + // just use the string formatting as opposed to underlying type to avoid having to import cosmrs + err: String, + }, + + #[error( + "the listening address of gateway {gateway_id} ({raw_listener}) is malformed: {source}" + )] + MalformedListener { + gateway_id: String, + + raw_listener: String, + + #[source] + source: url::ParseError, + }, } /// Set of messages that the client can send to listeners via the task manager diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index 06c5c8ef59..a0c7c6c8de 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -25,6 +25,7 @@ use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; #[cfg(not(target_arch = "wasm32"))] type WsConn = WebSocketStream>; use nym_validator_client::client::IdentityKeyRef; +use nym_validator_client::nyxd::AccountId; #[cfg(not(target_arch = "wasm32"))] use tokio::time::sleep; @@ -278,16 +279,17 @@ pub(super) fn get_specified_gateway( } pub(super) async fn register_with_gateway( - gateway: &GatewayEndpointConfig, + gateway_id: identity::PublicKey, + gateway_listener: Url, our_identity: Arc, ) -> Result { let mut gateway_client = - GatewayClient::new_init(gateway.to_owned().try_into()?, our_identity.clone()); + GatewayClient::new_init(gateway_listener, gateway_id, our_identity.clone()); gateway_client.establish_connection().await.map_err(|err| { log::warn!("Failed to establish connection with gateway!"); ClientCoreError::GatewayClientError { - gateway_id: gateway.gateway_id.clone(), + gateway_id: gateway_id.to_base58_string(), source: err, } })?; @@ -295,12 +297,9 @@ pub(super) async fn register_with_gateway( .perform_initial_authentication() .await .map_err(|err| { - log::warn!( - "Failed to register with the gateway {}!", - gateway.gateway_id - ); + log::warn!("Failed to register with the gateway {gateway_id}: {err}"); ClientCoreError::GatewayClientError { - gateway_id: gateway.gateway_id.clone(), + gateway_id: gateway_id.to_base58_string(), source: err, } })?; diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 72b6f67996..38b5c398ab 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -1,25 +1,23 @@ -// Copyright 2022-2023 - Nym Technologies SA +// Copyright 2022-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 //! Collection of initialization steps used by client implementations -use crate::client::base_client::storage::gateway_details::PersistedGatewayDetails; use crate::client::key_manager::persistence::KeyStore; -use crate::client::key_manager::ManagedKeys; -use crate::config::GatewayEndpointConfig; +use crate::client::key_manager::KeyManager; use crate::error::ClientCoreError; use crate::init::helpers::{ choose_gateway_by_latency, get_specified_gateway, uniformly_random_gateway, }; use crate::init::types::{ - CustomGatewayDetails, GatewayDetails, GatewaySelectionSpecification, GatewaySetup, - InitialisationResult, + GatewaySelectionSpecification, GatewaySetup, InitialisationResult, SelectedGateway, }; use nym_client_core_gateways_storage::GatewaysDetailsStore; +use nym_client_core_gateways_storage::{GatewayDetails, GatewayRegistration}; use nym_gateway_client::client::InitGatewayClient; use nym_topology::gateway; use rand::rngs::OsRng; -use serde::de::DeserializeOwned; +use rand::{CryptoRng, RngCore}; use serde::Serialize; use std::sync::Arc; @@ -29,7 +27,7 @@ pub mod types; // helpers for error wrapping async fn _store_gateway_details( details_store: &D, - details: &PersistedGatewayDetails, + details: &GatewayDetails, ) -> Result<(), ClientCoreError> where D: GatewaysDetailsStore, @@ -44,41 +42,91 @@ where // }) } -async fn _load_gateway_details( +async fn _load_active_gateway_details( details_store: &D, -) -> Result +) -> Result where D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, { - todo!() - // details_store - // .load_gateway_details() - // .await - // .map_err(|source| ClientCoreError::UnavailableGatewayDetails { - // source: Box::new(source), - // }) + details_store + .active_gateway() + .await + .map_err(|source| ClientCoreError::GatewayDetailsStoreError { + source: Box::new(source), + })? + .ok_or(ClientCoreError::NoActiveGatewaySet) } -async fn _load_managed_keys(key_store: &K) -> Result +async fn _load_gateway_details( + details_store: &D, + gateway_id: &str, +) -> Result +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .load_gateway_details(gateway_id) + .await + .map_err(|source| ClientCoreError::UnavailableGatewayDetails { + gateway_id: gateway_id.to_string(), + source: Box::new(source), + }) +} + +async fn _has_gateway_details( + details_store: &D, + gateway_id: &str, +) -> Result +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .has_gateway_details(gateway_id) + .await + .map_err(|source| ClientCoreError::GatewayDetailsStoreError { + source: Box::new(source), + }) +} + +async fn _load_client_keys(key_store: &K) -> Result where K: KeyStore, K::StorageError: Send + Sync + 'static, { - ManagedKeys::try_load(key_store) + KeyManager::load_keys(key_store) .await .map_err(|source| ClientCoreError::KeyStoreError { source: Box::new(source), }) } -fn ensure_valid_details( - details: &PersistedGatewayDetails, - loaded_keys: &ManagedKeys, -) -> Result<(), ClientCoreError> { - details.validate(loaded_keys.gateway_shared_key().as_deref()) +pub async fn generate_new_client_keys( + rng: &mut R, + key_store: &K, +) -> Result<(), ClientCoreError> +where + R: RngCore + CryptoRng, + K: KeyStore, + K::StorageError: Send + Sync + 'static, +{ + KeyManager::generate_new(rng) + .persist_keys(key_store) + .await + .map_err(|source| ClientCoreError::KeyStoreError { + source: Box::new(source), + }) } +// fn ensure_valid_details( +// details: &PersistedGatewayDetails, +// loaded_keys: &ManagedKeys, +// ) -> Result<(), ClientCoreError> { +// details.validate(loaded_keys.gateway_shared_key().as_deref()) +// } + async fn setup_new_gateway( key_store: &K, details_store: &D, @@ -94,6 +142,9 @@ where { log::trace!("Setting up new gateway"); + // if we're setting up new gateway, we must have had generated long-term client keys before + let client_keys = _load_client_keys(key_store).await?; + // if we're setting up new gateway, failing to load existing information is fine. // as a matter of fact, it's only potentially a problem if we DO succeed @@ -102,73 +153,83 @@ where // return Err(ClientCoreError::ForbiddenKeyOverwrite); // } - if _load_managed_keys(key_store).await.is_ok() && !overwrite_data { - return Err(ClientCoreError::ForbiddenKeyOverwrite); - } - let mut rng = OsRng; - let mut new_keys = ManagedKeys::generate_new(&mut rng); - let gateway_details = match selection_specification { + let selected_gateway = match selection_specification { GatewaySelectionSpecification::UniformRemote { must_use_tls } => { let gateway = uniformly_random_gateway(&mut rng, &available_gateways, must_use_tls)?; - GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?) + SelectedGateway::from_topology_node(gateway, must_use_tls)? } GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => { let gateway = choose_gateway_by_latency(&mut rng, &available_gateways, must_use_tls).await?; - GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?) + SelectedGateway::from_topology_node(gateway, must_use_tls)? } GatewaySelectionSpecification::Specified { must_use_tls, identity, } => { let gateway = get_specified_gateway(&identity, &available_gateways, must_use_tls)?; - GatewayDetails::Configured(GatewayEndpointConfig::from_node(gateway, must_use_tls)?) + SelectedGateway::from_topology_node(gateway, must_use_tls)? } GatewaySelectionSpecification::Custom { gateway_identity, additional_data, - } => GatewayDetails::Custom(CustomGatewayDetails::new(gateway_identity, additional_data)), + } => SelectedGateway::custom(gateway_identity, additional_data)?, }; - let registration_result = if let GatewayDetails::Configured(gateway_cfg) = &gateway_details { - // if we're using a 'normal' gateway setup, do register - let our_identity = new_keys.identity_keypair(); - Some(helpers::register_with_gateway(gateway_cfg, our_identity).await?) - } else { - None + // check if we already have details associated with this particular gateway + // and if so, see if we can overwrite it + let selected_id = selected_gateway.gateway_id().to_base58_string(); + if _has_gateway_details(details_store, &selected_id).await? && !overwrite_data { + return Err(ClientCoreError::ForbiddenGatewayKeyOverwrite { + gateway_id: selected_id, + }); + } + + let (gateway_details, client) = match selected_gateway { + SelectedGateway::Remote { + gateway_id, + gateway_owner_address, + gateway_listener, + } => { + // if we're using a 'normal' gateway setup, do register + let our_identity = client_keys.identity_keypair(); + let registration = + helpers::register_with_gateway(gateway_id, gateway_listener, our_identity).await?; + ( + GatewayDetails::new_remote( + gateway_id, + registration.shared_keys, + gateway_owner_address, + gateway_listener, + ), + Some(registration.authenticated_ephemeral_client), + ) + } + SelectedGateway::Custom { + gateway_id, + additional_data, + } => ( + GatewayDetails::new_custom(gateway_id, additional_data), + None, + ), }; - let maybe_shared_keys = registration_result - .as_ref() - .map(|r| Arc::clone(&r.shared_keys)); - - let persisted_details = - PersistedGatewayDetails::new(gateway_details, maybe_shared_keys.as_deref())?; - - // persist the keys - new_keys - .deal_with_gateway_key(maybe_shared_keys, key_store) - .await - .map_err(|source| ClientCoreError::KeyStoreError { - source: Box::new(source), - })?; - - // persist gateway configs - _store_gateway_details(details_store, &persisted_details).await?; + // persist gateway details + _store_gateway_details(details_store, &gateway_details).await?; Ok(InitialisationResult { - gateway_details: persisted_details.into(), - managed_keys: new_keys, - authenticated_ephemeral_client: registration_result - .map(|r| r.authenticated_ephemeral_client), + gateway_registration: gateway_details.into(), + client_keys, + authenticated_ephemeral_client: client, }) } async fn use_loaded_gateway_details( key_store: &K, details_store: &D, + gateway_id: Option, ) -> Result where K: KeyStore, @@ -176,26 +237,29 @@ where K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, { - let loaded_details = _load_gateway_details(details_store).await?; - let loaded_keys = _load_managed_keys(key_store).await?; + let loaded_details = if let Some(gateway_id) = gateway_id { + _load_gateway_details(details_store, &gateway_id).await? + } else { + _load_active_gateway_details(details_store).await? + }; - ensure_valid_details(&loaded_details, &loaded_keys)?; + let loaded_keys = _load_client_keys(key_store).await?; // no need to persist anything as we got everything from the storage Ok(InitialisationResult::new_loaded( - loaded_details.into(), + loaded_details, loaded_keys, )) } fn reuse_gateway_connection( authenticated_ephemeral_client: InitGatewayClient, - gateway_details: GatewayDetails, - managed_keys: ManagedKeys, + gateway_registration: GatewayRegistration, + client_keys: KeyManager, ) -> InitialisationResult { InitialisationResult { - gateway_details, - managed_keys, + gateway_registration, + client_keys, authenticated_ephemeral_client: Some(authenticated_ephemeral_client), } } @@ -213,7 +277,9 @@ where { log::debug!("Setting up gateway"); match setup { - GatewaySetup::MustLoad => use_loaded_gateway_details(key_store, details_store).await, + GatewaySetup::MustLoad { gateway_id } => { + use_loaded_gateway_details(key_store, details_store, gateway_id).await + } GatewaySetup::New { specification, available_gateways, diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 9863fc7c07..563205eb22 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -1,24 +1,100 @@ -// Copyright 2023 - Nym Technologies SA +// Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::client::base_client::storage::gateway_details::{ - GatewayDetailsStore, PersistedCustomGatewayDetails, PersistedGatewayDetails, -}; use crate::client::key_manager::persistence::KeyStore; -use crate::client::key_manager::ManagedKeys; +use crate::client::key_manager::{KeyManager, ManagedKeys}; use crate::config::{Config, GatewayEndpointConfig}; use crate::error::ClientCoreError; -use crate::init::{_load_gateway_details, _load_managed_keys, setup_gateway}; +use crate::init::{setup_gateway, use_loaded_gateway_details}; +use nym_client_core_gateways_storage::{ + BadGateway, 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 std::fmt::Display; +use std::str::FromStr; use std::sync::Arc; +use time::OffsetDateTime; +use url::Url; + +pub enum SelectedGateway { + Remote { + gateway_id: identity::PublicKey, + + gateway_owner_address: AccountId, + + gateway_listener: Url, + }, + Custom { + gateway_id: identity::PublicKey, + additional_data: Option>, + }, +} + +impl SelectedGateway { + pub fn from_topology_node( + node: gateway::Node, + must_use_tls: bool, + ) -> Result { + let gateway_listener = if must_use_tls { + node.clients_address_tls() + .ok_or(ClientCoreError::UnsupportedWssProtocol { + gateway: node.identity_key.to_base58_string(), + })? + } else { + node.clients_address() + }; + + let gateway_owner_address = AccountId::from_str(&node.owner).map_err(|source| { + ClientCoreError::MalformedGatewayOwnerAccountAddress { + gateway_id: node.identity_key.to_base58_string(), + raw_owner: node.owner, + err: source.to_string(), + } + })?; + + let gateway_listener = + Url::parse(&gateway_listener).map_err(|source| ClientCoreError::MalformedListener { + gateway_id: node.identity_key.to_base58_string(), + raw_listener: gateway_listener, + source, + })?; + + Ok(SelectedGateway::Remote { + gateway_id: node.identity_key, + gateway_owner_address, + gateway_listener, + }) + } + + pub fn custom( + gateway_id: String, + additional_data: Option>, + ) -> Result { + let gateway_id = identity::PublicKey::from_base58_string(&gateway_id) + .map_err(|source| ClientCoreError::MalformedGatewayIdentity { gateway_id, source })?; + + Ok(SelectedGateway::Custom { + gateway_id, + additional_data, + }) + } + + pub fn gateway_id(&self) -> &identity::PublicKey { + match self { + SelectedGateway::Remote { gateway_id, .. } => gateway_id, + SelectedGateway::Custom { gateway_id, .. } => gateway_id, + } + } +} /// Result of registering with a gateway: /// - shared keys derived between ourselves and the node @@ -34,16 +110,16 @@ pub struct RegistrationResult { /// - an optional authenticated handle of an ephemeral gateway handle created for the purposes of registration, /// if this was the first time this client registered pub struct InitialisationResult { - pub gateway_details: GatewayDetails, - pub managed_keys: ManagedKeys, + pub gateway_registration: GatewayRegistration, + pub client_keys: KeyManager, pub authenticated_ephemeral_client: Option, } impl InitialisationResult { - pub fn new_loaded(gateway_details: GatewayDetails, managed_keys: ManagedKeys) -> Self { + pub fn new_loaded(gateway_registration: GatewayRegistration, client_keys: KeyManager) -> Self { InitialisationResult { - gateway_details, - managed_keys, + gateway_registration, + client_keys, authenticated_ephemeral_client: None, } } @@ -51,127 +127,106 @@ impl InitialisationResult { pub async fn try_load(key_store: &K, details_store: &D) -> Result where K: KeyStore, - D: GatewayDetailsStore, + D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, { - todo!() - // let loaded_details = _load_gateway_details(details_store).await?; - // let loaded_keys = _load_managed_keys(key_store).await?; - // - // match &loaded_details { - // PersistedGatewayDetails::Default(loaded_default) => { - // if !loaded_default.verify(&loaded_keys.must_get_gateway_shared_key()) { - // return Err(ClientCoreError::MismatchedGatewayDetails { - // gateway_id: loaded_default.details.gateway_id.clone(), - // }); - // } - // } - // PersistedGatewayDetails::Custom(_) => {} - // } - // - // Ok(InitialisationResult { - // gateway_details: loaded_details.into(), - // managed_keys: loaded_keys, - // authenticated_ephemeral_client: None, - // }) + use_loaded_gateway_details(key_store, details_store, None).await } - pub fn client_address(&self) -> Result { - let client_recipient = Recipient::new( - *self.managed_keys.identity_public_key(), - *self.managed_keys.encryption_public_key(), + pub fn client_address(&self) -> Recipient { + Recipient::new( + *self.client_keys.identity_keypair().public_key(), + *self.client_keys.encryption_keypair().public_key(), // TODO: below only works under assumption that gateway address == gateway id // (which currently is true) - NodeIdentity::from_base58_string(self.gateway_details.gateway_id())?, - ); - - Ok(client_recipient) - } -} - -/// 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, -} - -impl CustomGatewayDetails { - pub fn new(gateway_id: String, additional_data: Vec) -> 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 for GatewayDetails { - fn from(value: GatewayEndpointConfig) -> Self { - GatewayDetails::Configured(value) - } -} - -impl From for CustomGatewayDetails { - fn from(value: PersistedCustomGatewayDetails) -> Self { - CustomGatewayDetails { - gateway_id: value.gateway_id, - additional_data: value.additional_data, - } - } -} - -impl From for PersistedCustomGatewayDetails { - fn from(value: CustomGatewayDetails) -> Self { - PersistedCustomGatewayDetails { - gateway_id: value.gateway_id, - additional_data: value.additional_data, - } - } -} - -impl From for GatewayDetails { - fn from(value: PersistedGatewayDetails) -> Self { - match value { - PersistedGatewayDetails::Default(default) => { - GatewayDetails::Configured(default.details) - } - PersistedGatewayDetails::Custom(custom) => GatewayDetails::Custom(custom.into()), - } + self.gateway_registration.details.gateway_id(), + ) } } +// +// /// 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, +// } +// +// impl CustomGatewayDetails { +// pub fn new(gateway_id: String, additional_data: Vec) -> 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 for GatewayDetails { +// fn from(value: GatewayEndpointConfig) -> Self { +// GatewayDetails::Configured(value) +// } +// } +// +// impl From for CustomGatewayDetails { +// fn from(value: PersistedCustomGatewayDetails) -> Self { +// CustomGatewayDetails { +// gateway_id: value.gateway_id, +// additional_data: value.additional_data, +// } +// } +// } +// +// impl From for PersistedCustomGatewayDetails { +// fn from(value: CustomGatewayDetails) -> Self { +// PersistedCustomGatewayDetails { +// gateway_id: value.gateway_id, +// additional_data: value.additional_data, +// } +// } +// } +// +// impl From 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 { @@ -192,7 +247,7 @@ pub enum GatewaySelectionSpecification { /// This client has handled the selection by itself Custom { gateway_identity: String, - additional_data: Vec, + additional_data: Option>, }, } @@ -225,7 +280,10 @@ impl GatewaySelectionSpecification { pub enum GatewaySetup { /// The gateway specification (details + keys) MUST BE loaded from the underlying storage. - MustLoad, + MustLoad { + /// Optionally specify concrete gateway id. If none is selected, the current active gateway will be used. + gateway_id: Option, + }, /// Specifies usage of a new gateway New { @@ -243,23 +301,24 @@ pub enum GatewaySetup { authenticated_ephemeral_client: InitGatewayClient, // Details of this pre-initialised client (i.e. gateway and keys) - gateway_details: GatewayDetails, + gateway_details: GatewayRegistration, - managed_keys: ManagedKeys, + managed_keys: KeyManager, }, } impl GatewaySetup { pub fn try_reuse_connection(init_res: InitialisationResult) -> Result { - 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) - } + 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) + // } } pub async fn try_setup( @@ -269,7 +328,7 @@ impl GatewaySetup { ) -> Result where K: KeyStore, - D: GatewayDetailsStore, + D: GatewaysDetailsStore, K::StorageError: Send + Sync + 'static, D::StorageError: Send + Sync + 'static, { @@ -278,7 +337,7 @@ impl GatewaySetup { } pub fn is_must_load(&self) -> bool { - matches!(self, GatewaySetup::MustLoad) + matches!(self, GatewaySetup::MustLoad { .. }) } pub fn has_full_details(&self) -> bool { @@ -299,14 +358,19 @@ pub struct InitResults { } impl InitResults { - pub fn new(config: &Config, address: Recipient, gateway: &GatewayEndpointConfig) -> Self { + pub fn new( + config: &Config, + address: Recipient, + gateway: &RemoteGatewayDetails, + registration: OffsetDateTime, + ) -> Self { Self { version: config.client.version.clone(), id: config.client.id.clone(), identity_key: address.identity().to_base58_string(), encryption_key: address.encryption_key().to_base58_string(), - gateway_id: gateway.gateway_id.clone(), - gateway_listener: gateway.gateway_listener.clone(), + gateway_id: gateway.gateway_id.to_base58_string(), + gateway_listener: gateway.gateway_listener.to_string(), address, } } diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index 77d28ca2a7..2d7d4b9b57 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -32,6 +32,7 @@ use std::convert::TryFrom; use std::sync::Arc; use std::time::Duration; use tungstenite::protocol::Message; +use url::Url; #[cfg(unix)] use std::os::fd::RawFd; @@ -63,6 +64,20 @@ pub struct GatewayConfig { pub gateway_listener: String, } +impl GatewayConfig { + pub fn new( + gateway_identity: identity::PublicKey, + gateway_owner: Option, + gateway_listener: String, + ) -> Self { + GatewayConfig { + gateway_identity, + gateway_owner, + gateway_listener, + } + } +} + // TODO: this should be refactored into a state machine that keeps track of its authentication state pub struct GatewayClient { authenticated: bool, @@ -836,7 +851,11 @@ pub struct InitOnly; impl GatewayClient { // for initialisation we do not need credential storage. Though it's still a bit weird we have to set the generic... - pub fn new_init(config: GatewayConfig, local_identity: Arc) -> Self { + pub fn new_init( + gateway_listener: Url, + gateway_identity: identity::PublicKey, + local_identity: Arc, + ) -> Self { log::trace!("Initialising gateway client"); use futures::channel::mpsc; @@ -851,8 +870,8 @@ impl GatewayClient { authenticated: false, disabled_credentials_mode: true, bandwidth_remaining: 0, - gateway_address: config.gateway_listener, - gateway_identity: config.gateway_identity, + gateway_address: gateway_listener.to_string(), + gateway_identity, local_identity, shared_key: None, connection: SocketState::NotConnected, diff --git a/common/crypto/src/asymmetric/encryption/mod.rs b/common/crypto/src/asymmetric/encryption/mod.rs index bc97f67df4..5e095beeab 100644 --- a/common/crypto/src/asymmetric/encryption/mod.rs +++ b/common/crypto/src/asymmetric/encryption/mod.rs @@ -381,3 +381,18 @@ mod sphinx_key_conversion { } } } + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_zeroize_on_drop() {} + + fn assert_zeroize() {} + + #[test] + fn private_key_is_zeroized() { + assert_zeroize::(); + assert_zeroize_on_drop::(); + } +} diff --git a/common/crypto/src/asymmetric/identity/mod.rs b/common/crypto/src/asymmetric/identity/mod.rs index ffbcac88ac..7d1db5a8c1 100644 --- a/common/crypto/src/asymmetric/identity/mod.rs +++ b/common/crypto/src/asymmetric/identity/mod.rs @@ -359,3 +359,18 @@ impl<'d> Deserialize<'d> for Signature { Signature::from_bytes(bytes.as_ref()).map_err(SerdeError::custom) } } + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_zeroize_on_drop() {} + + fn assert_zeroize() {} + + #[test] + fn private_key_is_zeroized() { + assert_zeroize::(); + assert_zeroize_on_drop::(); + } +} diff --git a/common/nymsphinx/acknowledgements/src/key.rs b/common/nymsphinx/acknowledgements/src/key.rs index d3615c3718..869f713657 100644 --- a/common/nymsphinx/acknowledgements/src/key.rs +++ b/common/nymsphinx/acknowledgements/src/key.rs @@ -77,3 +77,18 @@ impl PemStorableKey for AckKey { Self::try_from_bytes(bytes) } } + +#[cfg(test)] +mod tests { + use super::*; + + fn assert_zeroize_on_drop() {} + + fn assert_zeroize() {} + + #[test] + fn ack_key_is_zeroized() { + assert_zeroize::(); + assert_zeroize_on_drop::(); + } +} From 1916adedcc73af0d9797767d586dfbcd59e744b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 16:53:27 +0000 Subject: [PATCH 11/56] socks5 client compiling but definitely not working yet --- clients/socks5/src/commands/init.rs | 2 +- clients/socks5/src/commands/mod.rs | 83 ++++++++++---- clients/socks5/src/config/mod.rs | 1 + .../socks5/src/config/old_config_v1_1_20.rs | 4 +- .../socks5/src/config/old_config_v1_1_20_2.rs | 3 +- .../socks5/src/config/old_config_v1_1_30.rs | 11 +- .../socks5/src/config/old_config_v1_1_33.rs | 49 ++++++++ .../src/client/base_client/storage/mod.rs | 2 +- common/socks5-client-core/src/config/mod.rs | 9 +- .../src/config/old_config_v1_1_30.rs | 16 +-- .../src/config/old_config_v1_1_33.rs | 107 ++++++++++++++++++ common/socks5-client-core/src/lib.rs | 4 +- 12 files changed, 243 insertions(+), 48 deletions(-) create mode 100644 clients/socks5/src/config/old_config_v1_1_33.rs create mode 100644 common/socks5-client-core/src/config/old_config_v1_1_33.rs diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index ce13a1b7cc..3bc5cd098a 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -118,7 +118,7 @@ impl InitResults { Self { client_address: res.init_results.address.to_string(), client_core: res.init_results, - socks5_listening_address: res.config.core.socks5.bind_adddress, + socks5_listening_address: res.config.core.socks5.bind_address, } } } diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index da3166fd7e..24a1112781 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -5,6 +5,7 @@ use crate::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::config::old_config_v1_1_20::ConfigV1_1_20; use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::config::old_config_v1_1_30::ConfigV1_1_30; +use crate::config::old_config_v1_1_33::ConfigV1_1_33; use crate::config::{BaseClientConfig, Config, SocksClientPaths}; use crate::error::Socks5ClientError; use clap::CommandFactory; @@ -172,21 +173,29 @@ fn persist_gateway_details( storage_paths: &SocksClientPaths, details: GatewayEndpointConfig, ) -> Result<(), Socks5ClientError> { - let details_store = OnDiskGatewayDetails::new(&storage_paths.common_paths.gateway_details); - let keys_store = OnDiskKeys::new(storage_paths.common_paths.keys.clone()); - let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError { - source: Box::new(source), - }) - })?; - let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - details_store - .store_to_disk(&persisted_details) - .map_err(|source| { - Socks5ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - }) - }) + todo!() + // let details_store = OnDiskGatewayDetails::new(&storage_paths.common_paths.gateway_details); + // let keys_store = OnDiskKeys::new(storage_paths.common_paths.keys.clone()); + // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { + // Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError { + // source: Box::new(source), + // }) + // })?; + // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; + // details_store + // .store_to_disk(&persisted_details) + // .map_err(|source| { + // Socks5ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { + // source: Box::new(source), + // }) + // }) +} + +fn migrate_gateway_details( + config: &Config, + old_details: Option, +) -> Result<(), Socks5ClientError> { + todo!() } fn try_upgrade_v1_1_13_config(id: &str) -> Result { @@ -204,9 +213,11 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; - persist_gateway_details(&updated_step3.storage_paths, gateway_config)?; + let updated_step4: ConfigV1_1_33 = updated_step3.into(); + let updated = updated_step4.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; - let updated: Config = updated_step3.into(); updated.save_to_default_location()?; Ok(true) } @@ -225,9 +236,11 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; - persist_gateway_details(&updated_step2.storage_paths, gateway_config)?; + let updated_step3: ConfigV1_1_33 = updated_step2.into(); + let updated = updated_step3.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; - let updated: Config = updated_step2.into(); updated.save_to_default_location()?; Ok(true) } @@ -243,9 +256,11 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let (updated_step1, gateway_config) = old_config.upgrade()?; - persist_gateway_details(&updated_step1.storage_paths, gateway_config)?; + let updated_step2: ConfigV1_1_33 = updated_step1.into(); + let updated = updated_step2.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; - let updated: Config = updated_step1.into(); updated.save_to_default_location()?; Ok(true) } @@ -260,7 +275,28 @@ fn try_upgrade_v1_1_30_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.30 config template."); info!("It is going to get updated to the current specification."); - let updated: Config = old_config.into(); + let updated_step1: ConfigV1_1_33 = old_config.into(); + let updated = updated_step1.try_upgrade()?; + migrate_gateway_details(&updated, None)?; + + updated.save_to_default_location()?; + Ok(true) +} + +fn try_upgrade_v1_1_33_config(id: &str) -> Result { + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) + let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.33 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + + migrate_gateway_details(&updated, None)?; + updated.save_to_default_location()?; Ok(true) } @@ -278,6 +314,9 @@ fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> { if try_upgrade_v1_1_30_config(id)? { return Ok(()); } + if try_upgrade_v1_1_33_config(id)? { + return Ok(()); + } Ok(()) } diff --git a/clients/socks5/src/config/mod.rs b/clients/socks5/src/config/mod.rs index 9df903e64b..2a04d6d66d 100644 --- a/clients/socks5/src/config/mod.rs +++ b/clients/socks5/src/config/mod.rs @@ -24,6 +24,7 @@ pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_30; +pub mod old_config_v1_1_33; mod persistence; mod template; diff --git a/clients/socks5/src/config/old_config_v1_1_20.rs b/clients/socks5/src/config/old_config_v1_1_20.rs index 4acc4fccbd..fbad434c68 100644 --- a/clients/socks5/src/config/old_config_v1_1_20.rs +++ b/clients/socks5/src/config/old_config_v1_1_20.rs @@ -5,8 +5,8 @@ use crate::config::old_config_v1_1_20_2::{ ConfigV1_1_20_2, CoreConfigV1_1_20_2, SocksClientPathsV1_1_20_2, }; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; +use nym_client_core::config::disk_persistence::old_v1_1_33::ClientKeysPathsV1_1_33; use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20; use nym_client_core::config::old_config_v1_1_20_2::ClientV1_1_20_2; use nym_config::legacy_helpers::nym_config::MigrationNymConfig; @@ -50,7 +50,7 @@ impl From for ConfigV1_1_20_2 { }, storage_paths: SocksClientPathsV1_1_20_2 { common_paths: CommonClientPathsV1_1_20_2 { - keys: ClientKeysPaths { + keys: ClientKeysPathsV1_1_33 { private_identity_key_file: value.base.client.private_identity_key_file, public_identity_key_file: value.base.client.public_identity_key_file, private_encryption_key_file: value.base.client.private_encryption_key_file, diff --git a/clients/socks5/src/config/old_config_v1_1_20_2.rs b/clients/socks5/src/config/old_config_v1_1_20_2.rs index 4668e3ea9d..d396082e68 100644 --- a/clients/socks5/src/config/old_config_v1_1_20_2.rs +++ b/clients/socks5/src/config/old_config_v1_1_20_2.rs @@ -14,6 +14,7 @@ use serde::{Deserialize, Serialize}; use std::io; use std::path::Path; +use crate::config::old_config_v1_1_33::SocksClientPathsV1_1_33; pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2; #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] @@ -47,7 +48,7 @@ impl ConfigV1_1_20_2 { let gateway_details = self.core.base.client.gateway_endpoint.clone().into(); let config = ConfigV1_1_30 { core: self.core.into(), - storage_paths: SocksClientPaths { + storage_paths: SocksClientPathsV1_1_33 { common_paths: self.storage_paths.common_paths.upgrade_default()?, }, logging: self.logging, diff --git a/clients/socks5/src/config/old_config_v1_1_30.rs b/clients/socks5/src/config/old_config_v1_1_30.rs index cd7a5ab9e4..7395891dc3 100644 --- a/clients/socks5/src/config/old_config_v1_1_30.rs +++ b/clients/socks5/src/config/old_config_v1_1_30.rs @@ -1,7 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::persistence::SocksClientPaths; +use crate::config::old_config_v1_1_33::{ConfigV1_1_33, SocksClientPathsV1_1_33}; use crate::config::{default_config_filepath, Config}; use nym_bin_common::logging::LoggingSettings; use nym_config::read_config_from_toml_file; @@ -15,17 +15,14 @@ use std::path::Path; pub struct ConfigV1_1_30 { pub core: CoreConfigV1_1_30, - // I'm leaving a landmine here for when the paths actually do change the next time, - // but propagating the change right now (in ALL clients) would be such a hassle..., - // so sorry for the next person looking at it : ) - pub storage_paths: SocksClientPaths, + pub storage_paths: SocksClientPathsV1_1_33, pub logging: LoggingSettings, } -impl From for Config { +impl From for ConfigV1_1_33 { fn from(value: ConfigV1_1_30) -> Self { - Config { + ConfigV1_1_33 { core: value.core.into(), storage_paths: value.storage_paths, logging: LoggingSettings::default(), diff --git a/clients/socks5/src/config/old_config_v1_1_33.rs b/clients/socks5/src/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..fb14259bf4 --- /dev/null +++ b/clients/socks5/src/config/old_config_v1_1_33.rs @@ -0,0 +1,49 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::{default_config_filepath, Config, SocksClientPaths}; +use crate::error::Socks5ClientError; +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; +use nym_config::read_config_from_toml_file; +use nym_socks5_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as CoreConfigV1_1_33; +use serde::{Deserialize, Serialize}; +use std::io; +use std::path::Path; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct SocksClientPathsV1_1_33 { + #[serde(flatten)] + pub common_paths: CommonClientPathsV1_1_33, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_33 { + pub core: CoreConfigV1_1_33, + + // \/ CHANGED + pub storage_paths: SocksClientPathsV1_1_33, + // /\ CHANGED + pub logging: LoggingSettings, +} + +impl ConfigV1_1_33 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + core: self.core.into(), + storage_paths: SocksClientPaths { + common_paths: self.storage_paths.common_paths.upgrade_default()?, + }, + logging: self.logging, + }) + } +} diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 86180b99eb..f31370a30d 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -10,7 +10,6 @@ use crate::client::key_manager::persistence::{InMemEphemeralKeys, KeyStore}; use crate::client::replies::reply_storage; use crate::client::replies::reply_storage::ReplyStorageBackend; -use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; use nym_credential_storage::storage::Storage as CredentialStorage; @@ -34,6 +33,7 @@ use crate::error::ClientCoreError; 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; diff --git a/common/socks5-client-core/src/config/mod.rs b/common/socks5-client-core/src/config/mod.rs index 8c5c722093..e4b3a8b623 100644 --- a/common/socks5-client-core/src/config/mod.rs +++ b/common/socks5-client-core/src/config/mod.rs @@ -12,6 +12,7 @@ use std::str::FromStr; pub mod old_config_v1_1_20_2; pub mod old_config_v1_1_30; +pub mod old_config_v1_1_33; pub use nym_service_providers_common::interface::ProviderInterfaceVersion; pub use nym_socks5_requests::Socks5ProtocolVersion; @@ -47,13 +48,13 @@ impl Config { #[must_use] pub fn with_port(mut self, port: u16) -> Self { - self.socks5.bind_adddress = SocketAddr::new(self.socks5.bind_adddress.ip(), port); + self.socks5.bind_address = SocketAddr::new(self.socks5.bind_address.ip(), port); self } #[must_use] pub fn with_ip(mut self, ip: IpAddr) -> Self { - self.socks5.bind_adddress = SocketAddr::new(ip, self.socks5.bind_adddress.port()); + self.socks5.bind_address = SocketAddr::new(ip, self.socks5.bind_address.port()); self } @@ -112,7 +113,7 @@ impl Config { pub struct Socks5 { /// The address on which the client will be listening for incoming requests /// (default: 127.0.0.1:1080) - pub bind_adddress: SocketAddr, + pub bind_address: SocketAddr, /// The mix address of the provider to which all requests are going to be sent. pub provider_mix_address: String, @@ -141,7 +142,7 @@ pub struct Socks5 { impl Socks5 { pub fn new>(provider_mix_address: S) -> Self { Socks5 { - bind_adddress: SocketAddr::new( + bind_address: SocketAddr::new( IpAddr::V4(Ipv4Addr::LOCALHOST), DEFAULT_SOCKS5_LISTENING_PORT, ), diff --git a/common/socks5-client-core/src/config/old_config_v1_1_30.rs b/common/socks5-client-core/src/config/old_config_v1_1_30.rs index 3f3f877797..13591f7d9a 100644 --- a/common/socks5-client-core/src/config/old_config_v1_1_30.rs +++ b/common/socks5-client-core/src/config/old_config_v1_1_30.rs @@ -1,7 +1,7 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use super::{Config, Socks5, Socks5Debug}; +use super::old_config_v1_1_33::{ConfigV1_1_33, Socks5DebugV1_1_33, Socks5V1_1_33}; pub use nym_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as BaseClientConfigV1_1_30; use serde::{Deserialize, Serialize}; use std::fmt::Debug; @@ -23,9 +23,9 @@ pub struct ConfigV1_1_30 { pub socks5: Socks5V1_1_30, } -impl From for Config { +impl From for ConfigV1_1_33 { fn from(value: ConfigV1_1_30) -> Self { - Config { + ConfigV1_1_33 { base: value.base.into(), socks5: value.socks5.into(), } @@ -62,11 +62,11 @@ pub struct Socks5V1_1_30 { pub socks5_debug: Socks5DebugV1_1_30, } -impl From for Socks5 { +impl From for Socks5V1_1_33 { fn from(value: Socks5V1_1_30) -> Self { - Socks5 { + Socks5V1_1_33 { // in <= 1.1.30 the address was hardcoded to 127.0.0.1 - bind_adddress: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), value.listening_port), + bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), value.listening_port), provider_mix_address: value.provider_mix_address, provider_interface_version: value.provider_interface_version, socks5_protocol_version: value.socks5_protocol_version, @@ -86,9 +86,9 @@ pub struct Socks5DebugV1_1_30 { pub per_request_surbs: u32, } -impl From for Socks5Debug { +impl From for Socks5DebugV1_1_33 { fn from(value: Socks5DebugV1_1_30) -> Self { - Socks5Debug { + Socks5DebugV1_1_33 { connection_start_surbs: value.connection_start_surbs, per_request_surbs: value.per_request_surbs, } diff --git a/common/socks5-client-core/src/config/old_config_v1_1_33.rs b/common/socks5-client-core/src/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..c306d42888 --- /dev/null +++ b/common/socks5-client-core/src/config/old_config_v1_1_33.rs @@ -0,0 +1,107 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use super::{Config, Socks5, Socks5Debug}; +pub use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseClientConfigV1_1_33; +use serde::{Deserialize, Serialize}; +use std::fmt::Debug; +use std::net::SocketAddr; + +// TODO: those should really be redefined here in case we change them... +use nym_service_providers_common::interface::ProviderInterfaceVersion; +use nym_socks5_requests::Socks5ProtocolVersion; + +const DEFAULT_CONNECTION_START_SURBS: u32 = 20; +const DEFAULT_PER_REQUEST_SURBS: u32 = 3; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_33 { + #[serde(flatten)] + pub base: BaseClientConfigV1_1_33, + + pub socks5: Socks5V1_1_33, +} + +impl From for Config { + fn from(value: ConfigV1_1_33) -> Self { + Config { + base: value.base.into(), + socks5: value.socks5.into(), + } + } +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct Socks5V1_1_33 { + /// The address on which the client will be listening for incoming requests + /// (default: 127.0.0.1:1080) + // there was a typo in here, so accept the wrong name for the purposes of backwards compatibility + #[serde(alias = "bind_adddress")] + pub bind_address: SocketAddr, + + /// The mix address of the provider to which all requests are going to be sent. + pub provider_mix_address: String, + + /// The version of the 'service provider' this client is going to use in its communication with the + /// specified socks5 provider. + // if in doubt, use the legacy version as initially nobody will be using the updated binaries + #[serde(default)] + pub provider_interface_version: ProviderInterfaceVersion, + + #[serde(default)] + pub socks5_protocol_version: Socks5ProtocolVersion, + + /// Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. + /// While this is going to hide its actual address information, it will make the actual communication + /// slower and consume nearly double the bandwidth as it will require sending reply SURBs. + /// + /// Note that some service providers might not support this. + #[serde(default)] + pub send_anonymously: bool, + + #[serde(default)] + pub socks5_debug: Socks5DebugV1_1_33, +} + +impl From for Socks5 { + fn from(value: Socks5V1_1_33) -> Self { + Socks5 { + bind_address: value.bind_address, + provider_mix_address: value.provider_mix_address, + provider_interface_version: value.provider_interface_version, + socks5_protocol_version: value.socks5_protocol_version, + send_anonymously: value.send_anonymously, + socks5_debug: value.socks5_debug.into(), + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct Socks5DebugV1_1_33 { + /// Number of reply SURBs attached to each `Request::Connect` message. + pub connection_start_surbs: u32, + + /// Number of reply SURBs attached to each `Request::Send` message. + pub per_request_surbs: u32, +} + +impl From for Socks5Debug { + fn from(value: Socks5DebugV1_1_33) -> Self { + Socks5Debug { + connection_start_surbs: value.connection_start_surbs, + per_request_surbs: value.per_request_surbs, + } + } +} + +impl Default for Socks5DebugV1_1_33 { + fn default() -> Self { + Socks5DebugV1_1_33 { + connection_start_surbs: DEFAULT_CONNECTION_START_SURBS, + per_request_surbs: DEFAULT_PER_REQUEST_SURBS, + } + } +} diff --git a/common/socks5-client-core/src/lib.rs b/common/socks5-client-core/src/lib.rs index d9d036d1a8..41a7105dad 100644 --- a/common/socks5-client-core/src/lib.rs +++ b/common/socks5-client-core/src/lib.rs @@ -78,7 +78,7 @@ where NymClient { config, storage, - setup_method: GatewaySetup::MustLoad, + setup_method: GatewaySetup::MustLoad { gateway_id: None }, custom_mixnet, } } @@ -124,7 +124,7 @@ where let authenticator = Authenticator::new(auth_methods, allowed_users); let mut sphinx_socks = NymSocksServer::new( - socks5_config.bind_adddress, + socks5_config.bind_address, authenticator, socks5_config.get_provider_mix_address(), self_address, From cdc49e074981ffed415b67a65621bd0e57f0eead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 16:57:51 +0000 Subject: [PATCH 12/56] ibid for rust sdk --- sdk/rust/nym-sdk/src/mixnet/client.rs | 4 ++-- sdk/rust/nym-sdk/src/mixnet/paths.rs | 19 ++----------------- sdk/rust/nym-sdk/src/mixnet/socks5_client.rs | 2 +- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index c075acdfef..bba70e96a1 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -414,7 +414,7 @@ where } /// Client keys are generated at client creation if none were found. The gateway shared - /// key, however, is created during the gateway registration handshake so it might not + /// key, however, is created during the gateway registration handshake, so it might not /// necessarily be available. /// Furthermore, it has to be coupled with particular gateway's config. async fn has_valid_gateway_info(&self) -> bool { @@ -466,7 +466,7 @@ where let api_endpoints = self.get_api_endpoints(); let gateway_setup = if self.has_valid_gateway_info().await { - GatewaySetup::MustLoad + GatewaySetup::MustLoad { gateway_id: None } } else { let selection_spec = GatewaySelectionSpecification::new( self.config.user_chosen_gateway.clone(), diff --git a/sdk/rust/nym-sdk/src/mixnet/paths.rs b/sdk/rust/nym-sdk/src/mixnet/paths.rs index 88ae655d6a..8051b49350 100644 --- a/sdk/rust/nym-sdk/src/mixnet/paths.rs +++ b/sdk/rust/nym-sdk/src/mixnet/paths.rs @@ -1,8 +1,7 @@ -// Copyright 2022-2023 - Nym Technologies SA +// Copyright 2022-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::error::{Error, Result}; -use nym_client_core::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; use nym_client_core::client::base_client::storage::OnDiskGatewaysDetails; use nym_client_core::client::base_client::{non_wasm_helpers, storage}; use nym_client_core::client::key_manager::persistence::OnDiskKeys; @@ -32,20 +31,13 @@ pub struct StoragePaths { /// Key for handling acks pub ack_key: PathBuf, - /// Key setup after authenticating with a gateway - #[deprecated] - pub gateway_shared_key: PathBuf, - /// The database containing credentials pub credential_database_path: PathBuf, /// The database storing reply surbs in-between sessions pub reply_surb_database_path: PathBuf, - /// Details of the used gateway - #[deprecated] - pub gateway_details_path: PathBuf, - + /// Details of the used gateways pub gateway_registrations: PathBuf, } @@ -68,10 +60,8 @@ impl StoragePaths { private_encryption: dir.join("private_encryption.pem"), public_encryption: dir.join("public_encryption.pem"), ack_key: dir.join("ack_key.pem"), - gateway_shared_key: dir.join("gateway_shared.pem"), credential_database_path: dir.join("db.sqlite"), reply_surb_database_path: dir.join("persistent_reply_store.sqlite"), - gateway_details_path: dir.join("gateway_details.json"), gateway_registrations: dir.join("gateways_registrations.sqlite"), }) } @@ -145,7 +135,6 @@ impl StoragePaths { public_identity_key_file: self.public_identity.clone(), private_encryption_key_file: self.private_encryption.clone(), public_encryption_key_file: self.public_encryption.clone(), - gateway_shared_key_file: self.gateway_shared_key.clone(), ack_key_file: self.ack_key.clone(), } } @@ -159,10 +148,8 @@ impl From for CommonClientPaths { public_identity_key_file: value.public_identity, private_encryption_key_file: value.private_encryption, public_encryption_key_file: value.public_encryption, - gateway_shared_key_file: value.gateway_shared_key, ack_key_file: value.ack_key, }, - gateway_details: value.gateway_details_path, gateway_registrations: value.gateway_registrations, credentials_database: value.credential_database_path, reply_surb_database: value.reply_surb_database_path, @@ -178,10 +165,8 @@ impl From for StoragePaths { private_encryption: value.keys.private_encryption_key_file, public_encryption: value.keys.public_encryption_key_file, ack_key: value.keys.ack_key_file, - gateway_shared_key: value.keys.gateway_shared_key_file, credential_database_path: value.credentials_database, reply_surb_database_path: value.reply_surb_database, - gateway_details_path: value.gateway_details, gateway_registrations: value.gateway_registrations, } } diff --git a/sdk/rust/nym-sdk/src/mixnet/socks5_client.rs b/sdk/rust/nym-sdk/src/mixnet/socks5_client.rs index ab340447f9..6bc2a46a06 100644 --- a/sdk/rust/nym-sdk/src/mixnet/socks5_client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/socks5_client.rs @@ -56,7 +56,7 @@ impl Socks5MixnetClient { /// Get the SOCKS5 proxy URL that a HTTP(S) client can connect to. pub fn socks5_url(&self) -> String { - format!("socks5h://{}", self.socks5_config.bind_adddress) + format!("socks5h://{}", self.socks5_config.bind_address) } /// Get a shallow clone of [`LaneQueueLengths`]. This is useful to manually implement some form From 337d53b2ecc41badb94893aee31230726122fb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 17:18:38 +0000 Subject: [PATCH 13/56] ibid for network requester --- .../network-requester/src/cli/mod.rs | 84 ++++++++--- .../network-requester/src/config/mod.rs | 1 + .../src/config/old_config_v1_1_20.rs | 3 +- .../src/config/old_config_v1_1_20_2.rs | 24 ++- .../src/config/old_config_v1_1_33.rs | 139 ++++++++++++++++++ .../src/config/persistence.rs | 2 - .../network-requester/src/lib.rs | 5 +- 7 files changed, 215 insertions(+), 43 deletions(-) create mode 100644 service-providers/network-requester/src/config/old_config_v1_1_33.rs diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index cd5e84071e..fb0b8699f3 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -4,6 +4,7 @@ use crate::config::old_config_v1_1_13::OldConfigV1_1_13; use crate::config::old_config_v1_1_20::ConfigV1_1_20; use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; +use crate::config::old_config_v1_1_33::ConfigV1_1_33; use crate::{ config::{BaseClientConfig, Config}, error::NetworkRequesterError, @@ -170,22 +171,34 @@ fn persist_gateway_details( config: &Config, details: GatewayEndpointConfig, ) -> Result<(), NetworkRequesterError> { - let details_store = - OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - NetworkRequesterError::ClientCoreError(ClientCoreError::KeyStoreError { - source: Box::new(source), - }) - })?; - let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - details_store - .store_to_disk(&persisted_details) - .map_err(|source| { - NetworkRequesterError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - }) - }) + todo!() + // let details_store = + // OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); + // let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); + // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { + // NetworkRequesterError::ClientCoreError(ClientCoreError::KeyStoreError { + // source: Box::new(source), + // }) + // })?; + // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; + // details_store + // .store_to_disk(&persisted_details) + // .map_err(|source| { + // NetworkRequesterError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { + // source: Box::new(source), + // }) + // }) +} + +fn migrate_gateway_details( + config: &Config, + old_details: Option, +) -> Result<(), NetworkRequesterError> { + todo!() +} + +fn extract_gateway_details(config: &ConfigV1_1_33) -> Result<(), NetworkRequesterError> { + todo!() } fn try_upgrade_v1_1_13_config(id: &str) -> Result { @@ -203,8 +216,10 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); - let (updated, gateway_config) = updated_step2.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let updated = updated_step3.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; updated.save_to_default_location()?; Ok(true) @@ -225,8 +240,10 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let updated_step1: ConfigV1_1_20_2 = old_config.into(); - let (updated, gateway_config) = updated_step1.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let updated = updated_step2.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; updated.save_to_default_location()?; Ok(true) @@ -244,8 +261,28 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result info!("It seems the client is using <= v1.1.20_2 config template."); info!("It is going to get updated to the current specification."); - let (updated, gateway_config) = old_config.upgrade()?; - persist_gateway_details(&updated, gateway_config)?; + let (updated_step1, gateway_config) = old_config.upgrade()?; + let updated = updated_step1.try_upgrade()?; + + migrate_gateway_details(&updated, Some(gateway_config))?; + + updated.save_to_default_location()?; + Ok(true) +} + +fn try_upgrade_v1_1_33_config(id: &str) -> Result { + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) + let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.33 config template."); + info!("It is going to get updated to the current specification."); + + let updated = old_config.try_upgrade()?; + + migrate_gateway_details(&updated, None)?; updated.save_to_default_location()?; Ok(true) @@ -262,6 +299,9 @@ fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> { if try_upgrade_v1_1_20_2_config(id)? { return Ok(()); } + if try_upgrade_v1_1_33_config(id)? { + return Ok(()); + } Ok(()) } diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index bce2d5effa..72a51d6edc 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -28,6 +28,7 @@ pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; mod persistence; mod template; +pub mod old_config_v1_1_33; const DEFAULT_NETWORK_REQUESTERS_DIR: &str = "network-requester"; diff --git a/service-providers/network-requester/src/config/old_config_v1_1_20.rs b/service-providers/network-requester/src/config/old_config_v1_1_20.rs index a3ab8c6610..42d82646fa 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_20.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_20.rs @@ -6,6 +6,7 @@ use crate::config::old_config_v1_1_20_2::{ }; use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; +use nym_client_core::config::disk_persistence::old_v1_1_33::ClientKeysPathsV1_1_33; use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20; use nym_client_core::config::old_config_v1_1_20_2::{ ClientV1_1_20_2, ConfigV1_1_20_2 as BaseClientConfigV1_1_20_2, @@ -47,7 +48,7 @@ impl From for ConfigV1_1_20_2 { network_requester: Default::default(), storage_paths: NetworkRequesterPathsV1_1_20_2 { common_paths: CommonClientPathsV1_1_20_2 { - keys: ClientKeysPaths { + keys: ClientKeysPathsV1_1_33 { private_identity_key_file: value.base.client.private_identity_key_file, public_identity_key_file: value.base.client.public_identity_key_file, private_encryption_key_file: value.base.client.private_encryption_key_file, diff --git a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs index 2263bfd42a..6c9d3e0255 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs @@ -1,14 +1,10 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::{ - config::{ - default_config_filepath, persistence::NetworkRequesterPaths, Config, Debug, - NetworkRequester, - }, - error::NetworkRequesterError, +use super::old_config_v1_1_33::{ + ConfigV1_1_33, DebugV1_1_33, NetworkRequesterPathsV1_1_33, NetworkRequesterV1_1_33, }; - +use crate::{config::default_config_filepath, error::NetworkRequesterError}; use log::trace; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; @@ -65,7 +61,7 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(Config, GatewayEndpointConfig), NetworkRequesterError> { + pub fn upgrade(self) -> Result<(ConfigV1_1_33, GatewayEndpointConfig), NetworkRequesterError> { trace!("Upgrading from v1.1.20_2"); let gateway_details = self.base.client.gateway_endpoint.clone().into(); let nr_description = self @@ -76,9 +72,9 @@ impl ConfigV1_1_20_2 { .parent() .expect("config paths upgrade failure") .join(DEFAULT_DESCRIPTION_FILENAME); - let config = Config { + let config = ConfigV1_1_33 { base: BaseConfigV1_1_30::from(self.base).into(), - storage_paths: NetworkRequesterPaths { + storage_paths: NetworkRequesterPathsV1_1_33 { common_paths: self.storage_paths.common_paths.upgrade_default()?, allowed_list_location: self.storage_paths.allowed_list_location, unknown_list_location: self.storage_paths.unknown_list_location, @@ -97,9 +93,9 @@ impl ConfigV1_1_20_2 { #[serde(default, deny_unknown_fields)] pub struct NetworkRequesterV1_1_20_2 {} -impl From for NetworkRequester { +impl From for NetworkRequesterV1_1_33 { fn from(_value: NetworkRequesterV1_1_20_2) -> Self { - NetworkRequester::default() + NetworkRequesterV1_1_33::default() } } @@ -111,9 +107,9 @@ pub struct DebugV1_1_20_2 { pub standard_list_update_interval: Duration, } -impl From for Debug { +impl From for DebugV1_1_33 { fn from(value: DebugV1_1_20_2) -> Self { - Debug { + DebugV1_1_33 { standard_list_update_interval: value.standard_list_update_interval, } } diff --git a/service-providers/network-requester/src/config/old_config_v1_1_33.rs b/service-providers/network-requester/src/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..b49bb514d1 --- /dev/null +++ b/service-providers/network-requester/src/config/old_config_v1_1_33.rs @@ -0,0 +1,139 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::persistence::NetworkRequesterPaths; +use crate::config::Config; +use crate::config::{default_config_filepath, Debug, NetworkRequester}; +use crate::error::NetworkRequesterError; +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; +use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseConfigV1_1_33; +use nym_config::read_config_from_toml_file; +use nym_config::serde_helpers::de_maybe_stringified; +use serde::{Deserialize, Serialize}; +use std::io; +use std::path::{Path, PathBuf}; +use std::time::Duration; +use url::Url; + +pub const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60); + +#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] +pub struct NetworkRequesterPathsV1_1_33 { + #[serde(flatten)] + pub common_paths: CommonClientPathsV1_1_33, + + /// Location of the file containing our allow.list + pub allowed_list_location: PathBuf, + + /// Location of the file containing our unknown.list + pub unknown_list_location: PathBuf, + + #[serde(default)] + pub nr_description: PathBuf, +} + +#[derive(Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_33 { + pub base: BaseConfigV1_1_33, + + #[serde(default)] + pub network_requester: NetworkRequesterV1_1_33, + + pub storage_paths: NetworkRequesterPathsV1_1_33, + + #[serde(default)] + pub network_requester_debug: DebugV1_1_33, + + pub logging: LoggingSettings, +} + +impl ConfigV1_1_33 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + network_requester: self.network_requester.into(), + storage_paths: NetworkRequesterPaths { + common_paths: self.storage_paths.common_paths.upgrade_default()?, + allowed_list_location: self.storage_paths.allowed_list_location, + unknown_list_location: self.storage_paths.unknown_list_location, + nr_description: self.storage_paths.nr_description, + }, + network_requester_debug: self.network_requester_debug.into(), + logging: self.logging, + }) + } +} + +#[derive(Debug, Default, Clone, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct NetworkRequesterV1_1_33 { + /// specifies whether this network requester should run in 'open-proxy' mode + /// and thus would attempt to resolve **ANY** request it receives. + pub open_proxy: bool, + + /// specifies whether this network requester would send anonymized statistics to a statistics aggregator server + pub enabled_statistics: bool, + + /// in case of enabled statistics, specifies mixnet client address where a statistics aggregator is running + pub statistics_recipient: Option, + + /// Disable Poisson sending rate. + /// This is equivalent to setting debug.traffic.disable_main_poisson_packet_distribution = true, + pub disable_poisson_rate: bool, + + /// Specifies whether this network requester should be using the deprecated allow-list, + /// as opposed to the new ExitPolicy. + /// Note: this field will be removed in a near future. + pub use_deprecated_allow_list: bool, + + /// Specifies the url for an upstream source of the exit policy used by this node. + #[serde(deserialize_with = "de_maybe_stringified")] + pub upstream_exit_policy_url: Option, +} + +impl From for NetworkRequester { + fn from(value: NetworkRequesterV1_1_33) -> Self { + NetworkRequester { + open_proxy: value.open_proxy, + enabled_statistics: value.enabled_statistics, + statistics_recipient: value.statistics_recipient, + disable_poisson_rate: value.disable_poisson_rate, + use_deprecated_allow_list: value.use_deprecated_allow_list, + upstream_exit_policy_url: value.upstream_exit_policy_url, + } + } +} + +#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct DebugV1_1_33 { + /// Defines how often the standard allow list should get updated + #[serde(with = "humantime_serde")] + pub standard_list_update_interval: Duration, +} + +impl From for Debug { + fn from(value: DebugV1_1_33) -> Self { + Debug { + standard_list_update_interval: value.standard_list_update_interval, + } + } +} + +impl Default for DebugV1_1_33 { + fn default() -> Self { + DebugV1_1_33 { + standard_list_update_interval: DEFAULT_STANDARD_LIST_UPDATE_INTERVAL, + } + } +} diff --git a/service-providers/network-requester/src/config/persistence.rs b/service-providers/network-requester/src/config/persistence.rs index 242562c1c7..cc3d4378ba 100644 --- a/service-providers/network-requester/src/config/persistence.rs +++ b/service-providers/network-requester/src/config/persistence.rs @@ -23,8 +23,6 @@ pub struct NetworkRequesterPaths { pub unknown_list_location: PathBuf, /// Location of the file containing our description - // For upgrade use default if missing. On next config upgrade iteration, remove the serde(default) - #[serde(default)] pub nr_description: PathBuf, } diff --git a/service-providers/network-requester/src/lib.rs b/service-providers/network-requester/src/lib.rs index f8d783b13d..01bdaf3a42 100644 --- a/service-providers/network-requester/src/lib.rs +++ b/service-providers/network-requester/src/lib.rs @@ -22,10 +22,7 @@ pub use nym_client_core::{ }, init::{ setup_gateway, - types::{ - CustomGatewayDetails, GatewayDetails, GatewaySelectionSpecification, GatewaySetup, - InitResults, InitialisationResult, - }, + types::{GatewaySelectionSpecification, GatewaySetup, InitResults, InitialisationResult}, }, }; pub use request_filter::RequestFilter; From daa5f016832d40fd4ce22d81c9b77ba7ab2513d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 6 Mar 2024 17:24:49 +0000 Subject: [PATCH 14/56] further compilation fixes --- common/client-core/src/lib.rs | 5 +++++ gateway/src/commands/helpers.rs | 4 ++-- sdk/lib/socks5-listener/src/persistence.rs | 7 +++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/common/client-core/src/lib.rs b/common/client-core/src/lib.rs index 1eb90ddcf7..8c84737049 100644 --- a/common/client-core/src/lib.rs +++ b/common/client-core/src/lib.rs @@ -32,3 +32,8 @@ where { tokio::spawn(future); } + +fn unused_function() { + let with_unused_variable = 42; + todo!("update all client config templates after changes stabilise") +} diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index 956c78834f..8ea29169f2 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -293,7 +293,7 @@ pub(crate) async fn initialise_local_network_requester( ) .await?; - let address = init_res.client_address()?; + let address = init_res.client_address(); if let Err(err) = save_formatted_config_to_file(&nr_cfg, nr_cfg_path) { log::error!("Failed to save the network requester config file: {err}"); @@ -366,7 +366,7 @@ pub(crate) async fn initialise_local_ip_packet_router( ) .await?; - let address = init_res.client_address()?; + let address = init_res.client_address(); if let Err(err) = save_formatted_config_to_file(&ip_cfg, ip_cfg_path) { log::error!("Failed to save the ip packet router config file: {err}"); diff --git a/sdk/lib/socks5-listener/src/persistence.rs b/sdk/lib/socks5-listener/src/persistence.rs index 93916feb42..9ee4990e6c 100644 --- a/sdk/lib/socks5-listener/src/persistence.rs +++ b/sdk/lib/socks5-listener/src/persistence.rs @@ -2,8 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::Config; -use nym_client_core::client::base_client::storage::gateway_details::InMemGatewayDetails; -use nym_client_core::client::base_client::storage::MixnetClientStorage; +use nym_client_core::client::base_client::storage::{InMemGatewaysDetails, MixnetClientStorage}; use nym_client_core::client::key_manager::persistence::InMemEphemeralKeys; use nym_client_core::client::replies::reply_storage; use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage; @@ -11,7 +10,7 @@ use nym_credential_storage::ephemeral_storage::EphemeralStorage as EphemeralCred pub struct MobileClientStorage { // the key storage is now useless without gateway details store. so use ephemeral for everything. key_store: InMemEphemeralKeys, - gateway_details_store: InMemGatewayDetails, + gateway_details_store: InMemGatewaysDetails, reply_store: reply_storage::Empty, credential_store: EphemeralCredentialStorage, @@ -21,7 +20,7 @@ impl MixnetClientStorage for MobileClientStorage { type KeyStore = InMemEphemeralKeys; type ReplyStore = reply_storage::Empty; type CredentialStore = EphemeralCredentialStorage; - type GatewaysDetailsStore = InMemGatewayDetails; + type GatewaysDetailsStore = InMemGatewaysDetails; fn into_runtime_stores(self) -> (Self::ReplyStore, Self::CredentialStore) { (self.reply_store, self.credential_store) From c0ae924c585be158bd2af4101a53928fc0f2a868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 10:10:40 +0000 Subject: [PATCH 15/56] move storage helpers --- .../src/backend/fs_backend/mod.rs | 2 +- .../src/backend/mem_backend.rs | 2 +- .../client-core/gateways-storage/src/lib.rs | 2 +- .../src/cli_helpers/client_init.rs | 42 ++++--- .../client/base_client/non_wasm_helpers.rs | 2 +- .../src/client/base_client/storage/helpers.rs | 101 ++++++++++++++++ .../src/client/base_client/storage/mod.rs | 1 + common/client-core/src/error.rs | 4 +- common/client-core/src/init/mod.rs | 113 +++--------------- .../desktop/src-tauri/src/config/upgrade.rs | 2 +- .../ip-packet-router/src/cli/mod.rs | 2 +- 11 files changed, 154 insertions(+), 119 deletions(-) create mode 100644 common/client-core/src/client/base_client/storage/helpers.rs diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 8aa5c3ff9d..c447d407e2 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -50,7 +50,7 @@ impl GatewaysDetailsStore for OnDiskGatewaysDetails { async fn store_gateway_details( &self, - details: GatewayDetails, + details: &GatewayRegistration, ) -> Result<(), Self::StorageError> { todo!() } diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 003284622e..092772c9f0 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -66,7 +66,7 @@ impl GatewaysDetailsStore for InMemGatewaysDetails { async fn store_gateway_details( &self, - details: GatewayDetails, + details: &GatewayRegistration, ) -> Result<(), Self::StorageError> { todo!() } diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 0c11b51f52..7416abfc90 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -48,7 +48,7 @@ pub trait GatewaysDetailsStore { /// Store the provided gateway details. async fn store_gateway_details( &self, - details: GatewayDetails, + details: &GatewayRegistration, ) -> Result<(), Self::StorageError>; /// Remove given gateway details from the underlying store. diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 9c93cd1729..a75573b3eb 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -5,7 +5,9 @@ use crate::config::disk_persistence::CommonClientPaths; use crate::error::ClientCoreError; use crate::{ client::{ - base_client::non_wasm_helpers::setup_fs_gateways_storage, + base_client::{ + non_wasm_helpers::setup_fs_gateways_storage, storage::helpers::set_active_gateway, + }, key_manager::persistence::OnDiskKeys, }, init::types::{GatewaySelectionSpecification, GatewaySetup, InitResults}, @@ -203,7 +205,8 @@ where crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? }; - todo!("remove registered gateways from the list"); + let unused_variable = 42; + // todo!("remove registered gateways from the list"); let gateway_setup = GatewaySetup::New { specification: selection_spec, @@ -216,27 +219,30 @@ where // TODO: ask the service provider we specified for its interface version and set it in the config - let config_save_location = config.default_store_location(); - if let Err(err) = config.save_to(&config_save_location) { - return Err(ClientCoreError::ConfigSaveFailure { - typ: C::NAME.to_string(), - id: id.to_string(), - path: config_save_location, - source: err, + if !already_init { + let config_save_location = config.default_store_location(); + if let Err(err) = config.save_to(&config_save_location) { + return Err(ClientCoreError::ConfigSaveFailure { + typ: C::NAME.to_string(), + id: id.to_string(), + path: config_save_location, + source: err, + } + .into()); } - .into()); - } - eprintln!( - "Saved configuration file to {}", - config_save_location.display() - ); + eprintln!( + "Saved configuration file to {}", + config_save_location.display() + ); + } let address = init_details.client_address(); let GatewayDetails::Remote(gateway_details) = init_details.gateway_registration.details else { return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; }; + let init_results = InitResults::new( config.core_config(), address, @@ -244,6 +250,12 @@ where init_details.gateway_registration.registration_timestamp, ); + if init_args.as_ref().set_active { + set_active_gateway(&init_results.gateway_id, &details_store).await?; + } else { + info!("registered with new gateway {} (under address {address}), but this will not be our default address", init_results.gateway_id); + } + Ok(InitResultsWithConfig { config, init_results, diff --git a/common/client-core/src/client/base_client/non_wasm_helpers.rs b/common/client-core/src/client/base_client/non_wasm_helpers.rs index 70ad8358e6..740e75bb33 100644 --- a/common/client-core/src/client/base_client/non_wasm_helpers.rs +++ b/common/client-core/src/client/base_client/non_wasm_helpers.rs @@ -108,7 +108,7 @@ pub async fn setup_fs_gateways_storage>( info!("setting up gateways details storage"); OnDiskGatewaysDetails::init(db_path) .await - .map_err(|source| ClientCoreError::GatewayDetailsStoreError { + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { source: Box::new(source), }) } diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs new file mode 100644 index 0000000000..54535a918e --- /dev/null +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -0,0 +1,101 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::client::key_manager::persistence::KeyStore; +use crate::client::key_manager::KeyManager; +use crate::error::ClientCoreError; +use nym_client_core_gateways_storage::{GatewayRegistration, GatewaysDetailsStore}; + +// helpers for error wrapping +pub async fn set_active_gateway( + gateway_id: &str, + details_store: &D, +) -> Result<(), ClientCoreError> +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .set_active_gateway(gateway_id) + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + }) +} + +pub async fn store_gateway_details( + details_store: &D, + details: &GatewayRegistration, +) -> Result<(), ClientCoreError> +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .store_gateway_details(details) + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + }) +} + +pub async fn load_active_gateway_details( + details_store: &D, +) -> Result +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .active_gateway() + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + })? + .ok_or(ClientCoreError::NoActiveGatewaySet) +} + +pub async fn load_gateway_details( + details_store: &D, + gateway_id: &str, +) -> Result +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .load_gateway_details(gateway_id) + .await + .map_err(|source| ClientCoreError::UnavailableGatewayDetails { + gateway_id: gateway_id.to_string(), + source: Box::new(source), + }) +} + +pub async fn has_gateway_details( + details_store: &D, + gateway_id: &str, +) -> Result +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .has_gateway_details(gateway_id) + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + }) +} + +pub async fn load_client_keys(key_store: &K) -> Result +where + K: KeyStore, + K::StorageError: Send + Sync + 'static, +{ + KeyManager::load_keys(key_store) + .await + .map_err(|source| ClientCoreError::KeyStoreError { + source: Box::new(source), + }) +} diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index f31370a30d..55bfb12e36 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -37,6 +37,7 @@ pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDe #[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}; diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index 72fcf7762e..9fa43c8ef2 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -56,8 +56,8 @@ pub enum ClientCoreError { source: Box, }, - #[error("experienced a failure with our gateway details storage: {source}")] - GatewayDetailsStoreError { + #[error("experienced a failure with our gateways details storage: {source}")] + GatewaysDetailsStoreError { source: Box, }, diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 38b5c398ab..7dce228834 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -3,6 +3,10 @@ //! Collection of initialization steps used by client implementations +use crate::client::base_client::storage::helpers::{ + has_gateway_details, load_active_gateway_details, load_client_keys, load_gateway_details, + store_gateway_details, +}; use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::KeyManager; use crate::error::ClientCoreError; @@ -19,89 +23,11 @@ use nym_topology::gateway; use rand::rngs::OsRng; use rand::{CryptoRng, RngCore}; use serde::Serialize; -use std::sync::Arc; pub mod helpers; pub mod types; // helpers for error wrapping -async fn _store_gateway_details( - details_store: &D, - details: &GatewayDetails, -) -> Result<(), ClientCoreError> -where - D: GatewaysDetailsStore, - D::StorageError: Send + Sync + 'static, -{ - todo!() - // details_store - // .store_gateway_details(details) - // .await - // .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { - // source: Box::new(source), - // }) -} - -async fn _load_active_gateway_details( - details_store: &D, -) -> Result -where - D: GatewaysDetailsStore, - D::StorageError: Send + Sync + 'static, -{ - details_store - .active_gateway() - .await - .map_err(|source| ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - })? - .ok_or(ClientCoreError::NoActiveGatewaySet) -} - -async fn _load_gateway_details( - details_store: &D, - gateway_id: &str, -) -> Result -where - D: GatewaysDetailsStore, - D::StorageError: Send + Sync + 'static, -{ - details_store - .load_gateway_details(gateway_id) - .await - .map_err(|source| ClientCoreError::UnavailableGatewayDetails { - gateway_id: gateway_id.to_string(), - source: Box::new(source), - }) -} - -async fn _has_gateway_details( - details_store: &D, - gateway_id: &str, -) -> Result -where - D: GatewaysDetailsStore, - D::StorageError: Send + Sync + 'static, -{ - details_store - .has_gateway_details(gateway_id) - .await - .map_err(|source| ClientCoreError::GatewayDetailsStoreError { - source: Box::new(source), - }) -} - -async fn _load_client_keys(key_store: &K) -> Result -where - K: KeyStore, - K::StorageError: Send + Sync + 'static, -{ - KeyManager::load_keys(key_store) - .await - .map_err(|source| ClientCoreError::KeyStoreError { - source: Box::new(source), - }) -} pub async fn generate_new_client_keys( rng: &mut R, @@ -143,15 +69,7 @@ where log::trace!("Setting up new gateway"); // if we're setting up new gateway, we must have had generated long-term client keys before - let client_keys = _load_client_keys(key_store).await?; - - // if we're setting up new gateway, failing to load existing information is fine. - // as a matter of fact, it's only potentially a problem if we DO succeed - - todo!("check gateway details (maybe not even needed anymore, idk)"); - // if _load_gateway_details(details_store).await.is_ok() && !overwrite_data { - // return Err(ClientCoreError::ForbiddenKeyOverwrite); - // } + let client_keys = load_client_keys(key_store).await?; let mut rng = OsRng; @@ -181,13 +99,13 @@ where // check if we already have details associated with this particular gateway // and if so, see if we can overwrite it let selected_id = selected_gateway.gateway_id().to_base58_string(); - if _has_gateway_details(details_store, &selected_id).await? && !overwrite_data { + if has_gateway_details(details_store, &selected_id).await? && !overwrite_data { return Err(ClientCoreError::ForbiddenGatewayKeyOverwrite { gateway_id: selected_id, }); } - let (gateway_details, client) = match selected_gateway { + let (gateway_details, authenticated_ephemeral_client) = match selected_gateway { SelectedGateway::Remote { gateway_id, gateway_owner_address, @@ -196,7 +114,8 @@ where // if we're using a 'normal' gateway setup, do register let our_identity = client_keys.identity_keypair(); let registration = - helpers::register_with_gateway(gateway_id, gateway_listener, our_identity).await?; + helpers::register_with_gateway(gateway_id, gateway_listener.clone(), our_identity) + .await?; ( GatewayDetails::new_remote( gateway_id, @@ -216,13 +135,15 @@ where ), }; + let gateway_registration = gateway_details.into(); + // persist gateway details - _store_gateway_details(details_store, &gateway_details).await?; + store_gateway_details(details_store, &gateway_registration).await?; Ok(InitialisationResult { - gateway_registration: gateway_details.into(), + gateway_registration, client_keys, - authenticated_ephemeral_client: client, + authenticated_ephemeral_client, }) } @@ -238,12 +159,12 @@ where D::StorageError: Send + Sync + 'static, { let loaded_details = if let Some(gateway_id) = gateway_id { - _load_gateway_details(details_store, &gateway_id).await? + load_gateway_details(details_store, &gateway_id).await? } else { - _load_active_gateway_details(details_store).await? + load_active_gateway_details(details_store).await? }; - let loaded_keys = _load_client_keys(key_store).await?; + let loaded_keys = load_client_keys(key_store).await?; // no need to persist anything as we got everything from the storage Ok(InitialisationResult::new_loaded( diff --git a/nym-connect/desktop/src-tauri/src/config/upgrade.rs b/nym-connect/desktop/src-tauri/src/config/upgrade.rs index 5ec509e733..2c7118196e 100644 --- a/nym-connect/desktop/src-tauri/src/config/upgrade.rs +++ b/nym-connect/desktop/src-tauri/src/config/upgrade.rs @@ -37,7 +37,7 @@ fn persist_gateway_details( details_store .store_to_disk(&persisted_details) .map_err(|source| BackendError::ClientCoreError { - source: ClientCoreError::GatewayDetailsStoreError { + source: ClientCoreError::GatewaysDetailsStoreError { source: Box::new(source), }, }) diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index eda51a5554..44b6901438 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -126,7 +126,7 @@ fn persist_gateway_details( details_store .store_to_disk(&persisted_details) .map_err(|source| { - IpPacketRouterError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { + IpPacketRouterError::ClientCoreError(ClientCoreError::GatewaysDetailsStoreError { source: Box::new(source), }) }) From 5bb96bf42cccac1b881a4cc8b28752ff6b2060ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 14:58:06 +0000 Subject: [PATCH 16/56] additional fixes to key creation --- clients/native/src/commands/mod.rs | 3 - clients/socks5/src/commands/mod.rs | 3 - .../src/backend/fs_backend/mod.rs | 3 +- .../src/backend/mem_backend.rs | 67 +++-- .../client-core/gateways-storage/src/types.rs | 8 +- .../client-core/src/client/base_client/mod.rs | 11 + .../base_client/storage/gateway_details.rs | 282 ------------------ .../src/client/base_client/storage/helpers.rs | 18 +- .../src/client/base_client/storage/mod.rs | 29 +- .../client-core/src/client/key_manager/mod.rs | 261 +--------------- .../src/client/key_manager/persistence.rs | 22 +- common/client-core/src/init/helpers.rs | 1 - common/client-core/src/init/mod.rs | 10 +- common/client-core/src/init/types.rs | 123 ++------ .../src/storage/core_client_traits.rs | 11 +- .../src-tauri/src/operations/export.rs | 4 +- sdk/rust/nym-sdk/examples/change_gateway.rs | 9 + .../examples/manually_handle_storage.rs | 9 +- sdk/rust/nym-sdk/examples/simple.rs | 2 +- sdk/rust/nym-sdk/src/mixnet.rs | 2 +- sdk/rust/nym-sdk/src/mixnet/client.rs | 3 - .../ip-packet-router/src/cli/mod.rs | 3 - .../network-requester/src/cli/mod.rs | 3 - 23 files changed, 148 insertions(+), 739 deletions(-) delete mode 100644 common/client-core/src/client/base_client/storage/gateway_details.rs create mode 100644 sdk/rust/nym-sdk/examples/change_gateway.rs diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index 39ab24913f..2c9dfde3cc 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -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; diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 24a1112781..47de0929ef 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -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}; diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index c447d407e2..4b759c0e5f 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // 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 { todo!() } diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 092772c9f0..01385342bb 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -26,52 +26,81 @@ pub struct InMemGatewaysDetails { #[derive(Debug, Default)] struct InMemStorageInner { active_gateway: Option, - gateways: HashMap, + gateways: HashMap, } #[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 { - todo!() - } - async fn active_gateway(&self) -> Result, 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 { + Ok(self.inner.read().await.gateways.contains_key(gateway_id)) + } + + async fn active_gateway(&self) -> Result, 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, Self::StorageError> { - todo!() + Ok(self.inner.read().await.gateways.values().cloned().collect()) } async fn load_gateway_details( &self, gateway_id: &str, ) -> Result { - 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(()) } } diff --git a/common/client-core/gateways-storage/src/types.rs b/common/client-core/gateways-storage/src/types.rs index abb20708a3..c165147bba 100644 --- a/common/client-core/gateways-storage/src/types.rs +++ b/common/client-core/gateways-storage/src/types.rs @@ -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 for RawRemoteGatewayDetails { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct RemoteGatewayDetails { pub gateway_id: identity::PublicKey, @@ -245,7 +245,7 @@ impl From for RawCustomGatewayDetails { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct CustomGatewayDetails { pub gateway_id: identity::PublicKey, pub data: Option>, diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index c2400a7dc5..7870c5cc39 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -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 ::StorageError: Sync + Send, ::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 } diff --git a/common/client-core/src/client/base_client/storage/gateway_details.rs b/common/client-core/src/client/base_client/storage/gateway_details.rs deleted file mode 100644 index 552de2dbbd..0000000000 --- a/common/client-core/src/client/base_client/storage/gateway_details.rs +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2023 - Nym Technologies SA -// 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; - - 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, - - /// 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, -} - -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 { - // 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 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(bytes: &[u8], serializer: S) -> Result { - serializer.serialize_str(&STANDARD.encode(bytes)) - } - - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result, D::Error> { - let s = ::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>(path: P) -> Self { - OnDiskGatewayDetails { - file_location: path.as_ref().to_owned(), - } - } - - pub fn load_from_disk(&self) -> Result { - 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 { - 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>, -} - -#[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 { - 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(()) - } -} diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index 54535a918e..628942902c 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -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(key_store: &K) -> Result +pub async fn load_client_keys(key_store: &K) -> Result 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(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), diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 55bfb12e36..8a674e80aa 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -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 { diff --git a/common/client-core/src/client/key_manager/mod.rs b/common/client-core/src/client/key_manager/mod.rs index b15ca52f44..095980e753 100644 --- a/common/client-core/src/client/key_manager/mod.rs +++ b/common/client-core/src/client/key_manager/mod.rs @@ -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>, -} -// -// 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 for ManagedKeys { -// fn from(value: KeyManagerBuilder) -> Self { -// ManagedKeys::Initial(value) -// } -// } -// -// impl From 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(key_store: &S) -> Result { - // Ok(ManagedKeys::FullyDerived( - // KeyManager::load_keys(key_store).await?, - // )) - // } - // - // pub fn generate_new(rng: &mut R) -> Self - // where - // R: RngCore + CryptoRng, - // { - // ManagedKeys::Initial(KeyManagerBuilder::new(rng)) - // } - // - // pub async fn load_or_generate(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 { - // 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 { - // 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 { - // 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 { - // self.gateway_shared_key() - // .expect("failed to extract gateway shared key") - // } - // - // pub fn gateway_shared_key(&self) -> Option> { - // 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>) { - // 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( - // &mut self, - // gateway_shared_key: Option>, - // 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, -// -// /// encryption key associated with the client instance. -// encryption_keypair: Arc, -// -// /// key used for producing and processing acknowledgement packets. -// ack_key: Arc, -// } -// -// impl KeyManagerBuilder { -// /// Creates new instance of a [`KeyManager`] -// pub fn new(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>, -// ) -> 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 { -// Arc::clone(&self.identity_keypair) -// } -// -// pub fn encryption_keypair(&self) -> Arc { -// Arc::clone(&self.encryption_keypair) -// } -// -// pub fn ack_key(&self) -> Arc { -// 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 has Deref implementation for T #[derive(Clone)] -pub struct KeyManager { +pub struct ClientKeys { /// identity key associated with the client instance. identity_keypair: Arc, /// encryption key associated with the client instance. encryption_keypair: Arc, - // /// 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>, /// key used for producing and processing acknowledgement packets. ack_key: Arc, } -impl KeyManager { - /// Creates new instance of a [`KeyManager`] +impl ClientKeys { + /// Creates new instance of a [`ClientKeys`] pub fn generate_new(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, 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 { Arc::clone(&self.ack_key) } - - // fn must_get_gateway_shared_key(&self) -> &Arc { - // 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> { - // 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() { diff --git a/common/client-core/src/client/key_manager/persistence.rs b/common/client-core/src/client/key_manager/persistence.rs index a7a4196d30..e2312194b0 100644 --- a/common/client-core/src/client/key_manager/persistence.rs +++ b/common/client-core/src/client/key_manager/persistence.rs @@ -1,7 +1,7 @@ // Copyright 2023 - Nym Technologies SA // 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; + async fn load_keys(&self) -> Result; - 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 { + fn load_keys(&self) -> Result { 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 { + async fn load_keys(&self) -> Result { 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>, + keys: Mutex>, } #[derive(Debug, thiserror::Error)] @@ -209,11 +209,11 @@ pub struct EphemeralKeysError; impl KeyStore for InMemEphemeralKeys { type StorageError = EphemeralKeysError; - async fn load_keys(&self) -> Result { + async fn load_keys(&self) -> Result { 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(()) } diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index a0c7c6c8de..a5cd4a4a43 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -1,7 +1,6 @@ // Copyright 2022-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::GatewayEndpointConfig; use crate::error::ClientCoreError; use crate::init::types::RegistrationResult; use futures::{SinkExt, StreamExt}; diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 7dce228834..d82faaba69 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -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, )), } diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 563205eb22..7c0f1ae71b 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -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, } 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, -// } -// -// impl CustomGatewayDetails { -// pub fn new(gateway_id: String, additional_data: Vec) -> 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 for GatewayDetails { -// fn from(value: GatewayEndpointConfig) -> Self { -// GatewayDetails::Configured(value) -// } -// } -// -// impl From for CustomGatewayDetails { -// fn from(value: PersistedCustomGatewayDetails) -> Self { -// CustomGatewayDetails { -// gateway_id: value.gateway_id, -// additional_data: value.additional_data, -// } -// } -// } -// -// impl From for PersistedCustomGatewayDetails { -// fn from(value: CustomGatewayDetails) -> Self { -// PersistedCustomGatewayDetails { -// gateway_id: value.gateway_id, -// additional_data: value.additional_data, -// } -// } -// } -// -// impl From 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, - managed_keys: KeyManager, + client_keys: ClientKeys, }, } impl GatewaySetup { pub fn try_reuse_connection(init_res: InitialisationResult) -> Result { - 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( @@ -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 { diff --git a/common/wasm/client-core/src/storage/core_client_traits.rs b/common/wasm/client-core/src/storage/core_client_traits.rs index 7e4ae13e03..dde0b89f08 100644 --- a/common/wasm/client-core/src/storage/core_client_traits.rs +++ b/common/wasm/client-core/src/storage/core_client_traits.rs @@ -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 { + async fn load_keys(&self) -> Result { 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()) diff --git a/nym-connect/desktop/src-tauri/src/operations/export.rs b/nym-connect/desktop/src-tauri/src/operations/export.rs index 3b11891e9c..a8c53e9d37 100644 --- a/nym-connect/desktop/src-tauri/src/operations/export.rs +++ b/nym-connect/desktop/src-tauri/src/operations/export.rs @@ -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), diff --git a/sdk/rust/nym-sdk/examples/change_gateway.rs b/sdk/rust/nym-sdk/examples/change_gateway.rs new file mode 100644 index 0000000000..7a6771a7b9 --- /dev/null +++ b/sdk/rust/nym-sdk/examples/change_gateway.rs @@ -0,0 +1,9 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +#[tokio::main] +async fn main() { + nym_bin_common::logging::setup_logging(); + + todo!() +} diff --git a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs index b4844005bf..8b1cce1fc1 100644 --- a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs +++ b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs @@ -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 { + async fn load_keys(&self) -> Result { 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(()) diff --git a/sdk/rust/nym-sdk/examples/simple.rs b/sdk/rust/nym-sdk/examples/simple.rs index 14720ba24c..72b6568b6d 100644 --- a/sdk/rust/nym-sdk/examples/simple.rs +++ b/sdk/rust/nym-sdk/examples/simple.rs @@ -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 diff --git a/sdk/rust/nym-sdk/src/mixnet.rs b/sdk/rust/nym-sdk/src/mixnet.rs index b54ef462ee..41fb99998d 100644 --- a/sdk/rust/nym-sdk/src/mixnet.rs +++ b/sdk/rust/nym-sdk/src/mixnet.rs @@ -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, diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index bba70e96a1..56666b1c0d 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -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, }; diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index 44b6901438..c2ef5b800e 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -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; diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index fb0b8699f3..73710781a1 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -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; From c7f7e7709928343818a70106ac133ba2415a9525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 15:14:51 +0000 Subject: [PATCH 17/56] updated config templates --- clients/native/src/client/config/template.rs | 10 +++------- clients/socks5/src/config/template.rs | 12 ++++------- common/client-core/src/lib.rs | 5 ----- .../src/config/old_config_v1_1_33.rs | 2 +- common/socks5-client-core/src/socks/server.rs | 6 +++--- .../desktop/src-tauri/src/config/mod.rs | 2 +- .../desktop/src-tauri/src/config/template.rs | 2 +- .../socks5-listener/src/config/template.rs | 20 ++++--------------- .../ip-packet-router/src/config/template.rs | 12 ++++------- .../network-requester/src/config/template.rs | 12 ++++------- 10 files changed, 25 insertions(+), 58 deletions(-) diff --git a/clients/native/src/client/config/template.rs b/clients/native/src/client/config/template.rs index 413b61790d..965fc07991 100644 --- a/clients/native/src/client/config/template.rs +++ b/clients/native/src/client/config/template.rs @@ -50,10 +50,6 @@ keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key # Path to file containing public encryption key. keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' -# A gateway specific, optional, base58 stringified shared key used for -# communication with particular gateway. -keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' - # Path to file containing key used for encrypting and decrypting the content of an # acknowledgement so that nobody besides the client knows which packet it refers to. keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' @@ -64,9 +60,9 @@ credentials_database = '{{ storage_paths.credentials_database }}' # Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. reply_surb_database = '{{ storage_paths.reply_surb_database }}' -# Path to the file containing information about gateway used by this client, -# i.e. details such as its public key, owner address or the network information. -gateway_details = '{{ storage_paths.gateway_details }}' +# Path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +gateway_registrations = '{{ storage_paths.gateway_registrations }}' ##### socket config options ##### diff --git a/clients/socks5/src/config/template.rs b/clients/socks5/src/config/template.rs index 764a7c6884..07556a5401 100644 --- a/clients/socks5/src/config/template.rs +++ b/clients/socks5/src/config/template.rs @@ -50,10 +50,6 @@ keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key # Path to file containing public encryption key. keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' -# A gateway specific, optional, base58 stringified shared key used for -# communication with particular gateway. -keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' - # Path to file containing key used for encrypting and decrypting the content of an # acknowledgement so that nobody besides the client knows which packet it refers to. keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' @@ -64,9 +60,9 @@ credentials_database = '{{ storage_paths.credentials_database }}' # Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. reply_surb_database = '{{ storage_paths.reply_surb_database }}' -# Path to the file containing information about gateway used by this client, -# i.e. details such as its public key, owner address or the network information. -gateway_details = '{{ storage_paths.gateway_details }}' +# Path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +gateway_registrations = '{{ storage_paths.gateway_registrations }}' ##### socket config options ##### @@ -77,7 +73,7 @@ provider_mix_address = '{{ core.socks5.provider_mix_address }}' # The address on which the client will be listening for incoming requests # (default: 127.0.0.1:1080) -bind_adddress = '{{ core.socks5.bind_adddress }}' +bind_address = '{{ core.socks5.bind_address }}' # Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. # While this is going to hide its actual address information, it will make the actual communication diff --git a/common/client-core/src/lib.rs b/common/client-core/src/lib.rs index 8c84737049..1eb90ddcf7 100644 --- a/common/client-core/src/lib.rs +++ b/common/client-core/src/lib.rs @@ -32,8 +32,3 @@ where { tokio::spawn(future); } - -fn unused_function() { - let with_unused_variable = 42; - todo!("update all client config templates after changes stabilise") -} diff --git a/common/socks5-client-core/src/config/old_config_v1_1_33.rs b/common/socks5-client-core/src/config/old_config_v1_1_33.rs index c306d42888..715b9d108a 100644 --- a/common/socks5-client-core/src/config/old_config_v1_1_33.rs +++ b/common/socks5-client-core/src/config/old_config_v1_1_33.rs @@ -38,7 +38,7 @@ pub struct Socks5V1_1_33 { /// The address on which the client will be listening for incoming requests /// (default: 127.0.0.1:1080) // there was a typo in here, so accept the wrong name for the purposes of backwards compatibility - #[serde(alias = "bind_adddress")] + #[serde(alias = "bind_address")] pub bind_address: SocketAddr, /// The mix address of the provider to which all requests are going to be sent. diff --git a/common/socks5-client-core/src/socks/server.rs b/common/socks5-client-core/src/socks/server.rs index a67ed64e19..1a3fc22f3f 100644 --- a/common/socks5-client-core/src/socks/server.rs +++ b/common/socks5-client-core/src/socks/server.rs @@ -33,7 +33,7 @@ impl NymSocksServer { /// Create a new SphinxSocks instance #[allow(clippy::too_many_arguments)] pub(crate) fn new( - bind_adddress: SocketAddr, + bind_address: SocketAddr, authenticator: Authenticator, service_provider: Recipient, self_address: Recipient, @@ -42,10 +42,10 @@ impl NymSocksServer { shutdown: TaskClient, packet_type: PacketType, ) -> Self { - info!("Listening on {bind_adddress}"); + info!("Listening on {bind_address}"); NymSocksServer { authenticator, - listening_address: bind_adddress, + listening_address: bind_address, service_provider, self_address, client_config, diff --git a/nym-connect/desktop/src-tauri/src/config/mod.rs b/nym-connect/desktop/src-tauri/src/config/mod.rs index 3426cf36b2..34176af06a 100644 --- a/nym-connect/desktop/src-tauri/src/config/mod.rs +++ b/nym-connect/desktop/src-tauri/src/config/mod.rs @@ -255,7 +255,7 @@ fn print_saved_config(config: &Config, gateway_details: &GatewayEndpointConfig) ); log::info!( "Service provider port: {}", - config.core.socks5.bind_adddress.port() + config.core.socks5.bind_address.port() ); log::info!("Client configuration completed."); } diff --git a/nym-connect/desktop/src-tauri/src/config/template.rs b/nym-connect/desktop/src-tauri/src/config/template.rs index 27e2ed435a..3de6a1be5e 100644 --- a/nym-connect/desktop/src-tauri/src/config/template.rs +++ b/nym-connect/desktop/src-tauri/src/config/template.rs @@ -78,7 +78,7 @@ provider_mix_address = '{{ core.socks5.provider_mix_address }}' # The address on which the client will be listening for incoming requests # (default: 127.0.0.1:1080) -bind_adddress = '{{ core.socks5.bind_adddress }}' +bind_address = '{{ core.socks5.bind_address }}' # Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. # While this is going to hide its actual address information, it will make the actual communication diff --git a/sdk/lib/socks5-listener/src/config/template.rs b/sdk/lib/socks5-listener/src/config/template.rs index e310ef2e32..e2ad4c414d 100644 --- a/sdk/lib/socks5-listener/src/config/template.rs +++ b/sdk/lib/socks5-listener/src/config/template.rs @@ -50,10 +50,6 @@ keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key # Path to file containing public encryption key. keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' -# A gateway specific, optional, base58 stringified shared key used for -# communication with particular gateway. -keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' - # Path to file containing key used for encrypting and decrypting the content of an # acknowledgement so that nobody besides the client knows which packet it refers to. keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' @@ -64,17 +60,9 @@ credentials_database = '{{ storage_paths.credentials_database }}' # Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. reply_surb_database = '{{ storage_paths.reply_surb_database }}' -# DEPRECATED -[core.client.gateway_endpoint] -# ID of the gateway from which the client should be fetching messages. -gateway_id = '{{ core.client.gateway_endpoint.gateway_id }}' - -# Address of the gateway owner to which the client should send messages. -gateway_owner = '{{ core.client.gateway_endpoint.gateway_owner }}' - -# Address of the gateway listener to which all client requests should be sent. -gateway_listener = '{{ core.client.gateway_endpoint.gateway_listener }}' - +# Path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +gateway_registrations = '{{ storage_paths.gateway_registrations }}' ##### socket config options ##### @@ -85,7 +73,7 @@ provider_mix_address = '{{ core.socks5.provider_mix_address }}' # The address on which the client will be listening for incoming requests # (default: 127.0.0.1:1080) -bind_adddress = '{{ core.socks5.bind_adddress }}' +bind_address = '{{ core.socks5.bind_address }}' # Specifies whether this client is going to use an anonymous sender tag for communication with the service provider. # While this is going to hide its actual address information, it will make the actual communication diff --git a/service-providers/ip-packet-router/src/config/template.rs b/service-providers/ip-packet-router/src/config/template.rs index bbd9e18d5d..ab5db7bbe8 100644 --- a/service-providers/ip-packet-router/src/config/template.rs +++ b/service-providers/ip-packet-router/src/config/template.rs @@ -51,10 +51,6 @@ keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key # Path to file containing public encryption key. keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' -# A gateway specific, optional, base58 stringified shared key used for -# communication with particular gateway. -keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' - # Path to file containing key used for encrypting and decrypting the content of an # acknowledgement so that nobody besides the client knows which packet it refers to. keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' @@ -62,13 +58,13 @@ keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' # Path to the database containing bandwidth credentials credentials_database = '{{ storage_paths.credentials_database }}' -# Path to the file containing information about gateway used by this client, -# i.e. details such as its public key, owner address or the network information. -gateway_details = '{{ storage_paths.gateway_details }}' - # Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. reply_surb_database = '{{ storage_paths.reply_surb_database }}' +# Path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +gateway_registrations = '{{ storage_paths.gateway_registrations }}' + # Location of the file containing our allow.list allowed_list_location = '{{ storage_paths.allowed_list_location }}' diff --git a/service-providers/network-requester/src/config/template.rs b/service-providers/network-requester/src/config/template.rs index ee6e3ffc51..84cb00e80c 100644 --- a/service-providers/network-requester/src/config/template.rs +++ b/service-providers/network-requester/src/config/template.rs @@ -51,10 +51,6 @@ keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key # Path to file containing public encryption key. keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}' -# A gateway specific, optional, base58 stringified shared key used for -# communication with particular gateway. -keys.gateway_shared_key_file = '{{ storage_paths.keys.gateway_shared_key_file }}' - # Path to file containing key used for encrypting and decrypting the content of an # acknowledgement so that nobody besides the client knows which packet it refers to. keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' @@ -62,13 +58,13 @@ keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}' # Path to the database containing bandwidth credentials credentials_database = '{{ storage_paths.credentials_database }}' -# Path to the file containing information about gateway used by this client, -# i.e. details such as its public key, owner address or the network information. -gateway_details = '{{ storage_paths.gateway_details }}' - # Path to the persistent store for received reply surbs, unused encryption keys and used sender tags. reply_surb_database = '{{ storage_paths.reply_surb_database }}' +# Path to the file containing information about gateways used by this client, +# i.e. details such as their public keys, owner addresses or the network information. +gateway_registrations = '{{ storage_paths.gateway_registrations }}' + # Location of the file containing our allow.list allowed_list_location = '{{ storage_paths.allowed_list_location }}' From a3b1a7337dbd73c483dfe1125d5b7bf043641a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 16:00:31 +0000 Subject: [PATCH 18/56] checking for already registered gateways --- .../client-core/gateways-storage/src/lib.rs | 20 ++++++++++++ .../src/cli_helpers/client_init.rs | 32 ++++++++++++++++--- .../src/client/base_client/storage/helpers.rs | 20 +++++++++++- .../src/client/base_client/storage/mod.rs | 6 ++-- .../src/client/key_manager/persistence.rs | 2 -- common/client-core/src/error.rs | 3 ++ common/client-core/src/init/helpers.rs | 12 +++---- 7 files changed, 79 insertions(+), 16 deletions(-) diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 7416abfc90..3f87cdf526 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -21,6 +21,7 @@ pub use error::BadGateway; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] pub use backend::fs_backend::{error::StorageError, OnDiskGatewaysDetails}; +use nym_crypto::asymmetric::identity; #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] @@ -54,3 +55,22 @@ pub trait GatewaysDetailsStore { /// Remove given gateway details from the underlying store. async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError>; } + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +pub trait GatewaysDetailsStoreExt: GatewaysDetailsStore { + async fn all_gateways_identities( + &self, + ) -> Result, Self::StorageError> { + Ok(self + .all_gateways() + .await? + .into_iter() + .map(|gateway| gateway.details.gateway_id()) + .collect()) + } +} + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +impl GatewaysDetailsStoreExt for T where T: GatewaysDetailsStore {} diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index a75573b3eb..3fd821a9f4 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -6,7 +6,8 @@ use crate::error::ClientCoreError; use crate::{ client::{ base_client::{ - non_wasm_helpers::setup_fs_gateways_storage, storage::helpers::set_active_gateway, + non_wasm_helpers::setup_fs_gateways_storage, + storage::helpers::{get_all_registered_identities, set_active_gateway}, }, key_manager::persistence::OnDiskKeys, }, @@ -181,6 +182,7 @@ where ); let key_store = OnDiskKeys::new(paths.keys.clone()); + let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; // if this is a first time client with this particular id is initialised, generated long-term keys if !already_init { @@ -188,10 +190,21 @@ where crate::init::generate_new_client_keys(&mut rng, &key_store).await?; } + let registered_gateways = get_all_registered_identities(&details_store).await?; + + // if user provided gateway id (and we can't overwrite data), make sure we're not trying to register + // with a known gateway + if let Some(user_chosen) = user_chosen_gateway_id { + if !common_args.force_register_gateway && registered_gateways.contains(&user_chosen) { + return Err(ClientCoreError::AlreadyRegistered { + gateway_id: user_chosen.to_base58_string(), + } + .into()); + } + } + // Setup gateway by either registering a new one, or creating a new config from the selected // one but with keys kept, or reusing the gateway configuration. - let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; - let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { ClientCoreError::CustomTopologyLoadFailure { @@ -205,8 +218,17 @@ where crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? }; - let unused_variable = 42; - // todo!("remove registered gateways from the list"); + // since we're registering with a brand new gateway, + // make sure the list of available gateways doesn't overlap the list of known gateways + let available_gateways = if common_args.force_register_gateway { + // if we're force registering, all bets are off + available_gateways + } else { + available_gateways + .into_iter() + .filter(|g| !registered_gateways.contains(g.identity())) + .collect() + }; let gateway_setup = GatewaySetup::New { specification: selection_spec, diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index 628942902c..8c58605bda 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -4,7 +4,10 @@ use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::ClientKeys; use crate::error::ClientCoreError; -use nym_client_core_gateways_storage::{GatewayRegistration, GatewaysDetailsStore}; +use nym_client_core_gateways_storage::{ + GatewayRegistration, GatewaysDetailsStore, GatewaysDetailsStoreExt, +}; +use nym_crypto::asymmetric::identity; // helpers for error wrapping pub async fn set_active_gateway( @@ -23,6 +26,21 @@ where }) } +pub async fn get_all_registered_identities( + details_store: &D, +) -> Result, ClientCoreError> +where + D: GatewaysDetailsStore + Sync, + D::StorageError: Send + Sync + 'static, +{ + details_store + .all_gateways_identities() + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + }) +} + pub async fn store_gateway_details( details_store: &D, details: &GatewayRegistration, diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 8a674e80aa..70266be27d 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -26,7 +26,9 @@ use crate::{ #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; -pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; +pub use nym_client_core_gateways_storage::{ + GatewaysDetailsStore, GatewaysDetailsStoreExt, InMemGatewaysDetails, +}; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; @@ -34,7 +36,7 @@ pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; pub mod helpers; // TODO: ideally this should be changed into -// `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewayDetailsStore` +// `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewaysDetailsStore` pub trait MixnetClientStorage { type KeyStore: KeyStore; type ReplyStore: ReplyStorageBackend; diff --git a/common/client-core/src/client/key_manager/persistence.rs b/common/client-core/src/client/key_manager/persistence.rs index e2312194b0..a4711e3d39 100644 --- a/common/client-core/src/client/key_manager/persistence.rs +++ b/common/client-core/src/client/key_manager/persistence.rs @@ -11,8 +11,6 @@ use crate::config::disk_persistence::keys_paths::ClientKeysPaths; #[cfg(not(target_arch = "wasm32"))] use nym_crypto::asymmetric::{encryption, identity}; #[cfg(not(target_arch = "wasm32"))] -use nym_gateway_requests::registration::handshake::SharedKeys; -#[cfg(not(target_arch = "wasm32"))] use nym_pemstore::traits::{PemStorableKey, PemStorableKeyPair}; #[cfg(not(target_arch = "wasm32"))] use nym_pemstore::KeyPairPath; diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index 9fa43c8ef2..cca66e6b7f 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -195,6 +195,9 @@ pub enum ClientCoreError { #[source] source: url::ParseError, }, + + #[error("this client has already registered with gateway {gateway_id}")] + AlreadyRegistered { gateway_id: String }, } /// Set of messages that the client can send to listeners via the task manager diff --git a/common/client-core/src/init/helpers.rs b/common/client-core/src/init/helpers.rs index a5cd4a4a43..4d15327634 100644 --- a/common/client-core/src/init/helpers.rs +++ b/common/client-core/src/init/helpers.rs @@ -8,6 +8,7 @@ use log::{debug, info, trace, warn}; use nym_crypto::asymmetric::identity; use nym_gateway_client::GatewayClient; use nym_topology::{filter::VersionFilterable, gateway, mix}; +use nym_validator_client::client::IdentityKeyRef; use rand::{seq::SliceRandom, Rng}; use std::{sync::Arc, time::Duration}; use tungstenite::Message; @@ -16,17 +17,13 @@ use url::Url; #[cfg(not(target_arch = "wasm32"))] use tokio::net::TcpStream; #[cfg(not(target_arch = "wasm32"))] +use tokio::time::sleep; +#[cfg(not(target_arch = "wasm32"))] use tokio::time::Instant; #[cfg(not(target_arch = "wasm32"))] use tokio_tungstenite::connect_async; #[cfg(not(target_arch = "wasm32"))] use tokio_tungstenite::{MaybeTlsStream, WebSocketStream}; -#[cfg(not(target_arch = "wasm32"))] -type WsConn = WebSocketStream>; -use nym_validator_client::client::IdentityKeyRef; -use nym_validator_client::nyxd::AccountId; -#[cfg(not(target_arch = "wasm32"))] -use tokio::time::sleep; #[cfg(target_arch = "wasm32")] use wasm_utils::websocket::JSWebsocket; @@ -35,6 +32,9 @@ use wasmtimer::std::Instant; #[cfg(target_arch = "wasm32")] use wasmtimer::tokio::sleep; +#[cfg(not(target_arch = "wasm32"))] +type WsConn = WebSocketStream>; + #[cfg(target_arch = "wasm32")] type WsConn = JSWebsocket; From 14ee279ec89e33dd3770595eea25a758e557a956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 16:13:44 +0000 Subject: [PATCH 19/56] dead code --- common/client-core/gateways-storage/src/backend/mem_backend.rs | 2 +- common/client-core/src/error.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index 01385342bb..b06e4eb5e9 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::{GatewayDetails, GatewayRegistration}; +use crate::types::GatewayRegistration; use crate::{BadGateway, GatewaysDetailsStore}; use async_trait::async_trait; use std::collections::HashMap; diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index cca66e6b7f..ef2349356b 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -4,7 +4,6 @@ use crate::client::mix_traffic::transceiver::ErasedGatewayError; use nym_crypto::asymmetric::identity::Ed25519RecoveryError; use nym_gateway_client::error::GatewayClientError; -use nym_gateway_requests::registration::handshake::shared_key::SharedKeyConversionError; use nym_topology::gateway::GatewayConversionError; use nym_topology::NymTopologyError; use nym_validator_client::ValidatorClientError; From d31fddf940530c32c73ea80dc5f3ecf9ff7b2d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 7 Mar 2024 17:52:40 +0000 Subject: [PATCH 20/56] gateway info migration + impl for native client other clients are broken --- clients/native/src/client/config/mod.rs | 2 +- .../src/client/config/old_config_v1_1_20_2.rs | 4 +- .../native/src/commands/import_credential.rs | 2 +- clients/native/src/commands/init.rs | 4 +- clients/native/src/commands/mod.rs | 95 ++++---- clients/native/src/commands/run.rs | 2 +- .../src/cli_helpers/client_init.rs | 8 +- .../src/client/base_client/storage/helpers.rs | 2 +- .../base_client/storage/migration_helpers.rs | 211 ++++++++++++++++++ .../src/client/base_client/storage/mod.rs | 10 +- common/client-core/src/config/mod.rs | 81 +------ .../src/config/old_config_v1_1_20_2.rs | 6 +- .../src/config/old_config_v1_1_33.rs | 13 ++ common/client-core/src/error.rs | 3 + 14 files changed, 293 insertions(+), 150 deletions(-) create mode 100644 common/client-core/src/client/base_client/storage/migration_helpers.rs diff --git a/clients/native/src/client/config/mod.rs b/clients/native/src/client/config/mod.rs index 5c0d156bd5..264c3fec5b 100644 --- a/clients/native/src/client/config/mod.rs +++ b/clients/native/src/client/config/mod.rs @@ -19,7 +19,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; pub use nym_client_core::config::Config as BaseClientConfig; -pub use nym_client_core::config::{DebugConfig, GatewayEndpointConfig}; +pub use nym_client_core::config::DebugConfig; pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; diff --git a/clients/native/src/client/config/old_config_v1_1_20_2.rs b/clients/native/src/client/config/old_config_v1_1_20_2.rs index b6d9703a92..90e161827a 100644 --- a/clients/native/src/client/config/old_config_v1_1_20_2.rs +++ b/clients/native/src/client/config/old_config_v1_1_20_2.rs @@ -9,7 +9,7 @@ use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseConfigV1_1_20_2; use nym_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as BaseConfigV1_1_30; -use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; use nym_config::read_config_from_toml_file; use nym_network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use serde::{Deserialize, Serialize}; @@ -46,7 +46,7 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(ConfigV1_1_33, GatewayEndpointConfig), ClientError> { + pub fn upgrade(self) -> Result<(ConfigV1_1_33, OldGatewayEndpointConfigV1_1_33), ClientError> { let gateway_details = self.base.client.gateway_endpoint.clone().into(); let config = ConfigV1_1_33 { base: BaseConfigV1_1_30::from(self.base).into(), diff --git a/clients/native/src/commands/import_credential.rs b/clients/native/src/commands/import_credential.rs index 8554f74ee7..7fa7fa3b52 100644 --- a/clients/native/src/commands/import_credential.rs +++ b/clients/native/src/commands/import_credential.rs @@ -34,7 +34,7 @@ pub(crate) struct Args { } pub(crate) async fn execute(args: Args) -> Result<(), ClientError> { - let config = try_load_current_config(&args.id)?; + let config = try_load_current_config(&args.id).await?; let credentials_store = nym_credential_storage::initialise_persistent_storage( &config.storage_paths.common_paths.credentials_database, diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index def0072d26..dfc7b95cd9 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -29,8 +29,8 @@ impl InitialisableClient for NativeClientInit { type InitArgs = Init; type Config = Config; - fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id) + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index 2c9dfde3cc..d3947b876e 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -12,10 +12,7 @@ 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::OnDiskGatewaysDetails; -use nym_client_core::client::key_manager::persistence::OnDiskKeys; -use nym_client_core::config::GatewayEndpointConfig; -use nym_client_core::error::ClientCoreError; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; use std::error::Error; use std::net::IpAddr; @@ -121,41 +118,7 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { ) } -fn persist_gateway_details( - config: &Config, - details: GatewayEndpointConfig, -) -> Result<(), ClientError> { - todo!() - // let details_store = - // OnDiskGatewaysDetails::new(&config.storage_paths.common_paths.gateway_details); - // let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - // ClientError::ClientCoreError(ClientCoreError::KeyStoreError { - // source: Box::new(source), - // }) - // })?; - // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - // details_store - // .store_to_disk(&persisted_details) - // .map_err(|source| { - // ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - // source: Box::new(source), - // }) - // }) -} - -fn migrate_gateway_details( - config: &Config, - old_details: Option, -) -> Result<(), ClientError> { - todo!() -} - -fn extract_gateway_details(config: &ConfigV1_1_33) -> Result<(), ClientError> { - todo!() -} - -fn try_upgrade_v1_1_13_config(id: &str) -> Result { +async fn try_upgrade_v1_1_13_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) @@ -170,15 +133,21 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let old_paths = updated_step3.storage_paths.clone(); let updated = updated_step3.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) @@ -192,15 +161,20 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let old_paths = updated_step2.storage_paths.clone(); let updated = updated_step2.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; - + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -211,15 +185,20 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let (updated_step1, gateway_config) = old_config.upgrade()?; + let old_paths = updated_step1.storage_paths.clone(); let updated = updated_step1.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; - + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_33_config(id: &str) -> Result { +async fn try_upgrade_v1_1_33_config(id: &str) -> Result { // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -229,32 +208,38 @@ fn try_upgrade_v1_1_33_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.33 config template."); info!("It is going to get updated to the current specification."); + let old_paths = old_config.storage_paths.clone(); let updated = old_config.try_upgrade()?; - migrate_gateway_details(&updated, None)?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_config(id: &str) -> Result<(), ClientError> { - if try_upgrade_v1_1_13_config(id)? { +async fn try_upgrade_config(id: &str) -> Result<(), ClientError> { + if try_upgrade_v1_1_13_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_config(id)? { + if try_upgrade_v1_1_20_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_2_config(id)? { + if try_upgrade_v1_1_20_2_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_33_config(id)? { + if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } Ok(()) } -fn try_load_current_config(id: &str) -> Result { +async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { return if !cfg.validate() { @@ -265,7 +250,7 @@ fn try_load_current_config(id: &str) -> Result { } // we couldn't load it - try upgrading it from older revisions - try_upgrade_config(id)?; + try_upgrade_config(id).await?; let config = match Config::read_from_default_path(id) { Ok(cfg) => cfg, diff --git a/clients/native/src/commands/run.rs b/clients/native/src/commands/run.rs index b836fe6d20..2ab3fc8489 100644 --- a/clients/native/src/commands/run.rs +++ b/clients/native/src/commands/run.rs @@ -69,7 +69,7 @@ fn version_check(cfg: &Config) -> bool { pub(crate) async fn execute(args: Run) -> Result<(), Box> { eprintln!("Starting client {}...", args.common_args.id); - let mut config = try_load_current_config(&args.common_args.id)?; + let mut config = try_load_current_config(&args.common_args.id).await?; config = override_config(config, OverrideConfig::from(args.clone())); if !version_check(&config) { diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 3fd821a9f4..93ad844b08 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -20,13 +20,15 @@ use nym_topology::NymTopology; use rand::rngs::OsRng; use std::path::{Path, PathBuf}; +// we can suppress this warning (as suggested by linter itself) since we're only using it in our own code +#[allow(async_fn_in_trait)] pub trait InitialisableClient { const NAME: &'static str; type Error: From; type InitArgs: AsRef; type Config: ClientConfig; - fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>; + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>; fn initialise_storage_paths(id: &str) -> Result<(), Self::Error>; @@ -134,7 +136,7 @@ where let already_init = if C::default_config_path(id).exists() { // in case we're using old config, try to upgrade it // (if we're using the current version, it's a no-op) - C::try_upgrade_outdated_config(id)?; + C::try_upgrade_outdated_config(id).await?; eprintln!("{} client \"{id}\" was already initialised before", C::NAME); true } else { @@ -273,7 +275,7 @@ where ); if init_args.as_ref().set_active { - set_active_gateway(&init_results.gateway_id, &details_store).await?; + set_active_gateway(&details_store, &init_results.gateway_id).await?; } else { info!("registered with new gateway {} (under address {address}), but this will not be our default address", init_results.gateway_id); } diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index 8c58605bda..c6f2cf65c2 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -11,8 +11,8 @@ use nym_crypto::asymmetric::identity; // helpers for error wrapping pub async fn set_active_gateway( - gateway_id: &str, details_store: &D, + gateway_id: &str, ) -> Result<(), ClientCoreError> where D: GatewaysDetailsStore, diff --git a/common/client-core/src/client/base_client/storage/migration_helpers.rs b/common/client-core/src/client/base_client/storage/migration_helpers.rs new file mode 100644 index 0000000000..c81011a37f --- /dev/null +++ b/common/client-core/src/client/base_client/storage/migration_helpers.rs @@ -0,0 +1,211 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +pub mod v1_1_33 { + use crate::client::base_client::{ + non_wasm_helpers::setup_fs_gateways_storage, + storage::helpers::{set_active_gateway, store_gateway_details}, + }; + use crate::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; + use crate::config::disk_persistence::CommonClientPaths; + use crate::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; + use crate::error::ClientCoreError; + use nym_client_core_gateways_storage::{ + CustomGatewayDetails, GatewayDetails, GatewayRegistration, RemoteGatewayDetails, + }; + use nym_gateway_requests::registration::handshake::SharedKeys; + use serde::{Deserialize, Serialize}; + use sha2::{digest::Digest, Sha256}; + use std::ops::Deref; + use std::path::Path; + use std::sync::Arc; + use zeroize::Zeroizing; + + mod base64 { + use base64::{engine::general_purpose::STANDARD, Engine as _}; + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(bytes: &[u8], serializer: S) -> Result { + serializer.serialize_str(&STANDARD.encode(bytes)) + } + + pub fn deserialize<'de, D: Deserializer<'de>>( + deserializer: D, + ) -> Result, D::Error> { + let s = ::deserialize(deserializer)?; + STANDARD.decode(s).map_err(serde::de::Error::custom) + } + } + + #[derive(Debug, Clone, Serialize, Deserialize)] + #[serde(untagged)] + enum PersistedGatewayDetails { + /// Standard details of a remote gateway + Default(PersistedGatewayConfig), + + /// Custom gateway setup, such as for a client embedded inside gateway itself + Custom(PersistedCustomGatewayDetails), + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + struct PersistedGatewayConfig { + /// The hash of the shared keys to ensure the correct ones are used with those gateway details. + #[serde(with = "base64")] + key_hash: Vec, + + /// Actual gateway details being persisted. + details: OldGatewayEndpointConfigV1_1_33, + } + + impl PersistedGatewayConfig { + 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() + } + } + + #[derive(Debug, Clone, Serialize, Deserialize)] + struct PersistedCustomGatewayDetails { + gateway_id: String, + } + + fn load_shared_key>(path: P) -> Result { + // the shared key was a simple pem file + Ok(nym_pemstore::load_key(path)?) + } + + fn gateway_details_from_raw( + gateway_id: String, + gateway_owner: String, + gateway_listener: String, + gateway_shared_key: SharedKeys, + ) -> Result { + Ok(GatewayDetails::Remote(RemoteGatewayDetails { + gateway_id: gateway_id + .parse() + .map_err(|err| ClientCoreError::UpgradeFailure { + message: format!("the stored gateway id was malformed: {err}"), + })?, + derived_aes128_ctr_blake3_hmac_keys: Arc::new(gateway_shared_key), + gateway_owner_address: gateway_owner.parse().map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!("the stored gateway owner address was malformed: {err}"), + } + })?, + gateway_listener: gateway_listener.parse().map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!("the stored gateway listener address was malformed: {err}"), + } + })?, + })) + } + + // helper to extract shared key and gateway details into the new GatewayRegistration + fn extract_gateway_registration( + storage_paths: &CommonClientPathsV1_1_33, + ) -> Result { + let details_file = std::fs::File::open(&storage_paths.gateway_details).map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!( + "failed to open gateway details file at {}: {err}", + storage_paths.gateway_details.display() + ), + } + })?; + + // in v1.1.33 of the clients, the gateway details struct was saved as json + let details: PersistedGatewayDetails = + serde_json::from_reader(details_file).map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!( + "failed to deserialize gateway details from {}: {err}", + storage_paths.gateway_details.display() + ), + } + })?; + + let details = match details { + PersistedGatewayDetails::Default(config) => { + let gateway_shared_key = + load_shared_key(&storage_paths.keys.gateway_shared_key_file)?; + if !config.verify(&gateway_shared_key) { + return Err(ClientCoreError::UpgradeFailure { + message: "failed to verify consistency of the existing gateway details" + .to_string(), + }); + } + gateway_details_from_raw( + config.details.gateway_id, + config.details.gateway_owner, + config.details.gateway_listener, + gateway_shared_key, + )? + } + PersistedGatewayDetails::Custom(custom) => { + GatewayDetails::Custom(CustomGatewayDetails { + gateway_id: custom.gateway_id.parse().map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!("the stored gateway id was malformed: {err}"), + } + })?, + data: None, + }) + } + }; + + Ok(details.into()) + } + + // it's responsibility of the caller to ensure this is called **after** new registration has already been saved + fn remove_old_gateway_details(storage_paths: &CommonClientPathsV1_1_33) -> std::io::Result<()> { + std::fs::remove_file(&storage_paths.gateway_details)?; + + if storage_paths.keys.gateway_shared_key_file.exists() { + std::fs::remove_file(&storage_paths.keys.gateway_shared_key_file)?; + } + Ok(()) + } + + pub async fn migrate_gateway_details( + old_storage_paths: &CommonClientPathsV1_1_33, + new_storage_paths: &CommonClientPaths, + preloaded_config: Option, + ) -> Result<(), ClientCoreError> { + let gateway_registration = match preloaded_config { + Some(config) => { + let gateway_shared_key = + load_shared_key(&old_storage_paths.keys.gateway_shared_key_file)?; + gateway_details_from_raw( + config.gateway_id, + config.gateway_owner, + config.gateway_listener, + gateway_shared_key, + )? + .into() + } + None => extract_gateway_registration(old_storage_paths)?, + }; + + // since we're migrating to a brand new store, the store should be empty + // and thus set the 'new' gateway as the active one + let details_store = + setup_fs_gateways_storage(&new_storage_paths.gateway_registrations).await?; + store_gateway_details(&details_store, &gateway_registration).await?; + set_active_gateway( + &details_store, + &gateway_registration.details.gateway_id().to_base58_string(), + ) + .await?; + + remove_old_gateway_details(&old_storage_paths).map_err(|err| { + ClientCoreError::UpgradeFailure { + message: format!("failed to remove old data: {err}"), + } + }) + } +} diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 70266be27d..2158788cd3 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -27,7 +27,8 @@ use crate::{ use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; pub use nym_client_core_gateways_storage::{ - GatewaysDetailsStore, GatewaysDetailsStoreExt, InMemGatewaysDetails, + CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, GatewaysDetailsStore, + GatewaysDetailsStoreExt, InMemGatewaysDetails, RegisteredGateway, RemoteGatewayDetails, }; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] @@ -35,6 +36,13 @@ pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; pub mod helpers; +#[cfg(all( + not(target_arch = "wasm32"), + feature = "fs-surb-storage", + feature = "fs-gateways-storage" +))] +pub mod migration_helpers; + // TODO: ideally this should be changed into // `MixnetClientStorage: KeyStore + ReplyStorageBackend + CredentialStorage + GatewaysDetailsStore` pub trait MixnetClientStorage { diff --git a/common/client-core/src/config/mod.rs b/common/client-core/src/config/mod.rs index 1fd2cf26f3..2333c58df4 100644 --- a/common/client-core/src/config/mod.rs +++ b/common/client-core/src/config/mod.rs @@ -1,10 +1,8 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::{client::topology_control::geo_aware_provider::CountryGroup, error::ClientCoreError}; +use crate::client::topology_control::geo_aware_provider::CountryGroup; use nym_config::defaults::NymNetworkDetails; -use nym_crypto::asymmetric::identity; -use nym_gateway_client::client::GatewayConfig; use nym_sphinx::{ addressing::clients::Recipient, params::{PacketSize, PacketType}, @@ -13,9 +11,6 @@ use serde::{Deserialize, Serialize}; use std::time::Duration; use url::Url; -#[cfg(target_arch = "wasm32")] -use wasm_bindgen::prelude::*; - pub mod disk_persistence; pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; @@ -232,80 +227,6 @@ impl Config { } } -#[deprecated] -#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen(getter_with_clone))] -pub struct GatewayEndpointConfig { - /// gateway_id specifies ID of the gateway to which the client should send messages. - /// If initially omitted, a random gateway will be chosen from the available topology. - pub gateway_id: String, - - /// Address of the gateway owner to which the client should send messages. - pub gateway_owner: String, - - /// Address of the gateway listener to which all client requests should be sent. - pub gateway_listener: String, -} - -impl TryFrom for GatewayConfig { - type Error = ClientCoreError; - - fn try_from(value: GatewayEndpointConfig) -> Result { - Ok(GatewayConfig { - gateway_identity: identity::PublicKey::from_base58_string(value.gateway_id) - .map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId)?, - gateway_owner: Some(value.gateway_owner), - gateway_listener: value.gateway_listener, - }) - } -} - -#[deprecated] -#[cfg_attr(target_arch = "wasm32", wasm_bindgen)] -impl GatewayEndpointConfig { - #[cfg_attr(target_arch = "wasm32", wasm_bindgen(constructor))] - pub fn new( - gateway_id: String, - gateway_owner: String, - gateway_listener: String, - ) -> GatewayEndpointConfig { - GatewayEndpointConfig { - gateway_id, - gateway_owner, - gateway_listener, - } - } -} - -// separate block so it wouldn't be exported via wasm bindgen -#[deprecated] -impl GatewayEndpointConfig { - pub fn try_get_gateway_identity_key(&self) -> Result { - identity::PublicKey::from_base58_string(&self.gateway_id) - .map_err(ClientCoreError::UnableToCreatePublicKeyFromGatewayId) - } - - pub fn from_node( - node: nym_topology::gateway::Node, - must_use_tls: bool, - ) -> Result { - let gateway_listener = if must_use_tls { - node.clients_address_tls() - .ok_or(ClientCoreError::UnsupportedWssProtocol { - gateway: node.identity_key.to_base58_string(), - })? - } else { - node.clients_address() - }; - - Ok(GatewayEndpointConfig { - gateway_id: node.identity_key.to_base58_string(), - gateway_listener, - gateway_owner: node.owner, - }) - } -} - #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] // note: the deny_unknown_fields is VITAL here to allow upgrades from v1.1.20_2 #[serde(deny_unknown_fields)] diff --git a/common/client-core/src/config/old_config_v1_1_20_2.rs b/common/client-core/src/config/old_config_v1_1_20_2.rs index a7abd41ddc..5fe039fc82 100644 --- a/common/client-core/src/config/old_config_v1_1_20_2.rs +++ b/common/client-core/src/config/old_config_v1_1_20_2.rs @@ -5,7 +5,7 @@ use crate::config::old_config_v1_1_30::{ AcknowledgementsV1_1_30, ClientV1_1_30, ConfigV1_1_30, CoverTrafficV1_1_30, DebugConfigV1_1_30, GatewayConnectionV1_1_30, ReplySurbsV1_1_30, TopologyV1_1_30, TrafficV1_1_30, }; -use crate::config::GatewayEndpointConfig; +use crate::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; use nym_sphinx::params::{PacketSize, PacketType}; use serde::{Deserialize, Serialize}; use std::time::Duration; @@ -81,9 +81,9 @@ pub struct GatewayEndpointConfigV1_1_20_2 { pub gateway_listener: String, } -impl From for GatewayEndpointConfig { +impl From for OldGatewayEndpointConfigV1_1_33 { fn from(value: GatewayEndpointConfigV1_1_20_2) -> Self { - GatewayEndpointConfig { + OldGatewayEndpointConfigV1_1_33 { gateway_id: value.gateway_id, gateway_owner: value.gateway_owner, gateway_listener: value.gateway_listener, diff --git a/common/client-core/src/config/old_config_v1_1_33.rs b/common/client-core/src/config/old_config_v1_1_33.rs index 0d47b95361..028b35fb52 100644 --- a/common/client-core/src/config/old_config_v1_1_33.rs +++ b/common/client-core/src/config/old_config_v1_1_33.rs @@ -55,6 +55,19 @@ const DEFAULT_MAXIMUM_REPLY_SURB_AGE: Duration = Duration::from_secs(12 * 60 * 6 // 24 hours const DEFAULT_MAXIMUM_REPLY_KEY_AGE: Duration = Duration::from_secs(24 * 60 * 60); +#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize)] +pub struct OldGatewayEndpointConfigV1_1_33 { + /// gateway_id specifies ID of the gateway to which the client should send messages. + /// If initially omitted, a random gateway will be chosen from the available topology. + pub gateway_id: String, + + /// Address of the gateway owner to which the client should send messages. + pub gateway_owner: String, + + /// Address of the gateway listener to which all client requests should be sent. + pub gateway_listener: String, +} + #[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct ConfigV1_1_33 { diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index ef2349356b..d2d391f102 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -127,6 +127,9 @@ pub enum ClientCoreError { #[error("unable to upgrade config file to `{new_version}`")] UnableToUpgradeConfigFile { new_version: String }, + #[error("failed to upgrade config file: {message}")] + UpgradeFailure { message: String }, + #[error("the provided gateway details don't much the stored data")] MismatchedStoredGatewayDetails, From 35d84b6e420ab72dec257e8885a82528731837fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 09:47:24 +0000 Subject: [PATCH 21/56] ibid for socks5 --- .../socks5/src/commands/import_credential.rs | 3 +- clients/socks5/src/commands/init.rs | 4 +- clients/socks5/src/commands/mod.rs | 108 +++++++++--------- clients/socks5/src/commands/run.rs | 2 +- .../socks5/src/config/old_config_v1_1_20_2.rs | 13 +-- .../socks5/src/config/old_config_v1_1_30.rs | 2 +- 6 files changed, 68 insertions(+), 64 deletions(-) diff --git a/clients/socks5/src/commands/import_credential.rs b/clients/socks5/src/commands/import_credential.rs index 8a13e799d3..a3bfd7dd45 100644 --- a/clients/socks5/src/commands/import_credential.rs +++ b/clients/socks5/src/commands/import_credential.rs @@ -4,7 +4,6 @@ use crate::commands::try_load_current_config; use crate::error::Socks5ClientError; use clap::ArgGroup; - use nym_id::import_credential; use std::fs; use std::path::PathBuf; @@ -34,7 +33,7 @@ pub(crate) struct Args { } pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> { - let config = try_load_current_config(&args.id)?; + let config = try_load_current_config(&args.id).await?; let credentials_store = nym_credential_storage::initialise_persistent_storage( &config.storage_paths.common_paths.credentials_database, diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 3bc5cd098a..548059d701 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -29,8 +29,8 @@ impl InitialisableClient for Socks5ClientInit { type InitArgs = Init; type Config = Config; - fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id) + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 47de0929ef..d367a061cd 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -6,17 +6,16 @@ use crate::config::old_config_v1_1_20::ConfigV1_1_20; use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::config::old_config_v1_1_30::ConfigV1_1_30; use crate::config::old_config_v1_1_33::ConfigV1_1_33; -use crate::config::{BaseClientConfig, Config, SocksClientPaths}; +use crate::config::{BaseClientConfig, Config}; use crate::error::Socks5ClientError; use clap::CommandFactory; 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::key_manager::persistence::OnDiskKeys; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; -use nym_client_core::config::{GatewayEndpointConfig, GroupBy, TopologyStructure}; -use nym_client_core::error::ClientCoreError; +use nym_client_core::config::{GroupBy, TopologyStructure}; use nym_config::OptionalSet; use nym_sphinx::params::{PacketSize, PacketType}; use std::error::Error; @@ -166,36 +165,7 @@ pub(crate) fn override_config(config: Config, args: OverrideConfig) -> Config { ) } -fn persist_gateway_details( - storage_paths: &SocksClientPaths, - details: GatewayEndpointConfig, -) -> Result<(), Socks5ClientError> { - todo!() - // let details_store = OnDiskGatewayDetails::new(&storage_paths.common_paths.gateway_details); - // let keys_store = OnDiskKeys::new(storage_paths.common_paths.keys.clone()); - // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - // Socks5ClientError::ClientCoreError(ClientCoreError::KeyStoreError { - // source: Box::new(source), - // }) - // })?; - // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - // details_store - // .store_to_disk(&persisted_details) - // .map_err(|source| { - // Socks5ClientError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - // source: Box::new(source), - // }) - // }) -} - -fn migrate_gateway_details( - config: &Config, - old_details: Option, -) -> Result<(), Socks5ClientError> { - todo!() -} - -fn try_upgrade_v1_1_13_config(id: &str) -> Result { +async fn try_upgrade_v1_1_13_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) @@ -210,16 +180,23 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let old_paths = updated_step3.storage_paths.clone(); + let updated_step4: ConfigV1_1_33 = updated_step3.into(); let updated = updated_step4.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) @@ -233,16 +210,23 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let old_paths = updated_step2.storage_paths.clone(); + let updated_step3: ConfigV1_1_33 = updated_step2.into(); let updated = updated_step3.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -253,16 +237,23 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let (updated_step1, gateway_config) = old_config.upgrade()?; + let old_paths = updated_step1.storage_paths.clone(); + let updated_step2: ConfigV1_1_33 = updated_step1.into(); let updated = updated_step2.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_30_config(id: &str) -> Result { +async fn try_upgrade_v1_1_30_config(id: &str) -> Result { // explicitly load it as v1.1.30 (which is incompatible with the current one, i.e. +1.1.31) let Ok(old_config) = ConfigV1_1_30::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -272,15 +263,23 @@ fn try_upgrade_v1_1_30_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.30 config template."); info!("It is going to get updated to the current specification."); + let old_paths = old_config.storage_paths.clone(); + let updated_step1: ConfigV1_1_33 = old_config.into(); let updated = updated_step1.try_upgrade()?; - migrate_gateway_details(&updated, None)?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_33_config(id: &str) -> Result { +async fn try_upgrade_v1_1_33_config(id: &str) -> Result { // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -290,35 +289,42 @@ fn try_upgrade_v1_1_33_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.33 config template."); info!("It is going to get updated to the current specification."); + let old_paths = old_config.storage_paths.clone(); + let updated = old_config.try_upgrade()?; - migrate_gateway_details(&updated, None)?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> { - if try_upgrade_v1_1_13_config(id)? { +async fn try_upgrade_config(id: &str) -> Result<(), Socks5ClientError> { + if try_upgrade_v1_1_13_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_config(id)? { + if try_upgrade_v1_1_20_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_2_config(id)? { + if try_upgrade_v1_1_20_2_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_30_config(id)? { + if try_upgrade_v1_1_30_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_33_config(id)? { + if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } Ok(()) } -fn try_load_current_config(id: &str) -> Result { +async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { return if !cfg.validate() { @@ -329,7 +335,7 @@ fn try_load_current_config(id: &str) -> Result { } // we couldn't load it - try upgrading it from older revisions - try_upgrade_config(id)?; + try_upgrade_config(id).await?; let config = match Config::read_from_default_path(id) { Ok(cfg) => cfg, diff --git a/clients/socks5/src/commands/run.rs b/clients/socks5/src/commands/run.rs index 5638c80d9b..87234d676c 100644 --- a/clients/socks5/src/commands/run.rs +++ b/clients/socks5/src/commands/run.rs @@ -105,7 +105,7 @@ fn version_check(cfg: &Config) -> bool { pub(crate) async fn execute(args: Run) -> Result<(), Box> { eprintln!("Starting client {}...", args.common_args.id); - let mut config = try_load_current_config(&args.common_args.id)?; + let mut config = try_load_current_config(&args.common_args.id).await?; config = override_config(config, OverrideConfig::from(args.clone())); if !version_check(&config) { diff --git a/clients/socks5/src/config/old_config_v1_1_20_2.rs b/clients/socks5/src/config/old_config_v1_1_20_2.rs index d396082e68..6b1e5f0219 100644 --- a/clients/socks5/src/config/old_config_v1_1_20_2.rs +++ b/clients/socks5/src/config/old_config_v1_1_20_2.rs @@ -2,19 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::old_config_v1_1_30::ConfigV1_1_30; -use crate::{ - config::{default_config_filepath, persistence::SocksClientPaths}, - error::Socks5ClientError, -}; +use crate::config::old_config_v1_1_33::SocksClientPathsV1_1_33; +use crate::{config::default_config_filepath, error::Socks5ClientError}; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; -use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; use nym_config::read_config_from_toml_file; use serde::{Deserialize, Serialize}; use std::io; use std::path::Path; -use crate::config::old_config_v1_1_33::SocksClientPathsV1_1_33; pub use nym_socks5_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as CoreConfigV1_1_20_2; #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] @@ -44,7 +41,9 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(ConfigV1_1_30, GatewayEndpointConfig), Socks5ClientError> { + pub fn upgrade( + self, + ) -> Result<(ConfigV1_1_30, OldGatewayEndpointConfigV1_1_33), Socks5ClientError> { let gateway_details = self.core.base.client.gateway_endpoint.clone().into(); let config = ConfigV1_1_30 { core: self.core.into(), diff --git a/clients/socks5/src/config/old_config_v1_1_30.rs b/clients/socks5/src/config/old_config_v1_1_30.rs index 7395891dc3..e6f3a12bc0 100644 --- a/clients/socks5/src/config/old_config_v1_1_30.rs +++ b/clients/socks5/src/config/old_config_v1_1_30.rs @@ -1,8 +1,8 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::config::default_config_filepath; use crate::config::old_config_v1_1_33::{ConfigV1_1_33, SocksClientPathsV1_1_33}; -use crate::config::{default_config_filepath, Config}; use nym_bin_common::logging::LoggingSettings; use nym_config::read_config_from_toml_file; use nym_socks5_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as CoreConfigV1_1_30; From 6e1b869c99901030201a291f841ea1478c9e24dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 09:52:46 +0000 Subject: [PATCH 22/56] ibid for network requester --- .../src/cli/import_credential.rs | 3 +- .../network-requester/src/cli/init.rs | 4 +- .../network-requester/src/cli/mod.rs | 92 ++++++++----------- .../network-requester/src/cli/run.rs | 2 +- .../network-requester/src/cli/sign.rs | 2 +- .../src/config/old_config_v1_1_20.rs | 1 - .../src/config/old_config_v1_1_20_2.rs | 6 +- 7 files changed, 49 insertions(+), 61 deletions(-) diff --git a/service-providers/network-requester/src/cli/import_credential.rs b/service-providers/network-requester/src/cli/import_credential.rs index d46b0442bf..31a11c92a0 100644 --- a/service-providers/network-requester/src/cli/import_credential.rs +++ b/service-providers/network-requester/src/cli/import_credential.rs @@ -4,7 +4,6 @@ use crate::cli::try_load_current_config; use crate::error::NetworkRequesterError; use clap::ArgGroup; - use nym_id::import_credential; use std::fs; use std::path::PathBuf; @@ -34,7 +33,7 @@ pub(crate) struct Args { } pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { - let config = try_load_current_config(&args.id)?; + let config = try_load_current_config(&args.id).await?; let credentials_store = nym_credential_storage::initialise_persistent_storage( &config.storage_paths.common_paths.credentials_database, diff --git a/service-providers/network-requester/src/cli/init.rs b/service-providers/network-requester/src/cli/init.rs index 630c4546f4..b8771961eb 100644 --- a/service-providers/network-requester/src/cli/init.rs +++ b/service-providers/network-requester/src/cli/init.rs @@ -26,8 +26,8 @@ impl InitialisableClient for NetworkRequesterInit { type InitArgs = Init; type Config = Config; - fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id) + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 73710781a1..6aedc24cf0 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -14,9 +14,7 @@ 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::key_manager::persistence::OnDiskKeys; -use nym_client_core::config::GatewayEndpointConfig; -use nym_client_core::error::ClientCoreError; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; use std::sync::OnceLock; @@ -164,41 +162,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Ok(()) } -fn persist_gateway_details( - config: &Config, - details: GatewayEndpointConfig, -) -> Result<(), NetworkRequesterError> { - todo!() - // let details_store = - // OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - // let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - // let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - // NetworkRequesterError::ClientCoreError(ClientCoreError::KeyStoreError { - // source: Box::new(source), - // }) - // })?; - // let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - // details_store - // .store_to_disk(&persisted_details) - // .map_err(|source| { - // NetworkRequesterError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError { - // source: Box::new(source), - // }) - // }) -} - -fn migrate_gateway_details( - config: &Config, - old_details: Option, -) -> Result<(), NetworkRequesterError> { - todo!() -} - -fn extract_gateway_details(config: &ConfigV1_1_33) -> Result<(), NetworkRequesterError> { - todo!() -} - -fn try_upgrade_v1_1_13_config(id: &str) -> Result { +async fn try_upgrade_v1_1_13_config(id: &str) -> Result { trace!("Trying to load as v1.1.13 config"); use nym_config::legacy_helpers::nym_config::MigrationNymConfig; @@ -214,15 +178,21 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let old_paths = updated_step3.storage_paths.clone(); let updated = updated_step3.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_config(id: &str) -> Result { trace!("Trying to load as v1.1.20 config"); use nym_config::legacy_helpers::nym_config::MigrationNymConfig; @@ -238,15 +208,21 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let old_paths = updated_step2.storage_paths.clone(); let updated = updated_step2.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { trace!("Trying to load as v1.1.20_2 config"); // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) @@ -259,15 +235,21 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result info!("It is going to get updated to the current specification."); let (updated_step1, gateway_config) = old_config.upgrade()?; + let old_paths = updated_step1.storage_paths.clone(); let updated = updated_step1.try_upgrade()?; - migrate_gateway_details(&updated, Some(gateway_config))?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_33_config(id: &str) -> Result { +async fn try_upgrade_v1_1_33_config(id: &str) -> Result { // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -277,33 +259,39 @@ fn try_upgrade_v1_1_33_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.33 config template."); info!("It is going to get updated to the current specification."); + let old_paths = old_config.storage_paths.clone(); let updated = old_config.try_upgrade()?; - migrate_gateway_details(&updated, None)?; + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> { +async fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> { trace!("Attempting to upgrade config"); - if try_upgrade_v1_1_13_config(id)? { + if try_upgrade_v1_1_13_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_config(id)? { + if try_upgrade_v1_1_20_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_2_config(id)? { + if try_upgrade_v1_1_20_2_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_33_config(id)? { + if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } Ok(()) } -fn try_load_current_config(id: &str) -> Result { +async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { return if !cfg.validate() { @@ -314,7 +302,7 @@ fn try_load_current_config(id: &str) -> Result { } // we couldn't load it - try upgrading it from older revisions - try_upgrade_config(id)?; + try_upgrade_config(id).await?; let config = match Config::read_from_default_path(id) { Ok(cfg) => cfg, diff --git a/service-providers/network-requester/src/cli/run.rs b/service-providers/network-requester/src/cli/run.rs index 1295734bda..cd3a5ad653 100644 --- a/service-providers/network-requester/src/cli/run.rs +++ b/service-providers/network-requester/src/cli/run.rs @@ -66,7 +66,7 @@ impl From for OverrideConfig { } pub(crate) async fn execute(args: &Run) -> Result<(), NetworkRequesterError> { - let mut config = try_load_current_config(&args.common_args.id)?; + let mut config = try_load_current_config(&args.common_args.id).await?; config = override_config(config, OverrideConfig::from(args.clone())); log::debug!("Using config: {:#?}", config); diff --git a/service-providers/network-requester/src/cli/sign.rs b/service-providers/network-requester/src/cli/sign.rs index 7a0dc29d7b..9e43de6009 100644 --- a/service-providers/network-requester/src/cli/sign.rs +++ b/service-providers/network-requester/src/cli/sign.rs @@ -55,7 +55,7 @@ fn print_signed_contract_msg( } pub(crate) async fn execute(args: &Sign) -> Result<(), NetworkRequesterError> { - let config = try_load_current_config(&args.id)?; + let config = try_load_current_config(&args.id).await?; if !version_check(&config) { log::error!("Failed the local version check"); diff --git a/service-providers/network-requester/src/config/old_config_v1_1_20.rs b/service-providers/network-requester/src/config/old_config_v1_1_20.rs index 42d82646fa..603b0f6d92 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_20.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_20.rs @@ -4,7 +4,6 @@ use crate::config::old_config_v1_1_20_2::{ ConfigV1_1_20_2, DebugV1_1_20_2, NetworkRequesterPathsV1_1_20_2, }; -use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::disk_persistence::old_v1_1_33::ClientKeysPathsV1_1_33; use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20; diff --git a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs index 6c9d3e0255..642270911b 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs @@ -10,7 +10,7 @@ use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; use nym_client_core::config::old_config_v1_1_20_2::ConfigV1_1_20_2 as BaseClientConfigV1_1_20_2; use nym_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as BaseConfigV1_1_30; -use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; use nym_config::read_config_from_toml_file; use serde::{Deserialize, Serialize}; use std::io; @@ -61,7 +61,9 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(ConfigV1_1_33, GatewayEndpointConfig), NetworkRequesterError> { + pub fn upgrade( + self, + ) -> Result<(ConfigV1_1_33, OldGatewayEndpointConfigV1_1_33), NetworkRequesterError> { trace!("Upgrading from v1.1.20_2"); let gateway_details = self.base.client.gateway_endpoint.clone().into(); let nr_description = self From fc43cb590bbed8f28dc3a4df6e6426d6a0763ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 14:54:16 +0000 Subject: [PATCH 23/56] further adjusting storage and setup to allow for wg use --- .../20240304120000_create_initial_tables.sql | 3 +- .../src/backend/fs_backend/mod.rs | 7 +- .../src/backend/mem_backend.rs | 10 +- .../client-core/gateways-storage/src/lib.rs | 6 +- .../client-core/gateways-storage/src/types.rs | 24 ++ .../src/cli_helpers/client_init.rs | 1 + .../client-core/src/client/base_client/mod.rs | 65 +++-- .../src/client/base_client/storage/helpers.rs | 14 +- .../base_client/storage/migration_helpers.rs | 1 + common/client-core/src/init/mod.rs | 31 ++- common/client-core/src/init/types.rs | 53 ++++ common/network-defaults/src/lib.rs | 2 + gateway/src/commands/helpers.rs | 25 +- sdk/rust/nym-sdk/src/mixnet.rs | 2 +- sdk/rust/nym-sdk/src/mixnet/client.rs | 226 ++++++++++-------- 15 files changed, 291 insertions(+), 179 deletions(-) diff --git a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql index bb4d59f7a1..77c32b4fa9 100644 --- a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql +++ b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql @@ -24,7 +24,8 @@ CREATE TABLE remote_gateway_details gateway_id_bs58 TEXT NOT NULL UNIQUE PRIMARY KEY REFERENCES registered_gateway (gateway_id_bs58), derived_aes128_ctr_blake3_hmac_keys_bs58 TEXT NOT NULL, gateway_owner_address TEXT NOT NULL, - gateway_listener TEXT NOT NULL + gateway_listener TEXT NOT NULL, + wg_tun_address TEXT ); CREATE TABLE custom_gateway_details diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 4b759c0e5f..5061fe60fc 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::types::GatewayRegistration; -use crate::{GatewaysDetailsStore, StorageError}; +use crate::{ActiveGateway, GatewaysDetailsStore, StorageError}; use async_trait::async_trait; use manager::StorageManager; use std::path::Path; @@ -26,11 +26,12 @@ impl OnDiskGatewaysDetails { #[async_trait] impl GatewaysDetailsStore for OnDiskGatewaysDetails { type StorageError = error::StorageError; - + async fn has_gateway_details(&self, gateway_id: &str) -> Result { todo!() } - async fn active_gateway(&self) -> Result, Self::StorageError> { + + async fn active_gateway(&self) -> Result { todo!() } diff --git a/common/client-core/gateways-storage/src/backend/mem_backend.rs b/common/client-core/gateways-storage/src/backend/mem_backend.rs index b06e4eb5e9..451f6b2187 100644 --- a/common/client-core/gateways-storage/src/backend/mem_backend.rs +++ b/common/client-core/gateways-storage/src/backend/mem_backend.rs @@ -1,7 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::GatewayRegistration; +use crate::types::{ActiveGateway, GatewayRegistration}; use crate::{BadGateway, GatewaysDetailsStore}; use async_trait::async_trait; use std::collections::HashMap; @@ -38,14 +38,16 @@ impl GatewaysDetailsStore for InMemGatewaysDetails { Ok(self.inner.read().await.gateways.contains_key(gateway_id)) } - async fn active_gateway(&self) -> Result, Self::StorageError> { + async fn active_gateway(&self) -> Result { let guard = self.inner.read().await; - Ok(guard.active_gateway.as_ref().map(|id| { + let registration = 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() - })) + }); + + Ok(ActiveGateway { registration }) } async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 3f87cdf526..26deeec049 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -13,8 +13,8 @@ pub mod types; // todo: export port types pub use crate::types::{ - CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, RegisteredGateway, - RemoteGatewayDetails, + ActiveGateway, CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, + RegisteredGateway, RemoteGatewayDetails, }; pub use backend::mem_backend::{InMemGatewaysDetails, InMemStorageError}; pub use error::BadGateway; @@ -29,7 +29,7 @@ pub trait GatewaysDetailsStore { type StorageError: Error + From; /// Returns details of the currently active gateway, if available. - async fn active_gateway(&self) -> Result, Self::StorageError>; + async fn active_gateway(&self) -> Result; /// Set the provided gateway as the currently active gateway. async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError>; diff --git a/common/client-core/gateways-storage/src/types.rs b/common/client-core/gateways-storage/src/types.rs index c165147bba..a63cd4f5d8 100644 --- a/common/client-core/gateways-storage/src/types.rs +++ b/common/client-core/gateways-storage/src/types.rs @@ -16,6 +16,11 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; pub const REMOTE_GATEWAY_TYPE: &str = "remote"; pub const CUSTOM_GATEWAY_TYPE: &str = "custom"; +#[derive(Debug, Clone, Default)] +pub struct ActiveGateway { + pub registration: Option, +} + #[derive(Debug, Clone)] pub struct GatewayRegistration { pub details: GatewayDetails, @@ -46,12 +51,14 @@ impl GatewayDetails { derived_aes128_ctr_blake3_hmac_keys: Arc, gateway_owner_address: AccountId, gateway_listener: Url, + wg_tun_address: Option, ) -> Self { GatewayDetails::Remote(RemoteGatewayDetails { gateway_id, derived_aes128_ctr_blake3_hmac_keys, gateway_owner_address, gateway_listener, + wg_tun_address, }) } @@ -136,6 +143,7 @@ pub struct RawRemoteGatewayDetails { pub derived_aes128_ctr_blake3_hmac_keys_bs58: String, pub gateway_owner_address: String, pub gateway_listener: String, + pub wg_tun_address: Option, } impl TryFrom for RemoteGatewayDetails { @@ -175,11 +183,24 @@ impl TryFrom for RemoteGatewayDetails { } })?; + let wg_tun_address = value + .wg_tun_address + .as_ref() + .map(|addr| { + Url::parse(addr).map_err(|source| BadGateway::MalformedListener { + gateway_id: value.gateway_id_bs58.clone(), + raw_listener: addr.clone(), + source, + }) + }) + .transpose()?; + Ok(RemoteGatewayDetails { gateway_id, derived_aes128_ctr_blake3_hmac_keys, gateway_owner_address, gateway_listener, + wg_tun_address, }) } } @@ -193,6 +214,7 @@ impl From for RawRemoteGatewayDetails { .to_base58_string(), gateway_owner_address: value.gateway_owner_address.to_string(), gateway_listener: value.gateway_listener.to_string(), + wg_tun_address: value.wg_tun_address.map(|addr| addr.to_string()), } } } @@ -208,6 +230,8 @@ pub struct RemoteGatewayDetails { pub gateway_owner_address: AccountId, pub gateway_listener: Url, + + pub wg_tun_address: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 93ad844b08..e878a12028 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -236,6 +236,7 @@ where specification: selection_spec, available_gateways, overwrite_data: common_args.force_register_gateway, + wg_tun_address: None, }; let init_details = diff --git a/common/client-core/src/client/base_client/mod.rs b/common/client-core/src/client/base_client/mod.rs index 7870c5cc39..42adcf2da4 100644 --- a/common/client-core/src/client/base_client/mod.rs +++ b/common/client-core/src/client/base_client/mod.rs @@ -35,7 +35,7 @@ use crate::init::{ }; use crate::{config, spawn_future}; use futures::channel::mpsc; -use log::{debug, error, info}; +use log::{debug, error, info, warn}; use nym_bandwidth_controller::BandwidthController; use nym_client_core_gateways_storage::{GatewayDetails, GatewaysDetailsStore}; use nym_credential_storage::storage::Storage as CredentialStorage; @@ -43,6 +43,7 @@ use nym_crypto::asymmetric::encryption; use nym_gateway_client::{ AcknowledgementReceiver, GatewayClient, GatewayConfig, MixnetMessageReceiver, PacketRouter, }; +use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, WG_TUN_DEVICE_ADDRESS}; use nym_sphinx::acknowledgements::AckKey; use nym_sphinx::addressing::clients::Recipient; use nym_sphinx::addressing::nodes::NodeIdentity; @@ -179,6 +180,7 @@ pub struct BaseClientBuilder<'a, C, S: MixnetClientStorage> { dkg_query_client: Option, wait_for_gateway: bool, + wireguard_connection: bool, custom_topology_provider: Option>, custom_gateway_transceiver: Option>, shutdown: Option, @@ -201,6 +203,7 @@ where client_store, dkg_query_client, wait_for_gateway: false, + wireguard_connection: false, custom_topology_provider: None, custom_gateway_transceiver: None, shutdown: None, @@ -220,6 +223,12 @@ where self } + #[must_use] + pub fn with_wireguard_connection(mut self, wireguard_connection: bool) -> Self { + self.wireguard_connection = wireguard_connection; + self + } + #[must_use] pub fn with_topology_provider( mut self, @@ -343,6 +352,7 @@ where async fn start_gateway_client( config: &Config, + wireguard_connection: bool, initialisation_result: InitialisationResult, bandwidth_controller: Option>, packet_router: PacketRouter, @@ -358,27 +368,41 @@ where return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails); }; - let mut gateway_client = - if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client { - existing_client.upgrade(packet_router, bandwidth_controller, shutdown) + let mut gateway_client = if let Some(existing_client) = + initialisation_result.authenticated_ephemeral_client + { + existing_client.upgrade(packet_router, bandwidth_controller, shutdown) + } else { + let gateway_listener = if wireguard_connection { + if let Some(tun_address) = details.wg_tun_address { + tun_address.to_string() + } else { + let default = + format!("ws://{WG_TUN_DEVICE_ADDRESS}:{DEFAULT_CLIENT_LISTENING_PORT}"); + warn!("gateway {} does not have tun device address set. defaulting to '{default}'", details.gateway_id); + default + } } else { - let cfg = GatewayConfig::new( - details.gateway_id, - Some(details.gateway_owner_address.to_string()), - details.gateway_listener.to_string(), - ); - GatewayClient::new( - cfg, - managed_keys.identity_keypair(), - Some(details.derived_aes128_ctr_blake3_hmac_keys), - packet_router, - bandwidth_controller, - shutdown, - ) - .with_disabled_credentials_mode(config.client.disabled_credentials_mode) - .with_response_timeout(config.debug.gateway_connection.gateway_response_timeout) + details.gateway_listener.to_string() }; + let cfg = GatewayConfig::new( + details.gateway_id, + Some(details.gateway_owner_address.to_string()), + gateway_listener, + ); + GatewayClient::new( + cfg, + managed_keys.identity_keypair(), + Some(details.derived_aes128_ctr_blake3_hmac_keys), + packet_router, + bandwidth_controller, + shutdown, + ) + .with_disabled_credentials_mode(config.client.disabled_credentials_mode) + .with_response_timeout(config.debug.gateway_connection.gateway_response_timeout) + }; + gateway_client .authenticate_and_start() .await @@ -396,6 +420,7 @@ where async fn setup_gateway_transceiver( custom_gateway_transceiver: Option>, config: &Config, + wireguard_connection: bool, initialisation_result: InitialisationResult, bandwidth_controller: Option>, packet_router: PacketRouter, @@ -424,6 +449,7 @@ where // otherwise, setup normal gateway client, etc let gateway_client = Self::start_gateway_client( config, + wireguard_connection, initialisation_result, bandwidth_controller, packet_router, @@ -680,6 +706,7 @@ where let gateway_transceiver = Self::setup_gateway_transceiver( self.custom_gateway_transceiver, self.config, + self.wireguard_connection, init_res, bandwidth_controller, gateway_packet_router, diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index c6f2cf65c2..d760499c31 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -5,7 +5,7 @@ use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::ClientKeys; use crate::error::ClientCoreError; use nym_client_core_gateways_storage::{ - GatewayRegistration, GatewaysDetailsStore, GatewaysDetailsStoreExt, + ActiveGateway, GatewayRegistration, GatewaysDetailsStore, GatewaysDetailsStoreExt, }; use nym_crypto::asymmetric::identity; @@ -59,18 +59,16 @@ where pub async fn load_active_gateway_details( details_store: &D, -) -> Result +) -> Result where D: GatewaysDetailsStore, D::StorageError: Send + Sync + 'static, { - details_store - .active_gateway() - .await - .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + details_store.active_gateway().await.map_err(|source| { + ClientCoreError::GatewaysDetailsStoreError { source: Box::new(source), - })? - .ok_or(ClientCoreError::NoActiveGatewaySet) + } + }) } pub async fn load_gateway_details( diff --git a/common/client-core/src/client/base_client/storage/migration_helpers.rs b/common/client-core/src/client/base_client/storage/migration_helpers.rs index c81011a37f..83869b5796 100644 --- a/common/client-core/src/client/base_client/storage/migration_helpers.rs +++ b/common/client-core/src/client/base_client/storage/migration_helpers.rs @@ -102,6 +102,7 @@ pub mod v1_1_33 { message: format!("the stored gateway listener address was malformed: {err}"), } })?, + wg_tun_address: None, })) } diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index d82faaba69..6bc0fa8e91 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -23,6 +23,7 @@ use nym_topology::gateway; use rand::rngs::OsRng; use rand::{CryptoRng, RngCore}; use serde::Serialize; +use std::net::IpAddr; pub mod helpers; pub mod types; @@ -46,19 +47,13 @@ where }) } -// fn ensure_valid_details( -// details: &PersistedGatewayDetails, -// loaded_keys: &ManagedKeys, -// ) -> Result<(), ClientCoreError> { -// details.validate(loaded_keys.gateway_shared_key().as_deref()) -// } - async fn setup_new_gateway( key_store: &K, details_store: &D, overwrite_data: bool, selection_specification: GatewaySelectionSpecification, available_gateways: Vec, + wg_tun_ip_address: Option, ) -> Result where K: KeyStore, @@ -76,19 +71,19 @@ where let selected_gateway = match selection_specification { GatewaySelectionSpecification::UniformRemote { must_use_tls } => { let gateway = uniformly_random_gateway(&mut rng, &available_gateways, must_use_tls)?; - SelectedGateway::from_topology_node(gateway, must_use_tls)? + SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)? } GatewaySelectionSpecification::RemoteByLatency { must_use_tls } => { let gateway = choose_gateway_by_latency(&mut rng, &available_gateways, must_use_tls).await?; - SelectedGateway::from_topology_node(gateway, must_use_tls)? + SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)? } GatewaySelectionSpecification::Specified { must_use_tls, identity, } => { let gateway = get_specified_gateway(&identity, &available_gateways, must_use_tls)?; - SelectedGateway::from_topology_node(gateway, must_use_tls)? + SelectedGateway::from_topology_node(gateway, wg_tun_ip_address, must_use_tls)? } GatewaySelectionSpecification::Custom { gateway_identity, @@ -110,18 +105,23 @@ where gateway_id, gateway_owner_address, gateway_listener, + wg_tun_address, } => { // if we're using a 'normal' gateway setup, do register let our_identity = client_keys.identity_keypair(); + + // if wg address is set, use that one + let url = wg_tun_address.clone().unwrap_or(gateway_listener.clone()); + let registration = - helpers::register_with_gateway(gateway_id, gateway_listener.clone(), our_identity) - .await?; + helpers::register_with_gateway(gateway_id, url, our_identity).await?; ( GatewayDetails::new_remote( gateway_id, registration.shared_keys, gateway_owner_address, gateway_listener, + wg_tun_address, ), Some(registration.authenticated_ephemeral_client), ) @@ -161,7 +161,10 @@ where let loaded_details = if let Some(gateway_id) = gateway_id { load_gateway_details(details_store, &gateway_id).await? } else { - load_active_gateway_details(details_store).await? + load_active_gateway_details(details_store) + .await? + .registration + .ok_or(ClientCoreError::NoActiveGatewaySet)? }; let loaded_keys = load_client_keys(key_store).await?; @@ -205,6 +208,7 @@ where specification, available_gateways, overwrite_data, + wg_tun_address, } => { setup_new_gateway( key_store, @@ -212,6 +216,7 @@ where overwrite_data, specification, available_gateways, + wg_tun_address, ) .await } diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 7c0f1ae71b..cfbac41121 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -6,6 +6,7 @@ use crate::client::key_manager::ClientKeys; use crate::config::Config; use crate::error::ClientCoreError; use crate::init::{setup_gateway, use_loaded_gateway_details}; +use log::info; use nym_client_core_gateways_storage::{ GatewayRegistration, GatewaysDetailsStore, RemoteGatewayDetails, }; @@ -18,6 +19,7 @@ use nym_validator_client::client::IdentityKey; use nym_validator_client::nyxd::AccountId; use serde::Serialize; use std::fmt::Display; +use std::net::IpAddr; use std::str::FromStr; use std::sync::Arc; use time::OffsetDateTime; @@ -30,6 +32,8 @@ pub enum SelectedGateway { gateway_owner_address: AccountId, gateway_listener: Url, + + wg_tun_address: Option, }, Custom { gateway_id: identity::PublicKey, @@ -37,9 +41,36 @@ pub enum SelectedGateway { }, } +fn wg_tun_address( + tun_ip: Option, + gateway: &gateway::Node, +) -> Result, ClientCoreError> { + let Some(tun_ip) = tun_ip else { + return Ok(None); + }; + + // log this so we'd remember about it if we ever decided to actually use that port + if gateway.clients_wss_port.is_some() { + info!( + "gateway {} exposes wss but for wireguard we're going to use ws", + gateway.identity_key + ); + } + + let raw_url = format!("ws://{tun_ip}:{}", gateway.clients_ws_port); + Ok(Some(raw_url.as_str().parse().map_err(|source| { + ClientCoreError::MalformedListener { + gateway_id: gateway.identity_key.to_base58_string(), + raw_listener: raw_url, + source, + } + })?)) +} + impl SelectedGateway { pub fn from_topology_node( node: gateway::Node, + wg_tun_ip_address: Option, must_use_tls: bool, ) -> Result { let gateway_listener = if must_use_tls { @@ -51,6 +82,8 @@ impl SelectedGateway { node.clients_address() }; + let wg_tun_address = wg_tun_address(wg_tun_ip_address, &node)?; + let gateway_owner_address = AccountId::from_str(&node.owner).map_err(|source| { ClientCoreError::MalformedGatewayOwnerAccountAddress { gateway_id: node.identity_key.to_base58_string(), @@ -70,6 +103,7 @@ impl SelectedGateway { gateway_id: node.identity_key, gateway_owner_address, gateway_listener, + wg_tun_address, }) } @@ -209,6 +243,12 @@ pub enum GatewaySetup { /// Specifies whether old data should be overwritten whilst setting up new gateway client. overwrite_data: bool, + + /// Implicitly specify whether the chosen gateway must use wireguard mode by setting the tun address. + /// + /// Currently this is imperfect solution as I'd imagine this address could vary from gateway to gateway + /// so perhaps it should be part of gateway::Node struct + wg_tun_address: Option, }, ReuseConnection { @@ -235,6 +275,19 @@ impl GatewaySetup { } } + /// new gateway setup performed by each client that's inbuilt in a gateway (like NR or IPR) + pub fn new_inbuilt(identity: identity::PublicKey) -> Self { + GatewaySetup::New { + specification: GatewaySelectionSpecification::Custom { + gateway_identity: identity.to_base58_string(), + additional_data: None, + }, + available_gateways: vec![], + overwrite_data: false, + wg_tun_address: None, + } + } + pub async fn try_setup( self, key_store: &K, diff --git a/common/network-defaults/src/lib.rs b/common/network-defaults/src/lib.rs index 17968821bb..55037c50ee 100644 --- a/common/network-defaults/src/lib.rs +++ b/common/network-defaults/src/lib.rs @@ -4,6 +4,7 @@ use crate::var_names::{DEPRECATED_API_VALIDATOR, DEPRECATED_NYMD_VALIDATOR, NYM_API, NYXD}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use std::net::{IpAddr, Ipv4Addr}; use std::path::Path; use std::{ env::{var, VarError}, @@ -521,4 +522,5 @@ pub const WG_PORT: u16 = 51822; // The interface used to route traffic pub const WG_TUN_BASE_NAME: &str = "nymwg"; pub const WG_TUN_DEVICE_ADDRESS: &str = "10.1.0.1"; +pub const WG_TUN_DEVICE_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1)); pub const WG_TUN_DEVICE_NETMASK: &str = "255.255.255.0"; diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index 8ea29169f2..e12cc337f1 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -16,10 +16,7 @@ use nym_network_defaults::mainnet; use nym_network_defaults::var_names::NYXD; use nym_network_defaults::var_names::{BECH32_PREFIX, NYM_API, STATISTICS_SERVICE_DOMAIN_ADDRESS}; use nym_network_requester::config::BaseClientConfig; -use nym_network_requester::{ - setup_fs_gateways_storage, setup_gateway, GatewaySelectionSpecification, GatewaySetup, - OnDiskKeys, -}; +use nym_network_requester::{setup_fs_gateways_storage, setup_gateway, GatewaySetup, OnDiskKeys}; use nym_types::gateway::{GatewayIpPacketRouterDetails, GatewayNetworkRequesterDetails}; use nym_validator_client::nyxd::AccountId; use std::net::IpAddr; @@ -251,7 +248,7 @@ pub(crate) fn override_ip_packet_router_config( // disable poisson rate in the BASE client if the IPR option is enabled if cfg.ip_packet_router.disable_poisson_rate { - log::info!("Disabling poisson rate for ip packet router"); + info!("Disabling poisson rate for ip packet router"); cfg.set_no_poisson_process(); } @@ -280,14 +277,7 @@ pub(crate) async fn initialise_local_network_requester( // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( - GatewaySetup::New { - specification: GatewaySelectionSpecification::Custom { - gateway_identity: identity.to_base58_string(), - additional_data: Default::default(), - }, - available_gateways: vec![], - overwrite_data: false, - }, + GatewaySetup::new_inbuilt(identity), &key_store, &details_store, ) @@ -353,14 +343,7 @@ pub(crate) async fn initialise_local_ip_packet_router( // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( - GatewaySetup::New { - specification: GatewaySelectionSpecification::Custom { - gateway_identity: identity.to_base58_string(), - additional_data: Default::default(), - }, - available_gateways: vec![], - overwrite_data: false, - }, + GatewaySetup::new_inbuilt(identity), &key_store, &details_store, ) diff --git a/sdk/rust/nym-sdk/src/mixnet.rs b/sdk/rust/nym-sdk/src/mixnet.rs index 41fb99998d..23c951119b 100644 --- a/sdk/rust/nym-sdk/src/mixnet.rs +++ b/sdk/rust/nym-sdk/src/mixnet.rs @@ -56,7 +56,7 @@ pub use nym_client_core::{ }, topology_control::geo_aware_provider::{CountryGroup, GeoAwareTopologyProvider}, }, - config::{GatewayEndpointConfig, GroupBy}, + config::GroupBy, }; pub use nym_credential_storage::{ ephemeral_storage::EphemeralStorage as EphemeralCredentialStorage, diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index 56666b1c0d..de0299b314 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -11,25 +11,27 @@ use crate::{Error, Result}; use futures::channel::mpsc; use futures::StreamExt; use log::warn; +use nym_client_core::client::base_client::storage::helpers::get_all_registered_identities; use nym_client_core::client::base_client::storage::{ Ephemeral, GatewaysDetailsStore, MixnetClientStorage, OnDiskPersistent, }; use nym_client_core::client::base_client::BaseClient; use nym_client_core::client::key_manager::persistence::KeyStore; +use nym_client_core::client::{ + base_client::BaseClientBuilder, replies::reply_storage::ReplyStorageBackend, +}; use nym_client_core::config::DebugConfig; +use nym_client_core::error::ClientCoreError; use nym_client_core::init::helpers::current_gateways; use nym_client_core::init::types::{GatewaySelectionSpecification, GatewaySetup}; -use nym_client_core::{ - client::{base_client::BaseClientBuilder, replies::reply_storage::ReplyStorageBackend}, - config::GatewayEndpointConfig, -}; -use nym_network_defaults::{DEFAULT_CLIENT_LISTENING_PORT, WG_TUN_DEVICE_ADDRESS}; +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::{nyxd, QueryHttpRpcNyxdClient}; use rand::rngs::OsRng; +use std::net::IpAddr; use std::path::Path; use std::path::PathBuf; use url::Url; @@ -41,7 +43,6 @@ const DEFAULT_NUMBER_OF_SURBS: u32 = 10; pub struct MixnetClientBuilder { config: Config, storage_paths: Option, - gateway_config: Option, socks5_config: Option, wireguard_mode: bool, @@ -78,7 +79,6 @@ impl MixnetClientBuilder { Ok(MixnetClientBuilder { config: Default::default(), storage_paths: None, - gateway_config: None, socks5_config: None, wireguard_mode: false, wait_for_gateway: false, @@ -98,6 +98,7 @@ impl MixnetClientBuilder where S: MixnetClientStorage + 'static, S::ReplyStore: Send + Sync, + S::GatewaysDetailsStore: Sync, ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, @@ -109,7 +110,6 @@ where MixnetClientBuilder { config: Default::default(), storage_paths: None, - gateway_config: None, socks5_config: None, wireguard_mode: false, wait_for_gateway: false, @@ -128,7 +128,6 @@ where MixnetClientBuilder { config: self.config, storage_paths: self.storage_paths, - gateway_config: self.gateway_config, socks5_config: self.socks5_config, wireguard_mode: self.wireguard_mode, wait_for_gateway: self.wait_for_gateway, @@ -303,6 +302,7 @@ impl DisconnectedMixnetClient where S: MixnetClientStorage + 'static, S::ReplyStore: Send + Sync, + S::GatewaysDetailsStore: Sync, ::StorageError: Sync + Send, ::StorageError: Send + Sync, ::StorageError: Send + Sync, @@ -410,40 +410,58 @@ where .collect() } - /// Client keys are generated at client creation if none were found. The gateway shared - /// key, however, is created during the gateway registration handshake, so it might not - /// necessarily be available. - /// Furthermore, it has to be coupled with particular gateway's config. - async fn has_valid_gateway_info(&self) -> bool { - let keys = match self.storage.key_store().load_keys().await { - Ok(keys) => keys, + fn wireguard_tun_address(&self) -> Option { + // currently use a hardcoded value here, but perhaps we should change that later + if self.wireguard_mode { + Some(WG_TUN_DEVICE_IP_ADDRESS) + } else { + None + } + } + + async fn new_gateway_setup(&self) -> Result { + let nym_api_endpoints = self.get_api_endpoints(); + + let selection_spec = GatewaySelectionSpecification::new( + self.config.user_chosen_gateway.clone(), + None, + self.force_tls, + ); + + let mut rng = OsRng; + let available_gateways = current_gateways(&mut rng, &nym_api_endpoints).await?; + + Ok(GatewaySetup::New { + specification: selection_spec, + available_gateways, + overwrite_data: !self.config.key_mode.is_keep(), + wg_tun_address: self.wireguard_tun_address(), + }) + } + + /// Check if the client already has an active gateway enabled. + async fn has_active_gateway(&self) -> bool { + let storage = self.storage.gateway_details_store(); + + if storage.active_gateway().await.is_ok() { + return true; + } + + match get_all_registered_identities(storage).await { Err(err) => { - warn!("failed to load stored keys: {err}"); - return false; + warn!("failed to query for all registered gateways: {err}") } - }; + Ok(all_ids) => { + if !all_ids.is_empty() { + warn!("this client doesn't have an active gateway set, however, it's already registered with the following gateways (consider making one of them active):"); + for id in all_ids { + warn!("{id}") + } + } + } + } - todo!() - - // let gateway_details = match self - // .storage - // .gateway_details_store() - // .load_gateway_details() - // .await - // { - // Ok(details) => details, - // Err(err) => { - // warn!("failed to load stored gateway details: {err}"); - // return false; - // } - // }; - // - // if let Err(err) = gateway_details.validate(keys.gateway_shared_key().as_deref()) { - // warn!("stored key verification failure: {err}"); - // return false; - // } - // - // true + false } /// Register with a gateway. If a gateway is provided in the config then that will try to be @@ -460,24 +478,10 @@ where log::debug!("Registering with gateway"); - let api_endpoints = self.get_api_endpoints(); - - let gateway_setup = if self.has_valid_gateway_info().await { + let gateway_setup = if self.has_active_gateway().await { GatewaySetup::MustLoad { gateway_id: None } } else { - let selection_spec = GatewaySelectionSpecification::new( - self.config.user_chosen_gateway.clone(), - None, - self.force_tls, - ); - - let mut rng = OsRng; - - GatewaySetup::New { - specification: selection_spec, - available_gateways: current_gateways(&mut rng, &api_endpoints).await?, - overwrite_data: !self.config.key_mode.is_keep(), - } + self.new_gateway_setup().await? }; // this will perform necessary key and details load and optional store @@ -525,60 +529,70 @@ where .config .as_base_client_config(nyxd_endpoints, nym_api_endpoints.clone()); - let known_gateway = self.has_valid_gateway_info().await; + let known_gateway = self.has_active_gateway().await; - let mut base_builder: BaseClientBuilder<_, _> = if !known_gateway { - let selection_spec = GatewaySelectionSpecification::new( - self.config.user_chosen_gateway, - None, - self.force_tls, - ); - - let mut rng = OsRng; - let mut available_gateways = current_gateways(&mut rng, &nym_api_endpoints).await?; - if self.wireguard_mode { - available_gateways - .iter_mut() - .for_each(|node| node.host = WG_TUN_DEVICE_ADDRESS.parse().unwrap()); - } - let setup = GatewaySetup::New { - specification: selection_spec, - available_gateways, - overwrite_data: !self.config.key_mode.is_keep(), - }; - - BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) - .with_wait_for_gateway(self.wait_for_gateway) - .with_gateway_setup(setup) - } else if self.wireguard_mode { - todo!() - // if let Ok(PersistedGatewayDetails::Default(mut config)) = self - // .storage - // .gateway_details_store() - // .load_gateway_details() - // .await - // { - // config.details.gateway_listener = format!( - // "ws://{}:{}", - // WG_TUN_DEVICE_ADDRESS, DEFAULT_CLIENT_LISTENING_PORT - // ); - // if let Err(e) = self - // .storage - // .gateway_details_store() - // .store_gateway_details(&PersistedGatewayDetails::Default(config)) - // .await - // { - // warn!("Could not switch to using wireguard mode - {:?}", e); - // } - // } else { - // warn!("Storage type not supported with wireguard mode"); - // } - // BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) - // .with_wait_for_gateway(self.wait_for_gateway) + // if we have a known gateway, don't bother doing all of those queries + let gateway_setup = if known_gateway { + None } else { + Some(self.new_gateway_setup().await?) + }; + + let mut base_builder: BaseClientBuilder<_, _> = BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) .with_wait_for_gateway(self.wait_for_gateway) - }; + .with_wireguard_connection(self.wireguard_mode); + + if !known_gateway { + // safety: `gateway_setup` is always set whenever `known_gateway` is false + base_builder = base_builder.with_gateway_setup(gateway_setup.unwrap()); + } + + // let mut base_builder: BaseClientBuilder<_, _> = if !known_gateway { + // // we need to setup a new gateway + // let setup = self.new_gateway_setup().await; + // + // BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) + // .with_wait_for_gateway(self.wait_for_gateway) + // .with_gateway_setup(setup) + // // } else if self.wireguard_mode { + // // // load current active gateway in wireguard mode + // // details_store.set_wireguard_mode(true).await?; + // // + // // if let Ok(PersistedGatewayDetails::Default(mut config)) = self + // // .storage + // // .gateway_details_store() + // // .load_gateway_details() + // // .await + // // { + // // config.details.gateway_listener = format!( + // // "ws://{}:{}", + // // WG_TUN_DEVICE_ADDRESS, DEFAULT_CLIENT_LISTENING_PORT + // // ); + // // if let Err(e) = self + // // .storage + // // .gateway_details_store() + // // .store_gateway_details(&PersistedGatewayDetails::Default(config)) + // // .await + // // { + // // warn!("Could not switch to using wireguard mode - {:?}", e); + // // } + // // } else { + // // warn!("Storage type not supported with wireguard mode"); + // // } + // // BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) + // // .with_wait_for_gateway(self.wait_for_gateway) + // } else { + // // load current active gateway in non-wireguard mode + // + // // make sure our current storage mode matches the desired wg mode + // details_store + // .set_wireguard_mode(self.wireguard_mode) + // .await?; + // + // BaseClientBuilder::new(&base_config, self.storage, self.dkg_query_client) + // .with_wait_for_gateway(self.wait_for_gateway) + // }; if let Some(topology_provider) = self.custom_topology_provider { base_builder = base_builder.with_topology_provider(topology_provider); From b4e45ef3ef76236c573f805d18a011f7c32ee1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 15:08:26 +0000 Subject: [PATCH 24/56] fixed active gateway detection in rust sdk --- sdk/rust/nym-sdk/src/mixnet/client.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index de0299b314..b59b7d20bb 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -443,8 +443,16 @@ where async fn has_active_gateway(&self) -> bool { let storage = self.storage.gateway_details_store(); - if storage.active_gateway().await.is_ok() { - return true; + match storage.active_gateway().await { + Err(err) => { + warn!("failed to query for the current active gateway: {err}"); + return false; + } + Ok(active) => { + if active.registration.is_some() { + return true; + } + } } match get_all_registered_identities(storage).await { From 40f08dcbb20026798a50cb63bad722b322b0a8dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 16:02:06 +0000 Subject: [PATCH 25/56] impl GatewaysDetailsStore for OnDiskGatewaysDetails without the underlying sql --- .../20240304120000_create_initial_tables.sql | 3 + .../src/backend/fs_backend/manager.rs | 92 ++++++++++++++- .../src/backend/fs_backend/mod.rs | 105 ++++++++++++++++-- .../client-core/gateways-storage/src/lib.rs | 31 ++---- .../client-core/gateways-storage/src/types.rs | 36 +++++- .../src/client/base_client/storage/helpers.rs | 4 +- .../src/client/base_client/storage/mod.rs | 2 +- 7 files changed, 234 insertions(+), 39 deletions(-) diff --git a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql index 77c32b4fa9..0382f37313 100644 --- a/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql +++ b/common/client-core/gateways-storage/fs_gateways_migrations/20240304120000_create_initial_tables.sql @@ -34,3 +34,6 @@ CREATE TABLE custom_gateway_details data BLOB ); + +INSERT INTO active_gateway(id, active_gateway_id_bs58) +values (0, NULL); \ No newline at end of file diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs index 5447c6c9ab..72d886bce6 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -1,7 +1,12 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::backend::fs_backend::error::StorageError; +use crate::{ + backend::fs_backend::error::StorageError, + types::{ + RawActiveGateway, RawCustomGatewayDetails, RawRegisteredGateway, RawRemoteGatewayDetails, + }, +}; use log::{error, info}; use sqlx::ConnectOptions; use std::path::Path; @@ -47,4 +52,89 @@ impl StorageManager { info!("Database migration finished!"); Ok(StorageManager { connection_pool }) } + + pub(crate) async fn get_active_gateway(&self) -> Result { + todo!() + } + + pub(crate) async fn set_active_gateway( + &self, + gateway_id: Option<&str>, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn maybe_get_registered_gateway( + &self, + gateway_id: &str, + ) -> Result, sqlx::Error> { + todo!() + } + + pub(crate) async fn must_get_registered_gateway( + &self, + gateway_id: &str, + ) -> Result { + todo!() + } + + pub(crate) async fn set_registered_gateway( + &self, + registered_gateway: &RawRegisteredGateway, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn remove_registered_gateway( + &self, + gateway_id: &str, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn get_remote_gateway_details( + &self, + gateway_id: &str, + ) -> Result { + todo!() + } + + pub(crate) async fn set_remote_gateway_details( + &self, + remote: &RawRemoteGatewayDetails, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn remove_remote_gateway_details( + &self, + gateway_id: &str, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn get_custom_gateway_details( + &self, + gateway_id: &str, + ) -> Result { + todo!() + } + + pub(crate) async fn set_custom_gateway_details( + &self, + custom: &RawCustomGatewayDetails, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn remove_custom_gateway_details( + &self, + gateway_id: &str, + ) -> Result<(), sqlx::Error> { + todo!() + } + + pub(crate) async fn registered_gateways(&self) -> Result, sqlx::Error> { + todo!() + } } diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 5061fe60fc..7e0fbcdebc 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -1,10 +1,13 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::types::GatewayRegistration; -use crate::{ActiveGateway, GatewaysDetailsStore, StorageError}; +use crate::{ + ActiveGateway, BadGateway, GatewayDetails, GatewayRegistration, GatewayType, + GatewaysDetailsStore, StorageError, +}; use async_trait::async_trait; use manager::StorageManager; +use nym_crypto::asymmetric::identity::PublicKey; use std::path::Path; pub mod error; @@ -28,36 +31,120 @@ impl GatewaysDetailsStore for OnDiskGatewaysDetails { type StorageError = error::StorageError; async fn has_gateway_details(&self, gateway_id: &str) -> Result { - todo!() + Ok(self + .manager + .maybe_get_registered_gateway(gateway_id) + .await? + .is_some()) } async fn active_gateway(&self) -> Result { - todo!() + let raw_active = self.manager.get_active_gateway().await?; + let registration = match raw_active.active_gateway_id_bs58 { + None => None, + Some(gateway_id) => Some(self.load_gateway_details(&gateway_id).await?), + }; + + Ok(ActiveGateway { registration }) } async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { - todo!() + Ok(self.manager.set_active_gateway(Some(gateway_id)).await?) } async fn all_gateways(&self) -> Result, Self::StorageError> { - todo!() + let identities = self.manager.registered_gateways().await?; + let mut registered = Vec::with_capacity(identities.len()); + for gateway_id in identities { + registered.push(self.load_gateway_details(&gateway_id).await?) + } + + Ok(registered) + } + + async fn all_gateways_identities(&self) -> Result, Self::StorageError> { + Ok(self + .manager + .registered_gateways() + .await? + .into_iter() + .map(|gateway_id| { + gateway_id + .as_str() + .parse() + .map_err(|source| BadGateway::MalformedGatewayIdentity { gateway_id, source }) + }) + .collect::>()?) } async fn load_gateway_details( &self, gateway_id: &str, ) -> Result { - todo!() + let raw_registration = self.manager.must_get_registered_gateway(gateway_id).await?; + let typ: GatewayType = raw_registration.gateway_type.parse()?; + + let details = match typ { + GatewayType::Remote => { + let raw_details = self.manager.get_remote_gateway_details(gateway_id).await?; + GatewayDetails::Remote(raw_details.try_into()?) + } + GatewayType::Custom => { + let raw_details = self.manager.get_custom_gateway_details(gateway_id).await?; + GatewayDetails::Custom(raw_details.try_into()?) + } + }; + + Ok(GatewayRegistration { + details, + registration_timestamp: raw_registration.registration_timestamp, + }) } async fn store_gateway_details( &self, details: &GatewayRegistration, ) -> Result<(), Self::StorageError> { - todo!() + let raw_registration = details.into(); + self.manager + .set_registered_gateway(&raw_registration) + .await?; + + match &details.details { + GatewayDetails::Remote(remote_details) => { + let raw_details = remote_details.into(); + self.manager + .set_remote_gateway_details(&raw_details) + .await?; + } + GatewayDetails::Custom(custom_details) => { + let raw_details = custom_details.into(); + self.manager + .set_custom_gateway_details(&raw_details) + .await?; + } + } + Ok(()) } + // ideally all of those should be run under a storage tx to ensure storage consistency, + // but at that point it's fine async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> { - todo!() + let active = self.manager.get_active_gateway().await?; + if let Some(currently_active) = &active.active_gateway_id_bs58 { + if currently_active == gateway_id { + self.manager.set_active_gateway(None).await?; + } + } + + // just try remove it from all tables even if it doesn't actually exist + self.manager.remove_registered_gateway(gateway_id).await?; + self.manager + .remove_remote_gateway_details(gateway_id) + .await?; + self.manager + .remove_custom_gateway_details(gateway_id) + .await?; + Ok(()) } } diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 26deeec049..42c10b9df9 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -37,6 +37,18 @@ pub trait GatewaysDetailsStore { /// Returns details of all registered gateways. async fn all_gateways(&self) -> Result, Self::StorageError>; + /// Return identity keys of all registered gateways. + async fn all_gateways_identities( + &self, + ) -> Result, Self::StorageError> { + Ok(self + .all_gateways() + .await? + .into_iter() + .map(|gateway| gateway.details.gateway_id()) + .collect()) + } + /// Check if the gateway with the provided id already exists in the store. async fn has_gateway_details(&self, gateway_id: &str) -> Result; @@ -55,22 +67,3 @@ pub trait GatewaysDetailsStore { /// Remove given gateway details from the underlying store. async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError>; } - -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait GatewaysDetailsStoreExt: GatewaysDetailsStore { - async fn all_gateways_identities( - &self, - ) -> Result, Self::StorageError> { - Ok(self - .all_gateways() - .await? - .into_iter() - .map(|gateway| gateway.details.gateway_id()) - .collect()) - } -} - -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl GatewaysDetailsStoreExt for T where T: GatewaysDetailsStore {} diff --git a/common/client-core/gateways-storage/src/types.rs b/common/client-core/gateways-storage/src/types.rs index a63cd4f5d8..3755cb6127 100644 --- a/common/client-core/gateways-storage/src/types.rs +++ b/common/client-core/gateways-storage/src/types.rs @@ -27,6 +27,16 @@ pub struct GatewayRegistration { pub registration_timestamp: OffsetDateTime, } +impl<'a> From<&'a GatewayRegistration> for RawRegisteredGateway { + fn from(value: &'a GatewayRegistration) -> Self { + RawRegisteredGateway { + gateway_id_bs58: value.details.gateway_id().to_base58_string(), + registration_timestamp: value.registration_timestamp, + gateway_type: value.details.typ().to_string(), + } + } +} + #[derive(Debug, Clone)] pub enum GatewayDetails { /// Standard details of a remote gateway @@ -83,6 +93,13 @@ impl GatewayDetails { pub fn is_custom(&self) -> bool { matches!(self, GatewayDetails::Custom(..)) } + + pub fn typ(&self) -> GatewayType { + match self { + GatewayDetails::Remote(_) => GatewayType::Remote, + GatewayDetails::Custom(_) => GatewayType::Custom, + } + } } #[derive(Debug, Copy, Clone, Default)] @@ -116,6 +133,12 @@ impl Display for GatewayType { } } +#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +pub struct RawActiveGateway { + pub active_gateway_id_bs58: Option, +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct RawRegisteredGateway { @@ -205,8 +228,8 @@ impl TryFrom for RemoteGatewayDetails { } } -impl From for RawRemoteGatewayDetails { - fn from(value: RemoteGatewayDetails) -> Self { +impl<'a> From<&'a RemoteGatewayDetails> for RawRemoteGatewayDetails { + fn from(value: &'a RemoteGatewayDetails) -> Self { RawRemoteGatewayDetails { gateway_id_bs58: value.gateway_id.to_base58_string(), derived_aes128_ctr_blake3_hmac_keys_bs58: value @@ -214,7 +237,7 @@ impl From for RawRemoteGatewayDetails { .to_base58_string(), gateway_owner_address: value.gateway_owner_address.to_string(), gateway_listener: value.gateway_listener.to_string(), - wg_tun_address: value.wg_tun_address.map(|addr| addr.to_string()), + wg_tun_address: value.wg_tun_address.as_ref().map(|addr| addr.to_string()), } } } @@ -260,11 +283,12 @@ impl TryFrom for CustomGatewayDetails { } } -impl From for RawCustomGatewayDetails { - fn from(value: CustomGatewayDetails) -> Self { +impl<'a> From<&'a CustomGatewayDetails> for RawCustomGatewayDetails { + fn from(value: &'a CustomGatewayDetails) -> Self { RawCustomGatewayDetails { gateway_id_bs58: value.gateway_id.to_base58_string(), - data: value.data, + // I don't know what to feel about that clone here given it might contain possibly sensitive data + data: value.data.clone(), } } } diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index d760499c31..3ed3379b10 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -4,9 +4,7 @@ use crate::client::key_manager::persistence::KeyStore; use crate::client::key_manager::ClientKeys; use crate::error::ClientCoreError; -use nym_client_core_gateways_storage::{ - ActiveGateway, GatewayRegistration, GatewaysDetailsStore, GatewaysDetailsStoreExt, -}; +use nym_client_core_gateways_storage::{ActiveGateway, GatewayRegistration, GatewaysDetailsStore}; use nym_crypto::asymmetric::identity; // helpers for error wrapping diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 2158788cd3..583625cddf 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -28,7 +28,7 @@ use nym_credential_storage::persistent_storage::PersistentStorage as PersistentC pub use nym_client_core_gateways_storage::{ CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, GatewaysDetailsStore, - GatewaysDetailsStoreExt, InMemGatewaysDetails, RegisteredGateway, RemoteGatewayDetails, + InMemGatewaysDetails, RegisteredGateway, RemoteGatewayDetails, }; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] From c4bc156cacd984c654cb1699f324bb034753cffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 16:39:38 +0000 Subject: [PATCH 26/56] actual sql --- .../client-core/gateways-storage/Cargo.toml | 2 +- .../src/backend/fs_backend/manager.rs | 110 +++++++++++++++--- .../base_client/storage/migration_helpers.rs | 2 +- nym-connect/desktop/Cargo.lock | 1 + 4 files changed, 100 insertions(+), 15 deletions(-) diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index 3968df079e..567744d1b6 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -21,7 +21,7 @@ nym-gateway-requests = { path = "../../../gateway/gateway-requests" } [target."cfg(not(target_arch = \"wasm32\"))".dependencies.sqlx] workspace = true -features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate"] +features = ["runtime-tokio-rustls", "sqlite", "macros", "migrate", "time"] optional = true [build-dependencies] diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs index 72d886bce6..965ace23f6 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -54,87 +54,171 @@ impl StorageManager { } pub(crate) async fn get_active_gateway(&self) -> Result { - todo!() + sqlx::query_as!( + RawActiveGateway, + "SELECT active_gateway_id_bs58 FROM active_gateway" + ) + .fetch_one(&self.connection_pool) + .await } pub(crate) async fn set_active_gateway( &self, gateway_id: Option<&str>, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + "UPDATE active_gateway SET active_gateway_id_bs58 = ?", + gateway_id + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn maybe_get_registered_gateway( &self, gateway_id: &str, ) -> Result, sqlx::Error> { - todo!() + sqlx::query_as("SELECT * FROM registered_gateway WHERE gateway_id_bs58 = ?") + .bind(gateway_id) + .fetch_optional(&self.connection_pool) + .await } pub(crate) async fn must_get_registered_gateway( &self, gateway_id: &str, ) -> Result { - todo!() + sqlx::query_as("SELECT * FROM registered_gateway WHERE gateway_id_bs58 = ?") + .bind(gateway_id) + .fetch_one(&self.connection_pool) + .await } pub(crate) async fn set_registered_gateway( &self, registered_gateway: &RawRegisteredGateway, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + r#" + INSERT INTO registered_gateway(gateway_id_bs58, registration_timestamp, gateway_type) + VALUES (?, ?, ?) + "#, + registered_gateway.gateway_id_bs58, + registered_gateway.registration_timestamp, + registered_gateway.gateway_type, + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn remove_registered_gateway( &self, gateway_id: &str, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + "DELETE FROM registered_gateway WHERE gateway_id_bs58 = ?", + gateway_id + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn get_remote_gateway_details( &self, gateway_id: &str, ) -> Result { - todo!() + sqlx::query_as!( + RawRemoteGatewayDetails, + "SELECT * FROM remote_gateway_details WHERE gateway_id_bs58 = ?", + gateway_id + ) + .fetch_one(&self.connection_pool) + .await } pub(crate) async fn set_remote_gateway_details( &self, remote: &RawRemoteGatewayDetails, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + r#" + INSERT INTO remote_gateway_details(gateway_id_bs58, derived_aes128_ctr_blake3_hmac_keys_bs58, gateway_owner_address, gateway_listener, wg_tun_address) + VALUES (?, ?, ?, ?, ?) + "#, + remote.gateway_id_bs58, + remote.derived_aes128_ctr_blake3_hmac_keys_bs58, + remote.gateway_owner_address, + remote.gateway_listener, + remote.wg_tun_address, + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn remove_remote_gateway_details( &self, gateway_id: &str, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + "DELETE FROM remote_gateway_details WHERE gateway_id_bs58 = ?", + gateway_id + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn get_custom_gateway_details( &self, gateway_id: &str, ) -> Result { - todo!() + sqlx::query_as!( + RawCustomGatewayDetails, + "SELECT * FROM custom_gateway_details WHERE gateway_id_bs58 = ?", + gateway_id + ) + .fetch_one(&self.connection_pool) + .await } pub(crate) async fn set_custom_gateway_details( &self, custom: &RawCustomGatewayDetails, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + r#" + INSERT INTO custom_gateway_details(gateway_id_bs58, data) + VALUES (?, ?) + "#, + custom.gateway_id_bs58, + custom.data, + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn remove_custom_gateway_details( &self, gateway_id: &str, ) -> Result<(), sqlx::Error> { - todo!() + sqlx::query!( + "DELETE FROM custom_gateway_details WHERE gateway_id_bs58 = ?", + gateway_id + ) + .execute(&self.connection_pool) + .await?; + Ok(()) } pub(crate) async fn registered_gateways(&self) -> Result, sqlx::Error> { - todo!() + sqlx::query!("SELECT gateway_id_bs58 FROM registered_gateway") + .fetch_all(&self.connection_pool) + .await + .map(|records| records.into_iter().map(|r| r.gateway_id_bs58).collect()) } } diff --git a/common/client-core/src/client/base_client/storage/migration_helpers.rs b/common/client-core/src/client/base_client/storage/migration_helpers.rs index 83869b5796..87738faef4 100644 --- a/common/client-core/src/client/base_client/storage/migration_helpers.rs +++ b/common/client-core/src/client/base_client/storage/migration_helpers.rs @@ -203,7 +203,7 @@ pub mod v1_1_33 { ) .await?; - remove_old_gateway_details(&old_storage_paths).map_err(|err| { + remove_old_gateway_details(old_storage_paths).map_err(|err| { ClientCoreError::UpgradeFailure { message: format!("failed to remove old data: {err}"), } diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 86afcd16e4..afbc2f403f 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -6618,6 +6618,7 @@ dependencies = [ "sqlx-rt", "stringprep", "thiserror", + "time", "tokio-stream", "url", "webpki-roots", From 765ac715c103b440fa56b0d13be429ae3a50d9ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Fri, 8 Mar 2024 17:25:36 +0000 Subject: [PATCH 27/56] fixing builds of x86-based binaries --- .../src/client/base_client/storage/mod.rs | 5 +- common/client-core/src/init/types.rs | 5 +- common/wasm/client-core/src/lib.rs | 2 +- .../desktop/src-tauri/src/config/mod.rs | 72 +++++----- .../src/config/old_config_v1_1_20.rs | 4 +- .../src/config/old_config_v1_1_20_2.rs | 8 +- .../src/config/old_config_v1_1_30.rs | 13 +- .../src/config/old_config_v1_1_33.rs | 47 ++++++ .../desktop/src-tauri/src/config/upgrade.rs | 135 +++++++++++------- .../src-tauri/src/operations/export.rs | 4 - nym-connect/desktop/src-tauri/src/state.rs | 8 +- nym-connect/desktop/src-tauri/src/tasks.rs | 14 +- sdk/lib/socks5-listener/src/lib.rs | 1 + .../examples/manually_handle_storage.rs | 50 ++++++- 14 files changed, 245 insertions(+), 123 deletions(-) create mode 100644 nym-connect/desktop/src-tauri/src/config/old_config_v1_1_33.rs diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 583625cddf..e1b02fc347 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -27,8 +27,9 @@ use crate::{ use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; pub use nym_client_core_gateways_storage::{ - CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, GatewaysDetailsStore, - InMemGatewaysDetails, RegisteredGateway, RemoteGatewayDetails, + ActiveGateway, BadGateway, CustomGatewayDetails, GatewayDetails, GatewayRegistration, + GatewayType, GatewaysDetailsStore, InMemGatewaysDetails, RegisteredGateway, + RemoteGatewayDetails, }; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index cfbac41121..019b5218e3 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -320,6 +320,7 @@ pub struct InitResults { pub encryption_key: String, pub gateway_id: String, pub gateway_listener: String, + pub gateway_registration: OffsetDateTime, pub address: Recipient, } @@ -337,6 +338,7 @@ impl InitResults { encryption_key: address.encryption_key().to_base58_string(), gateway_id: gateway.gateway_id.to_base58_string(), gateway_listener: gateway.gateway_listener.to_string(), + gateway_registration: registration, address, } } @@ -349,6 +351,7 @@ impl Display for InitResults { writeln!(f, "Identity key: {}", self.identity_key)?; writeln!(f, "Encryption: {}", self.encryption_key)?; writeln!(f, "Gateway ID: {}", self.gateway_id)?; - write!(f, "Gateway: {}", self.gateway_listener) + writeln!(f, "Gateway: {}", self.gateway_listener)?; + write!(f, "Registered at: {}", self.gateway_registration) } } diff --git a/common/wasm/client-core/src/lib.rs b/common/wasm/client-core/src/lib.rs index 568b2b459e..5204b75925 100644 --- a/common/wasm/client-core/src/lib.rs +++ b/common/wasm/client-core/src/lib.rs @@ -16,7 +16,7 @@ pub mod topology; pub use nym_bandwidth_controller::BandwidthController; pub use nym_client_core::*; pub use nym_client_core::{ - client::key_manager::ManagedKeys, error::ClientCoreError, init::types::InitialisationResult, + client::key_manager::ClientKeys, error::ClientCoreError, init::types::InitialisationResult, }; pub use nym_gateway_client::{error::GatewayClientError, GatewayClient, GatewayConfig}; pub use nym_sphinx::{ diff --git a/nym-connect/desktop/src-tauri/src/config/mod.rs b/nym-connect/desktop/src-tauri/src/config/mod.rs index 34176af06a..2a855b82ba 100644 --- a/nym-connect/desktop/src-tauri/src/config/mod.rs +++ b/nym-connect/desktop/src-tauri/src/config/mod.rs @@ -5,10 +5,11 @@ use crate::config::persistence::NymConnectPaths; use crate::config::template::CONFIG_TEMPLATE; use crate::config::upgrade::try_upgrade_config; use crate::error::{BackendError, Result}; -use nym_client_core::client::base_client::storage::gateway_details::OnDiskGatewayDetails; +use nym_client_core::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; +use nym_client_core::client::base_client::storage::{GatewayDetails, RemoteGatewayDetails}; use nym_client_core::client::key_manager::persistence::OnDiskKeys; -use nym_client_core::config::GatewayEndpointConfig; use nym_client_core::error::ClientCoreError; +use nym_client_core::init::generate_new_client_keys; use nym_client_core::init::helpers::current_gateways; use nym_client_core::init::types::{GatewaySelectionSpecification, GatewaySetup}; use nym_config::{ @@ -17,6 +18,7 @@ use nym_config::{ }; use nym_crypto::asymmetric::identity; use nym_socks5_client_core::config::Config as Socks5CoreConfig; +use rand_07::rngs::OsRng; use serde::{Deserialize, Serialize}; use std::path::{Path, PathBuf}; use std::{fs, io}; @@ -26,6 +28,7 @@ mod old_config_v1_1_13; mod old_config_v1_1_20; mod old_config_v1_1_20_2; mod old_config_v1_1_30; +mod old_config_v1_1_33; mod persistence; mod template; mod upgrade; @@ -163,24 +166,21 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str let already_init = if config_path.exists() { // in case we're using old config, try to upgrade it // (if we're using the current version, it's a no-op) - if let Err(err) = try_upgrade_config(&id) { + if let Err(err) = try_upgrade_config(&id).await { log::error!( - "Failed to upgrade config file {}: {:?}", + "Failed to upgrade config file {}: {err}", config_path.display(), - err ); - if let Some(failed_at_version) = try_extract_version_for_upgrade_failure(err) { - return Err( + return if let Some(failed_at_version) = try_extract_version_for_upgrade_failure(err) { + Err( BackendError::CouldNotUpgradeExistingConfigurationFileAtVersion { file: config_path, failed_at_version, }, - ); + ) } else { - return Err(BackendError::CouldNotUpgradeExistingConfigurationFile { - file: config_path, - }); - } + Err(BackendError::CouldNotUpgradeExistingConfigurationFile { file: config_path }) + }; }; eprintln!("SOCKS5 client \"{id}\" was already initialised before"); true @@ -189,13 +189,8 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str false }; - // Future proofing. This flag exists for the other clients - let user_wants_force_register = false; - - // If the client was already initialized, don't generate new keys and don't re-register with - // the gateway (because this would create a new shared key). - // Unless the user really wants to. - let register_gateway = !already_init || user_wants_force_register; + // // Future proofing. This flag exists for the other clients + // let user_wants_force_register = false; log::trace!("Creating config for id: {id}"); let mut config = Config::new(&id, &provider_address); @@ -204,7 +199,17 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str config.core.base.client.nym_api_urls = nym_config::parse_urls(&raw_validators); } - let gateway_setup = if register_gateway { + let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); + let details_store = + setup_fs_gateways_storage(&config.storage_paths.common_paths.gateway_registrations).await?; + + // if this is a first time client with this particular id is initialised, generated long-term keys + if !already_init { + let mut rng = OsRng; + generate_new_client_keys(&mut rng, &key_store).await?; + } + + let gateway_setup = if !already_init { let selection_spec = GatewaySelectionSpecification::new(Some(chosen_gateway_id), None, false); let mut rng = rand_07::thread_rng(); @@ -213,41 +218,40 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: register_gateway, + overwrite_data: true, + wg_tun_address: None, } } else { - GatewaySetup::MustLoad + GatewaySetup::MustLoad { + gateway_id: Some(chosen_gateway_id), + } }; - // Setup gateway by either registering a new one, or reusing exiting keys - let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - let details_store = - OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); let init_details = nym_client_core::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; - let gateway_endpoint = init_details - .gateway_details - .try_get_configured_endpoint() - .unwrap(); + + let GatewayDetails::Remote(gateway_details) = &init_details.gateway_registration.details else { + return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; + }; config.save_to_default_location().tap_err(|_| { log::error!("Failed to save the config file"); })?; - print_saved_config(&config, gateway_endpoint); + print_saved_config(&config, gateway_details); - let address = init_details.client_address()?; + let address = init_details.client_address(); log::info!("The address of this client is: {address}"); Ok(()) } -fn print_saved_config(config: &Config, gateway_details: &GatewayEndpointConfig) { +fn print_saved_config(config: &Config, gateway_details: &RemoteGatewayDetails) { log::info!( "Saved configuration file to {}", config.default_location().display() ); log::info!("Gateway id: {}", gateway_details.gateway_id); - log::info!("Gateway owner: {}", gateway_details.gateway_owner); + log::info!("Gateway owner: {}", gateway_details.gateway_owner_address); log::info!("Gateway listener: {}", gateway_details.gateway_listener); log::info!( "Service provider address: {}", diff --git a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20.rs b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20.rs index 4acc4fccbd..fbad434c68 100644 --- a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20.rs +++ b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20.rs @@ -5,8 +5,8 @@ use crate::config::old_config_v1_1_20_2::{ ConfigV1_1_20_2, CoreConfigV1_1_20_2, SocksClientPathsV1_1_20_2, }; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::config::disk_persistence::keys_paths::ClientKeysPaths; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; +use nym_client_core::config::disk_persistence::old_v1_1_33::ClientKeysPathsV1_1_33; use nym_client_core::config::old_config_v1_1_20::ConfigV1_1_20 as BaseConfigV1_1_20; use nym_client_core::config::old_config_v1_1_20_2::ClientV1_1_20_2; use nym_config::legacy_helpers::nym_config::MigrationNymConfig; @@ -50,7 +50,7 @@ impl From for ConfigV1_1_20_2 { }, storage_paths: SocksClientPathsV1_1_20_2 { common_paths: CommonClientPathsV1_1_20_2 { - keys: ClientKeysPaths { + keys: ClientKeysPathsV1_1_33 { private_identity_key_file: value.base.client.private_identity_key_file, public_identity_key_file: value.base.client.public_identity_key_file, private_encryption_key_file: value.base.client.private_encryption_key_file, diff --git a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20_2.rs b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20_2.rs index d87f41ae0f..6af24d249a 100644 --- a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20_2.rs +++ b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_20_2.rs @@ -3,11 +3,11 @@ use crate::config::default_config_filepath; use crate::config::old_config_v1_1_30::ConfigV1_1_30; -use crate::config::persistence::NymConnectPaths; +use crate::config::old_config_v1_1_33::NymConnectPathsV1_1_33; use crate::error::Result; use nym_bin_common::logging::LoggingSettings; use nym_client_core::config::disk_persistence::old_v1_1_20_2::CommonClientPathsV1_1_20_2; -use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::config::old_config_v1_1_33::OldGatewayEndpointConfigV1_1_33; use nym_config::read_config_from_toml_file; use serde::{Deserialize, Serialize}; use std::io; @@ -42,11 +42,11 @@ impl ConfigV1_1_20_2 { // in this upgrade, gateway endpoint configuration was moved out of the config file, // so its returned to be stored elsewhere. - pub fn upgrade(self) -> Result<(ConfigV1_1_30, GatewayEndpointConfig)> { + pub fn upgrade(self) -> Result<(ConfigV1_1_30, OldGatewayEndpointConfigV1_1_33)> { let gateway_details = self.core.base.client.gateway_endpoint.clone().into(); let config = ConfigV1_1_30 { core: self.core.into(), - storage_paths: NymConnectPaths { + storage_paths: NymConnectPathsV1_1_33 { common_paths: self.storage_paths.common_paths.upgrade_default()?, }, // logging: self.logging, diff --git a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_30.rs b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_30.rs index a18ae5831c..3d64011c8c 100644 --- a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_30.rs +++ b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_30.rs @@ -1,8 +1,8 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::persistence::NymConnectPaths; -use crate::config::{default_config_filepath, Config}; +use crate::config::default_config_filepath; +use crate::config::old_config_v1_1_33::{ConfigV1_1_33, NymConnectPathsV1_1_33}; use nym_config::read_config_from_toml_file; use nym_socks5_client_core::config::old_config_v1_1_30::ConfigV1_1_30 as CoreConfigV1_1_30; use serde::{Deserialize, Serialize}; @@ -14,15 +14,12 @@ use std::path::Path; pub struct ConfigV1_1_30 { pub core: CoreConfigV1_1_30, - // I'm leaving a landmine here for when the paths actually do change the next time, - // but propagating the change right now (in ALL clients) would be such a hassle..., - // so sorry for the next person looking at it : ) - pub storage_paths: NymConnectPaths, + pub storage_paths: NymConnectPathsV1_1_33, } -impl From for Config { +impl From for ConfigV1_1_33 { fn from(value: ConfigV1_1_30) -> Self { - Config { + ConfigV1_1_33 { core: value.core.into(), storage_paths: value.storage_paths, } diff --git a/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_33.rs b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_33.rs new file mode 100644 index 0000000000..15de9d1750 --- /dev/null +++ b/nym-connect/desktop/src-tauri/src/config/old_config_v1_1_33.rs @@ -0,0 +1,47 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::persistence::NymConnectPaths; +use crate::config::{default_config_filepath, Config}; +use crate::error::BackendError; +use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; +use nym_config::read_config_from_toml_file; +use nym_socks5_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as CoreConfigV1_1_33; +use serde::{Deserialize, Serialize}; +use std::io; +use std::path::Path; + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +pub struct NymConnectPathsV1_1_33 { + #[serde(flatten)] + pub common_paths: CommonClientPathsV1_1_33, +} + +#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1_1_33 { + pub core: CoreConfigV1_1_33, + + // \/ CHANGED + pub storage_paths: NymConnectPathsV1_1_33, + // /\ CHANGED +} + +impl ConfigV1_1_33 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + core: self.core.into(), + storage_paths: NymConnectPaths { + common_paths: self.storage_paths.common_paths.upgrade_default()?, + }, + }) + } +} diff --git a/nym-connect/desktop/src-tauri/src/config/upgrade.rs b/nym-connect/desktop/src-tauri/src/config/upgrade.rs index 2c7118196e..8df77ab7b6 100644 --- a/nym-connect/desktop/src-tauri/src/config/upgrade.rs +++ b/nym-connect/desktop/src-tauri/src/config/upgrade.rs @@ -2,47 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 use crate::config::old_config_v1_1_30::ConfigV1_1_30; -use crate::config::persistence::NymConnectPaths; +use crate::config::old_config_v1_1_33::ConfigV1_1_33; use crate::{ config::{ old_config_v1_1_13::OldConfigV1_1_13, old_config_v1_1_20::ConfigV1_1_20, - old_config_v1_1_20_2::ConfigV1_1_20_2, Config, + old_config_v1_1_20_2::ConfigV1_1_20_2, }, - error::{BackendError, Result}, + error::Result, }; use log::{debug, info}; -use nym_client_core::{ - client::{ - base_client::storage::gateway_details::{OnDiskGatewayDetails, PersistedGatewayDetails}, - key_manager::persistence::OnDiskKeys, - }, - config::GatewayEndpointConfig, - error::ClientCoreError, -}; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; -fn persist_gateway_details( - storage_paths: &NymConnectPaths, - details: GatewayEndpointConfig, -) -> Result<()> { - let details_store = OnDiskGatewayDetails::new(&storage_paths.common_paths.gateway_details); - let keys_store = OnDiskKeys::new(storage_paths.common_paths.keys.clone()); - let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - BackendError::ClientCoreError { - source: ClientCoreError::KeyStoreError { - source: Box::new(source), - }, - } - })?; - let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - details_store - .store_to_disk(&persisted_details) - .map_err(|source| BackendError::ClientCoreError { - source: ClientCoreError::GatewaysDetailsStoreError { - source: Box::new(source), - }, - }) -} -fn try_upgrade_v1_1_13_config(id: &str) -> Result { +async fn try_upgrade_v1_1_13_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) @@ -57,14 +28,23 @@ fn try_upgrade_v1_1_13_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20 = old_config.into(); let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); let (updated_step3, gateway_config) = updated_step2.upgrade()?; - persist_gateway_details(&updated_step3.storage_paths, gateway_config)?; + let old_paths = updated_step3.storage_paths.clone(); + + let updated_step4: ConfigV1_1_33 = updated_step3.into(); + let updated = updated_step4.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; - let updated: Config = updated_step3.into(); updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_config(id: &str) -> Result { use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) @@ -78,14 +58,23 @@ fn try_upgrade_v1_1_20_config(id: &str) -> Result { let updated_step1: ConfigV1_1_20_2 = old_config.into(); let (updated_step2, gateway_config) = updated_step1.upgrade()?; - persist_gateway_details(&updated_step2.storage_paths, gateway_config)?; + let old_paths = updated_step2.storage_paths.clone(); + + let updated_step3: ConfigV1_1_33 = updated_step2.into(); + let updated = updated_step3.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; - let updated: Config = updated_step2.into(); updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { +async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -96,14 +85,23 @@ fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { info!("It is going to get updated to the current specification."); let (updated_step1, gateway_config) = old_config.upgrade()?; - persist_gateway_details(&updated_step1.storage_paths, gateway_config)?; + let old_paths = updated_step1.storage_paths.clone(); + + let updated_step2: ConfigV1_1_33 = updated_step1.into(); + let updated = updated_step2.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; - let updated: Config = updated_step1.into(); updated.save_to_default_location()?; Ok(true) } -fn try_upgrade_v1_1_30_config(id: &str) -> Result { +async fn try_upgrade_v1_1_30_config(id: &str) -> Result { // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) let Ok(old_config) = ConfigV1_1_30::read_from_default_path(id) else { // if we failed to load it, there might have been nothing to upgrade @@ -113,23 +111,62 @@ fn try_upgrade_v1_1_30_config(id: &str) -> Result { info!("It seems the client is using <= v1.1.30 config template."); info!("It is going to get updated to the current specification."); - let updated: Config = old_config.into(); + let old_paths = old_config.storage_paths.clone(); + + let updated_step1: ConfigV1_1_33 = old_config.into(); + let updated = updated_step1.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; + updated.save_to_default_location()?; Ok(true) } -pub fn try_upgrade_config(id: &str) -> Result<()> { +async fn try_upgrade_v1_1_33_config(id: &str) -> Result { + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) + let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.33 config template."); + info!("It is going to get updated to the current specification."); + + let old_paths = old_config.storage_paths.clone(); + + let updated = old_config.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +pub async fn try_upgrade_config(id: &str) -> Result<()> { debug!("Attempting to upgrade config file for \"{id}\""); - if try_upgrade_v1_1_13_config(id)? { + if try_upgrade_v1_1_13_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_config(id)? { + if try_upgrade_v1_1_20_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_20_2_config(id)? { + if try_upgrade_v1_1_20_2_config(id).await? { return Ok(()); } - if try_upgrade_v1_1_30_config(id)? { + if try_upgrade_v1_1_30_config(id).await? { + return Ok(()); + } + if try_upgrade_v1_1_33_config(id).await? { return Ok(()); } diff --git a/nym-connect/desktop/src-tauri/src/operations/export.rs b/nym-connect/desktop/src-tauri/src/operations/export.rs index a8c53e9d37..bf047ee84e 100644 --- a/nym-connect/desktop/src-tauri/src/operations/export.rs +++ b/nym-connect/desktop/src-tauri/src/operations/export.rs @@ -54,7 +54,6 @@ pub async fn export_keys(state: tauri::State<'_, Arc>>) -> Result< // Get key paths let ack_key_file = key_paths.ack_key(); - let gateway_shared_key_file = key_paths.gateway_shared_key(); let pub_id_key_file = key_paths.public_identity_key(); let priv_id_key_file = key_paths.private_identity_key(); @@ -64,7 +63,6 @@ pub async fn export_keys(state: tauri::State<'_, Arc>>) -> Result< // Read file contents let ack_key = fs::read_to_string(ack_key_file)?; - let gateway_shared_key = fs::read_to_string(gateway_shared_key_file)?; let pub_id_key = fs::read_to_string(pub_id_key_file)?; let priv_id_key = fs::read_to_string(priv_id_key_file)?; @@ -73,7 +71,6 @@ pub async fn export_keys(state: tauri::State<'_, Arc>>) -> Result< let priv_enc_key = fs::read_to_string(priv_enc_key_file)?; let ack_key_file = key_filename(&key_paths.ack_key_file)?; - let gateway_shared_key_file = key_filename(&key_paths.gateway_shared_key_file)?; let pub_id_key_file = key_filename(&key_paths.public_identity_key_file)?; let priv_id_key_file = key_filename(&key_paths.private_identity_key_file)?; let pub_enc_key_file = key_filename(&key_paths.public_encryption_key_file)?; @@ -82,7 +79,6 @@ pub async fn export_keys(state: tauri::State<'_, Arc>>) -> Result< // Format and return as json let json = serde_json::json!({ ack_key_file: ack_key, - gateway_shared_key_file: gateway_shared_key, pub_id_key_file: pub_id_key, priv_id_key_file: priv_id_key, pub_enc_key_file: pub_enc_key, diff --git a/nym-connect/desktop/src-tauri/src/state.rs b/nym-connect/desktop/src-tauri/src/state.rs index 20471e6171..83350b98fe 100644 --- a/nym-connect/desktop/src-tauri/src/state.rs +++ b/nym-connect/desktop/src-tauri/src/state.rs @@ -257,13 +257,7 @@ impl State { let (control_tx, msg_rx, exit_status_rx, used_gateway) = tasks::start_nym_socks5_client(&id, &privacy_level).await?; self.socks5_client_sender = Some(control_tx); - self.gateway = Some( - used_gateway - .try_get_configured_endpoint() - .unwrap() - .gateway_id - .clone(), - ); + self.gateway = Some(used_gateway.gateway_id().to_base58_string()); Ok((msg_rx, exit_status_rx)) } diff --git a/nym-connect/desktop/src-tauri/src/tasks.rs b/nym-connect/desktop/src-tauri/src/tasks.rs index d4264f2274..6431979fa2 100644 --- a/nym-connect/desktop/src-tauri/src/tasks.rs +++ b/nym-connect/desktop/src-tauri/src/tasks.rs @@ -1,9 +1,7 @@ use futures::{channel::mpsc, StreamExt}; -use nym_client_core::init::types::GatewayDetails; +use nym_client_core::client::base_client::storage::{GatewayDetails, GatewaysDetailsStore}; use nym_client_core::{ - client::base_client::storage::{ - gateway_details::GatewayDetailsStore, MixnetClientStorage, OnDiskPersistent, - }, + client::base_client::storage::{MixnetClientStorage, OnDiskPersistent}, config::{GroupBy, TopologyStructure}, error::ClientCoreStatusMessage, }; @@ -90,10 +88,12 @@ pub async fn start_nym_socks5_client( let used_gateway = storage .gateway_details_store() - .load_gateway_details() + .active_gateway() .await - .expect("failed to load gateway details") - .into(); + .expect("failed to load active gateway details") + .registration + .expect("no active gateway set") + .details; log::info!("Starting socks5 client"); diff --git a/sdk/lib/socks5-listener/src/lib.rs b/sdk/lib/socks5-listener/src/lib.rs index 0c9e2f7771..a4059a14d8 100644 --- a/sdk/lib/socks5-listener/src/lib.rs +++ b/sdk/lib/socks5-listener/src/lib.rs @@ -277,6 +277,7 @@ where }, available_gateways: current_gateways(&mut rng, &nym_apis).await?, overwrite_data: false, + wg_tun_address: None, }); eprintln!("starting the socks5 client"); diff --git a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs index 8b1cce1fc1..529a69688f 100644 --- a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs +++ b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs @@ -1,3 +1,6 @@ +use nym_client_core::client::base_client::storage::{ + ActiveGateway, BadGateway, GatewayRegistration, GatewaysDetailsStore, +}; use nym_sdk::mixnet::{ self, ClientKeys, EmptyReplyStorage, EphemeralCredentialStorage, KeyStore, MixnetClientStorage, MixnetMessageSender, @@ -106,23 +109,56 @@ impl KeyStore for MockKeyStore { struct MockGatewayDetailsStore; #[async_trait] -impl GatewayDetailsStore for MockGatewayDetailsStore { +impl GatewaysDetailsStore for MockGatewayDetailsStore { type StorageError = MyError; - async fn load_gateway_details(&self) -> Result { - println!("loading stored gateway details"); + async fn active_gateway(&self) -> Result { + println!("getting active gateway"); + + Err(MyError) + } + + async fn set_active_gateway(&self, _gateway_id: &str) -> Result<(), Self::StorageError> { + println!("setting active gateway"); + + Ok(()) + } + + async fn all_gateways(&self) -> Result, Self::StorageError> { + println!("getting all registered gateways"); + + Err(MyError) + } + + async fn has_gateway_details(&self, _gateway_id: &str) -> Result { + println!("checking for gateway details"); + + Err(MyError) + } + + async fn load_gateway_details( + &self, + _gateway_id: &str, + ) -> Result { + println!("loading gateway details"); Err(MyError) } async fn store_gateway_details( &self, - _details: &PersistedGatewayDetails, + _details: &GatewayRegistration, ) -> Result<(), Self::StorageError> { println!("storing gateway details"); Ok(()) } + + async fn remove_gateway_details(&self, _gateway_id: &str) -> Result<(), Self::StorageError> { + println!("removing gateway details"); + + Ok(()) + } } // @@ -178,3 +214,9 @@ impl GatewayDetailsStore for MockGatewayDetailsStore { #[derive(thiserror::Error, Debug)] #[error("foobar")] struct MyError; + +impl From for MyError { + fn from(_: BadGateway) -> Self { + MyError + } +} From 67c5a3689496d52e362da46632a9c7e120ed932e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 11 Mar 2024 11:12:56 +0000 Subject: [PATCH 28/56] building wasm-client-core --- Cargo.lock | 1 + .../client-core/gateways-storage/src/lib.rs | 5 +- .../src/client/base_client/storage/mod.rs | 7 +- common/wasm/client-core/src/error.rs | 12 +- common/wasm/client-core/src/helpers.rs | 12 +- .../src/storage/core_client_traits.rs | 55 ++++-- common/wasm/client-core/src/storage/mod.rs | 19 +- common/wasm/client-core/src/storage/types.rs | 62 +++++++ .../src/storage/wasm_client_traits.rs | 168 +++++++++++------- common/wasm/client-core/src/topology.rs | 5 - 10 files changed, 250 insertions(+), 96 deletions(-) create mode 100644 common/wasm/client-core/src/storage/types.rs diff --git a/Cargo.lock b/Cargo.lock index d136c0c614..966999d607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10878,6 +10878,7 @@ dependencies = [ "serde", "serde-wasm-bindgen", "thiserror", + "time", "tsify", "url", "wasm-bindgen", diff --git a/common/client-core/gateways-storage/src/lib.rs b/common/client-core/gateways-storage/src/lib.rs index 42c10b9df9..2d4f18422f 100644 --- a/common/client-core/gateways-storage/src/lib.rs +++ b/common/client-core/gateways-storage/src/lib.rs @@ -12,10 +12,7 @@ pub mod error; pub mod types; // todo: export port types -pub use crate::types::{ - ActiveGateway, CustomGatewayDetails, GatewayDetails, GatewayRegistration, GatewayType, - RegisteredGateway, RemoteGatewayDetails, -}; +pub use crate::types::*; pub use backend::mem_backend::{InMemGatewaysDetails, InMemStorageError}; pub use error::BadGateway; diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index e1b02fc347..2680707e35 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -26,11 +26,8 @@ use crate::{ #[cfg(all(not(target_arch = "wasm32"), feature = "fs-surb-storage"))] use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; -pub use nym_client_core_gateways_storage::{ - ActiveGateway, BadGateway, CustomGatewayDetails, GatewayDetails, GatewayRegistration, - GatewayType, GatewaysDetailsStore, InMemGatewaysDetails, RegisteredGateway, - RemoteGatewayDetails, -}; +pub use nym_client_core_gateways_storage as gateways_storage; +use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; diff --git a/common/wasm/client-core/src/error.rs b/common/wasm/client-core/src/error.rs index 01cbbcd757..f80327265a 100644 --- a/common/wasm/client-core/src/error.rs +++ b/common/wasm/client-core/src/error.rs @@ -4,7 +4,7 @@ use crate::storage::wasm_client_traits::WasmClientStorageError; use crate::topology::WasmTopologyError; use js_sys::Promise; -use nym_client_core::config::GatewayEndpointConfig; +use nym_client_core::client::base_client::storage::gateways_storage::BadGateway; use nym_client_core::error::ClientCoreError; use nym_crypto::asymmetric::identity::Ed25519RecoveryError; use nym_gateway_client::error::GatewayClientError; @@ -89,10 +89,14 @@ pub enum WasmCoreError { source: WasmClientStorageError, }, - #[error("this client has already registered with a gateway: {gateway_config:?}")] - AlreadyRegistered { - gateway_config: GatewayEndpointConfig, + #[error(transparent)] + MalformedGateway { + #[from] + source: BadGateway, }, + + #[error("this client has already registered with a gateway: {gateway_id:?}")] + AlreadyRegistered { gateway_id: String }, } wasm_error!(WasmCoreError); diff --git a/common/wasm/client-core/src/helpers.rs b/common/wasm/client-core/src/helpers.rs index 6b59d30d80..a64341907c 100644 --- a/common/wasm/client-core/src/helpers.rs +++ b/common/wasm/client-core/src/helpers.rs @@ -90,8 +90,15 @@ pub async fn setup_gateway_wasm( chosen_gateway: Option, gateways: &[gateway::Node], ) -> Result { - let setup = if client_store.has_full_gateway_info().await? { - GatewaySetup::MustLoad + // TODO: so much optimization and extra features could be added here, but that's for the future + + let setup = if client_store + .get_active_gateway_id() + .await? + .active_gateway_id_bs58 + .is_some() + { + GatewaySetup::MustLoad { gateway_id: None } } else { let selection_spec = GatewaySelectionSpecification::new(chosen_gateway.clone(), None, force_tls); @@ -100,6 +107,7 @@ pub async fn setup_gateway_wasm( specification: selection_spec, available_gateways: gateways.to_vec(), overwrite_data: false, + wg_tun_address: None, } }; diff --git a/common/wasm/client-core/src/storage/core_client_traits.rs b/common/wasm/client-core/src/storage/core_client_traits.rs index dde0b89f08..20105ac339 100644 --- a/common/wasm/client-core/src/storage/core_client_traits.rs +++ b/common/wasm/client-core/src/storage/core_client_traits.rs @@ -7,7 +7,10 @@ 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::MixnetClientStorage; +use nym_client_core::client::base_client::storage::{ + gateways_storage::{ActiveGateway, GatewayRegistration, GatewaysDetailsStore}, + MixnetClientStorage, +}; use nym_client_core::client::key_manager::persistence::KeyStore; use nym_client_core::client::key_manager::ClientKeys; use nym_client_core::client::replies::reply_storage::browser_backend; @@ -72,12 +75,10 @@ impl KeyStore for ClientStorage { let identity_keypair = self.must_read_identity_keypair().await?; let encryption_keypair = self.must_read_encryption_keypair().await?; let ack_keypair = self.must_read_ack_key().await?; - let gateway_shared_key = self.must_read_gateway_shared_key().await?; Ok(ClientKeys::from_keys( identity_keypair, encryption_keypair, - Some(gateway_shared_key), ack_keypair, )) } @@ -91,25 +92,57 @@ impl KeyStore for ClientStorage { .await?; self.store_ack_key(&keys.ack_key()).await?; - if let Some(shared_keys) = keys.gateway_shared_key() { - self.store_gateway_shared_key(&shared_keys).await?; - } Ok(()) } } #[async_trait(?Send)] -impl GatewayDetailsStore for ClientStorage { +impl GatewaysDetailsStore for ClientStorage { type StorageError = WasmCoreError; - async fn load_gateway_details(&self) -> Result { - self.must_read_gateway_details().await + async fn active_gateway(&self) -> Result { + let raw_active = self.get_active_gateway_id().await?; + let registration = match raw_active.active_gateway_id_bs58 { + None => None, + Some(gateway_id) => Some(self.load_gateway_details(&gateway_id).await?), + }; + + Ok(ActiveGateway { registration }) + } + + async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + ::set_active_gateway(self, Some(gateway_id)).await?; + Ok(()) + } + + async fn all_gateways(&self) -> Result, Self::StorageError> { + todo!() + // let identities = self.all + } + + async fn has_gateway_details(&self, gateway_id: &str) -> Result { + self.has_registered_gateway(gateway_id).await + } + + async fn load_gateway_details( + &self, + gateway_id: &str, + ) -> Result { + Ok(self + .must_get_registered_gateway(gateway_id) + .await? + .try_into()?) } async fn store_gateway_details( &self, - details: &PersistedGatewayDetails, + details: &GatewayRegistration, ) -> Result<(), Self::StorageError> { - ::store_gateway_details(self, details).await + let raw_registration = details.into(); + self.store_registered_gateway(&raw_registration).await + } + + async fn remove_gateway_details(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + self.remove_registered_gateway(gateway_id).await } } diff --git a/common/wasm/client-core/src/storage/mod.rs b/common/wasm/client-core/src/storage/mod.rs index c94e8fc599..c210dc1dcc 100644 --- a/common/wasm/client-core/src/storage/mod.rs +++ b/common/wasm/client-core/src/storage/mod.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::WasmCoreError; -use crate::storage::wasm_client_traits::{v1, WasmClientStorage}; +use crate::storage::wasm_client_traits::{v1, v2, WasmClientStorage}; use async_trait::async_trait; use js_sys::{Array, Promise}; use serde::de::DeserializeOwned; @@ -11,14 +11,15 @@ use wasm_bindgen::prelude::*; use wasm_bindgen_futures::future_to_promise; use wasm_storage::traits::BaseWasmStorage; use wasm_storage::{IdbVersionChangeEvent, WasmStorage}; -use wasm_utils::error::PromisableResult; +use wasm_utils::error::{simple_js_error, PromisableResult}; use zeroize::Zeroizing; pub mod core_client_traits; +mod types; pub mod wasm_client_traits; const STORAGE_NAME_PREFIX: &str = "wasm-client-storage"; -const STORAGE_VERSION: u32 = 1; +const STORAGE_VERSION: u32 = 2; #[wasm_bindgen] pub struct ClientStorage { @@ -48,13 +49,21 @@ impl ClientStorage { // works with an unsigned integer. // See let old_version = evt.old_version() as u32; + let db = evt.db(); if old_version < 1 { - // migrating to version 1 - let db = evt.db(); + // migrating to version 2 db.create_object_store(v1::KEYS_STORE)?; db.create_object_store(v1::CORE_STORE)?; + + db.create_object_store(v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE)?; + db.create_object_store(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE)?; + } + + // version 1 -> unimplemented migration + if old_version < 2 { + return Err(simple_js_error("this client is incompatible with existing storage. please initialise it again.")); } Ok(()) diff --git a/common/wasm/client-core/src/storage/types.rs b/common/wasm/client-core/src/storage/types.rs new file mode 100644 index 0000000000..5b40629778 --- /dev/null +++ b/common/wasm/client-core/src/storage/types.rs @@ -0,0 +1,62 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use nym_client_core::client::base_client::storage::gateways_storage::{ + BadGateway, GatewayDetails, GatewayRegistration, RawRemoteGatewayDetails, RemoteGatewayDetails, +}; +use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; + +// a more nested struct since we only have a single gateway type in wasm (no 'custom') +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WasmRawRegisteredGateway { + pub gateway_id_bs58: String, + + pub registration_timestamp: OffsetDateTime, + + pub derived_aes128_ctr_blake3_hmac_keys_bs58: String, + + pub gateway_owner_address: String, + + pub gateway_listener: String, +} + +impl TryFrom for GatewayRegistration { + type Error = BadGateway; + + fn try_from(value: WasmRawRegisteredGateway) -> Result { + // offload some parsing to an existing impl + let raw_remote = RawRemoteGatewayDetails { + gateway_id_bs58: value.gateway_id_bs58, + derived_aes128_ctr_blake3_hmac_keys_bs58: value + .derived_aes128_ctr_blake3_hmac_keys_bs58, + gateway_owner_address: value.gateway_owner_address, + gateway_listener: value.gateway_listener, + wg_tun_address: None, + }; + let remote: RemoteGatewayDetails = raw_remote.try_into()?; + + Ok(GatewayRegistration { + details: GatewayDetails::Remote(remote), + registration_timestamp: value.registration_timestamp, + }) + } +} + +impl <'a> From<&'a GatewayRegistration> for WasmRawRegisteredGateway { + fn from(value: &'a GatewayRegistration) -> Self { + let GatewayDetails::Remote(remote_details) = &value.details else { + panic!("somehow obtained custom gateway registration in wasm!") + }; + + WasmRawRegisteredGateway { + gateway_id_bs58: remote_details.gateway_id.to_string(), + registration_timestamp: value.registration_timestamp, + derived_aes128_ctr_blake3_hmac_keys_bs58: remote_details + .derived_aes128_ctr_blake3_hmac_keys + .to_base58_string(), + gateway_owner_address: remote_details.gateway_owner_address.to_string(), + gateway_listener: remote_details.gateway_listener.to_string(), + } + } +} diff --git a/common/wasm/client-core/src/storage/wasm_client_traits.rs b/common/wasm/client-core/src/storage/wasm_client_traits.rs index 83e0ca1340..b8ad2c8065 100644 --- a/common/wasm/client-core/src/storage/wasm_client_traits.rs +++ b/common/wasm/client-core/src/storage/wasm_client_traits.rs @@ -1,10 +1,10 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::storage::types::WasmRawRegisteredGateway; use async_trait::async_trait; -use nym_client_core::client::base_client::storage::gateway_details::PersistedGatewayDetails; +use nym_client_core::client::base_client::storage::gateways_storage::RawActiveGateway; use nym_crypto::asymmetric::{encryption, identity}; -use nym_gateway_client::SharedKeys; use nym_sphinx_acknowledgements::AckKey; use std::error::Error; use thiserror::Error; @@ -19,14 +19,22 @@ pub(crate) mod v1 { // keys // pub const CONFIG: &str = "config"; - pub const GATEWAY_DETAILS: &str = "gateway_details"; + // pub const GATEWAY_DETAILS: &str = "gateway_details"; pub const ED25519_IDENTITY_KEYPAIR: &str = "ed25519_identity_keypair"; pub const X25519_ENCRYPTION_KEYPAIR: &str = "x25519_encryption_keypair"; // TODO: for those we could actually use the subtle crypto storage pub const AES128CTR_ACK_KEY: &str = "aes128ctr_ack_key"; - pub const AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS: &str = "aes128ctr_blake3_hmac_gateway_keys"; + // pub const AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS: &str = "aes128ctr_blake3_hmac_gateway_keys"; +} + +pub(crate) mod v2 { + pub const GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE: &str = "active_gateway"; + pub const ACTIVE_GATEWAY_KEY: &str = "active_gateway"; + + // there's no concept of 'custom' gateways in wasm so the store is simpler + pub const GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE: &str = "gateway_registrations"; } #[derive(Debug, Error)] @@ -34,32 +42,20 @@ pub enum WasmClientStorageError { #[error("{typ} cryptographic key is not available in storage")] CryptoKeyNotInStorage { typ: String }, - #[error("the prior gateway details are not available in the storage")] - GatewayDetailsNotInStorage, + #[error( + "the prior gateway details for gateway {gateway_id:?} are not available in the storage" + )] + GatewayDetailsNotInStorage { gateway_id: String }, } #[async_trait(?Send)] +#[async_trait] pub trait WasmClientStorage: BaseWasmStorage { type StorageError: Error + From<::StorageError> + From; - async fn may_read_gateway_details( - &self, - ) -> Result, ::StorageError> { - self.read_value(v1::CORE_STORE, JsValue::from_str(v1::GATEWAY_DETAILS)) - .await - .map_err(Into::into) - } - - async fn must_read_gateway_details( - &self, - ) -> Result::StorageError> { - self.may_read_gateway_details() - .await? - .ok_or(WasmClientStorageError::GatewayDetailsNotInStorage) - .map_err(Into::into) - } + // keys: async fn may_read_identity_keypair( &self, @@ -91,17 +87,6 @@ pub trait WasmClientStorage: BaseWasmStorage { .map_err(Into::into) } - async fn may_read_gateway_shared_key( - &self, - ) -> Result, ::StorageError> { - self.read_value( - v1::KEYS_STORE, - JsValue::from_str(v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS), - ) - .await - .map_err(Into::into) - } - async fn must_read_identity_keypair( &self, ) -> Result::StorageError> { @@ -133,17 +118,6 @@ pub trait WasmClientStorage: BaseWasmStorage { .map_err(Into::into) } - async fn must_read_gateway_shared_key( - &self, - ) -> Result::StorageError> { - self.may_read_gateway_shared_key() - .await? - .ok_or(WasmClientStorageError::CryptoKeyNotInStorage { - typ: v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS.to_string(), - }) - .map_err(Into::into) - } - async fn store_identity_keypair( &self, keypair: &identity::KeyPair, @@ -183,38 +157,112 @@ pub trait WasmClientStorage: BaseWasmStorage { .map_err(Into::into) } - async fn store_gateway_shared_key( + // gateways: + + async fn get_active_gateway_id( &self, - key: &SharedKeys, + ) -> Result::StorageError> { + let maybe_active: Option = self + .read_value( + v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE, + JsValue::from_str(v2::ACTIVE_GATEWAY_KEY), + ) + .await?; + + // a 'temporary' hack + // (proper solution: make sure to insert empty value during db creation) + Ok(RawActiveGateway { + active_gateway_id_bs58: maybe_active.map(|a| a.active_gateway_id_bs58).flatten(), + }) + } + + async fn set_active_gateway( + &self, + gateway_id: Option<&str>, ) -> Result<(), ::StorageError> { self.store_value( - v1::KEYS_STORE, - JsValue::from_str(v1::AES128CTR_BLAKE3_HMAC_GATEWAY_KEYS), - key, + v2::GATEWAY_REGISTRATIONS_ACTIVE_GATEWAY_STORE, + JsValue::from_str(v2::ACTIVE_GATEWAY_KEY), + &RawActiveGateway { + active_gateway_id_bs58: gateway_id.map(|id| id.to_string()), + }, ) .await .map_err(Into::into) } - async fn store_gateway_details( + async fn maybe_get_registered_gateway( &self, - gateway_endpoint: &PersistedGatewayDetails, - ) -> Result<(), ::StorageError> { - self.store_value( - v1::CORE_STORE, - JsValue::from_str(v1::GATEWAY_DETAILS), - gateway_endpoint, + gateway_id: &str, + ) -> Result, ::StorageError> { + self.read_value( + v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE, + JsValue::from_str(gateway_id), ) .await .map_err(Into::into) } - async fn has_full_gateway_info( + async fn must_get_registered_gateway( &self, + gateway_id: &str, + ) -> Result::StorageError> { + self.maybe_get_registered_gateway(gateway_id) + .await? + .ok_or(WasmClientStorageError::GatewayDetailsNotInStorage { + gateway_id: gateway_id.to_string(), + }) + .map_err(Into::into) + } + + async fn store_registered_gateway( + &self, + registered_gateway: &WasmRawRegisteredGateway, + ) -> Result<(), ::StorageError> { + self.store_value( + v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE, + JsValue::from_str(®istered_gateway.gateway_id_bs58), + registered_gateway, + ) + .await + .map_err(Into::into) + } + + async fn remove_registered_gateway( + &self, + gateway_id: &str, + ) -> Result<(), ::StorageError> { + self.remove_value( + v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE, + JsValue::from_str(gateway_id), + ) + .await + .map_err(Into::into) + } + + async fn has_registered_gateway( + &self, + gateway_id: &str, ) -> Result::StorageError> { - let has_keys = self.may_read_gateway_shared_key().await?.is_some(); - let has_details = self.may_read_gateway_details().await?.is_some(); + self.has_value( + v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE, + JsValue::from_str(gateway_id), + ) + .await + .map_err(Into::into) + } - Ok(has_keys && has_details) + async fn registered_gateways( + &self, + ) -> Result, ::StorageError> { + self.get_all_keys(v2::GATEWAY_REGISTRATIONS_REGISTERED_GATEWAYS_STORE) + .await + .map_err(Into::into) + .map(|arr| { + arr.to_vec() + .into_iter() + .filter_map(|key| key.as_string()) + .collect() + }) } } diff --git a/common/wasm/client-core/src/topology.rs b/common/wasm/client-core/src/topology.rs index 8c84dee4a1..25300c41a4 100644 --- a/common/wasm/client-core/src/topology.rs +++ b/common/wasm/client-core/src/topology.rs @@ -1,7 +1,6 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use nym_client_core::config::GatewayEndpointConfig; use nym_topology::SerializableTopologyError; use nym_validator_client::client::IdentityKeyRef; use wasm_utils::console_log; @@ -17,10 +16,6 @@ pub type WasmTopologyError = SerializableTopologyError; pub trait SerializableTopologyExt { fn print(&self); - fn ensure_contains(&self, gateway_config: &GatewayEndpointConfig) -> bool { - self.ensure_contains_gateway_id(&gateway_config.gateway_id) - } - fn ensure_contains_gateway_id(&self, gateway_id: IdentityKeyRef) -> bool; } From a4e5b2af93e0ec4382dae3c10a9dd9ba9b6463c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 11 Mar 2024 11:31:01 +0000 Subject: [PATCH 29/56] further wasm fixes --- Cargo.lock | 8 ++--- .../src/client/base_client/storage/mod.rs | 2 +- common/wasm/client-core/Cargo.toml | 1 + nym-browser-extension/storage/Cargo.toml | 2 +- .../desktop/src-tauri/src/config/mod.rs | 4 ++- nym-connect/desktop/src-tauri/src/tasks.rs | 4 ++- .../examples/manually_handle_storage.rs | 7 ++--- sdk/rust/nym-sdk/src/mixnet.rs | 7 ++++- .../codegen/contract-clients/package.json | 2 +- sdk/typescript/docs/package.json | 2 +- .../packages/mix-fetch-node/package.json | 2 +- .../packages/mix-fetch/package.json | 2 +- .../packages/node-tester/package.json | 2 +- .../packages/nodejs-client/package.json | 2 +- .../packages/sdk-react/package.json | 2 +- sdk/typescript/packages/sdk/package.json | 2 +- wasm/client/Cargo.toml | 2 +- wasm/mix-fetch/Cargo.toml | 2 +- wasm/node-tester/Cargo.toml | 2 +- wasm/node-tester/src/tester.rs | 29 +++++++++++-------- 20 files changed, 49 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 966999d607..23c3ccf211 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2549,7 +2549,7 @@ dependencies = [ [[package]] name = "extension-storage" -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" dependencies = [ "bip39", "console_error_panic_hook", @@ -4557,7 +4557,7 @@ dependencies = [ [[package]] name = "mix-fetch-wasm" -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" dependencies = [ "async-trait", "futures", @@ -5313,7 +5313,7 @@ dependencies = [ [[package]] name = "nym-client-wasm" -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" dependencies = [ "anyhow", "futures", @@ -6117,7 +6117,7 @@ dependencies = [ [[package]] name = "nym-node-tester-wasm" -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" dependencies = [ "futures", "js-sys", diff --git a/common/client-core/src/client/base_client/storage/mod.rs b/common/client-core/src/client/base_client/storage/mod.rs index 2680707e35..e7c15315a6 100644 --- a/common/client-core/src/client/base_client/storage/mod.rs +++ b/common/client-core/src/client/base_client/storage/mod.rs @@ -27,7 +27,7 @@ use crate::{ use nym_credential_storage::persistent_storage::PersistentStorage as PersistentCredentialStorage; pub use nym_client_core_gateways_storage as gateways_storage; -use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; +pub use nym_client_core_gateways_storage::{GatewaysDetailsStore, InMemGatewaysDetails}; #[cfg(all(not(target_arch = "wasm32"), feature = "fs-gateways-storage"))] pub use nym_client_core_gateways_storage::{OnDiskGatewaysDetails, StorageError}; diff --git a/common/wasm/client-core/Cargo.toml b/common/wasm/client-core/Cargo.toml index 3e8ec57163..5e6a701883 100644 --- a/common/wasm/client-core/Cargo.toml +++ b/common/wasm/client-core/Cargo.toml @@ -15,6 +15,7 @@ rand = { version = "0.7.3", features = ["wasm-bindgen"] } serde = { workspace = true, features = ["derive"] } serde-wasm-bindgen = { workspace = true } thiserror = { workspace = true } +time = { workspace = true, features = ["wasm-bindgen"] } tsify = { workspace = true, features = ["js"] } url = { workspace = true } wasm-bindgen = { workspace = true } diff --git a/nym-browser-extension/storage/Cargo.toml b/nym-browser-extension/storage/Cargo.toml index 037386774c..68ed96e26b 100644 --- a/nym-browser-extension/storage/Cargo.toml +++ b/nym-browser-extension/storage/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "extension-storage" -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" edition = "2021" license = "Apache-2.0" repository = "https://github.com/nymtech/nym" diff --git a/nym-connect/desktop/src-tauri/src/config/mod.rs b/nym-connect/desktop/src-tauri/src/config/mod.rs index 2a855b82ba..83c72dde79 100644 --- a/nym-connect/desktop/src-tauri/src/config/mod.rs +++ b/nym-connect/desktop/src-tauri/src/config/mod.rs @@ -6,7 +6,9 @@ use crate::config::template::CONFIG_TEMPLATE; use crate::config::upgrade::try_upgrade_config; use crate::error::{BackendError, Result}; use nym_client_core::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; -use nym_client_core::client::base_client::storage::{GatewayDetails, RemoteGatewayDetails}; +use nym_client_core::client::base_client::storage::gateways_storage::{ + GatewayDetails, RemoteGatewayDetails, +}; use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::error::ClientCoreError; use nym_client_core::init::generate_new_client_keys; diff --git a/nym-connect/desktop/src-tauri/src/tasks.rs b/nym-connect/desktop/src-tauri/src/tasks.rs index 6431979fa2..d2f2e1c3a7 100644 --- a/nym-connect/desktop/src-tauri/src/tasks.rs +++ b/nym-connect/desktop/src-tauri/src/tasks.rs @@ -1,5 +1,7 @@ use futures::{channel::mpsc, StreamExt}; -use nym_client_core::client::base_client::storage::{GatewayDetails, GatewaysDetailsStore}; +use nym_client_core::client::base_client::storage::gateways_storage::{ + GatewayDetails, GatewaysDetailsStore, +}; use nym_client_core::{ client::base_client::storage::{MixnetClientStorage, OnDiskPersistent}, config::{GroupBy, TopologyStructure}, diff --git a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs index 529a69688f..298502458c 100644 --- a/sdk/rust/nym-sdk/examples/manually_handle_storage.rs +++ b/sdk/rust/nym-sdk/examples/manually_handle_storage.rs @@ -1,9 +1,6 @@ -use nym_client_core::client::base_client::storage::{ - ActiveGateway, BadGateway, GatewayRegistration, GatewaysDetailsStore, -}; use nym_sdk::mixnet::{ - self, ClientKeys, EmptyReplyStorage, EphemeralCredentialStorage, KeyStore, MixnetClientStorage, - MixnetMessageSender, + self, ActiveGateway, BadGateway, ClientKeys, EmptyReplyStorage, EphemeralCredentialStorage, + GatewayRegistration, GatewaysDetailsStore, KeyStore, MixnetClientStorage, MixnetMessageSender, }; use nym_topology::provider_trait::async_trait; diff --git a/sdk/rust/nym-sdk/src/mixnet.rs b/sdk/rust/nym-sdk/src/mixnet.rs index 23c951119b..c89229fb28 100644 --- a/sdk/rust/nym-sdk/src/mixnet.rs +++ b/sdk/rust/nym-sdk/src/mixnet.rs @@ -44,7 +44,12 @@ pub use native_client::MixnetClient; pub use native_client::MixnetClientSender; pub use nym_client_core::{ client::{ - base_client::storage::{Ephemeral, MixnetClientStorage, OnDiskPersistent}, + base_client::storage::{ + gateways_storage::{ + ActiveGateway, BadGateway, GatewayRegistration, GatewaysDetailsStore, + }, + Ephemeral, MixnetClientStorage, OnDiskPersistent, + }, inbound_messages::InputMessage, key_manager::{ persistence::{InMemEphemeralKeys, KeyStore, OnDiskKeys}, diff --git a/sdk/typescript/codegen/contract-clients/package.json b/sdk/typescript/codegen/contract-clients/package.json index b4f91a948b..f429659cbb 100644 --- a/sdk/typescript/codegen/contract-clients/package.json +++ b/sdk/typescript/codegen/contract-clients/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/contract-clients", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "description": "A client for all Nym smart contracts", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/docs/package.json b/sdk/typescript/docs/package.json index 4d0bb71c80..abdf67048a 100644 --- a/sdk/typescript/docs/package.json +++ b/sdk/typescript/docs/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/ts-sdk-docs", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "description": "Nym Typescript SDK Docs", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/packages/mix-fetch-node/package.json b/sdk/typescript/packages/mix-fetch-node/package.json index 3367b87244..e1618cb318 100644 --- a/sdk/typescript/packages/mix-fetch-node/package.json +++ b/sdk/typescript/packages/mix-fetch-node/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch-node", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "description": "This package is a drop-in replacement for `fetch` in NodeJS to send HTTP requests over the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/packages/mix-fetch/package.json b/sdk/typescript/packages/mix-fetch/package.json index 381ea96372..9af4e116f2 100644 --- a/sdk/typescript/packages/mix-fetch/package.json +++ b/sdk/typescript/packages/mix-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/mix-fetch", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "description": "This package is a drop-in replacement for `fetch` to send HTTP requests over the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/packages/node-tester/package.json b/sdk/typescript/packages/node-tester/package.json index eb377423bd..de487b0729 100644 --- a/sdk/typescript/packages/node-tester/package.json +++ b/sdk/typescript/packages/node-tester/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/node-tester", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "description": "This package provides a tester that can send test packets to mixnode that is part of the Nym Mixnet.", "license": "Apache-2.0", "author": "Nym Technologies SA", diff --git a/sdk/typescript/packages/nodejs-client/package.json b/sdk/typescript/packages/nodejs-client/package.json index e8df393fc4..7cd003087c 100644 --- a/sdk/typescript/packages/nodejs-client/package.json +++ b/sdk/typescript/packages/nodejs-client/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/nodejs-client", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ diff --git a/sdk/typescript/packages/sdk-react/package.json b/sdk/typescript/packages/sdk-react/package.json index 6a163d7269..e67263157f 100644 --- a/sdk/typescript/packages/sdk-react/package.json +++ b/sdk/typescript/packages/sdk-react/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk-react", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ diff --git a/sdk/typescript/packages/sdk/package.json b/sdk/typescript/packages/sdk/package.json index fabc99574a..0a416329f4 100644 --- a/sdk/typescript/packages/sdk/package.json +++ b/sdk/typescript/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@nymproject/sdk", - "version": "1.2.4-rc.2", + "version": "1.3.0-rc.0", "license": "Apache-2.0", "author": "Nym Technologies SA", "files": [ diff --git a/wasm/client/Cargo.toml b/wasm/client/Cargo.toml index 6961325d61..2232c88877 100644 --- a/wasm/client/Cargo.toml +++ b/wasm/client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nym-client-wasm" authors = ["Dave Hrycyszyn ", "Jedrzej Stuczynski "] -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" edition = "2021" keywords = ["nym", "sphinx", "wasm", "webassembly", "privacy", "client"] license = "Apache-2.0" diff --git a/wasm/mix-fetch/Cargo.toml b/wasm/mix-fetch/Cargo.toml index 336cee63e3..373b6d423f 100644 --- a/wasm/mix-fetch/Cargo.toml +++ b/wasm/mix-fetch/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "mix-fetch-wasm" authors = ["Jedrzej Stuczynski "] -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" edition = "2021" keywords = ["nym", "fetch", "wasm", "webassembly", "privacy"] license = "Apache-2.0" diff --git a/wasm/node-tester/Cargo.toml b/wasm/node-tester/Cargo.toml index 6a3d8126e7..fd295cd0e3 100644 --- a/wasm/node-tester/Cargo.toml +++ b/wasm/node-tester/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nym-node-tester-wasm" authors = ["Jedrzej Stuczynski "] -version = "1.2.4-rc.2" +version = "1.3.0-rc.0" edition = "2021" keywords = ["nym", "sphinx", "webassembly", "privacy", "tester"] license = "Apache-2.0" diff --git a/wasm/node-tester/src/tester.rs b/wasm/node-tester/src/tester.rs index 1da2ee7a4f..790c80257d 100644 --- a/wasm/node-tester/src/tester.rs +++ b/wasm/node-tester/src/tester.rs @@ -20,16 +20,16 @@ use tokio::sync::Mutex as AsyncMutex; use tsify::Tsify; use wasm_bindgen::prelude::*; use wasm_bindgen_futures::future_to_promise; +use wasm_client_core::client::base_client::storage::gateways_storage::GatewayDetails; use wasm_client_core::client::mix_traffic::transceiver::PacketRouter; use wasm_client_core::helpers::{ current_network_topology_async, setup_from_topology, EphemeralCredentialStorage, }; -use wasm_client_core::init::types::GatewayDetails; use wasm_client_core::storage::ClientStorage; use wasm_client_core::topology::SerializableNymTopology; use wasm_client_core::{ - nym_task, BandwidthController, GatewayClient, GatewayConfig, IdentityKey, InitialisationResult, - ManagedKeys, NodeIdentity, NymTopology, QueryReqwestRpcNyxdClient, Recipient, + nym_task, BandwidthController, ClientKeys, GatewayClient, GatewayConfig, IdentityKey, + InitialisationResult, NodeIdentity, NymTopology, QueryReqwestRpcNyxdClient, Recipient, }; use wasm_utils::check_promise_result; use wasm_utils::error::PromisableResult; @@ -77,10 +77,10 @@ pub struct NymNodeTesterBuilder { Option>, } -fn address(keys: &ManagedKeys, gateway_identity: NodeIdentity) -> Recipient { +fn address(keys: &ClientKeys, gateway_identity: NodeIdentity) -> Recipient { Recipient::new( - *keys.identity_public_key(), - *keys.encryption_public_key(), + *keys.identity_keypair().public_key(), + *keys.encryption_keypair().public_key(), gateway_identity, ) } @@ -161,13 +161,14 @@ impl NymNodeTesterBuilder { let client_store = ClientStorage::new_async(&storage_id, None).await?; let initialisation_result = self.gateway_info(&client_store).await?; - let GatewayDetails::Configured(gateway_endpoint) = initialisation_result.gateway_details + let GatewayDetails::Remote(gateway_info) = + initialisation_result.gateway_registration.details else { // don't bother supporting it panic!("unsupported custom gateway configuration in wasm node tester") }; - let managed_keys = initialisation_result.managed_keys; + let managed_keys = initialisation_result.client_keys; let (mixnet_message_sender, mixnet_message_receiver) = mpsc::unbounded(); let (ack_sender, ack_receiver) = mpsc::unbounded(); @@ -179,8 +180,7 @@ impl NymNodeTesterBuilder { gateway_task.fork("packet_router"), ); - let gateway_config: GatewayConfig = gateway_endpoint.try_into()?; - let gateway_identity = gateway_config.gateway_identity; + let gateway_identity = gateway_info.gateway_id; let mut gateway_client = if let Some(existing_client) = initialisation_result.authenticated_ephemeral_client { @@ -190,10 +190,15 @@ impl NymNodeTesterBuilder { gateway_task, ) } else { + let cfg = GatewayConfig::new( + gateway_info.gateway_id, + Some(gateway_info.gateway_owner_address.to_string()), + gateway_info.gateway_listener.to_string(), + ); GatewayClient::new( - gateway_config, + cfg, managed_keys.identity_keypair(), - Some(managed_keys.must_get_gateway_shared_key()), + Some(gateway_info.derived_aes128_ctr_blake3_hmac_keys), packet_router, self.bandwidth_controller.take(), gateway_task, From e48af11e8fffe3b71d8f669002051306fa4217e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 11 Mar 2024 11:41:22 +0000 Subject: [PATCH 30/56] clippy et. al --- clients/native/src/client/config/persistence.rs | 2 -- common/wasm/client-core/src/storage/types.rs | 2 +- common/wasm/client-core/src/storage/wasm_client_traits.rs | 2 +- service-providers/network-requester/src/config/mod.rs | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/clients/native/src/client/config/persistence.rs b/clients/native/src/client/config/persistence.rs index bdd3cd6a65..a61913a2f7 100644 --- a/clients/native/src/client/config/persistence.rs +++ b/clients/native/src/client/config/persistence.rs @@ -5,8 +5,6 @@ use nym_client_core::config::disk_persistence::CommonClientPaths; use serde::{Deserialize, Serialize}; use std::path::Path; - - #[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] pub struct ClientPaths { #[serde(flatten)] diff --git a/common/wasm/client-core/src/storage/types.rs b/common/wasm/client-core/src/storage/types.rs index 5b40629778..e0cc790739 100644 --- a/common/wasm/client-core/src/storage/types.rs +++ b/common/wasm/client-core/src/storage/types.rs @@ -43,7 +43,7 @@ impl TryFrom for GatewayRegistration { } } -impl <'a> From<&'a GatewayRegistration> for WasmRawRegisteredGateway { +impl<'a> From<&'a GatewayRegistration> for WasmRawRegisteredGateway { fn from(value: &'a GatewayRegistration) -> Self { let GatewayDetails::Remote(remote_details) = &value.details else { panic!("somehow obtained custom gateway registration in wasm!") diff --git a/common/wasm/client-core/src/storage/wasm_client_traits.rs b/common/wasm/client-core/src/storage/wasm_client_traits.rs index b8ad2c8065..7c1b8e3e02 100644 --- a/common/wasm/client-core/src/storage/wasm_client_traits.rs +++ b/common/wasm/client-core/src/storage/wasm_client_traits.rs @@ -172,7 +172,7 @@ pub trait WasmClientStorage: BaseWasmStorage { // a 'temporary' hack // (proper solution: make sure to insert empty value during db creation) Ok(RawActiveGateway { - active_gateway_id_bs58: maybe_active.map(|a| a.active_gateway_id_bs58).flatten(), + active_gateway_id_bs58: maybe_active.and_then(|a| a.active_gateway_id_bs58), }) } diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index 72a51d6edc..1270d7d980 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -26,9 +26,9 @@ pub use nym_client_core::config::Config as BaseClientConfig; pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; +pub mod old_config_v1_1_33; mod persistence; mod template; -pub mod old_config_v1_1_33; const DEFAULT_NETWORK_REQUESTERS_DIR: &str = "network-requester"; From 9b10871efb4877e036b5d7ed33ffdfb52ddb9a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 11 Mar 2024 12:09:37 +0000 Subject: [PATCH 31/56] ipr config migration --- .../ip-packet-router/src/cli/init.rs | 4 +- .../ip-packet-router/src/cli/mod.rs | 71 +++++++------- .../ip-packet-router/src/cli/run.rs | 2 +- .../ip-packet-router/src/cli/sign.rs | 2 +- .../ip-packet-router/src/config/mod.rs | 1 + .../src/config/old_config_v1.rs | 95 +++++++++++++++++++ 6 files changed, 137 insertions(+), 38 deletions(-) create mode 100644 service-providers/ip-packet-router/src/config/old_config_v1.rs diff --git a/service-providers/ip-packet-router/src/cli/init.rs b/service-providers/ip-packet-router/src/cli/init.rs index 207a6a748c..9a5808b755 100644 --- a/service-providers/ip-packet-router/src/cli/init.rs +++ b/service-providers/ip-packet-router/src/cli/init.rs @@ -21,8 +21,8 @@ impl InitialisableClient for IpPacketRouterInit { type InitArgs = Init; type Config = Config; - fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id) + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index c2ef5b800e..1ed7ca2920 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -1,14 +1,12 @@ -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::key_manager::persistence::OnDiskKeys; -use nym_client_core::config::GatewayEndpointConfig; -use nym_client_core::error::ClientCoreError; -use std::sync::OnceLock; - use crate::config::{BaseClientConfig, Config}; use crate::error::IpPacketRouterError; +use clap::{CommandFactory, Parser, Subcommand}; +use log::{error, info, 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::migration_helpers::v1_1_33; +use nym_ip_packet_router::config::old_config_v1::ConfigV1; +use std::sync::OnceLock; mod build_info; mod init; @@ -105,36 +103,41 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { Ok(()) } -// Unused until we need to start implementing config upgrades -#[allow(unused)] -fn persist_gateway_details( - config: &Config, - details: GatewayEndpointConfig, -) -> Result<(), IpPacketRouterError> { - let details_store = - OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details); - let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone()); - let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| { - IpPacketRouterError::ClientCoreError(ClientCoreError::KeyStoreError { - source: Box::new(source), - }) - })?; - let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?; - details_store - .store_to_disk(&persisted_details) - .map_err(|source| { - IpPacketRouterError::ClientCoreError(ClientCoreError::GatewaysDetailsStoreError { - source: Box::new(source), - }) - }) +async fn try_upgrade_v1_config(id: &str) -> Result { + // explicitly load it as v1 (which is incompatible with the current one) + let Ok(old_config) = ConfigV1::read_from_default_path(id) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using v1 config template."); + info!("It is going to get updated to the current specification."); + + let old_paths = old_config.storage_paths.clone(); + let updated = old_config.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) } -fn try_upgrade_config(_id: &str) -> Result<(), IpPacketRouterError> { +async fn try_upgrade_config(id: &str) -> Result<(), IpPacketRouterError> { trace!("Attempting to upgrade config"); + + if try_upgrade_v1_config(id).await? { + return Ok(()); + } + Ok(()) } -fn try_load_current_config(id: &str) -> Result { +async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { return if !cfg.validate() { @@ -145,7 +148,7 @@ fn try_load_current_config(id: &str) -> Result { } // we couldn't load it - try upgrading it from older revisions - try_upgrade_config(id)?; + try_upgrade_config(id).await?; let config = match Config::read_from_default_path(id) { Ok(cfg) => cfg, diff --git a/service-providers/ip-packet-router/src/cli/run.rs b/service-providers/ip-packet-router/src/cli/run.rs index cbfb3f8453..6167de7666 100644 --- a/service-providers/ip-packet-router/src/cli/run.rs +++ b/service-providers/ip-packet-router/src/cli/run.rs @@ -25,7 +25,7 @@ impl From for OverrideConfig { } pub(crate) async fn execute(args: &Run) -> Result<(), IpPacketRouterError> { - let mut config = try_load_current_config(&args.common_args.id)?; + let mut config = try_load_current_config(&args.common_args.id).await?; config = override_config(config, OverrideConfig::from(args.clone())); log::debug!("Using config: {:#?}", config); diff --git a/service-providers/ip-packet-router/src/cli/sign.rs b/service-providers/ip-packet-router/src/cli/sign.rs index c282483de3..2b56007b47 100644 --- a/service-providers/ip-packet-router/src/cli/sign.rs +++ b/service-providers/ip-packet-router/src/cli/sign.rs @@ -52,7 +52,7 @@ fn print_signed_contract_msg( } pub(crate) async fn execute(args: &Sign) -> Result<(), IpPacketRouterError> { - let config = try_load_current_config(&args.id)?; + let config = try_load_current_config(&args.id).await?; if !version_check(&config) { log::error!("Failed the local version check"); diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 1ea0ee755b..1d36c97d16 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -22,6 +22,7 @@ use crate::config::persistence::IpPacketRouterPaths; use self::template::CONFIG_TEMPLATE; +pub mod old_config_v1; mod persistence; mod template; diff --git a/service-providers/ip-packet-router/src/config/old_config_v1.rs b/service-providers/ip-packet-router/src/config/old_config_v1.rs new file mode 100644 index 0000000000..34399af4cf --- /dev/null +++ b/service-providers/ip-packet-router/src/config/old_config_v1.rs @@ -0,0 +1,95 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::persistence::IpPacketRouterPaths; +use crate::config::Config; +use crate::config::{default_config_filepath, IpPacketRouter}; +use crate::error::IpPacketRouterError; +use nym_bin_common::logging::LoggingSettings; +use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33; +use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseConfigV1_1_33; +use nym_config::read_config_from_toml_file; +use nym_config::serde_helpers::de_maybe_stringified; +use nym_network_defaults::mainnet; +use serde::{Deserialize, Serialize}; +use std::io; +use std::path::{Path, PathBuf}; +use url::Url; + +#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)] +pub struct IpPacketRouterPathsV1 { + #[serde(flatten)] + pub common_paths: CommonClientPathsV1_1_33, + + /// Location of the file containing our description + pub ip_packet_router_description: PathBuf, +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ConfigV1 { + #[serde(flatten)] + pub base: BaseConfigV1_1_33, + + #[serde(default)] + pub ip_packet_router: IpPacketRouterV1, + + pub storage_paths: IpPacketRouterPathsV1, + + pub logging: LoggingSettings, +} + +impl ConfigV1 { + pub fn read_from_toml_file>(path: P) -> io::Result { + read_config_from_toml_file(path) + } + + pub fn read_from_default_path>(id: P) -> io::Result { + Self::read_from_toml_file(default_config_filepath(id)) + } + + pub fn try_upgrade(self) -> Result { + Ok(Config { + base: self.base.into(), + ip_packet_router: self.ip_packet_router.into(), + storage_paths: IpPacketRouterPaths { + common_paths: self.storage_paths.common_paths.upgrade_default()?, + ip_packet_router_description: self.storage_paths.ip_packet_router_description, + }, + logging: self.logging, + }) + } +} + +#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)] +#[serde(default, deny_unknown_fields)] +pub struct IpPacketRouterV1 { + /// Disable Poisson sending rate. + pub disable_poisson_rate: bool, + + /// Specifies the url for an upstream source of the exit policy used by this node. + #[serde(deserialize_with = "de_maybe_stringified")] + pub upstream_exit_policy_url: Option, +} + +impl Default for IpPacketRouterV1 { + fn default() -> Self { + IpPacketRouterV1 { + disable_poisson_rate: true, + upstream_exit_policy_url: Some( + mainnet::EXIT_POLICY_URL + .parse() + .expect("invalid default exit policy URL"), + ), + } + } +} + +impl From for IpPacketRouter { + fn from(value: IpPacketRouterV1) -> Self { + IpPacketRouter { + disable_poisson_rate: value.disable_poisson_rate, + upstream_exit_policy_url: value.upstream_exit_policy_url, + } + } +} From 0ac8098dad6d72cc463a793aa98e7395159237ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Mon, 11 Mar 2024 17:38:15 +0000 Subject: [PATCH 32/56] ability to reuse free passes from the storage for new gateways --- common/bandwidth-controller/src/lib.rs | 16 ++-- .../client-libs/gateway-client/src/client.rs | 6 +- ...0240311120000_credential_used_gateways.sql | 31 ++++++++ .../migrations/20240311120001_drop_erc20.sql | 7 ++ .../credential-storage/src/backends/memory.rs | 78 +++++++++++++++---- .../credential-storage/src/backends/sqlite.rs | 53 +++++++++++-- .../src/ephemeral_storage.rs | 20 ++++- common/credential-storage/src/models.rs | 7 +- .../src/persistent_storage.rs | 20 ++++- common/credential-storage/src/storage.rs | 8 +- 10 files changed, 206 insertions(+), 40 deletions(-) create mode 100644 common/credential-storage/migrations/20240311120000_credential_used_gateways.sql create mode 100644 common/credential-storage/migrations/20240311120001_drop_erc20.sql diff --git a/common/bandwidth-controller/src/lib.rs b/common/bandwidth-controller/src/lib.rs index 31d499dac9..33f9428e44 100644 --- a/common/bandwidth-controller/src/lib.rs +++ b/common/bandwidth-controller/src/lib.rs @@ -49,6 +49,7 @@ impl BandwidthController { /// It marks any retrieved intermediate credentials as expired. pub async fn get_next_usable_credential( &self, + gateway_id: &str, ) -> Result where ::StorageError: Send + Sync + 'static, @@ -56,7 +57,7 @@ impl BandwidthController { loop { let Some(maybe_next) = self .storage - .get_next_unspent_credential() + .get_next_unspent_credential(gateway_id) .await .map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err)))? else { @@ -114,12 +115,13 @@ impl BandwidthController { pub async fn prepare_bandwidth_credential( &self, + gateway_id: &str, ) -> Result where C: DkgQueryClient + Sync + Send, ::StorageError: Send + Sync + 'static, { - let retrieved_credential = self.get_next_usable_credential().await?; + let retrieved_credential = self.get_next_usable_credential(gateway_id).await?; let epoch_id = retrieved_credential.credential.epoch_id(); let credential_id = retrieved_credential.credential_id; @@ -137,14 +139,16 @@ impl BandwidthController { }) } - pub async fn consume_credential(&self, id: i64) -> Result<(), BandwidthControllerError> + pub async fn consume_credential( + &self, + id: i64, + gateway_id: &str, + ) -> Result<(), BandwidthControllerError> where ::StorageError: Send + Sync + 'static, { - // JS: shouldn't we send some contract/validator/gateway message here to actually, you know, - // consume it? self.storage - .consume_coconut_credential(id) + .consume_coconut_credential(id, gateway_id) .await .map_err(|err| BandwidthControllerError::CredentialStorageError(Box::new(err))) } diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index 2d7d4b9b57..5fb062065f 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -626,11 +626,13 @@ impl GatewayClient { }); } + let gateway_id = self.gateway_identity().to_base58_string(); + let prepared_credential = self .bandwidth_controller .as_ref() .unwrap() - .prepare_bandwidth_credential() + .prepare_bandwidth_credential(&gateway_id) .await?; self.claim_coconut_bandwidth(prepared_credential.data) @@ -638,7 +640,7 @@ impl GatewayClient { self.bandwidth_controller .as_ref() .unwrap() - .consume_credential(prepared_credential.credential_id) + .consume_credential(prepared_credential.credential_id, &gateway_id) .await?; Ok(()) diff --git a/common/credential-storage/migrations/20240311120000_credential_used_gateways.sql b/common/credential-storage/migrations/20240311120000_credential_used_gateways.sql new file mode 100644 index 0000000000..96398f6251 --- /dev/null +++ b/common/credential-storage/migrations/20240311120000_credential_used_gateways.sql @@ -0,0 +1,31 @@ +/* + * Copyright 2024 - Nym Technologies SA + * SPDX-License-Identifier: Apache-2.0 + */ + +DROP TABLE coconut_credentials; +CREATE TABLE coconut_credentials +( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + +-- introduce a way for us to introduce breaking changes in serialization + serialization_revision INTEGER NOT NULL, + +-- the best we can do without enums + credential_type TEXT CHECK ( credential_type IN ('BandwidthVoucher', 'FreeBandwidthPass') ) NOT NULL, + credential_data BLOB NOT NULL, + epoch_id INTEGER NOT NULL, + +-- this field is only really applicable to free passes + expired BOOLEAN NOT NULL +); + +-- for bandwidth vouchers there's going to be only a single entry; for freepasses there can be as many as there are gateways +CREATE TABLE credential_usage +( + credential_id INTEGER NOT NULL REFERENCES coconut_credentials (id), + gateway_id_bs58 TEXT NOT NULL, + +-- no matter credential type, we can't spend the same credential with the same gateway multiple times + UNIQUE (credential_id, gateway_id_bs58) +) \ No newline at end of file diff --git a/common/credential-storage/migrations/20240311120001_drop_erc20.sql b/common/credential-storage/migrations/20240311120001_drop_erc20.sql new file mode 100644 index 0000000000..f74034ffc6 --- /dev/null +++ b/common/credential-storage/migrations/20240311120001_drop_erc20.sql @@ -0,0 +1,7 @@ +/* + * Copyright 2024 - Nym Technologies SA + * SPDX-License-Identifier: Apache-2.0 + */ + +-- we never actually dropped that table... +DROP TABLE erc20_credentials; \ No newline at end of file diff --git a/common/credential-storage/src/backends/memory.rs b/common/credential-storage/src/backends/memory.rs index ddf5b7017e..78d18f3b88 100644 --- a/common/credential-storage/src/backends/memory.rs +++ b/common/credential-storage/src/backends/memory.rs @@ -1,7 +1,7 @@ // Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::models::StoredIssuedCredential; +use crate::models::{CredentialUsage, StoredIssuedCredential}; use std::sync::Arc; use tokio::sync::RwLock; @@ -12,7 +12,8 @@ pub struct CoconutCredentialManager { #[derive(Default)] struct CoconutCredentialManagerInner { - data: Vec, + credentials: Vec, + credential_usage: Vec, _next_id: i64, } @@ -41,25 +42,67 @@ impl CoconutCredentialManager { ) { let mut inner = self.inner.write().await; let id = inner.next_id(); - inner.data.push(StoredIssuedCredential { + inner.credentials.push(StoredIssuedCredential { id, serialization_revision, credential_data: credential_data.to_vec(), credential_type, epoch_id, - consumed: false, expired: false, }) } - /// Tries to retrieve one of the stored, unused credentials. - pub async fn get_next_unspent_credential(&self) -> Option { - let creds = self.inner.read().await; - creds - .data + async fn bandwidth_voucher_spent(&self, id: i64) -> bool { + self.inner + .read() + .await + .credential_usage .iter() - .find(|c| !c.consumed && !c.expired) - .cloned() + .any(|c| c.credential_id == id) + } + + async fn freepass_spent(&self, id: i64, gateway_id: &str) -> bool { + self.inner + .read() + .await + .credential_usage + .iter() + .any(|c| c.credential_id == id && c.gateway_id_bs58 == gateway_id) + } + + /// Tries to retrieve one of the stored, unused credentials. + pub async fn get_next_unspect_bandwidth_voucher(&self) -> Option { + let guard = self.inner.read().await; + for credential in guard + .credentials + .iter() + .filter(|c| c.credential_type == "BandwidthVoucher") + { + if !self.bandwidth_voucher_spent(credential.id).await { + return Some(credential.clone()); + } + } + None + } + + pub async fn get_next_unspect_freepass( + &self, + gateway_id: &str, + ) -> Option { + let guard = self.inner.read().await; + for credential in guard + .credentials + .iter() + .filter(|c| c.credential_type == "FreeBandwidthPass") + { + if credential.expired { + continue; + } + if !self.freepass_spent(credential.id, gateway_id).await { + return Some(credential.clone()); + } + } + None } /// Consumes in the database the specified credential. @@ -67,11 +110,12 @@ impl CoconutCredentialManager { /// # Arguments /// /// * `id`: Database id. - pub async fn consume_coconut_credential(&self, id: i64) { - let mut creds = self.inner.write().await; - if let Some(cred) = creds.data.get_mut(id as usize) { - cred.consumed = true; - } + pub async fn consume_coconut_credential(&self, id: i64, gateway_id: &str) { + let mut guard = self.inner.write().await; + guard.credential_usage.push(CredentialUsage { + credential_id: id, + gateway_id_bs58: gateway_id.to_string(), + }); } /// Marks the specified credential as expired @@ -81,7 +125,7 @@ impl CoconutCredentialManager { /// * `id`: Id of the credential to mark as expired. pub async fn mark_expired(&self, id: i64) { let mut creds = self.inner.write().await; - if let Some(cred) = creds.data.get_mut(id as usize) { + if let Some(cred) = creds.credentials.get_mut(id as usize) { cred.expired = true; } } diff --git a/common/credential-storage/src/backends/sqlite.rs b/common/credential-storage/src/backends/sqlite.rs index 50465f434d..c46c713a5f 100644 --- a/common/credential-storage/src/backends/sqlite.rs +++ b/common/credential-storage/src/backends/sqlite.rs @@ -27,19 +27,52 @@ impl CoconutCredentialManager { ) -> Result<(), sqlx::Error> { sqlx::query!( r#" - INSERT INTO coconut_credentials(serialization_revision, credential_type, credential_data, epoch_id, consumed, expired) - VALUES (?, ?, ?, ?, false, false) + INSERT INTO coconut_credentials(serialization_revision, credential_type, credential_data, epoch_id, expired) + VALUES (?, ?, ?, ?, false) "#, serialization_revision, credential_type, credential_data, epoch_id ).execute(&self.connection_pool).await?; Ok(()) } - pub async fn get_next_unspent_credential( + pub async fn get_next_unspect_freepass( + &self, + gateway_id: &str, + ) -> Result, sqlx::Error> { + // get a credential of freepass type that doesn't appear in `credential_usage` for the provided gateway_id + sqlx::query_as( + r#" + SELECT * + FROM coconut_credentials + WHERE coconut_credentials.credential_type == "FreeBandwidthPass" + AND NOT EXISTS (SELECT 1 + FROM credential_usage + WHERE credential_usage.credential_id = coconut_credential.id + AND credential_usage.gateway_id_bs58 == ?) + ORDER BY coconut_credentials.id + LIMIT 1 + "#, + ) + .bind(gateway_id) + .fetch_optional(&self.connection_pool) + .await + } + + pub async fn get_next_unspect_bandwidth_voucher( &self, ) -> Result, sqlx::Error> { + // get a credential of bandwidth voucher type that doesn't appear in `credential_usage` for any gateway_id sqlx::query_as( - "SELECT * FROM coconut_credentials WHERE NOT consumed AND NOT expired LIMIT 1", + r#" + SELECT * + FROM coconut_credentials + WHERE coconut_credentials.credential_type == "BandwidthVoucher" + AND NOT EXISTS (SELECT 1 + FROM credential_usage + WHERE credential_usage.credential_id = coconut_credential.id) + ORDER BY coconut_credentials.id + LIMIT 1 + "#, ) .fetch_optional(&self.connection_pool) .await @@ -50,10 +83,16 @@ impl CoconutCredentialManager { /// # Arguments /// /// * `id`: Database id. - pub async fn consume_coconut_credential(&self, id: i64) -> Result<(), sqlx::Error> { + /// * `gateway_id`: id of the gateway that received the credential + pub async fn consume_coconut_credential( + &self, + id: i64, + gateway_id: &str, + ) -> Result<(), sqlx::Error> { sqlx::query!( - "UPDATE coconut_credentials SET consumed = TRUE WHERE id = ?", - id + "INSERT INTO credential_usage (credential_id, gateway_id_bs58) VALUES (?, ?)", + id, + gateway_id ) .execute(&self.connection_pool) .await?; diff --git a/common/credential-storage/src/ephemeral_storage.rs b/common/credential-storage/src/ephemeral_storage.rs index 5b1b5b23e9..97d456ea46 100644 --- a/common/credential-storage/src/ephemeral_storage.rs +++ b/common/credential-storage/src/ephemeral_storage.rs @@ -44,16 +44,30 @@ impl Storage for EphemeralStorage { async fn get_next_unspent_credential( &self, + gateway_id: &str, ) -> Result, Self::StorageError> { + // first try to get a free pass if available, otherwise fallback to bandwidth voucher + let maybe_freepass = self + .coconut_credential_manager + .get_next_unspect_freepass(gateway_id) + .await; + if maybe_freepass.is_some() { + return Ok(maybe_freepass); + } + Ok(self .coconut_credential_manager - .get_next_unspent_credential() + .get_next_unspect_bandwidth_voucher() .await) } - async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> { + async fn consume_coconut_credential( + &self, + id: i64, + gateway_id: &str, + ) -> Result<(), StorageError> { self.coconut_credential_manager - .consume_coconut_credential(id) + .consume_coconut_credential(id, gateway_id) .await; Ok(()) diff --git a/common/credential-storage/src/models.rs b/common/credential-storage/src/models.rs index 5af5a3c089..49c004ece0 100644 --- a/common/credential-storage/src/models.rs +++ b/common/credential-storage/src/models.rs @@ -26,7 +26,6 @@ pub struct StoredIssuedCredential { pub credential_type: String, pub epoch_id: u32, - pub consumed: bool, pub expired: bool, } @@ -37,3 +36,9 @@ pub struct StorableIssuedCredential<'a> { pub epoch_id: u32, } + +#[cfg_attr(not(target_arch = "wasm32"), derive(sqlx::FromRow))] +pub struct CredentialUsage { + pub credential_id: i64, + pub gateway_id_bs58: String, +} diff --git a/common/credential-storage/src/persistent_storage.rs b/common/credential-storage/src/persistent_storage.rs index 8d0961c38d..f03d1abf68 100644 --- a/common/credential-storage/src/persistent_storage.rs +++ b/common/credential-storage/src/persistent_storage.rs @@ -76,16 +76,30 @@ impl Storage for PersistentStorage { async fn get_next_unspent_credential( &self, + gateway_id: &str, ) -> Result, Self::StorageError> { + // first try to get a free pass if available, otherwise fallback to bandwidth voucher + let maybe_freepass = self + .coconut_credential_manager + .get_next_unspect_freepass(gateway_id) + .await?; + if maybe_freepass.is_some() { + return Ok(maybe_freepass); + } + Ok(self .coconut_credential_manager - .get_next_unspent_credential() + .get_next_unspect_bandwidth_voucher() .await?) } - async fn consume_coconut_credential(&self, id: i64) -> Result<(), StorageError> { + async fn consume_coconut_credential( + &self, + id: i64, + gateway_id: &str, + ) -> Result<(), StorageError> { self.coconut_credential_manager - .consume_coconut_credential(id) + .consume_coconut_credential(id, gateway_id) .await?; Ok(()) diff --git a/common/credential-storage/src/storage.rs b/common/credential-storage/src/storage.rs index 8f8cb7798e..7880a3722e 100644 --- a/common/credential-storage/src/storage.rs +++ b/common/credential-storage/src/storage.rs @@ -18,6 +18,7 @@ pub trait Storage: Send + Sync { /// that is also not marked as expired async fn get_next_unspent_credential( &self, + gateway_id: &str, ) -> Result, Self::StorageError>; /// Marks as consumed in the database the specified credential. @@ -25,7 +26,12 @@ pub trait Storage: Send + Sync { /// # Arguments /// /// * `id`: Id of the credential to be consumed. - async fn consume_coconut_credential(&self, id: i64) -> Result<(), Self::StorageError>; + /// * `gateway_id`: id of the gateway that received the credential. + async fn consume_coconut_credential( + &self, + id: i64, + gateway_id: &str, + ) -> Result<(), Self::StorageError>; /// Marks the specified credential as expired /// From b59487cfb04d2395462bcfbfeec9eea288972f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 09:59:08 +0000 Subject: [PATCH 33/56] fixed ipr imports --- .../ip-packet-router/src/cli/init.rs | 10 ++++----- .../ip-packet-router/src/cli/mod.rs | 4 ++-- .../ip-packet-router/src/cli/run.rs | 8 +++---- .../ip-packet-router/src/cli/sign.rs | 2 +- .../ip-packet-router/src/main.rs | 22 +------------------ 5 files changed, 11 insertions(+), 35 deletions(-) diff --git a/service-providers/ip-packet-router/src/cli/init.rs b/service-providers/ip-packet-router/src/cli/init.rs index 9a5808b755..c7060410f7 100644 --- a/service-providers/ip-packet-router/src/cli/init.rs +++ b/service-providers/ip-packet-router/src/cli/init.rs @@ -1,17 +1,15 @@ -use std::{fmt::Display, fs, path::PathBuf}; - +use crate::cli::{override_config, try_upgrade_config, OverrideConfig}; use clap::Args; use nym_bin_common::output_format::OutputFormat; use nym_client_core::cli_helpers::client_init::{ initialise_client, CommonClientInitArgs, InitResultsWithConfig, InitialisableClient, }; -use serde::Serialize; - -use crate::{ - cli::{override_config, try_upgrade_config, OverrideConfig}, +use nym_ip_packet_router::{ config::{default_config_directory, default_config_filepath, default_data_directory, Config}, error::IpPacketRouterError, }; +use serde::Serialize; +use std::{fmt::Display, fs, path::PathBuf}; struct IpPacketRouterInit; diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index 1ed7ca2920..d809e0b9e7 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -1,11 +1,11 @@ -use crate::config::{BaseClientConfig, Config}; -use crate::error::IpPacketRouterError; use clap::{CommandFactory, Parser, Subcommand}; use log::{error, info, 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::migration_helpers::v1_1_33; use nym_ip_packet_router::config::old_config_v1::ConfigV1; +use nym_ip_packet_router::config::{BaseClientConfig, Config}; +use nym_ip_packet_router::error::IpPacketRouterError; use std::sync::OnceLock; mod build_info; diff --git a/service-providers/ip-packet-router/src/cli/run.rs b/service-providers/ip-packet-router/src/cli/run.rs index 6167de7666..32d97efddc 100644 --- a/service-providers/ip-packet-router/src/cli/run.rs +++ b/service-providers/ip-packet-router/src/cli/run.rs @@ -1,11 +1,9 @@ +use crate::cli::{override_config, OverrideConfig}; use crate::cli::{try_load_current_config, version_check}; -use crate::{ - cli::{override_config, OverrideConfig}, - error::IpPacketRouterError, -}; use clap::Args; use log::error; use nym_client_core::cli_helpers::client_run::CommonClientRunArgs; +use nym_ip_packet_router::error::IpPacketRouterError; #[allow(clippy::struct_excessive_bools)] #[derive(Args, Clone)] @@ -35,7 +33,7 @@ pub(crate) async fn execute(args: &Run) -> Result<(), IpPacketRouterError> { } log::info!("Starting ip packet router service provider"); - let mut server = crate::ip_packet_router::IpPacketRouter::new(config); + let mut server = nym_ip_packet_router::IpPacketRouter::new(config); if let Some(custom_mixnet) = &args.common_args.custom_mixnet { server = server.with_stored_topology(custom_mixnet)? } diff --git a/service-providers/ip-packet-router/src/cli/sign.rs b/service-providers/ip-packet-router/src/cli/sign.rs index 2b56007b47..968ce83536 100644 --- a/service-providers/ip-packet-router/src/cli/sign.rs +++ b/service-providers/ip-packet-router/src/cli/sign.rs @@ -1,10 +1,10 @@ use crate::cli::{try_load_current_config, version_check}; -use crate::error::IpPacketRouterError; use clap::Args; use nym_bin_common::output_format::OutputFormat; use nym_client_core::client::key_manager::persistence::OnDiskKeys; use nym_client_core::error::ClientCoreError; use nym_crypto::asymmetric::identity; +use nym_ip_packet_router::error::IpPacketRouterError; use nym_types::helpers::ConsoleSigningOutput; #[derive(Args, Clone)] diff --git a/service-providers/ip-packet-router/src/main.rs b/service-providers/ip-packet-router/src/main.rs index 143833aecb..0412ea62a9 100644 --- a/service-providers/ip-packet-router/src/main.rs +++ b/service-providers/ip-packet-router/src/main.rs @@ -1,29 +1,9 @@ #[cfg(target_os = "linux")] mod cli; -#[cfg(target_os = "linux")] -mod config; -#[cfg(target_os = "linux")] -mod connected_client_handler; -#[cfg(target_os = "linux")] -mod constants; -#[cfg(target_os = "linux")] -mod error; -#[cfg(target_os = "linux")] -mod ip_packet_router; -#[cfg(target_os = "linux")] -mod mixnet_client; -#[cfg(target_os = "linux")] -mod mixnet_listener; -#[cfg(target_os = "linux")] -mod request_filter; -#[cfg(target_os = "linux")] -mod tun_listener; -#[cfg(target_os = "linux")] -mod util; #[cfg(target_os = "linux")] #[tokio::main] -async fn main() -> Result<(), error::IpPacketRouterError> { +async fn main() -> Result<(), nym_ip_packet_router::error::IpPacketRouterError> { use clap::Parser; let args = cli::Cli::parse(); From 6c0573cb0121ab3798863dcfdd7b5b973faf4af2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 12:06:52 +0000 Subject: [PATCH 34/56] split up InitialisableClient trait --- clients/native/src/client/config/mod.rs | 4 +-- clients/native/src/commands/init.rs | 15 +++-------- clients/native/src/commands/mod.rs | 13 ++++++++++ clients/socks5/src/commands/init.rs | 15 +++-------- clients/socks5/src/commands/mod.rs | 13 ++++++++++ clients/socks5/src/config/mod.rs | 4 +-- .../src/cli_helpers/client_init.rs | 25 ++++-------------- common/client-core/src/cli_helpers/mod.rs | 4 +++ common/client-core/src/cli_helpers/traits.rs | 26 +++++++++++++++++++ .../ip-packet-router/src/cli/init.rs | 13 ++-------- .../ip-packet-router/src/cli/mod.rs | 13 ++++++++++ .../ip-packet-router/src/config/mod.rs | 6 ++--- .../network-requester/src/cli/init.rs | 15 +++-------- .../network-requester/src/cli/mod.rs | 13 ++++++++++ .../network-requester/src/config/mod.rs | 4 +-- 15 files changed, 106 insertions(+), 77 deletions(-) create mode 100644 common/client-core/src/cli_helpers/traits.rs diff --git a/clients/native/src/client/config/mod.rs b/clients/native/src/client/config/mod.rs index 264c3fec5b..f699d1e027 100644 --- a/clients/native/src/client/config/mod.rs +++ b/clients/native/src/client/config/mod.rs @@ -4,7 +4,7 @@ use crate::client::config::persistence::ClientPaths; use crate::client::config::template::CONFIG_TEMPLATE; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::cli_helpers::client_init::ClientConfig; +use nym_client_core::cli_helpers::CliClientConfig; use nym_client_core::config::disk_persistence::CommonClientPaths; use nym_config::defaults::DEFAULT_WEBSOCKET_LISTENING_PORT; use nym_config::{ @@ -75,7 +75,7 @@ impl NymConfigTemplate for Config { } } -impl ClientConfig for Config { +impl CliClientConfig for Config { fn common_paths(&self) -> &CommonClientPaths { &self.storage_paths.common_paths } diff --git a/clients/native/src/commands/init.rs b/clients/native/src/commands/init.rs index dfc7b95cd9..b71b168b03 100644 --- a/clients/native/src/commands/init.rs +++ b/clients/native/src/commands/init.rs @@ -4,7 +4,7 @@ use crate::client::config::{ default_config_directory, default_config_filepath, default_data_directory, }; -use crate::commands::try_upgrade_config; +use crate::commands::CliNativeClient; use crate::{ client::config::Config, commands::{override_config, OverrideConfig}, @@ -21,17 +21,8 @@ use std::fs; use std::net::IpAddr; use std::path::PathBuf; -struct NativeClientInit; - -impl InitialisableClient for NativeClientInit { - const NAME: &'static str = "native"; - type Error = ClientError; +impl InitialisableClient for CliNativeClient { type InitArgs = Init; - type Config = Config; - - async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id).await - } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { fs::create_dir_all(default_data_directory(id))?; @@ -124,7 +115,7 @@ pub(crate) async fn execute(args: Init) -> Result<(), ClientError> { eprintln!("Initialising client..."); let output = args.output; - let res = initialise_client::(args).await?; + let res = initialise_client::(args).await?; let init_results = InitResults::new(res); println!("{}", output.format(&init_results)); diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index d3947b876e..bb26918fa1 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -12,6 +12,7 @@ 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::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; use std::error::Error; @@ -23,6 +24,18 @@ pub(crate) mod import_credential; pub(crate) mod init; pub(crate) mod run; +pub(crate) struct CliNativeClient; + +impl CliClient for CliNativeClient { + const NAME: &'static str = "native"; + type Error = ClientError; + type Config = Config; + + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await + } +} + fn pretty_build_info_static() -> &'static str { static PRETTY_BUILD_INFORMATION: OnceLock = OnceLock::new(); PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print()) diff --git a/clients/socks5/src/commands/init.rs b/clients/socks5/src/commands/init.rs index 548059d701..83c26e7a3c 100644 --- a/clients/socks5/src/commands/init.rs +++ b/clients/socks5/src/commands/init.rs @@ -1,7 +1,7 @@ // Copyright 2021-2023 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::commands::try_upgrade_config; +use crate::commands::CliSocks5Client; use crate::config::{ default_config_directory, default_config_filepath, default_data_directory, Config, }; @@ -21,17 +21,8 @@ use std::fs; use std::net::{IpAddr, SocketAddr}; use std::path::PathBuf; -struct Socks5ClientInit; - -impl InitialisableClient for Socks5ClientInit { - const NAME: &'static str = "socks5"; - type Error = Socks5ClientError; +impl InitialisableClient for CliSocks5Client { type InitArgs = Init; - type Config = Config; - - async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id).await - } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { fs::create_dir_all(default_data_directory(id))?; @@ -139,7 +130,7 @@ pub(crate) async fn execute(args: Init) -> Result<(), Socks5ClientError> { eprintln!("Initialising client..."); let output = args.output; - let res = initialise_client::(args).await?; + let res = initialise_client::(args).await?; let init_results = InitResults::new(res); println!("{}", output.format(&init_results)); diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index d367a061cd..ba543a6e5c 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -13,6 +13,7 @@ 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::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; use nym_client_core::config::{GroupBy, TopologyStructure}; @@ -27,6 +28,18 @@ mod import_credential; pub mod init; pub(crate) mod run; +pub(crate) struct CliSocks5Client; + +impl CliClient for CliSocks5Client { + const NAME: &'static str = "socks5"; + type Error = Socks5ClientError; + type Config = Config; + + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await + } +} + fn pretty_build_info_static() -> &'static str { static PRETTY_BUILD_INFORMATION: OnceLock = OnceLock::new(); PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print()) diff --git a/clients/socks5/src/config/mod.rs b/clients/socks5/src/config/mod.rs index 2a04d6d66d..5f2f07d64d 100644 --- a/clients/socks5/src/config/mod.rs +++ b/clients/socks5/src/config/mod.rs @@ -3,7 +3,7 @@ use crate::config::template::CONFIG_TEMPLATE; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::cli_helpers::client_init::ClientConfig; +use nym_client_core::cli_helpers::CliClientConfig; use nym_client_core::config::disk_persistence::CommonClientPaths; use nym_config::{ must_get_home, read_config_from_toml_file, save_formatted_config_to_file, NymConfigTemplate, @@ -72,7 +72,7 @@ impl NymConfigTemplate for Config { } } -impl ClientConfig for Config { +impl CliClientConfig for Config { fn common_paths(&self) -> &CommonClientPaths { &self.storage_paths.common_paths } diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index e878a12028..1d83302210 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -1,7 +1,7 @@ -// Copyright 2023 - Nym Technologies SA +// Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::config::disk_persistence::CommonClientPaths; +use crate::cli_helpers::traits::{CliClient, CliClientConfig}; use crate::error::ClientCoreError; use crate::{ client::{ @@ -18,17 +18,12 @@ use nym_client_core_gateways_storage::GatewayDetails; use nym_crypto::asymmetric::identity; use nym_topology::NymTopology; use rand::rngs::OsRng; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; // we can suppress this warning (as suggested by linter itself) since we're only using it in our own code #[allow(async_fn_in_trait)] -pub trait InitialisableClient { - const NAME: &'static str; - type Error: From; +pub trait InitialisableClient: CliClient { type InitArgs: AsRef; - type Config: ClientConfig; - - async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>; fn initialise_storage_paths(id: &str) -> Result<(), Self::Error>; @@ -37,16 +32,6 @@ pub trait InitialisableClient { fn construct_config(init_args: &Self::InitArgs) -> Self::Config; } -pub trait ClientConfig { - fn common_paths(&self) -> &CommonClientPaths; - - fn core_config(&self) -> &crate::config::Config; - - fn default_store_location(&self) -> PathBuf; - - fn save_to>(&self, path: P) -> std::io::Result<()>; -} - #[cfg_attr(feature = "cli", derive(clap::Args))] #[derive(Debug, Clone)] pub struct CommonClientInitArgs { @@ -125,7 +110,7 @@ pub async fn initialise_client( ) -> Result, C::Error> where C: InitialisableClient, - ::Config: std::fmt::Debug, + ::Config: std::fmt::Debug, ::InitArgs: std::fmt::Debug, { info!("initialising {} client", C::NAME); diff --git a/common/client-core/src/cli_helpers/mod.rs b/common/client-core/src/cli_helpers/mod.rs index 874663b75e..985f0440bf 100644 --- a/common/client-core/src/cli_helpers/mod.rs +++ b/common/client-core/src/cli_helpers/mod.rs @@ -3,3 +3,7 @@ pub mod client_init; pub mod client_run; +pub mod traits; + +pub use client_init::InitialisableClient; +pub use traits::{CliClient, CliClientConfig}; diff --git a/common/client-core/src/cli_helpers/traits.rs b/common/client-core/src/cli_helpers/traits.rs new file mode 100644 index 0000000000..21b234d19b --- /dev/null +++ b/common/client-core/src/cli_helpers/traits.rs @@ -0,0 +1,26 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::disk_persistence::CommonClientPaths; +use crate::error::ClientCoreError; +use std::path::{Path, PathBuf}; + +// we can suppress this warning (as suggested by linter itself) since we're only using it in our own code +#[allow(async_fn_in_trait)] +pub trait CliClient { + const NAME: &'static str; + type Error: From; + type Config: CliClientConfig; + + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>; +} + +pub trait CliClientConfig { + fn common_paths(&self) -> &CommonClientPaths; + + fn core_config(&self) -> &crate::config::Config; + + fn default_store_location(&self) -> PathBuf; + + fn save_to>(&self, path: P) -> std::io::Result<()>; +} diff --git a/service-providers/ip-packet-router/src/cli/init.rs b/service-providers/ip-packet-router/src/cli/init.rs index c7060410f7..b5f4e0f05c 100644 --- a/service-providers/ip-packet-router/src/cli/init.rs +++ b/service-providers/ip-packet-router/src/cli/init.rs @@ -11,17 +11,8 @@ use nym_ip_packet_router::{ use serde::Serialize; use std::{fmt::Display, fs, path::PathBuf}; -struct IpPacketRouterInit; - -impl InitialisableClient for IpPacketRouterInit { - const NAME: &'static str = "ip packet router"; - type Error = IpPacketRouterError; +impl InitialisableClient for CliIpPacketRouterClient { type InitArgs = Init; - type Config = Config; - - async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id).await - } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { fs::create_dir_all(default_data_directory(id))?; @@ -97,7 +88,7 @@ pub(crate) async fn execute(args: Init) -> Result<(), IpPacketRouterError> { eprintln!("Initialising client..."); let output = args.output; - let res = initialise_client::(args).await?; + let res = initialise_client::(args).await?; let init_results = InitResults::new(res); println!("{}", output.format(&init_results)); diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index d809e0b9e7..e5168d3284 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -2,6 +2,7 @@ use clap::{CommandFactory, Parser, Subcommand}; use log::{error, info, trace}; use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::{bin_info, version_checker}; +use nym_client_core::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_ip_packet_router::config::old_config_v1::ConfigV1; use nym_ip_packet_router::config::{BaseClientConfig, Config}; @@ -13,6 +14,18 @@ mod init; mod run; mod sign; +pub(crate) struct CliIpPacketRouterClient; + +impl CliClient for CliIpPacketRouterClient { + const NAME: &'static str = "ip packet router"; + type Error = IpPacketRouterError; + type Config = Config; + + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await + } +} + fn pretty_build_info_static() -> &'static str { static PRETTY_BUILD_INFORMATION: OnceLock = OnceLock::new(); PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print()) diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 1d36c97d16..88f6b32e68 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -1,9 +1,7 @@ pub use nym_client_core::config::Config as BaseClientConfig; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::{ - cli_helpers::client_init::ClientConfig, config::disk_persistence::CommonClientPaths, -}; +use nym_client_core::{cli_helpers::CliClientConfig, config::disk_persistence::CommonClientPaths}; use nym_config::{ defaults::mainnet, must_get_home, save_formatted_config_to_file, serde_helpers::de_maybe_stringified, NymConfigTemplate, OptionalSet, DEFAULT_CONFIG_DIR, @@ -76,7 +74,7 @@ impl NymConfigTemplate for Config { } } -impl ClientConfig for Config { +impl CliClientConfig for Config { fn common_paths(&self) -> &CommonClientPaths { &self.storage_paths.common_paths } diff --git a/service-providers/network-requester/src/cli/init.rs b/service-providers/network-requester/src/cli/init.rs index b8771961eb..b9cef1f16a 100644 --- a/service-providers/network-requester/src/cli/init.rs +++ b/service-providers/network-requester/src/cli/init.rs @@ -1,7 +1,7 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::cli::try_upgrade_config; +use crate::cli::CliNetworkRequesterClient; use crate::config::{default_config_directory, default_config_filepath, default_data_directory}; use crate::{ cli::{override_config, OverrideConfig}, @@ -18,17 +18,8 @@ use std::fmt::Display; use std::fs; use std::path::PathBuf; -struct NetworkRequesterInit; - -impl InitialisableClient for NetworkRequesterInit { - const NAME: &'static str = "network requester"; - type Error = NetworkRequesterError; +impl InitialisableClient for CliNetworkRequesterClient { type InitArgs = Init; - type Config = Config; - - async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id).await - } fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> { fs::create_dir_all(default_data_directory(id))?; @@ -130,7 +121,7 @@ pub(crate) async fn execute(args: Init) -> Result<(), NetworkRequesterError> { eprintln!("Initialising client..."); let output = args.output; - let res = initialise_client::(args).await?; + let res = initialise_client::(args).await?; let init_results = InitResults::new(res); println!("{}", output.format(&init_results)); diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 6aedc24cf0..938464c6fc 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -14,6 +14,7 @@ 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::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; use std::sync::OnceLock; @@ -24,6 +25,18 @@ mod init; mod run; mod sign; +pub(crate) struct CliNetworkRequesterClient; + +impl CliClient for CliNetworkRequesterClient { + const NAME: &'static str = "network requester"; + type Error = NetworkRequesterError; + type Config = Config; + + async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { + try_upgrade_config(id).await + } +} + fn pretty_build_info_static() -> &'static str { static PRETTY_BUILD_INFORMATION: OnceLock = OnceLock::new(); PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print()) diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index 1270d7d980..a45180b200 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -4,7 +4,7 @@ use crate::config::persistence::NetworkRequesterPaths; use crate::config::template::CONFIG_TEMPLATE; use nym_bin_common::logging::LoggingSettings; -use nym_client_core::cli_helpers::client_init::ClientConfig; +use nym_client_core::cli_helpers::CliClientConfig; use nym_client_core::config::disk_persistence::CommonClientPaths; use nym_config::{ must_get_home, read_config_from_toml_file, save_formatted_config_to_file, @@ -85,7 +85,7 @@ impl NymConfigTemplate for Config { } } -impl ClientConfig for Config { +impl CliClientConfig for Config { fn common_paths(&self) -> &CommonClientPaths { &self.storage_paths.common_paths } From 1b5a0f8cf29a4e3fad74d9e10aabb663fde93251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 12:44:41 +0000 Subject: [PATCH 35/56] list gateways cli command --- clients/native/src/commands/list_gateways.rs | 32 ++++++ clients/native/src/commands/mod.rs | 9 ++ clients/socks5/src/commands/list_gateways.rs | 32 ++++++ clients/socks5/src/commands/mod.rs | 9 ++ .../src/cli_helpers/client_list_gateways.rs | 106 ++++++++++++++++++ .../src/cli_helpers/client_switch_gateway.rs | 2 + common/client-core/src/cli_helpers/mod.rs | 4 +- common/client-core/src/cli_helpers/traits.rs | 2 + .../src/client/base_client/storage/helpers.rs | 14 +++ .../ip-packet-router/src/cli/list_gateways.rs | 31 +++++ .../ip-packet-router/src/cli/mod.rs | 9 ++ .../src/cli/list_gateways.rs | 32 ++++++ .../network-requester/src/cli/mod.rs | 9 ++ 13 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 clients/native/src/commands/list_gateways.rs create mode 100644 clients/socks5/src/commands/list_gateways.rs create mode 100644 common/client-core/src/cli_helpers/client_list_gateways.rs create mode 100644 common/client-core/src/cli_helpers/client_switch_gateway.rs create mode 100644 service-providers/ip-packet-router/src/cli/list_gateways.rs create mode 100644 service-providers/network-requester/src/cli/list_gateways.rs diff --git a/clients/native/src/commands/list_gateways.rs b/clients/native/src/commands/list_gateways.rs new file mode 100644 index 0000000000..63f41e7bfb --- /dev/null +++ b/clients/native/src/commands/list_gateways.rs @@ -0,0 +1,32 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliNativeClient; +use crate::error::ClientError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), ClientError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index bb26918fa1..f4a2fb2ec9 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -22,6 +22,7 @@ use std::sync::OnceLock; pub(crate) mod build_info; pub(crate) mod import_credential; pub(crate) mod init; +mod list_gateways; pub(crate) mod run; pub(crate) struct CliNativeClient; @@ -34,6 +35,10 @@ impl CliClient for CliNativeClient { async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { try_upgrade_config(id).await } + + async fn try_load_current_config(id: &str) -> Result { + try_load_current_config(id).await + } } fn pretty_build_info_static() -> &'static str { @@ -67,6 +72,9 @@ pub(crate) enum Commands { /// Import a pre-generated credential ImportCredential(import_credential::Args), + /// List all registered with gateways + ListGateways(list_gateways::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -96,6 +104,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box init::execute(m).await?, Commands::Run(m) => run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, + Commands::ListGateways(args) => list_gateways::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/clients/socks5/src/commands/list_gateways.rs b/clients/socks5/src/commands/list_gateways.rs new file mode 100644 index 0000000000..e33921c05f --- /dev/null +++ b/clients/socks5/src/commands/list_gateways.rs @@ -0,0 +1,32 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliSocks5Client; +use crate::error::Socks5ClientError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index ba543a6e5c..5543fb7e67 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -26,6 +26,7 @@ use std::sync::OnceLock; pub(crate) mod build_info; mod import_credential; pub mod init; +mod list_gateways; pub(crate) mod run; pub(crate) struct CliSocks5Client; @@ -38,6 +39,10 @@ impl CliClient for CliSocks5Client { async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { try_upgrade_config(id).await } + + async fn try_load_current_config(id: &str) -> Result { + try_load_current_config(id).await + } } fn pretty_build_info_static() -> &'static str { @@ -71,6 +76,9 @@ pub(crate) enum Commands { /// Import a pre-generated credential ImportCredential(import_credential::Args), + /// List all registered with gateways + ListGateways(list_gateways::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -103,6 +111,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box init::execute(m).await?, Commands::Run(m) => run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, + Commands::ListGateways(args) => list_gateways::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/common/client-core/src/cli_helpers/client_list_gateways.rs b/common/client-core/src/cli_helpers/client_list_gateways.rs new file mode 100644 index 0000000000..cbb914b22d --- /dev/null +++ b/common/client-core/src/cli_helpers/client_list_gateways.rs @@ -0,0 +1,106 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli_helpers::{CliClient, CliClientConfig}; +use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; +use crate::client::base_client::storage::helpers::get_gateway_registrations; +use nym_client_core_gateways_storage::{GatewayDetails, GatewayRegistration, GatewayType}; +use nym_crypto::asymmetric::identity; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; +use time::OffsetDateTime; +use url::Url; + +#[cfg_attr(feature = "cli", derive(clap::Args))] +#[derive(Debug, Clone)] +pub struct CommonClientListGatewaysArgs { + /// Id of client we want to list gateways for. + #[cfg_attr(feature = "cli", clap(long))] + pub id: String, +} + +#[derive(Serialize, Deserialize)] +#[serde(transparent)] +pub struct RegisteredGateways(Vec); + +impl From> for RegisteredGateways { + fn from(value: Vec) -> Self { + RegisteredGateways(value.into_iter().map(Into::into).collect()) + } +} + +impl Display for RegisteredGateways { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + for (i, gateway) in self.0.iter().enumerate() { + writeln!(f, "[{i}]: {gateway}")?; + } + Ok(()) + } +} + +#[derive(Serialize, Deserialize)] +pub struct GatewayInfo { + pub registration: OffsetDateTime, + pub identity: identity::PublicKey, + + pub typ: String, + pub endpoint: Option, + pub wg_tun_address: Option, +} + +impl From for GatewayInfo { + fn from(value: GatewayRegistration) -> Self { + match value.details { + GatewayDetails::Remote(remote_details) => GatewayInfo { + registration: value.registration_timestamp, + identity: remote_details.gateway_id, + typ: GatewayType::Remote.to_string(), + endpoint: Some(remote_details.gateway_listener), + wg_tun_address: remote_details.wg_tun_address, + }, + GatewayDetails::Custom(_) => GatewayInfo { + registration: value.registration_timestamp, + identity: value.details.gateway_id(), + typ: value.details.typ().to_string(), + endpoint: None, + wg_tun_address: None, + }, + } + } +} + +impl Display for GatewayInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} gateway '{}' registered at: {}", + self.typ, self.identity, self.registration + )?; + if let Some(endpoint) = &self.endpoint { + write!(f, " endpoint: {endpoint}")?; + } + + if let Some(wg_tun_address) = &self.wg_tun_address { + write!(f, " wg tun address: {wg_tun_address}")?; + } + Ok(()) + } +} + +pub async fn list_gateways(args: A) -> Result +where + A: AsRef, + C: CliClient, +{ + let common_args = args.as_ref(); + let id = &common_args.id; + + let config = C::try_load_current_config(id).await?; + let paths = config.common_paths(); + + let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; + + let gateways = get_gateway_registrations(&details_store).await?; + + Ok(gateways.into()) +} diff --git a/common/client-core/src/cli_helpers/client_switch_gateway.rs b/common/client-core/src/cli_helpers/client_switch_gateway.rs new file mode 100644 index 0000000000..755fb6cc8b --- /dev/null +++ b/common/client-core/src/cli_helpers/client_switch_gateway.rs @@ -0,0 +1,2 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 diff --git a/common/client-core/src/cli_helpers/mod.rs b/common/client-core/src/cli_helpers/mod.rs index 985f0440bf..a513f7065a 100644 --- a/common/client-core/src/cli_helpers/mod.rs +++ b/common/client-core/src/cli_helpers/mod.rs @@ -1,8 +1,10 @@ -// Copyright 2023 - Nym Technologies SA +// Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 pub mod client_init; +pub mod client_list_gateways; pub mod client_run; +pub mod client_switch_gateway; pub mod traits; pub use client_init::InitialisableClient; diff --git a/common/client-core/src/cli_helpers/traits.rs b/common/client-core/src/cli_helpers/traits.rs index 21b234d19b..ec93cb09dd 100644 --- a/common/client-core/src/cli_helpers/traits.rs +++ b/common/client-core/src/cli_helpers/traits.rs @@ -13,6 +13,8 @@ pub trait CliClient { type Config: CliClientConfig; async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error>; + + async fn try_load_current_config(id: &str) -> Result; } pub trait CliClientConfig { diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index 3ed3379b10..f3c96d0cd4 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -39,6 +39,20 @@ where }) } +pub async fn get_gateway_registrations( + details_store: &D, +) -> Result, ClientCoreError> +where + D: GatewaysDetailsStore + Sync, + D::StorageError: Send + Sync + 'static, +{ + details_store.all_gateways().await.map_err(|source| { + ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + } + }) +} + pub async fn store_gateway_details( details_store: &D, details: &GatewayRegistration, diff --git a/service-providers/ip-packet-router/src/cli/list_gateways.rs b/service-providers/ip-packet-router/src/cli/list_gateways.rs new file mode 100644 index 0000000000..fc7f94a78f --- /dev/null +++ b/service-providers/ip-packet-router/src/cli/list_gateways.rs @@ -0,0 +1,31 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; +use nym_ip_packet_router::error::IpPacketRouterError; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index e5168d3284..8234e77444 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -11,6 +11,7 @@ use std::sync::OnceLock; mod build_info; mod init; +mod list_gateways; mod run; mod sign; @@ -24,6 +25,10 @@ impl CliClient for CliIpPacketRouterClient { async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { try_upgrade_config(id).await } + + async fn try_load_current_config(id: &str) -> Result { + try_load_current_config(id).await + } } fn pretty_build_info_static() -> &'static str { @@ -56,6 +61,9 @@ pub(crate) enum Commands { /// parameters. Run(run::Run), + /// List all registered with gateways + ListGateways(list_gateways::Args), + /// Sign to prove ownership of this network requester Sign(sign::Sign), @@ -108,6 +116,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { match args.command { Commands::Init(m) => init::execute(m).await?, Commands::Run(m) => run::execute(&m).await?, + Commands::ListGateways(args) => list_gateways::execute(args).await?, Commands::Sign(m) => sign::execute(&m).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), diff --git a/service-providers/network-requester/src/cli/list_gateways.rs b/service-providers/network-requester/src/cli/list_gateways.rs new file mode 100644 index 0000000000..ec4703045b --- /dev/null +++ b/service-providers/network-requester/src/cli/list_gateways.rs @@ -0,0 +1,32 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliNetworkRequesterClient; +use crate::error::NetworkRequesterError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 938464c6fc..ed5f82f82a 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -22,6 +22,7 @@ use std::sync::OnceLock; mod build_info; mod import_credential; mod init; +mod list_gateways; mod run; mod sign; @@ -35,6 +36,10 @@ impl CliClient for CliNetworkRequesterClient { async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { try_upgrade_config(id).await } + + async fn try_load_current_config(id: &str) -> Result { + try_load_current_config(id).await + } } fn pretty_build_info_static() -> &'static str { @@ -73,6 +78,9 @@ pub(crate) enum Commands { /// Import a pre-generated credential ImportCredential(import_credential::Args), + /// List all registered with gateways + ListGateways(list_gateways::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -168,6 +176,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Commands::Run(m) => run::execute(&m).await?, Commands::Sign(m) => sign::execute(&m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, + Commands::ListGateways(args) => list_gateways::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), From 28b02c83db0c79c120539f7bf757d58533f18507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 13:02:17 +0000 Subject: [PATCH 36/56] unified credential import cli + added it for ipr --- Cargo.lock | 220 ++++++------------ .../native/src/commands/import_credential.rs | 54 +---- clients/native/src/commands/mod.rs | 3 +- .../socks5/src/commands/import_credential.rs | 55 +---- clients/socks5/src/commands/mod.rs | 3 +- common/client-core/Cargo.toml | 2 + .../cli_helpers/client_import_credential.rs | 58 +++++ common/client-core/src/cli_helpers/mod.rs | 1 + service-providers/ip-packet-router/Cargo.toml | 1 + .../src/cli/import_credential.rs | 14 ++ .../ip-packet-router/src/cli/init.rs | 2 +- .../ip-packet-router/src/cli/list_gateways.rs | 1 + .../ip-packet-router/src/cli/mod.rs | 6 + .../ip-packet-router/src/error.rs | 4 + .../src/cli/import_credential.rs | 55 +---- .../network-requester/src/cli/mod.rs | 3 +- 16 files changed, 190 insertions(+), 292 deletions(-) create mode 100644 common/client-core/src/cli_helpers/client_import_credential.rs create mode 100644 service-providers/ip-packet-router/src/cli/import_credential.rs diff --git a/Cargo.lock b/Cargo.lock index 23c3ccf211..95910fc24b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,6 +389,16 @@ dependencies = [ "futures-core", ] +[[package]] +name = "async-file-watcher" +version = "0.1.0" +dependencies = [ + "futures", + "log", + "notify", + "tokio", +] + [[package]] name = "async-io" version = "1.13.0" @@ -547,9 +557,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "http", + "http-body", + "hyper", "itoa", "matchit", "memchr", @@ -577,8 +587,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http 0.2.9", - "http-body 0.4.5", + "http", + "http-body", "mime", "rustversion", "tower-layer", @@ -3001,7 +3011,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 0.2.9", + "http", "js-sys", "pin-project", "serde", @@ -3070,7 +3080,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.9", + "http", "indexmap 1.9.3", "slab", "tokio", @@ -3281,14 +3291,17 @@ dependencies = [ ] [[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +name = "http-api-client" +version = "0.1.0" dependencies = [ - "bytes", - "fnv", - "itoa", + "async-trait", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", + "wasmtimer", ] [[package]] @@ -3298,30 +3311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http 0.2.9", - "pin-project-lite 0.2.13", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" -dependencies = [ - "bytes", - "futures-core", - "http 1.1.0", - "http-body 1.0.0", + "http", "pin-project-lite 0.2.13", ] @@ -3389,8 +3379,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.9", - "http-body 0.4.5", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -3402,25 +3392,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "httparse", - "httpdate", - "itoa", - "pin-project-lite 0.2.13", - "smallvec", - "tokio", -] - [[package]] name = "hyper-rustls" version = "0.24.1" @@ -3428,8 +3399,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http 0.2.9", - "hyper 0.14.27", + "http", + "hyper", "rustls 0.21.10", "tokio", "tokio-rustls 0.24.1", @@ -3441,28 +3412,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper 0.14.27", + "hyper", "pin-project-lite 0.2.13", "tokio", "tokio-io-timeout", ] -[[package]] -name = "hyper-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" -dependencies = [ - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.2.0", - "pin-project-lite 0.2.13", - "socket2 0.5.4", - "tokio", -] - [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3787,7 +3742,7 @@ dependencies = [ "curl-sys", "event-listener", "futures-lite", - "http 0.2.9", + "http", "log", "once_cell", "polling", @@ -3919,6 +3874,17 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "ledger" +version = "0.1.0" +dependencies = [ + "bip32", + "k256", + "ledger-transport", + "ledger-transport-hid", + "thiserror", +] + [[package]] name = "ledger-apdu" version = "0.10.0" @@ -4561,9 +4527,9 @@ version = "1.3.0-rc.0" dependencies = [ "async-trait", "futures", + "http-api-client", "js-sys", "nym-bin-common", - "nym-http-api-client", "nym-ordered-buffer", "nym-service-providers-common", "nym-socks5-requests", @@ -4589,7 +4555,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 0.2.9", + "http", "httparse", "log", "memchr", @@ -5038,16 +5004,6 @@ dependencies = [ "ts-rs", ] -[[package]] -name = "nym-async-file-watcher" -version = "0.1.0" -dependencies = [ - "futures", - "log", - "notify", - "tokio", -] - [[package]] name = "nym-bandwidth-controller" version = "0.1.0" @@ -5230,14 +5186,12 @@ version = "1.1.15" dependencies = [ "async-trait", "base64 0.21.4", + "bs58 0.5.0", "cfg-if", "clap 4.4.7", "futures", "gloo-timers", - "http-body-util", "humantime-serde", - "hyper 1.2.0", - "hyper-util", "log", "nym-bandwidth-controller", "nym-client-core-gateways-storage", @@ -5248,7 +5202,7 @@ dependencies = [ "nym-explorer-client", "nym-gateway-client", "nym-gateway-requests", - "nym-metrics", + "nym-id", "nym-network-defaults", "nym-nonexhaustive-delayqueue", "nym-pemstore", @@ -5594,7 +5548,7 @@ dependencies = [ "dotenvy", "futures", "humantime-serde", - "hyper 0.14.27", + "hyper", "ipnetwork 0.16.0", "log", "nym-api-requests", @@ -5702,20 +5656,6 @@ dependencies = [ "serde", ] -[[package]] -name = "nym-http-api-client" -version = "0.1.0" -dependencies = [ - "async-trait", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tracing", - "url", - "wasmtimer", -] - [[package]] name = "nym-id" version = "0.1.0" @@ -5782,6 +5722,7 @@ dependencies = [ "nym-config", "nym-crypto", "nym-exit-policy", + "nym-id", "nym-ip-packet-requests", "nym-network-defaults", "nym-network-requester", @@ -5805,17 +5746,6 @@ dependencies = [ "url", ] -[[package]] -name = "nym-ledger" -version = "0.1.0" -dependencies = [ - "bip32", - "k256", - "ledger-transport", - "ledger-transport-hid", - "thiserror", -] - [[package]] name = "nym-metrics" version = "0.1.0" @@ -5824,6 +5754,7 @@ dependencies = [ "lazy_static", "log", "prometheus", + "regex", ] [[package]] @@ -5980,6 +5911,7 @@ version = "1.1.33" dependencies = [ "addr", "anyhow", + "async-file-watcher", "async-trait", "bs58 0.5.0", "clap 4.4.7", @@ -5988,7 +5920,6 @@ dependencies = [ "humantime-serde", "ipnetwork 0.20.0", "log", - "nym-async-file-watcher", "nym-bin-common", "nym-client-core", "nym-client-websocket-requests", @@ -6054,7 +5985,7 @@ dependencies = [ "dashmap", "fastrand 2.0.1", "hmac 0.12.1", - "hyper 0.14.27", + "hyper", "ipnetwork 0.16.0", "mime", "nym-config", @@ -6083,10 +6014,10 @@ version = "0.1.0" dependencies = [ "async-trait", "base64 0.21.4", + "http-api-client", "nym-bin-common", "nym-crypto", "nym-exit-policy", - "nym-http-api-client", "nym-wireguard-types", "schemars", "serde", @@ -6207,7 +6138,7 @@ dependencies = [ "dotenvy", "futures", "hex", - "http 0.2.9", + "http", "httpcodec", "libp2p", "log", @@ -6664,6 +6595,7 @@ dependencies = [ "eyre", "flate2", "futures", + "http-api-client", "itertools 0.10.5", "log", "nym-api-requests", @@ -6674,7 +6606,6 @@ dependencies = [ "nym-contracts-common", "nym-ephemera-common", "nym-group-contract-common", - "nym-http-api-client", "nym-mixnet-contract-common", "nym-multisig-contract-common", "nym-name-service-common", @@ -6800,6 +6731,7 @@ name = "nymvisor" version = "0.1.0" dependencies = [ "anyhow", + "async-file-watcher", "bytes", "clap 4.4.7", "dotenvy", @@ -6809,7 +6741,6 @@ dependencies = [ "humantime 2.1.0", "humantime-serde", "nix 0.27.1", - "nym-async-file-watcher", "nym-bin-common", "nym-config", "nym-task", @@ -6947,7 +6878,7 @@ checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906" dependencies = [ "async-trait", "bytes", - "http 0.2.9", + "http", "isahc", "opentelemetry_api", ] @@ -6961,7 +6892,7 @@ dependencies = [ "async-trait", "futures", "futures-executor", - "http 0.2.9", + "http", "isahc", "once_cell", "opentelemetry", @@ -8142,9 +8073,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "http", + "http-body", + "hyper", "hyper-rustls", "ipnet", "js-sys", @@ -8303,7 +8234,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfac3a1df83f8d4fc96aa41dba3b86c786417b7fc0f52ec76295df2ba781aa69" dependencies = [ - "http 0.2.9", + "http", "log", "regex", "rocket", @@ -8323,8 +8254,8 @@ dependencies = [ "cookie", "either", "futures", - "http 0.2.9", - "hyper 0.14.27", + "http", + "hyper", "indexmap 2.0.2", "log", "memchr", @@ -9128,9 +9059,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "snafu" @@ -9979,10 +9910,7 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls 0.21.10", - "rustls-native-certs", "tokio", - "tokio-rustls 0.24.1", "tungstenite", ] @@ -10085,9 +10013,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.9", - "http-body 0.4.5", - "hyper 0.14.27", + "http", + "http-body", + "hyper", "hyper-timeout", "percent-encoding", "pin-project", @@ -10130,8 +10058,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http 0.2.9", - "http-body 0.4.5", + "http", + "http-body", "http-range-header", "httpdate", "mime", @@ -10409,7 +10337,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.9", + "http", "httparse", "log", "rand 0.8.5", diff --git a/clients/native/src/commands/import_credential.rs b/clients/native/src/commands/import_credential.rs index 7fa7fa3b52..c7327797d0 100644 --- a/clients/native/src/commands/import_credential.rs +++ b/clients/native/src/commands/import_credential.rs @@ -1,54 +1,12 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::commands::try_load_current_config; +use crate::commands::CliNativeClient; use crate::error::ClientError; -use clap::ArgGroup; +use nym_client_core::cli_helpers::client_import_credential::{ + import_credential, CommonClientImportCredentialArgs, +}; -use nym_id::import_credential; -use std::fs; -use std::path::PathBuf; - -fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { - bs58::decode(raw).into_vec() -} - -#[derive(clap::Args)] -#[clap(group(ArgGroup::new("cred_data").required(true)))] -pub(crate) struct Args { - /// Id of client that is going to import the credential - #[clap(long)] - pub id: String, - - /// Explicitly provide the encoded credential data (as base58) - #[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)] - pub(crate) credential_data: Option>, - - /// Specifies the path to file containing binary credential data - #[clap(long, group = "cred_data")] - pub(crate) credential_path: Option, - - // currently hidden as there exists only a single serialization standard - #[clap(long, hide = true)] - pub(crate) version: Option, -} - -pub(crate) async fn execute(args: Args) -> Result<(), ClientError> { - let config = try_load_current_config(&args.id).await?; - - let credentials_store = nym_credential_storage::initialise_persistent_storage( - &config.storage_paths.common_paths.credentials_database, - ) - .await; - - let raw_credential = match args.credential_data { - Some(data) => data, - None => { - // SAFETY: one of those arguments must have been set - fs::read(args.credential_path.unwrap())? - } - }; - - import_credential(credentials_store, raw_credential, args.version).await?; - Ok(()) +pub(crate) async fn execute(args: CommonClientImportCredentialArgs) -> Result<(), ClientError> { + import_credential::(args).await } diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index f4a2fb2ec9..b13a09877d 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -12,6 +12,7 @@ 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::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; @@ -70,7 +71,7 @@ pub(crate) enum Commands { Run(run::Run), /// Import a pre-generated credential - ImportCredential(import_credential::Args), + ImportCredential(CommonClientImportCredentialArgs), /// List all registered with gateways ListGateways(list_gateways::Args), diff --git a/clients/socks5/src/commands/import_credential.rs b/clients/socks5/src/commands/import_credential.rs index a3bfd7dd45..91ea0bf552 100644 --- a/clients/socks5/src/commands/import_credential.rs +++ b/clients/socks5/src/commands/import_credential.rs @@ -1,53 +1,14 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::commands::try_load_current_config; +use crate::commands::CliSocks5Client; use crate::error::Socks5ClientError; -use clap::ArgGroup; -use nym_id::import_credential; -use std::fs; -use std::path::PathBuf; +use nym_client_core::cli_helpers::client_import_credential::{ + import_credential, CommonClientImportCredentialArgs, +}; -fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { - bs58::decode(raw).into_vec() -} - -#[derive(clap::Args)] -#[clap(group(ArgGroup::new("cred_data").required(true)))] -pub(crate) struct Args { - /// Id of client that is going to import the credential - #[clap(long)] - pub id: String, - - /// Explicitly provide the encoded credential data (as base58) - #[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)] - pub(crate) credential_data: Option>, - - /// Specifies the path to file containing binary credential data - #[clap(long, group = "cred_data")] - pub(crate) credential_path: Option, - - // currently hidden as there exists only a single serialization standard - #[clap(long, hide = true)] - pub(crate) version: Option, -} - -pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> { - let config = try_load_current_config(&args.id).await?; - - let credentials_store = nym_credential_storage::initialise_persistent_storage( - &config.storage_paths.common_paths.credentials_database, - ) - .await; - - let raw_credential = match args.credential_data { - Some(data) => data, - None => { - // SAFETY: one of those arguments must have been set - fs::read(args.credential_path.unwrap())? - } - }; - - import_credential(credentials_store, raw_credential, args.version).await?; - Ok(()) +pub(crate) async fn execute( + args: CommonClientImportCredentialArgs, +) -> Result<(), Socks5ClientError> { + import_credential::(args).await } diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index 5543fb7e67..d60b9a8574 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -13,6 +13,7 @@ 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::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_client_core::client::topology_control::geo_aware_provider::CountryGroup; @@ -74,7 +75,7 @@ pub(crate) enum Commands { Run(run::Run), /// Import a pre-generated credential - ImportCredential(import_credential::Args), + ImportCredential(CommonClientImportCredentialArgs), /// List all registered with gateways ListGateways(list_gateways::Args), diff --git a/common/client-core/Cargo.toml b/common/client-core/Cargo.toml index f144aa4373..b5c8aa5e2e 100644 --- a/common/client-core/Cargo.toml +++ b/common/client-core/Cargo.toml @@ -11,6 +11,7 @@ license.workspace = true [dependencies] async-trait = { workspace = true } base64 = "0.21.2" +bs58 = { workspace = true } cfg-if = "1.0.0" clap = { workspace = true, optional = true } futures = { workspace = true } @@ -30,6 +31,7 @@ time = { workspace = true } zeroize = { workspace = true } # internal +nym-id = { path = "../nym-id" } nym-bandwidth-controller = { path = "../bandwidth-controller" } nym-config = { path = "../config" } nym-crypto = { path = "../crypto" } diff --git a/common/client-core/src/cli_helpers/client_import_credential.rs b/common/client-core/src/cli_helpers/client_import_credential.rs new file mode 100644 index 0000000000..55d005975a --- /dev/null +++ b/common/client-core/src/cli_helpers/client_import_credential.rs @@ -0,0 +1,58 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli_helpers::{CliClient, CliClientConfig}; +use std::fs; +use std::path::PathBuf; + +fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { + bs58::decode(raw).into_vec() +} + +#[cfg_attr(feature = "cli", derive(clap::Args))] +#[cfg_attr(feature = "cli", clap(group(clap::ArgGroup::new("cred_data").required(true))))] +#[derive(Debug, Clone)] +pub struct CommonClientImportCredentialArgs { + /// Id of client that is going to import the credential + #[cfg_attr(feature = "cli", clap(long))] + pub id: String, + + /// Explicitly provide the encoded credential data (as base58) + #[cfg_attr(feature = "cli", clap(long, group = "cred_data", value_parser = parse_encoded_credential_data))] + pub(crate) credential_data: Option>, + + /// Specifies the path to file containing binary credential data + #[cfg_attr(feature = "cli", clap(long, group = "cred_data"))] + pub(crate) credential_path: Option, + + // currently hidden as there exists only a single serialization standard + #[cfg_attr(feature = "cli", clap(long, hide = true))] + pub(crate) version: Option, +} + +pub async fn import_credential(args: A) -> Result<(), C::Error> +where + A: Into, + C: CliClient, + C::Error: From + From, +{ + let common_args = args.into(); + let id = &common_args.id; + + let config = C::try_load_current_config(id).await?; + let paths = config.common_paths(); + + let credentials_store = + nym_credential_storage::initialise_persistent_storage(&paths.credentials_database).await; + + let raw_credential = match common_args.credential_data { + Some(data) => data, + None => { + // SAFETY: one of those arguments must have been set + fs::read(common_args.credential_path.unwrap())? + } + }; + + nym_id::import_credential(credentials_store, raw_credential, common_args.version).await?; + Ok(()) +} diff --git a/common/client-core/src/cli_helpers/mod.rs b/common/client-core/src/cli_helpers/mod.rs index a513f7065a..e2a018cb18 100644 --- a/common/client-core/src/cli_helpers/mod.rs +++ b/common/client-core/src/cli_helpers/mod.rs @@ -1,6 +1,7 @@ // Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +pub mod client_import_credential; pub mod client_init; pub mod client_list_gateways; pub mod client_run; diff --git a/service-providers/ip-packet-router/Cargo.toml b/service-providers/ip-packet-router/Cargo.toml index e700505a96..3029a66a61 100644 --- a/service-providers/ip-packet-router/Cargo.toml +++ b/service-providers/ip-packet-router/Cargo.toml @@ -32,6 +32,7 @@ nym-tun = { path = "../../common/tun" } nym-types = { path = "../../common/types" } nym-wireguard = { path = "../../common/wireguard" } nym-wireguard-types = { path = "../../common/wireguard-types" } +nym-id = { path = "../../common/nym-id" } rand = "0.8.5" reqwest.workspace = true serde = { workspace = true, features = ["derive"] } diff --git a/service-providers/ip-packet-router/src/cli/import_credential.rs b/service-providers/ip-packet-router/src/cli/import_credential.rs new file mode 100644 index 0000000000..2ef4119803 --- /dev/null +++ b/service-providers/ip-packet-router/src/cli/import_credential.rs @@ -0,0 +1,14 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliIpPacketRouterClient; +use nym_client_core::cli_helpers::client_import_credential::{ + import_credential, CommonClientImportCredentialArgs, +}; +use nym_ip_packet_router::error::IpPacketRouterError; + +pub(crate) async fn execute( + args: CommonClientImportCredentialArgs, +) -> Result<(), IpPacketRouterError> { + import_credential::(args).await +} diff --git a/service-providers/ip-packet-router/src/cli/init.rs b/service-providers/ip-packet-router/src/cli/init.rs index b5f4e0f05c..6b41b287d8 100644 --- a/service-providers/ip-packet-router/src/cli/init.rs +++ b/service-providers/ip-packet-router/src/cli/init.rs @@ -1,4 +1,4 @@ -use crate::cli::{override_config, try_upgrade_config, OverrideConfig}; +use crate::cli::{override_config, CliIpPacketRouterClient, OverrideConfig}; use clap::Args; use nym_bin_common::output_format::OutputFormat; use nym_client_core::cli_helpers::client_init::{ diff --git a/service-providers/ip-packet-router/src/cli/list_gateways.rs b/service-providers/ip-packet-router/src/cli/list_gateways.rs index fc7f94a78f..3050233c87 100644 --- a/service-providers/ip-packet-router/src/cli/list_gateways.rs +++ b/service-providers/ip-packet-router/src/cli/list_gateways.rs @@ -1,6 +1,7 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::cli::CliIpPacketRouterClient; use nym_bin_common::output_format::OutputFormat; use nym_client_core::cli_helpers::client_list_gateways::{ list_gateways, CommonClientListGatewaysArgs, diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index 8234e77444..da35a12add 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -2,6 +2,7 @@ use clap::{CommandFactory, Parser, Subcommand}; use log::{error, info, trace}; use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::{bin_info, version_checker}; +use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_ip_packet_router::config::old_config_v1::ConfigV1; @@ -10,6 +11,7 @@ use nym_ip_packet_router::error::IpPacketRouterError; use std::sync::OnceLock; mod build_info; +mod import_credential; mod init; mod list_gateways; mod run; @@ -61,6 +63,9 @@ pub(crate) enum Commands { /// parameters. Run(run::Run), + /// Import a pre-generated credential + ImportCredential(CommonClientImportCredentialArgs), + /// List all registered with gateways ListGateways(list_gateways::Args), @@ -116,6 +121,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { match args.command { Commands::Init(m) => init::execute(m).await?, Commands::Run(m) => run::execute(&m).await?, + Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, Commands::Sign(m) => sign::execute(&m).await?, Commands::BuildInfo(m) => build_info::execute(m), diff --git a/service-providers/ip-packet-router/src/error.rs b/service-providers/ip-packet-router/src/error.rs index 4732177191..2cff116db4 100644 --- a/service-providers/ip-packet-router/src/error.rs +++ b/service-providers/ip-packet-router/src/error.rs @@ -2,6 +2,7 @@ use std::net::SocketAddr; pub use nym_client_core::error::ClientCoreError; use nym_exit_policy::PolicyError; +use nym_id::NymIdError; #[derive(thiserror::Error, Debug)] pub enum IpPacketRouterError { @@ -81,6 +82,9 @@ pub enum IpPacketRouterError { #[error("failed to update client activity")] FailedToUpdateClientActivity, + + #[error(transparent)] + NymIdError(#[from] NymIdError), } pub type Result = std::result::Result; diff --git a/service-providers/network-requester/src/cli/import_credential.rs b/service-providers/network-requester/src/cli/import_credential.rs index 31a11c92a0..aeb42d79b7 100644 --- a/service-providers/network-requester/src/cli/import_credential.rs +++ b/service-providers/network-requester/src/cli/import_credential.rs @@ -1,53 +1,14 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 -use crate::cli::try_load_current_config; +use crate::cli::CliNetworkRequesterClient; use crate::error::NetworkRequesterError; -use clap::ArgGroup; -use nym_id::import_credential; -use std::fs; -use std::path::PathBuf; +use nym_client_core::cli_helpers::client_import_credential::{ + import_credential, CommonClientImportCredentialArgs, +}; -fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { - bs58::decode(raw).into_vec() -} - -#[derive(clap::Args)] -#[clap(group(ArgGroup::new("cred_data").required(true)))] -pub(crate) struct Args { - /// Id of client that is going to import the credential - #[clap(long)] - pub id: String, - - /// Explicitly provide the encoded credential data (as base58) - #[clap(long, group = "cred_data", value_parser = parse_encoded_credential_data)] - pub(crate) credential_data: Option>, - - /// Specifies the path to file containing binary credential data - #[clap(long, group = "cred_data")] - pub(crate) credential_path: Option, - - // currently hidden as there exists only a single serialization standard - #[clap(long, hide = true)] - pub(crate) version: Option, -} - -pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { - let config = try_load_current_config(&args.id).await?; - - let credentials_store = nym_credential_storage::initialise_persistent_storage( - &config.storage_paths.common_paths.credentials_database, - ) - .await; - - let raw_credential = match args.credential_data { - Some(data) => data, - None => { - // SAFETY: one of those arguments must have been set - fs::read(args.credential_path.unwrap())? - } - }; - - import_credential(credentials_store, raw_credential, args.version).await?; - Ok(()) +pub(crate) async fn execute( + args: CommonClientImportCredentialArgs, +) -> Result<(), NetworkRequesterError> { + import_credential::(args).await } diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index ed5f82f82a..e721d38614 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -14,6 +14,7 @@ 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::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; @@ -76,7 +77,7 @@ pub(crate) enum Commands { Sign(sign::Sign), /// Import a pre-generated credential - ImportCredential(import_credential::Args), + ImportCredential(CommonClientImportCredentialArgs), /// List all registered with gateways ListGateways(list_gateways::Args), From 062f4517d6b92ed0ff0b288355866cc8d29f2da5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 13:19:08 +0000 Subject: [PATCH 37/56] added cli command for switching active gateway --- clients/native/src/commands/mod.rs | 5 +++ clients/native/src/commands/switch_gateway.rs | 24 +++++++++++++ clients/socks5/src/commands/mod.rs | 5 +++ clients/socks5/src/commands/switch_gateway.rs | 24 +++++++++++++ .../src/backend/fs_backend/error.rs | 3 ++ .../src/backend/fs_backend/manager.rs | 10 ++++++ .../src/backend/fs_backend/mod.rs | 5 +++ .../src/cli_helpers/client_switch_gateway.rs | 35 +++++++++++++++++++ .../ip-packet-router/src/cli/mod.rs | 5 +++ .../src/cli/switch_gateway.rs | 24 +++++++++++++ .../network-requester/src/cli/mod.rs | 5 +++ .../src/cli/switch_gateway.rs | 24 +++++++++++++ 12 files changed, 169 insertions(+) create mode 100644 clients/native/src/commands/switch_gateway.rs create mode 100644 clients/socks5/src/commands/switch_gateway.rs create mode 100644 service-providers/ip-packet-router/src/cli/switch_gateway.rs create mode 100644 service-providers/network-requester/src/cli/switch_gateway.rs diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index b13a09877d..9c7c016580 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -25,6 +25,7 @@ pub(crate) mod import_credential; pub(crate) mod init; mod list_gateways; pub(crate) mod run; +mod switch_gateway; pub(crate) struct CliNativeClient; @@ -76,6 +77,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! + SwitchGateway(switch_gateway::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -106,6 +110,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/clients/native/src/commands/switch_gateway.rs b/clients/native/src/commands/switch_gateway.rs new file mode 100644 index 0000000000..f7dbcfa65d --- /dev/null +++ b/clients/native/src/commands/switch_gateway.rs @@ -0,0 +1,24 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliNativeClient; +use crate::error::ClientError; +use nym_client_core::cli_helpers::client_switch_gateway::{ + switch_gateway, CommonClientSwitchGatewaysArgs, +}; + +#[derive(clap::Args, Clone, Debug)] +pub struct Args { + #[command(flatten)] + common_args: CommonClientSwitchGatewaysArgs, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), ClientError> { + switch_gateway::(args).await +} diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index d60b9a8574..d982b86a9e 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -29,6 +29,7 @@ mod import_credential; pub mod init; mod list_gateways; pub(crate) mod run; +mod switch_gateway; pub(crate) struct CliSocks5Client; @@ -80,6 +81,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! + SwitchGateway(switch_gateway::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -113,6 +117,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/clients/socks5/src/commands/switch_gateway.rs b/clients/socks5/src/commands/switch_gateway.rs new file mode 100644 index 0000000000..6b24fbb6a3 --- /dev/null +++ b/clients/socks5/src/commands/switch_gateway.rs @@ -0,0 +1,24 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliSocks5Client; +use crate::error::Socks5ClientError; +use nym_client_core::cli_helpers::client_switch_gateway::{ + switch_gateway, CommonClientSwitchGatewaysArgs, +}; + +#[derive(clap::Args, Clone, Debug)] +pub struct Args { + #[command(flatten)] + common_args: CommonClientSwitchGatewaysArgs, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> { + switch_gateway::(args).await +} diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/error.rs b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs index 44cab38a8c..bdcaa0fdb5 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/error.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/error.rs @@ -39,4 +39,7 @@ pub enum StorageError { #[error(transparent)] MalformedGateway(#[from] BadGateway), + + #[error("gateway {gateway_id} does not exist in the storage")] + GatewayDoesNotExist { gateway_id: String }, } diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs index 965ace23f6..58cb451d97 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -75,6 +75,16 @@ impl StorageManager { Ok(()) } + pub(crate) async fn has_registered_gateway( + &self, + gateway_id: &str, + ) -> Result { + sqlx::query!("SELECT EXISTS (SELECT 1 FROM registered_gateway WHERE gateway_id_bs58 = ?) AS 'exists'", gateway_id) + .fetch_one(&self.connection_pool) + .await + .map(|result| result.exists == 1) + } + pub(crate) async fn maybe_get_registered_gateway( &self, gateway_id: &str, diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs index 7e0fbcdebc..0b93d284f6 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/mod.rs @@ -49,6 +49,11 @@ impl GatewaysDetailsStore for OnDiskGatewaysDetails { } async fn set_active_gateway(&self, gateway_id: &str) -> Result<(), Self::StorageError> { + if !self.manager.has_registered_gateway(gateway_id).await? { + return Err(StorageError::GatewayDoesNotExist { + gateway_id: gateway_id.to_string(), + }); + } Ok(self.manager.set_active_gateway(Some(gateway_id)).await?) } diff --git a/common/client-core/src/cli_helpers/client_switch_gateway.rs b/common/client-core/src/cli_helpers/client_switch_gateway.rs index 755fb6cc8b..0468575e63 100644 --- a/common/client-core/src/cli_helpers/client_switch_gateway.rs +++ b/common/client-core/src/cli_helpers/client_switch_gateway.rs @@ -1,2 +1,37 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 + +use crate::cli_helpers::{CliClient, CliClientConfig}; +use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; +use crate::client::base_client::storage::helpers::set_active_gateway; +use nym_crypto::asymmetric::identity; + +#[cfg_attr(feature = "cli", derive(clap::Args))] +#[derive(Debug, Clone)] +pub struct CommonClientSwitchGatewaysArgs { + /// Id of client we want to list gateways for. + #[cfg_attr(feature = "cli", clap(long))] + pub id: String, + + /// Id of the gateway we want to switch to. + #[cfg_attr(feature = "cli", clap(long))] + pub gateway_id: identity::PublicKey, +} + +pub async fn switch_gateway(args: A) -> Result<(), C::Error> +where + A: AsRef, + C: CliClient, +{ + let common_args = args.as_ref(); + let id = &common_args.id; + + let config = C::try_load_current_config(id).await?; + let paths = config.common_paths(); + + let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; + + set_active_gateway(&details_store, &common_args.gateway_id.to_base58_string()).await?; + + Ok(()) +} diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index da35a12add..dc04d7e3cb 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -16,6 +16,7 @@ mod init; mod list_gateways; mod run; mod sign; +mod switch_gateway; pub(crate) struct CliIpPacketRouterClient; @@ -69,6 +70,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! + SwitchGateway(switch_gateway::Args), + /// Sign to prove ownership of this network requester Sign(sign::Sign), @@ -123,6 +127,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { Commands::Run(m) => run::execute(&m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::Sign(m) => sign::execute(&m).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), diff --git a/service-providers/ip-packet-router/src/cli/switch_gateway.rs b/service-providers/ip-packet-router/src/cli/switch_gateway.rs new file mode 100644 index 0000000000..4a365a4bdb --- /dev/null +++ b/service-providers/ip-packet-router/src/cli/switch_gateway.rs @@ -0,0 +1,24 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliIpPacketRouterClient; +use nym_client_core::cli_helpers::client_switch_gateway::{ + switch_gateway, CommonClientSwitchGatewaysArgs, +}; +use nym_ip_packet_router::error::IpPacketRouterError; + +#[derive(clap::Args, Clone, Debug)] +pub struct Args { + #[command(flatten)] + common_args: CommonClientSwitchGatewaysArgs, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> { + switch_gateway::(args).await +} diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index e721d38614..29057aa523 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -26,6 +26,7 @@ mod init; mod list_gateways; mod run; mod sign; +mod switch_gateway; pub(crate) struct CliNetworkRequesterClient; @@ -82,6 +83,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! + SwitchGateway(switch_gateway::Args), + /// Show build information of this binary BuildInfo(build_info::BuildInfo), @@ -178,6 +182,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Commands::Sign(m) => sign::execute(&m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name), diff --git a/service-providers/network-requester/src/cli/switch_gateway.rs b/service-providers/network-requester/src/cli/switch_gateway.rs new file mode 100644 index 0000000000..7496fc0018 --- /dev/null +++ b/service-providers/network-requester/src/cli/switch_gateway.rs @@ -0,0 +1,24 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliNetworkRequesterClient; +use crate::error::NetworkRequesterError; +use nym_client_core::cli_helpers::client_switch_gateway::{ + switch_gateway, CommonClientSwitchGatewaysArgs, +}; + +#[derive(clap::Args, Clone, Debug)] +pub struct Args { + #[command(flatten)] + common_args: CommonClientSwitchGatewaysArgs, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { + switch_gateway::(args).await +} From c07b782afab2274052c3336eda21ececae4e1c82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 13:24:51 +0000 Subject: [PATCH 38/56] added bool to list gateways to indicate currently active gateway --- .../src/cli_helpers/client_list_gateways.rs | 64 ++++++++++--------- .../src/client/base_client/storage/helpers.rs | 16 +++++ 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/common/client-core/src/cli_helpers/client_list_gateways.rs b/common/client-core/src/cli_helpers/client_list_gateways.rs index cbb914b22d..641b29d16e 100644 --- a/common/client-core/src/cli_helpers/client_list_gateways.rs +++ b/common/client-core/src/cli_helpers/client_list_gateways.rs @@ -3,8 +3,10 @@ use crate::cli_helpers::{CliClient, CliClientConfig}; use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; -use crate::client::base_client::storage::helpers::get_gateway_registrations; -use nym_client_core_gateways_storage::{GatewayDetails, GatewayRegistration, GatewayType}; +use crate::client::base_client::storage::helpers::{ + get_active_gateway_identity, get_gateway_registrations, +}; +use nym_client_core_gateways_storage::{GatewayDetails, GatewayType}; use nym_crypto::asymmetric::identity; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; @@ -23,12 +25,6 @@ pub struct CommonClientListGatewaysArgs { #[serde(transparent)] pub struct RegisteredGateways(Vec); -impl From> for RegisteredGateways { - fn from(value: Vec) -> Self { - RegisteredGateways(value.into_iter().map(Into::into).collect()) - } -} - impl Display for RegisteredGateways { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { for (i, gateway) in self.0.iter().enumerate() { @@ -42,35 +38,18 @@ impl Display for RegisteredGateways { pub struct GatewayInfo { pub registration: OffsetDateTime, pub identity: identity::PublicKey, + pub active: bool, pub typ: String, pub endpoint: Option, pub wg_tun_address: Option, } -impl From for GatewayInfo { - fn from(value: GatewayRegistration) -> Self { - match value.details { - GatewayDetails::Remote(remote_details) => GatewayInfo { - registration: value.registration_timestamp, - identity: remote_details.gateway_id, - typ: GatewayType::Remote.to_string(), - endpoint: Some(remote_details.gateway_listener), - wg_tun_address: remote_details.wg_tun_address, - }, - GatewayDetails::Custom(_) => GatewayInfo { - registration: value.registration_timestamp, - identity: value.details.gateway_id(), - typ: value.details.typ().to_string(), - endpoint: None, - wg_tun_address: None, - }, - } - } -} - impl Display for GatewayInfo { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.active { + write!(f, "[ACTIVE] ")?; + } write!( f, "{} gateway '{}' registered at: {}", @@ -100,7 +79,30 @@ where let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; - let gateways = get_gateway_registrations(&details_store).await?; + let active_gateway = get_active_gateway_identity(&details_store).await?; - Ok(gateways.into()) + let gateways = get_gateway_registrations(&details_store).await?; + let mut info = Vec::with_capacity(gateways.len()); + for gateway in gateways { + match gateway.details { + GatewayDetails::Remote(remote_details) => info.push(GatewayInfo { + registration: gateway.registration_timestamp, + identity: remote_details.gateway_id, + active: active_gateway == Some(remote_details.gateway_id), + typ: GatewayType::Remote.to_string(), + endpoint: Some(remote_details.gateway_listener), + wg_tun_address: remote_details.wg_tun_address, + }), + GatewayDetails::Custom(_) => info.push(GatewayInfo { + registration: gateway.registration_timestamp, + identity: gateway.details.gateway_id(), + active: active_gateway == Some(gateway.details.gateway_id()), + typ: gateway.details.typ().to_string(), + endpoint: None, + wg_tun_address: None, + }), + }; + } + + Ok(RegisteredGateways(info)) } diff --git a/common/client-core/src/client/base_client/storage/helpers.rs b/common/client-core/src/client/base_client/storage/helpers.rs index f3c96d0cd4..b2a200579d 100644 --- a/common/client-core/src/client/base_client/storage/helpers.rs +++ b/common/client-core/src/client/base_client/storage/helpers.rs @@ -24,6 +24,22 @@ where }) } +pub async fn get_active_gateway_identity( + details_store: &D, +) -> Result, ClientCoreError> +where + D: GatewaysDetailsStore, + D::StorageError: Send + Sync + 'static, +{ + details_store + .active_gateway() + .await + .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { + source: Box::new(source), + }) + .map(|a| a.registration.map(|r| r.details.gateway_id())) +} + pub async fn get_all_registered_identities( details_store: &D, ) -> Result, ClientCoreError> From 7c14a92baa7fe138a98af45eafa80abfc1a29335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 13:26:44 +0000 Subject: [PATCH 39/56] decreased logging level --- .../gateways-storage/src/backend/fs_backend/manager.rs | 4 ++-- .../client-core/src/client/base_client/non_wasm_helpers.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs index 58cb451d97..4c3e3c48b5 100644 --- a/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs +++ b/common/client-core/gateways-storage/src/backend/fs_backend/manager.rs @@ -7,7 +7,7 @@ use crate::{ RawActiveGateway, RawCustomGatewayDetails, RawRegisteredGateway, RawRemoteGatewayDetails, }, }; -use log::{error, info}; +use log::{debug, error}; use sqlx::ConnectOptions; use std::path::Path; @@ -49,7 +49,7 @@ impl StorageManager { error!("Failed to initialize SQLx database: {err}"); })?; - info!("Database migration finished!"); + debug!("Database migration finished!"); Ok(StorageManager { connection_pool }) } diff --git a/common/client-core/src/client/base_client/non_wasm_helpers.rs b/common/client-core/src/client/base_client/non_wasm_helpers.rs index 740e75bb33..ce3f05b0f2 100644 --- a/common/client-core/src/client/base_client/non_wasm_helpers.rs +++ b/common/client-core/src/client/base_client/non_wasm_helpers.rs @@ -1,4 +1,4 @@ -// Copyright 2022-2023 - Nym Technologies SA +// Copyright 2022-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::client::replies::reply_storage::{ @@ -7,7 +7,7 @@ use crate::client::replies::reply_storage::{ use crate::config; use crate::config::Config; use crate::error::ClientCoreError; -use log::{error, info}; +use log::{error, info, trace}; use nym_bandwidth_controller::BandwidthController; use nym_client_core_gateways_storage::OnDiskGatewaysDetails; use nym_credential_storage::storage::Storage as CredentialStorage; @@ -105,7 +105,7 @@ pub async fn setup_fs_reply_surb_backend>( pub async fn setup_fs_gateways_storage>( db_path: P, ) -> Result { - info!("setting up gateways details storage"); + trace!("setting up gateways details storage"); OnDiskGatewaysDetails::init(db_path) .await .map_err(|source| ClientCoreError::GatewaysDetailsStoreError { From 06abe53399622176ceaf971cc8c3e555f7246d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 14:30:07 +0000 Subject: [PATCH 40/56] CT-80 From c95e42498149382b319150f5f5b92ac097445e64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 12 Mar 2024 15:26:59 +0000 Subject: [PATCH 41/56] missing licenses for new crates --- common/client-core/gateways-storage/Cargo.toml | 1 + common/client-core/surb-storage/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/common/client-core/gateways-storage/Cargo.toml b/common/client-core/gateways-storage/Cargo.toml index 567744d1b6..4392798c0b 100644 --- a/common/client-core/gateways-storage/Cargo.toml +++ b/common/client-core/gateways-storage/Cargo.toml @@ -2,6 +2,7 @@ name = "nym-client-core-gateways-storage" version = "0.1.0" edition = "2021" +license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/common/client-core/surb-storage/Cargo.toml b/common/client-core/surb-storage/Cargo.toml index 24f466e1e3..7a902bef94 100644 --- a/common/client-core/surb-storage/Cargo.toml +++ b/common/client-core/surb-storage/Cargo.toml @@ -2,6 +2,7 @@ name = "nym-client-core-surb-storage" version = "0.1.0" edition = "2021" +license.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 73d6e704c4f0582c00c2371fc1c64cba797d17f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 20 Mar 2024 14:28:14 +0000 Subject: [PATCH 42/56] fixed gateway not generating keys for nr and ipr --- common/client-core/src/init/mod.rs | 15 ++++++++++----- gateway/src/commands/helpers.rs | 17 ++++++++++++++++- service-providers/network-requester/src/lib.rs | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 6bc0fa8e91..388902045f 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -202,6 +202,7 @@ where log::debug!("Setting up gateway"); match setup { GatewaySetup::MustLoad { gateway_id } => { + log::trace!("GatewaySetup::MustLoad with id: {gateway_id:?}"); use_loaded_gateway_details(key_store, details_store, gateway_id).await } GatewaySetup::New { @@ -210,6 +211,7 @@ where overwrite_data, wg_tun_address, } => { + log::trace!("GatewaySetup::New with spec: {specification:?}"); setup_new_gateway( key_store, details_store, @@ -224,11 +226,14 @@ where authenticated_ephemeral_client, gateway_details, client_keys: managed_keys, - } => Ok(reuse_gateway_connection( - authenticated_ephemeral_client, - *gateway_details, - managed_keys, - )), + } => { + log::trace!("GatewaySetup::ReuseConnection"); + Ok(reuse_gateway_connection( + authenticated_ephemeral_client, + *gateway_details, + managed_keys, + )) + } } } diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index e12cc337f1..d7cc0c4743 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -16,9 +16,12 @@ use nym_network_defaults::mainnet; use nym_network_defaults::var_names::NYXD; use nym_network_defaults::var_names::{BECH32_PREFIX, NYM_API, STATISTICS_SERVICE_DOMAIN_ADDRESS}; use nym_network_requester::config::BaseClientConfig; -use nym_network_requester::{setup_fs_gateways_storage, setup_gateway, GatewaySetup, OnDiskKeys}; +use nym_network_requester::{ + generate_new_client_keys, setup_fs_gateways_storage, setup_gateway, GatewaySetup, OnDiskKeys, +}; use nym_types::gateway::{GatewayIpPacketRouterDetails, GatewayNetworkRequesterDetails}; use nym_validator_client::nyxd::AccountId; +use rand::rngs::OsRng; use std::net::IpAddr; use std::path::PathBuf; @@ -275,6 +278,12 @@ pub(crate) async fn initialise_local_network_requester( let details_store = setup_fs_gateways_storage(&nr_cfg.storage_paths.common_paths.gateway_registrations).await?; + // if this is a first time client with this particular id is initialised, generated long-term keys + if !nr_cfg_path.exists() { + let mut rng = OsRng; + generate_new_client_keys(&mut rng, &key_store).await?; + } + // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( GatewaySetup::new_inbuilt(identity), @@ -341,6 +350,12 @@ pub(crate) async fn initialise_local_ip_packet_router( let details_store = setup_fs_gateways_storage(&ip_cfg.storage_paths.common_paths.gateway_registrations).await?; + // if this is a first time client with this particular id is initialised, generated long-term keys + if !ip_cfg_path.exists() { + let mut rng = OsRng; + generate_new_client_keys(&mut rng, &key_store).await?; + } + // gateway setup here is way simpler as we're 'connecting' to ourselves let init_res = setup_gateway( GatewaySetup::new_inbuilt(identity), diff --git a/service-providers/network-requester/src/lib.rs b/service-providers/network-requester/src/lib.rs index 01bdaf3a42..6145b9681d 100644 --- a/service-providers/network-requester/src/lib.rs +++ b/service-providers/network-requester/src/lib.rs @@ -21,7 +21,7 @@ pub use nym_client_core::{ mix_traffic::transceiver::*, }, init::{ - setup_gateway, + generate_new_client_keys, setup_gateway, types::{GatewaySelectionSpecification, GatewaySetup, InitResults, InitialisationResult}, }, }; From 6259106b6baf5429ef17985a5fe641ed35af87d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 20 Mar 2024 14:34:09 +0000 Subject: [PATCH 43/56] fixed embedded SP not correctly setting active gateway --- common/client-core/src/init/types.rs | 6 +++++- gateway/src/commands/helpers.rs | 5 ++++- service-providers/network-requester/src/lib.rs | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index 019b5218e3..f8f5d93fdb 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -172,9 +172,13 @@ impl InitialisationResult { *self.client_keys.encryption_keypair().public_key(), // TODO: below only works under assumption that gateway address == gateway id // (which currently is true) - self.gateway_registration.details.gateway_id(), + self.gateway_id(), ) } + + pub fn gateway_id(&self) -> identity::PublicKey { + self.gateway_registration.details.gateway_id() + } } #[derive(Clone, Debug)] diff --git a/gateway/src/commands/helpers.rs b/gateway/src/commands/helpers.rs index d7cc0c4743..968b9b14c6 100644 --- a/gateway/src/commands/helpers.rs +++ b/gateway/src/commands/helpers.rs @@ -17,7 +17,8 @@ use nym_network_defaults::var_names::NYXD; use nym_network_defaults::var_names::{BECH32_PREFIX, NYM_API, STATISTICS_SERVICE_DOMAIN_ADDRESS}; use nym_network_requester::config::BaseClientConfig; use nym_network_requester::{ - generate_new_client_keys, setup_fs_gateways_storage, setup_gateway, GatewaySetup, OnDiskKeys, + generate_new_client_keys, set_active_gateway, setup_fs_gateways_storage, setup_gateway, + GatewaySetup, OnDiskKeys, }; use nym_types::gateway::{GatewayIpPacketRouterDetails, GatewayNetworkRequesterDetails}; use nym_validator_client::nyxd::AccountId; @@ -291,6 +292,7 @@ pub(crate) async fn initialise_local_network_requester( &details_store, ) .await?; + set_active_gateway(&details_store, &init_res.gateway_id().to_base58_string()).await?; let address = init_res.client_address(); @@ -363,6 +365,7 @@ pub(crate) async fn initialise_local_ip_packet_router( &details_store, ) .await?; + set_active_gateway(&details_store, &init_res.gateway_id().to_base58_string()).await?; let address = init_res.client_address(); diff --git a/service-providers/network-requester/src/lib.rs b/service-providers/network-requester/src/lib.rs index 6145b9681d..457afc99cd 100644 --- a/service-providers/network-requester/src/lib.rs +++ b/service-providers/network-requester/src/lib.rs @@ -15,7 +15,10 @@ pub use nym_client_core::{ client::{ base_client::{ non_wasm_helpers::{setup_fs_gateways_storage, setup_fs_reply_surb_backend}, - storage::{GatewaysDetailsStore, OnDiskGatewaysDetails, OnDiskPersistent}, + storage::{ + helpers::set_active_gateway, GatewaysDetailsStore, OnDiskGatewaysDetails, + OnDiskPersistent, + }, }, key_manager::persistence::OnDiskKeys, mix_traffic::transceiver::*, From 36f84ca18ff0b46420f2cfb9a37190ca9c52d840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 26 Mar 2024 10:49:25 +0000 Subject: [PATCH 44/56] fixed typo in SQL query --- common/credential-storage/src/backends/sqlite.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/credential-storage/src/backends/sqlite.rs b/common/credential-storage/src/backends/sqlite.rs index c46c713a5f..c356e09820 100644 --- a/common/credential-storage/src/backends/sqlite.rs +++ b/common/credential-storage/src/backends/sqlite.rs @@ -47,7 +47,7 @@ impl CoconutCredentialManager { WHERE coconut_credentials.credential_type == "FreeBandwidthPass" AND NOT EXISTS (SELECT 1 FROM credential_usage - WHERE credential_usage.credential_id = coconut_credential.id + WHERE credential_usage.credential_id = coconut_credentials.id AND credential_usage.gateway_id_bs58 == ?) ORDER BY coconut_credentials.id LIMIT 1 @@ -69,7 +69,7 @@ impl CoconutCredentialManager { WHERE coconut_credentials.credential_type == "BandwidthVoucher" AND NOT EXISTS (SELECT 1 FROM credential_usage - WHERE credential_usage.credential_id = coconut_credential.id) + WHERE credential_usage.credential_id = coconut_credentials.id) ORDER BY coconut_credentials.id LIMIT 1 "#, From ebd1eeb38df1fd5e95d4b79e08b6fdc13806a718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 26 Mar 2024 11:26:49 +0000 Subject: [PATCH 45/56] allow gateways to migrate configs of embedded NR/IPR --- gateway/src/commands/init.rs | 2 +- gateway/src/commands/node_details.rs | 2 +- gateway/src/commands/run.rs | 2 +- gateway/src/node/helpers.rs | 38 ++++- gateway/src/node/mod.rs | 4 +- .../ip-packet-router/src/cli/mod.rs | 39 +---- .../ip-packet-router/src/config/helpers.rs | 48 ++++++ .../ip-packet-router/src/config/mod.rs | 1 + .../network-requester/src/cli/mod.rs | 141 +--------------- .../network-requester/src/config/helpers.rs | 155 ++++++++++++++++++ .../network-requester/src/config/mod.rs | 1 + .../src/config/old_config_v1_1_20_2.rs | 1 + .../src/config/old_config_v1_1_33.rs | 1 + 13 files changed, 251 insertions(+), 184 deletions(-) create mode 100644 service-providers/ip-packet-router/src/config/helpers.rs create mode 100644 service-providers/network-requester/src/config/helpers.rs diff --git a/gateway/src/commands/init.rs b/gateway/src/commands/init.rs index b65cc062d2..010d270222 100644 --- a/gateway/src/commands/init.rs +++ b/gateway/src/commands/init.rs @@ -265,7 +265,7 @@ pub async fn execute(args: Init) -> anyhow::Result<()> { ); eprintln!("Gateway configuration completed.\n\n\n"); - output.to_stdout(&node_details(&config)?); + output.to_stdout(&node_details(&config).await?); Ok(()) } diff --git a/gateway/src/commands/node_details.rs b/gateway/src/commands/node_details.rs index 02c0ca9875..72840a8a7a 100644 --- a/gateway/src/commands/node_details.rs +++ b/gateway/src/commands/node_details.rs @@ -18,7 +18,7 @@ pub struct NodeDetails { pub async fn execute(args: NodeDetails) -> anyhow::Result<()> { let config = try_load_current_config(&args.id)?; - args.output.to_stdout(&node_details(&config)?); + args.output.to_stdout(&node_details(&config).await?); Ok(()) } diff --git a/gateway/src/commands/run.rs b/gateway/src/commands/run.rs index 3418c216ac..34c1b6be8d 100644 --- a/gateway/src/commands/run.rs +++ b/gateway/src/commands/run.rs @@ -248,7 +248,7 @@ pub async fn execute(args: Run) -> anyhow::Result<()> { show_binding_warning(config.gateway.listening_address); } - let node_details = node_details(&config)?; + let node_details = node_details(&config).await?; let gateway = crate::node::create_gateway(config, Some(nr_opts), Some(ip_opts), custom_mixnet).await?; eprintln!( diff --git a/gateway/src/node/helpers.rs b/gateway/src/node/helpers.rs index b6765cc7bb..3e2d54417a 100644 --- a/gateway/src/node/helpers.rs +++ b/gateway/src/node/helpers.rs @@ -23,7 +23,9 @@ fn display_path>(path: P) -> String { path.as_ref().display().to_string() } -pub(crate) fn node_details(config: &Config) -> Result { +pub(crate) async fn node_details( + config: &Config, +) -> Result { let gateway_identity_public_key: identity::PublicKey = load_public_key( &config.storage_paths.keys.public_identity_key_file, "gateway identity", @@ -36,7 +38,7 @@ pub(crate) fn node_details(config: &Config) -> Result Result Result>( +pub(crate) async fn load_network_requester_config>( + id: &str, + path: P, +) -> Result { + let path = path.as_ref(); + if let Ok(cfg) = read_network_requester_config(id, path) { + return Ok(cfg); + } + + nym_network_requester::config::helpers::try_upgrade_config(path).await?; + read_network_requester_config(id, path) +} + +pub(crate) async fn load_ip_packet_router_config>( + id: &str, + path: P, +) -> Result { + let path = path.as_ref(); + if let Ok(cfg) = read_ip_packet_router_config(id, path) { + return Ok(cfg); + } + + nym_ip_packet_router::config::helpers::try_upgrade_config(path).await?; + read_ip_packet_router_config(id, path) +} + +fn read_network_requester_config>( id: &str, path: P, ) -> Result { @@ -134,7 +162,7 @@ pub(crate) fn load_network_requester_config>( }) } -pub(crate) fn load_ip_packet_router_config>( +fn read_ip_packet_router_config>( id: &str, path: P, ) -> Result { diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index 30e1302d1a..26ad47b689 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -62,7 +62,7 @@ pub(crate) async fn create_gateway( // don't attempt to read config if NR is disabled let network_requester_config = if config.network_requester.enabled { if let Some(path) = &config.storage_paths.network_requester_config { - let cfg = load_network_requester_config(&config.gateway.id, path)?; + let cfg = load_network_requester_config(&config.gateway.id, path).await?; Some(override_network_requester_config(cfg, nr_config_override)) } else { // if NR is enabled, the config path must be specified @@ -75,7 +75,7 @@ pub(crate) async fn create_gateway( // don't attempt to read config if NR is disabled let ip_packet_router_config = if config.ip_packet_router.enabled { if let Some(path) = &config.storage_paths.ip_packet_router_config { - let cfg = load_ip_packet_router_config(&config.gateway.id, path)?; + let cfg = load_ip_packet_router_config(&config.gateway.id, path).await?; Some(override_ip_packet_router_config(cfg, ip_config_override)) } else { // if IPR is enabled, the config path must be specified diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index dc04d7e3cb..912c13cc7a 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -1,11 +1,10 @@ use clap::{CommandFactory, Parser, Subcommand}; -use log::{error, info, trace}; +use log::error; use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::{bin_info, version_checker}; use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; -use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; -use nym_ip_packet_router::config::old_config_v1::ConfigV1; +use nym_ip_packet_router::config::helpers::try_upgrade_config; use nym_ip_packet_router::config::{BaseClientConfig, Config}; use nym_ip_packet_router::error::IpPacketRouterError; use std::sync::OnceLock; @@ -136,40 +135,6 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { Ok(()) } -async fn try_upgrade_v1_config(id: &str) -> Result { - // explicitly load it as v1 (which is incompatible with the current one) - let Ok(old_config) = ConfigV1::read_from_default_path(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(false); - }; - info!("It seems the client is using v1 config template."); - info!("It is going to get updated to the current specification."); - - let old_paths = old_config.storage_paths.clone(); - let updated = old_config.try_upgrade()?; - - v1_1_33::migrate_gateway_details( - &old_paths.common_paths, - &updated.storage_paths.common_paths, - None, - ) - .await?; - - updated.save_to_default_location()?; - Ok(true) -} - -async fn try_upgrade_config(id: &str) -> Result<(), IpPacketRouterError> { - trace!("Attempting to upgrade config"); - - if try_upgrade_v1_config(id).await? { - return Ok(()); - } - - Ok(()) -} - async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { diff --git a/service-providers/ip-packet-router/src/config/helpers.rs b/service-providers/ip-packet-router/src/config/helpers.rs new file mode 100644 index 0000000000..5c965e8951 --- /dev/null +++ b/service-providers/ip-packet-router/src/config/helpers.rs @@ -0,0 +1,48 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::default_config_filepath; +use crate::config::old_config_v1::ConfigV1; +use crate::error::IpPacketRouterError; +use log::{info, trace}; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; +use std::path::Path; + +async fn try_upgrade_v1_config>( + config_path: P, +) -> Result { + // explicitly load it as v1 (which is incompatible with the current one) + let Ok(old_config) = ConfigV1::read_from_toml_file(config_path) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using v1 config template."); + info!("It is going to get updated to the current specification."); + + let old_paths = old_config.storage_paths.clone(); + let updated = old_config.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +pub async fn try_upgrade_config>(config_path: P) -> Result<(), IpPacketRouterError> { + trace!("Attempting to upgrade config"); + if try_upgrade_v1_config(config_path).await? { + return Ok(()); + } + + Ok(()) +} + +pub async fn try_upgrade_config_by_id(id: &str) -> Result<(), IpPacketRouterError> { + try_upgrade_config(default_config_filepath(id)).await +} diff --git a/service-providers/ip-packet-router/src/config/mod.rs b/service-providers/ip-packet-router/src/config/mod.rs index 88f6b32e68..048fcd67f8 100644 --- a/service-providers/ip-packet-router/src/config/mod.rs +++ b/service-providers/ip-packet-router/src/config/mod.rs @@ -20,6 +20,7 @@ use crate::config::persistence::IpPacketRouterPaths; use self::template::CONFIG_TEMPLATE; +pub mod helpers; pub mod old_config_v1; mod persistence; mod template; diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 29057aa523..7ba2462c61 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -1,22 +1,18 @@ // Copyright 2023 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only -use crate::config::old_config_v1_1_13::OldConfigV1_1_13; -use crate::config::old_config_v1_1_20::ConfigV1_1_20; -use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; -use crate::config::old_config_v1_1_33::ConfigV1_1_33; +use crate::config::helpers::try_upgrade_config_by_id; use crate::{ config::{BaseClientConfig, Config}, error::NetworkRequesterError, }; use clap::{CommandFactory, Parser, Subcommand}; -use log::{error, info, trace}; +use log::error; use nym_bin_common::bin_info; use nym_bin_common::completions::{fig_generate, ArgShell}; use nym_bin_common::version_checker; use nym_client_core::cli_helpers::client_import_credential::CommonClientImportCredentialArgs; use nym_client_core::cli_helpers::CliClient; -use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use nym_config::OptionalSet; use std::sync::OnceLock; @@ -36,7 +32,7 @@ impl CliClient for CliNetworkRequesterClient { type Config = Config; async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> { - try_upgrade_config(id).await + try_upgrade_config_by_id(id).await } async fn try_load_current_config(id: &str) -> Result { @@ -190,135 +186,6 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Ok(()) } -async fn try_upgrade_v1_1_13_config(id: &str) -> Result { - trace!("Trying to load as v1.1.13 config"); - use nym_config::legacy_helpers::nym_config::MigrationNymConfig; - - // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) - let Ok(old_config) = OldConfigV1_1_13::load_from_file(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(false); - }; - info!("It seems the client is using <= v1.1.13 config template."); - info!("It is going to get updated to the current specification."); - - let updated_step1: ConfigV1_1_20 = old_config.into(); - let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); - let (updated_step3, gateway_config) = updated_step2.upgrade()?; - let old_paths = updated_step3.storage_paths.clone(); - let updated = updated_step3.try_upgrade()?; - - v1_1_33::migrate_gateway_details( - &old_paths.common_paths, - &updated.storage_paths.common_paths, - Some(gateway_config), - ) - .await?; - - updated.save_to_default_location()?; - Ok(true) -} - -async fn try_upgrade_v1_1_20_config(id: &str) -> Result { - trace!("Trying to load as v1.1.20 config"); - use nym_config::legacy_helpers::nym_config::MigrationNymConfig; - - // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) - let Ok(old_config) = ConfigV1_1_20::load_from_file(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(false); - }; - - info!("It seems the client is using <= v1.1.20 config template."); - info!("It is going to get updated to the current specification."); - - let updated_step1: ConfigV1_1_20_2 = old_config.into(); - let (updated_step2, gateway_config) = updated_step1.upgrade()?; - let old_paths = updated_step2.storage_paths.clone(); - let updated = updated_step2.try_upgrade()?; - - v1_1_33::migrate_gateway_details( - &old_paths.common_paths, - &updated.storage_paths.common_paths, - Some(gateway_config), - ) - .await?; - - updated.save_to_default_location()?; - Ok(true) -} - -async fn try_upgrade_v1_1_20_2_config(id: &str) -> Result { - trace!("Trying to load as v1.1.20_2 config"); - - // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) - let Ok(old_config) = ConfigV1_1_20_2::read_from_default_path(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(false); - }; - info!("It seems the client is using <= v1.1.20_2 config template."); - info!("It is going to get updated to the current specification."); - - let (updated_step1, gateway_config) = old_config.upgrade()?; - let old_paths = updated_step1.storage_paths.clone(); - let updated = updated_step1.try_upgrade()?; - - v1_1_33::migrate_gateway_details( - &old_paths.common_paths, - &updated.storage_paths.common_paths, - Some(gateway_config), - ) - .await?; - - updated.save_to_default_location()?; - Ok(true) -} - -async fn try_upgrade_v1_1_33_config(id: &str) -> Result { - // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) - let Ok(old_config) = ConfigV1_1_33::read_from_default_path(id) else { - // if we failed to load it, there might have been nothing to upgrade - // or maybe it was an even older file. in either way. just ignore it and carry on with our day - return Ok(false); - }; - info!("It seems the client is using <= v1.1.33 config template."); - info!("It is going to get updated to the current specification."); - - let old_paths = old_config.storage_paths.clone(); - let updated = old_config.try_upgrade()?; - - v1_1_33::migrate_gateway_details( - &old_paths.common_paths, - &updated.storage_paths.common_paths, - None, - ) - .await?; - - updated.save_to_default_location()?; - Ok(true) -} - -async fn try_upgrade_config(id: &str) -> Result<(), NetworkRequesterError> { - trace!("Attempting to upgrade config"); - if try_upgrade_v1_1_13_config(id).await? { - return Ok(()); - } - if try_upgrade_v1_1_20_config(id).await? { - return Ok(()); - } - if try_upgrade_v1_1_20_2_config(id).await? { - return Ok(()); - } - if try_upgrade_v1_1_33_config(id).await? { - return Ok(()); - } - - Ok(()) -} - async fn try_load_current_config(id: &str) -> Result { // try to load the config as is if let Ok(cfg) = Config::read_from_default_path(id) { @@ -330,7 +197,7 @@ async fn try_load_current_config(id: &str) -> Result cfg, diff --git a/service-providers/network-requester/src/config/helpers.rs b/service-providers/network-requester/src/config/helpers.rs new file mode 100644 index 0000000000..5ef027d078 --- /dev/null +++ b/service-providers/network-requester/src/config/helpers.rs @@ -0,0 +1,155 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::config::default_config_filepath; +use crate::config::old_config_v1_1_13::OldConfigV1_1_13; +use crate::config::old_config_v1_1_20::ConfigV1_1_20; +use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; +use crate::config::old_config_v1_1_33::ConfigV1_1_33; +use crate::error::NetworkRequesterError; +use log::{info, trace}; +use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; +use std::path::Path; + +async fn try_upgrade_v1_1_13_config>( + config_path: P, +) -> Result { + trace!("Trying to load as v1.1.13 config"); + use nym_config::legacy_helpers::nym_config::MigrationNymConfig; + + // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) + let Ok(old_config) = OldConfigV1_1_13::load_from_filepath(config_path) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.13 config template."); + info!("It is going to get updated to the current specification."); + + let updated_step1: ConfigV1_1_20 = old_config.into(); + let updated_step2: ConfigV1_1_20_2 = updated_step1.into(); + let (updated_step3, gateway_config) = updated_step2.upgrade()?; + let old_paths = updated_step3.storage_paths.clone(); + let updated = updated_step3.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +async fn try_upgrade_v1_1_20_config>( + config_path: P, +) -> Result { + trace!("Trying to load as v1.1.20 config"); + use nym_config::legacy_helpers::nym_config::MigrationNymConfig; + + // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) + let Ok(old_config) = ConfigV1_1_20::load_from_filepath(config_path) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + + info!("It seems the client is using <= v1.1.20 config template."); + info!("It is going to get updated to the current specification."); + + let updated_step1: ConfigV1_1_20_2 = old_config.into(); + let (updated_step2, gateway_config) = updated_step1.upgrade()?; + let old_paths = updated_step2.storage_paths.clone(); + let updated = updated_step2.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +async fn try_upgrade_v1_1_20_2_config>( + config_path: P, +) -> Result { + trace!("Trying to load as v1.1.20_2 config"); + + // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) + let Ok(old_config) = ConfigV1_1_20_2::read_from_toml_file(config_path) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.20_2 config template."); + info!("It is going to get updated to the current specification."); + + let (updated_step1, gateway_config) = old_config.upgrade()?; + let old_paths = updated_step1.storage_paths.clone(); + let updated = updated_step1.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + Some(gateway_config), + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +async fn try_upgrade_v1_1_33_config>( + config_path: P, +) -> Result { + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) + let Ok(old_config) = ConfigV1_1_33::read_from_toml_file(config_path) else { + // if we failed to load it, there might have been nothing to upgrade + // or maybe it was an even older file. in either way. just ignore it and carry on with our day + return Ok(false); + }; + info!("It seems the client is using <= v1.1.33 config template."); + info!("It is going to get updated to the current specification."); + + let old_paths = old_config.storage_paths.clone(); + let updated = old_config.try_upgrade()?; + + v1_1_33::migrate_gateway_details( + &old_paths.common_paths, + &updated.storage_paths.common_paths, + None, + ) + .await?; + + updated.save_to_default_location()?; + Ok(true) +} + +pub async fn try_upgrade_config>( + config_path: P, +) -> Result<(), NetworkRequesterError> { + trace!("Attempting to upgrade config"); + if try_upgrade_v1_1_13_config(config_path.as_ref()).await? { + return Ok(()); + } + if try_upgrade_v1_1_20_config(config_path.as_ref()).await? { + return Ok(()); + } + if try_upgrade_v1_1_20_2_config(config_path.as_ref()).await? { + return Ok(()); + } + if try_upgrade_v1_1_33_config(config_path).await? { + return Ok(()); + } + + Ok(()) +} + +pub async fn try_upgrade_config_by_id(id: &str) -> Result<(), NetworkRequesterError> { + try_upgrade_config(default_config_filepath(id)).await +} diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index a45180b200..cba8253039 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -23,6 +23,7 @@ use url::Url; pub use nym_client_core::config::Config as BaseClientConfig; +pub mod helpers; pub mod old_config_v1_1_13; pub mod old_config_v1_1_20; pub mod old_config_v1_1_20_2; diff --git a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs index 642270911b..8fe4c90232 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_20_2.rs @@ -55,6 +55,7 @@ impl ConfigV1_1_20_2 { read_config_from_toml_file(path) } + #[allow(dead_code)] pub fn read_from_default_path>(id: P) -> io::Result { Self::read_from_toml_file(default_config_filepath(id)) } diff --git a/service-providers/network-requester/src/config/old_config_v1_1_33.rs b/service-providers/network-requester/src/config/old_config_v1_1_33.rs index b49bb514d1..e211256643 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_33.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_33.rs @@ -54,6 +54,7 @@ impl ConfigV1_1_33 { read_config_from_toml_file(path) } + #[allow(dead_code)] pub fn read_from_default_path>(id: P) -> io::Result { Self::read_from_toml_file(default_config_filepath(id)) } From dcd3d80b246d2cd4ffd867af8abecd7fb2b838be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 26 Mar 2024 11:55:28 +0000 Subject: [PATCH 46/56] fixed post-rebasing clippy issues --- Cargo.lock | 145 +++++++++++++----- .../cli_helpers/client_import_credential.rs | 1 + nym-connect/desktop/Cargo.lock | 30 +++- 3 files changed, 133 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 95910fc24b..c809facc92 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -557,9 +557,9 @@ dependencies = [ "bitflags 1.3.2", "bytes", "futures-util", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "itoa", "matchit", "memchr", @@ -587,8 +587,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "mime", "rustversion", "tower-layer", @@ -3011,7 +3011,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http", + "http 0.2.9", "js-sys", "pin-project", "serde", @@ -3080,7 +3080,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.9", "indexmap 1.9.3", "slab", "tokio", @@ -3290,6 +3290,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-api-client" version = "0.1.0" @@ -3311,7 +3322,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", - "http", + "http 0.2.9", + "pin-project-lite 0.2.13", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0475f8b2ac86659c21b64320d5d653f9efe42acd2a4e560073ec61a155a34f1d" +dependencies = [ + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", "pin-project-lite 0.2.13", ] @@ -3379,8 +3413,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "httparse", "httpdate", "itoa", @@ -3392,6 +3426,25 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186548d73ac615b32a73aafe38fb4f56c0d340e110e5a200bcadbaf2e199263a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite 0.2.13", + "smallvec", + "tokio", +] + [[package]] name = "hyper-rustls" version = "0.24.1" @@ -3399,8 +3452,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "rustls 0.21.10", "tokio", "tokio-rustls 0.24.1", @@ -3412,12 +3465,28 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" dependencies = [ - "hyper", + "hyper 0.14.27", "pin-project-lite 0.2.13", "tokio", "tokio-io-timeout", ] +[[package]] +name = "hyper-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.2.0", + "pin-project-lite 0.2.13", + "socket2 0.5.4", + "tokio", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3742,7 +3811,7 @@ dependencies = [ "curl-sys", "event-listener", "futures-lite", - "http", + "http 0.2.9", "log", "once_cell", "polling", @@ -4555,7 +4624,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 0.2.9", "httparse", "log", "memchr", @@ -5191,7 +5260,10 @@ dependencies = [ "clap 4.4.7", "futures", "gloo-timers", + "http-body-util", "humantime-serde", + "hyper 1.2.0", + "hyper-util", "log", "nym-bandwidth-controller", "nym-client-core-gateways-storage", @@ -5203,6 +5275,7 @@ dependencies = [ "nym-gateway-client", "nym-gateway-requests", "nym-id", + "nym-metrics", "nym-network-defaults", "nym-nonexhaustive-delayqueue", "nym-pemstore", @@ -5548,7 +5621,7 @@ dependencies = [ "dotenvy", "futures", "humantime-serde", - "hyper", + "hyper 0.14.27", "ipnetwork 0.16.0", "log", "nym-api-requests", @@ -5754,7 +5827,6 @@ dependencies = [ "lazy_static", "log", "prometheus", - "regex", ] [[package]] @@ -5985,7 +6057,7 @@ dependencies = [ "dashmap", "fastrand 2.0.1", "hmac 0.12.1", - "hyper", + "hyper 0.14.27", "ipnetwork 0.16.0", "mime", "nym-config", @@ -6138,7 +6210,7 @@ dependencies = [ "dotenvy", "futures", "hex", - "http", + "http 0.2.9", "httpcodec", "libp2p", "log", @@ -6878,7 +6950,7 @@ checksum = "a819b71d6530c4297b49b3cae2939ab3a8cc1b9f382826a1bc29dd0ca3864906" dependencies = [ "async-trait", "bytes", - "http", + "http 0.2.9", "isahc", "opentelemetry_api", ] @@ -6892,7 +6964,7 @@ dependencies = [ "async-trait", "futures", "futures-executor", - "http", + "http 0.2.9", "isahc", "once_cell", "opentelemetry", @@ -8073,9 +8145,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-rustls", "ipnet", "js-sys", @@ -8234,7 +8306,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfac3a1df83f8d4fc96aa41dba3b86c786417b7fc0f52ec76295df2ba781aa69" dependencies = [ - "http", + "http 0.2.9", "log", "regex", "rocket", @@ -8254,8 +8326,8 @@ dependencies = [ "cookie", "either", "futures", - "http", - "hyper", + "http 0.2.9", + "hyper 0.14.27", "indexmap 2.0.2", "log", "memchr", @@ -9059,9 +9131,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snafu" @@ -9910,7 +9982,10 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", + "rustls 0.21.10", + "rustls-native-certs", "tokio", + "tokio-rustls 0.24.1", "tungstenite", ] @@ -10013,9 +10088,9 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", + "http 0.2.9", + "http-body 0.4.5", + "hyper 0.14.27", "hyper-timeout", "percent-encoding", "pin-project", @@ -10058,8 +10133,8 @@ dependencies = [ "bytes", "futures-core", "futures-util", - "http", - "http-body", + "http 0.2.9", + "http-body 0.4.5", "http-range-header", "httpdate", "mime", @@ -10337,7 +10412,7 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.9", "httparse", "log", "rand 0.8.5", diff --git a/common/client-core/src/cli_helpers/client_import_credential.rs b/common/client-core/src/cli_helpers/client_import_credential.rs index 55d005975a..48468771da 100644 --- a/common/client-core/src/cli_helpers/client_import_credential.rs +++ b/common/client-core/src/cli_helpers/client_import_credential.rs @@ -5,6 +5,7 @@ use crate::cli_helpers::{CliClient, CliClientConfig}; use std::fs; use std::path::PathBuf; +#[cfg(feature = "cli")] fn parse_encoded_credential_data(raw: &str) -> bs58::decode::Result> { bs58::decode(raw).into_vec() } diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index afbc2f403f..3f3c7fd428 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -2844,6 +2844,20 @@ dependencies = [ "itoa 1.0.9", ] +[[package]] +name = "http-api-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", + "wasmtimer", +] + [[package]] name = "http-body" version = "0.4.5" @@ -3804,6 +3818,7 @@ version = "1.1.15" dependencies = [ "async-trait", "base64 0.21.4", + "bs58 0.5.0", "cfg-if", "futures", "gloo-timers", @@ -3821,6 +3836,7 @@ dependencies = [ "nym-explorer-client", "nym-gateway-client", "nym-gateway-requests", + "nym-id", "nym-metrics", "nym-network-defaults", "nym-nonexhaustive-delayqueue", @@ -4196,17 +4212,15 @@ dependencies = [ ] [[package]] -name = "nym-http-api-client" +name = "nym-id" version = "0.1.0" dependencies = [ - "async-trait", - "reqwest", - "serde", - "serde_json", + "nym-credential-storage", + "nym-credentials", "thiserror", + "time", "tracing", - "url", - "wasmtimer", + "zeroize", ] [[package]] @@ -4622,6 +4636,7 @@ dependencies = [ "eyre", "flate2", "futures", + "http-api-client", "itertools", "log", "nym-api-requests", @@ -4632,7 +4647,6 @@ dependencies = [ "nym-contracts-common", "nym-ephemera-common", "nym-group-contract-common", - "nym-http-api-client", "nym-mixnet-contract-common", "nym-multisig-contract-common", "nym-name-service-common", From b8ab07020c4495bb098a925ac09f5277031a150f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 26 Mar 2024 14:26:45 +0000 Subject: [PATCH 47/56] fixed eda61b57dc8d349a9b0af70cbd02743eba1e10bf --- .../ip-packet-router/src/config/helpers.rs | 5 +++-- .../network-requester/src/config/helpers.rs | 19 +++++++++++-------- .../src/config/old_config_v1_1_33.rs | 1 + 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/service-providers/ip-packet-router/src/config/helpers.rs b/service-providers/ip-packet-router/src/config/helpers.rs index 5c965e8951..e6abda1d98 100644 --- a/service-providers/ip-packet-router/src/config/helpers.rs +++ b/service-providers/ip-packet-router/src/config/helpers.rs @@ -5,6 +5,7 @@ use crate::config::default_config_filepath; use crate::config::old_config_v1::ConfigV1; use crate::error::IpPacketRouterError; use log::{info, trace}; +use nym_client_core::cli_helpers::CliClientConfig; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use std::path::Path; @@ -12,7 +13,7 @@ async fn try_upgrade_v1_config>( config_path: P, ) -> Result { // explicitly load it as v1 (which is incompatible with the current one) - let Ok(old_config) = ConfigV1::read_from_toml_file(config_path) else { + let Ok(old_config) = ConfigV1::read_from_toml_file(config_path.as_ref()) else { // if we failed to load it, there might have been nothing to upgrade // or maybe it was an even older file. in either way. just ignore it and carry on with our day return Ok(false); @@ -30,7 +31,7 @@ async fn try_upgrade_v1_config>( ) .await?; - updated.save_to_default_location()?; + updated.save_to(config_path)?; Ok(true) } diff --git a/service-providers/network-requester/src/config/helpers.rs b/service-providers/network-requester/src/config/helpers.rs index 5ef027d078..e03281fa01 100644 --- a/service-providers/network-requester/src/config/helpers.rs +++ b/service-providers/network-requester/src/config/helpers.rs @@ -8,6 +8,7 @@ use crate::config::old_config_v1_1_20_2::ConfigV1_1_20_2; use crate::config::old_config_v1_1_33::ConfigV1_1_33; use crate::error::NetworkRequesterError; use log::{info, trace}; +use nym_client_core::cli_helpers::CliClientConfig; use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33; use std::path::Path; @@ -18,7 +19,7 @@ async fn try_upgrade_v1_1_13_config>( use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19) - let Ok(old_config) = OldConfigV1_1_13::load_from_filepath(config_path) else { + let Ok(old_config) = OldConfigV1_1_13::load_from_filepath(config_path.as_ref()) else { // if we failed to load it, there might have been nothing to upgrade // or maybe it was an even older file. in either way. just ignore it and carry on with our day return Ok(false); @@ -39,7 +40,7 @@ async fn try_upgrade_v1_1_13_config>( ) .await?; - updated.save_to_default_location()?; + updated.save_to(config_path)?; Ok(true) } @@ -50,7 +51,7 @@ async fn try_upgrade_v1_1_20_config>( use nym_config::legacy_helpers::nym_config::MigrationNymConfig; // explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21) - let Ok(old_config) = ConfigV1_1_20::load_from_filepath(config_path) else { + let Ok(old_config) = ConfigV1_1_20::load_from_filepath(config_path.as_ref()) else { // if we failed to load it, there might have been nothing to upgrade // or maybe it was an even older file. in either way. just ignore it and carry on with our day return Ok(false); @@ -71,7 +72,7 @@ async fn try_upgrade_v1_1_20_config>( ) .await?; - updated.save_to_default_location()?; + updated.save_to(config_path)?; Ok(true) } @@ -81,7 +82,7 @@ async fn try_upgrade_v1_1_20_2_config>( trace!("Trying to load as v1.1.20_2 config"); // explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21) - let Ok(old_config) = ConfigV1_1_20_2::read_from_toml_file(config_path) else { + let Ok(old_config) = ConfigV1_1_20_2::read_from_toml_file(config_path.as_ref()) else { // if we failed to load it, there might have been nothing to upgrade // or maybe it was an even older file. in either way. just ignore it and carry on with our day return Ok(false); @@ -100,15 +101,17 @@ async fn try_upgrade_v1_1_20_2_config>( ) .await?; - updated.save_to_default_location()?; + updated.save_to(config_path)?; Ok(true) } async fn try_upgrade_v1_1_33_config>( config_path: P, ) -> Result { + trace!("Trying to load as v1.1.33 config"); + // explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34) - let Ok(old_config) = ConfigV1_1_33::read_from_toml_file(config_path) else { + let Ok(old_config) = ConfigV1_1_33::read_from_toml_file(config_path.as_ref()) else { // if we failed to load it, there might have been nothing to upgrade // or maybe it was an even older file. in either way. just ignore it and carry on with our day return Ok(false); @@ -126,7 +129,7 @@ async fn try_upgrade_v1_1_33_config>( ) .await?; - updated.save_to_default_location()?; + updated.save_to(config_path)?; Ok(true) } diff --git a/service-providers/network-requester/src/config/old_config_v1_1_33.rs b/service-providers/network-requester/src/config/old_config_v1_1_33.rs index e211256643..b3089b036f 100644 --- a/service-providers/network-requester/src/config/old_config_v1_1_33.rs +++ b/service-providers/network-requester/src/config/old_config_v1_1_33.rs @@ -36,6 +36,7 @@ pub struct NetworkRequesterPathsV1_1_33 { #[derive(Debug, Deserialize, PartialEq, Serialize)] #[serde(deny_unknown_fields)] pub struct ConfigV1_1_33 { + #[serde(flatten)] pub base: BaseConfigV1_1_33, #[serde(default)] From ff499869d33b6f297860f76f5ae2d2ce3ced1809 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Tue, 26 Mar 2024 14:39:53 +0000 Subject: [PATCH 48/56] clippy --- service-providers/network-requester/src/config/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/service-providers/network-requester/src/config/mod.rs b/service-providers/network-requester/src/config/mod.rs index cba8253039..53cdc143f4 100644 --- a/service-providers/network-requester/src/config/mod.rs +++ b/service-providers/network-requester/src/config/mod.rs @@ -135,6 +135,7 @@ impl Config { default_config_filepath(&self.base.client.id) } + #[allow(dead_code)] pub fn save_to_default_location(&self) -> io::Result<()> { let config_save_location: PathBuf = self.default_location(); save_formatted_config_to_file(self, config_save_location) From 74d03bfb3b9608ea83cd6dcd75758e004e3458cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 27 Mar 2024 14:01:48 +0000 Subject: [PATCH 49/56] moved for adding new gateways to separate command and made client init only first time setup related --- clients/native/src/commands/add_gateway.rs | 30 +++ clients/native/src/commands/mod.rs | 5 + clients/socks5/src/commands/add_gateway.rs | 30 +++ clients/socks5/src/commands/mod.rs | 5 + .../src/cli_helpers/client_add_gateway.rs | 174 ++++++++++++++++++ .../src/cli_helpers/client_init.rs | 108 +++-------- .../src/cli_helpers/client_list_gateways.rs | 36 +--- common/client-core/src/cli_helpers/mod.rs | 2 + common/client-core/src/cli_helpers/types.rs | 40 ++++ common/client-core/src/error.rs | 3 + .../mixnet-contract/src/nym_node.rs | 13 ++ .../ip-packet-router/src/cli/add_gateway.rs | 32 ++++ .../ip-packet-router/src/cli/mod.rs | 5 + .../network-requester/src/cli/add_gateway.rs | 32 ++++ .../network-requester/src/cli/mod.rs | 5 + 15 files changed, 402 insertions(+), 118 deletions(-) create mode 100644 clients/native/src/commands/add_gateway.rs create mode 100644 clients/socks5/src/commands/add_gateway.rs create mode 100644 common/client-core/src/cli_helpers/client_add_gateway.rs create mode 100644 common/client-core/src/cli_helpers/types.rs create mode 100644 common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs create mode 100644 service-providers/ip-packet-router/src/cli/add_gateway.rs create mode 100644 service-providers/network-requester/src/cli/add_gateway.rs diff --git a/clients/native/src/commands/add_gateway.rs b/clients/native/src/commands/add_gateway.rs new file mode 100644 index 0000000000..254839af04 --- /dev/null +++ b/clients/native/src/commands/add_gateway.rs @@ -0,0 +1,30 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliNativeClient; +use crate::error::ClientError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientAddGatewayArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientAddGatewayArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), ClientError> { + let output = args.output; + let res = add_gateway::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/clients/native/src/commands/mod.rs b/clients/native/src/commands/mod.rs index 9c7c016580..3f8e86e94f 100644 --- a/clients/native/src/commands/mod.rs +++ b/clients/native/src/commands/mod.rs @@ -20,6 +20,7 @@ use std::error::Error; use std::net::IpAddr; use std::sync::OnceLock; +mod add_gateway; pub(crate) mod build_info; pub(crate) mod import_credential; pub(crate) mod init; @@ -77,6 +78,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Add new gateway to this client + AddGateway(add_gateway::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! SwitchGateway(switch_gateway::Args), @@ -110,6 +114,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::AddGateway(args) => add_gateway::execute(args).await?, Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), diff --git a/clients/socks5/src/commands/add_gateway.rs b/clients/socks5/src/commands/add_gateway.rs new file mode 100644 index 0000000000..fb7b645619 --- /dev/null +++ b/clients/socks5/src/commands/add_gateway.rs @@ -0,0 +1,30 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::commands::CliSocks5Client; +use crate::error::Socks5ClientError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientAddGatewayArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientAddGatewayArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), Socks5ClientError> { + let output = args.output; + let res = add_gateway::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/clients/socks5/src/commands/mod.rs b/clients/socks5/src/commands/mod.rs index d982b86a9e..961c6551e5 100644 --- a/clients/socks5/src/commands/mod.rs +++ b/clients/socks5/src/commands/mod.rs @@ -24,6 +24,7 @@ use std::error::Error; use std::net::IpAddr; use std::sync::OnceLock; +mod add_gateway; pub(crate) mod build_info; mod import_credential; pub mod init; @@ -81,6 +82,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Add new gateway to this client + AddGateway(add_gateway::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! SwitchGateway(switch_gateway::Args), @@ -117,6 +121,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), Box run::execute(m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::AddGateway(args) => add_gateway::execute(args).await?, Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), diff --git a/common/client-core/src/cli_helpers/client_add_gateway.rs b/common/client-core/src/cli_helpers/client_add_gateway.rs new file mode 100644 index 0000000000..afcb236ec7 --- /dev/null +++ b/common/client-core/src/cli_helpers/client_add_gateway.rs @@ -0,0 +1,174 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli_helpers::types::GatewayInfo; +use crate::cli_helpers::{CliClient, CliClientConfig}; +use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; +use crate::{ + client::{ + base_client::storage::helpers::{get_all_registered_identities, set_active_gateway}, + key_manager::persistence::OnDiskKeys, + }, + error::ClientCoreError, + init::types::{GatewaySelectionSpecification, GatewaySetup}, +}; +use log::info; +use nym_client_core_gateways_storage::GatewayDetails; +use nym_crypto::asymmetric::identity; +use nym_topology::NymTopology; +use std::path::PathBuf; + +#[cfg_attr(feature = "cli", derive(clap::Args))] +#[derive(Debug, Clone)] +pub struct CommonClientAddGatewayArgs { + /// Id of client we want to add gateway for. + #[cfg_attr(feature = "cli", clap(long))] + pub id: String, + + /// Explicitly specify id of the gateway to register with. + /// If unspecified, a random gateway will be chosen instead. + #[cfg_attr(feature = "cli", clap(long))] + pub gateway: Option, + + /// Specifies whether the client will attempt to enforce tls connection to the desired gateway. + #[cfg_attr(feature = "cli", clap(long))] + pub force_tls_gateway: bool, + + /// Specifies whether the new gateway should be determined based by latency as opposed to being chosen + /// uniformly. + #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))] + pub latency_based_selection: bool, + + /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, + /// potentially causing loss of access. + #[cfg_attr(feature = "cli", clap(long))] + pub force_register_gateway: bool, + + /// Specify whether this new gateway should be set as the active one + #[cfg_attr(feature = "cli", clap(long, default_value_t = true))] + pub set_active: bool, + + /// Comma separated list of rest endpoints of the API validators + #[cfg_attr( + feature = "cli", + clap( + long, + alias = "api_validators", + value_delimiter = ',', + group = "network" + ) + )] + pub nym_apis: Option>, + + /// Path to .json file containing custom network specification. + #[cfg_attr(feature = "cli", clap(long, group = "network", hide = true))] + pub custom_mixnet: Option, +} + +pub async fn add_gateway(args: A) -> Result +where + A: AsRef, + C: CliClient, +{ + let common_args = args.as_ref(); + let id = &common_args.id; + + let config = C::try_load_current_config(id).await?; + let core = config.core_config(); + let paths = config.common_paths(); + + let key_store = OnDiskKeys::new(paths.keys.clone()); + let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; + + let user_wants_force_register = common_args.force_register_gateway; + if user_wants_force_register { + eprintln!("Instructed to force registering gateway. This might overwrite keys!"); + } + + // Attempt to use a user-provided gateway, if possible + let user_chosen_gateway_id = common_args.gateway; + log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); + + let selection_spec = GatewaySelectionSpecification::new( + user_chosen_gateway_id.map(|id| id.to_base58_string()), + Some(common_args.latency_based_selection), + common_args.force_tls_gateway, + ); + log::debug!("Gateway selection specification: {selection_spec:?}"); + + let registered_gateways = get_all_registered_identities(&details_store).await?; + + // if user provided gateway id (and we can't overwrite data), make sure we're not trying to register + // with a known gateway + if let Some(user_chosen) = user_chosen_gateway_id { + if !common_args.force_register_gateway && registered_gateways.contains(&user_chosen) { + return Err(ClientCoreError::AlreadyRegistered { + gateway_id: user_chosen.to_base58_string(), + } + .into()); + } + } + + // Setup gateway by either registering a new one, or creating a new config from the selected + // one but with keys kept, or reusing the gateway configuration. + let available_gateways = if let Some(custom_mixnet) = common_args.custom_mixnet.as_ref() { + let hardcoded_topology = NymTopology::new_from_file(custom_mixnet).map_err(|source| { + ClientCoreError::CustomTopologyLoadFailure { + file_path: custom_mixnet.clone(), + source, + } + })?; + hardcoded_topology.get_gateways() + } else { + let mut rng = rand::thread_rng(); + crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? + }; + + // since we're registering with a brand new gateway, + // make sure the list of available gateways doesn't overlap the list of known gateways + let available_gateways = if common_args.force_register_gateway { + // if we're force registering, all bets are off + available_gateways + } else { + available_gateways + .into_iter() + .filter(|g| !registered_gateways.contains(g.identity())) + .collect() + }; + + let gateway_setup = GatewaySetup::New { + specification: selection_spec, + available_gateways, + overwrite_data: common_args.force_register_gateway, + wg_tun_address: None, + }; + + let init_details = + crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; + + let address = init_details.client_address(); + + let gateway_registration = init_details.gateway_registration; + let GatewayDetails::Remote(ref gateway_details) = gateway_registration.details else { + return Err(ClientCoreError::UnexpectedPersistedCustomGatewayDetails)?; + }; + + if common_args.set_active { + set_active_gateway( + &details_store, + &gateway_details.gateway_id.to_base58_string(), + ) + .await?; + } else { + info!("registered with new gateway {} (under address {address}), but this will not be our default address", gateway_details.gateway_id); + } + + Ok(GatewayInfo { + registration: gateway_registration.registration_timestamp, + identity: gateway_details.gateway_id, + active: common_args.set_active, + typ: gateway_registration.details.typ().to_string(), + endpoint: Some(gateway_details.gateway_listener.clone()), + wg_tun_address: gateway_details.wg_tun_address.clone(), + }) +} diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index 1d83302210..f765117d35 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -6,8 +6,7 @@ use crate::error::ClientCoreError; use crate::{ client::{ base_client::{ - non_wasm_helpers::setup_fs_gateways_storage, - storage::helpers::{get_all_registered_identities, set_active_gateway}, + non_wasm_helpers::setup_fs_gateways_storage, storage::helpers::set_active_gateway, }, key_manager::persistence::OnDiskKeys, }, @@ -52,16 +51,6 @@ pub struct CommonClientInitArgs { #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))] pub latency_based_selection: bool, - /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, - /// potentially causing loss of access. - #[cfg_attr(feature = "cli", clap(long))] - pub force_register_gateway: bool, - - /// If the registration is happening against new gateway, - /// specify whether it should be set as the currently active gateway - #[cfg_attr(feature = "cli", clap(long, default_value_t = true))] - pub set_active: bool, - /// Comma separated list of rest endpoints of the nyxd validators #[cfg_attr( feature = "cli", @@ -118,28 +107,16 @@ where let common_args = init_args.as_ref(); let id = &common_args.id; - let already_init = if C::default_config_path(id).exists() { - // in case we're using old config, try to upgrade it - // (if we're using the current version, it's a no-op) - C::try_upgrade_outdated_config(id).await?; + if C::default_config_path(id).exists() { eprintln!("{} client \"{id}\" was already initialised before", C::NAME); - true - } else { - info!( - "{} client {id:?} hasn't been initialised before - new keys are going to be generated", - C::NAME - ); - C::initialise_storage_paths(id)?; - false - }; - - // Usually you only register with the gateway on the first init, however you can force - // re-registering if wanted. - let user_wants_force_register = common_args.force_register_gateway; - if user_wants_force_register { - eprintln!("Instructed to force registering gateway. This might overwrite keys!"); + return Err(ClientCoreError::AlreadyInitialised { + client_id: id.to_string(), + } + .into()); } + C::initialise_storage_paths(id)?; + // Attempt to use a user-provided gateway, if possible let user_chosen_gateway_id = common_args.gateway; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); @@ -171,24 +148,8 @@ where let key_store = OnDiskKeys::new(paths.keys.clone()); let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; - // if this is a first time client with this particular id is initialised, generated long-term keys - if !already_init { - let mut rng = OsRng; - crate::init::generate_new_client_keys(&mut rng, &key_store).await?; - } - - let registered_gateways = get_all_registered_identities(&details_store).await?; - - // if user provided gateway id (and we can't overwrite data), make sure we're not trying to register - // with a known gateway - if let Some(user_chosen) = user_chosen_gateway_id { - if !common_args.force_register_gateway && registered_gateways.contains(&user_chosen) { - return Err(ClientCoreError::AlreadyRegistered { - gateway_id: user_chosen.to_base58_string(), - } - .into()); - } - } + let mut rng = OsRng; + crate::init::generate_new_client_keys(&mut rng, &key_store).await?; // Setup gateway by either registering a new one, or creating a new config from the selected // one but with keys kept, or reusing the gateway configuration. @@ -205,22 +166,10 @@ where crate::init::helpers::current_gateways(&mut rng, &core.client.nym_api_urls).await? }; - // since we're registering with a brand new gateway, - // make sure the list of available gateways doesn't overlap the list of known gateways - let available_gateways = if common_args.force_register_gateway { - // if we're force registering, all bets are off - available_gateways - } else { - available_gateways - .into_iter() - .filter(|g| !registered_gateways.contains(g.identity())) - .collect() - }; - let gateway_setup = GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: common_args.force_register_gateway, + overwrite_data: false, wg_tun_address: None, }; @@ -228,25 +177,22 @@ where crate::init::setup_gateway(gateway_setup, &key_store, &details_store).await?; // TODO: ask the service provider we specified for its interface version and set it in the config - - if !already_init { - let config_save_location = config.default_store_location(); - if let Err(err) = config.save_to(&config_save_location) { - return Err(ClientCoreError::ConfigSaveFailure { - typ: C::NAME.to_string(), - id: id.to_string(), - path: config_save_location, - source: err, - } - .into()); + let config_save_location = config.default_store_location(); + if let Err(err) = config.save_to(&config_save_location) { + return Err(ClientCoreError::ConfigSaveFailure { + typ: C::NAME.to_string(), + id: id.to_string(), + path: config_save_location, + source: err, } - - eprintln!( - "Saved configuration file to {}", - config_save_location.display() - ); + .into()); } + eprintln!( + "Saved configuration file to {}", + config_save_location.display() + ); + let address = init_details.client_address(); let GatewayDetails::Remote(gateway_details) = init_details.gateway_registration.details else { @@ -260,11 +206,7 @@ where init_details.gateway_registration.registration_timestamp, ); - if init_args.as_ref().set_active { - set_active_gateway(&details_store, &init_results.gateway_id).await?; - } else { - info!("registered with new gateway {} (under address {address}), but this will not be our default address", init_results.gateway_id); - } + set_active_gateway(&details_store, &init_results.gateway_id).await?; Ok(InitResultsWithConfig { config, diff --git a/common/client-core/src/cli_helpers/client_list_gateways.rs b/common/client-core/src/cli_helpers/client_list_gateways.rs index 641b29d16e..1bfcafb027 100644 --- a/common/client-core/src/cli_helpers/client_list_gateways.rs +++ b/common/client-core/src/cli_helpers/client_list_gateways.rs @@ -1,17 +1,15 @@ // Copyright 2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use super::types::GatewayInfo; use crate::cli_helpers::{CliClient, CliClientConfig}; use crate::client::base_client::non_wasm_helpers::setup_fs_gateways_storage; use crate::client::base_client::storage::helpers::{ get_active_gateway_identity, get_gateway_registrations, }; use nym_client_core_gateways_storage::{GatewayDetails, GatewayType}; -use nym_crypto::asymmetric::identity; use serde::{Deserialize, Serialize}; use std::fmt::{Display, Formatter}; -use time::OffsetDateTime; -use url::Url; #[cfg_attr(feature = "cli", derive(clap::Args))] #[derive(Debug, Clone)] @@ -34,38 +32,6 @@ impl Display for RegisteredGateways { } } -#[derive(Serialize, Deserialize)] -pub struct GatewayInfo { - pub registration: OffsetDateTime, - pub identity: identity::PublicKey, - pub active: bool, - - pub typ: String, - pub endpoint: Option, - pub wg_tun_address: Option, -} - -impl Display for GatewayInfo { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - if self.active { - write!(f, "[ACTIVE] ")?; - } - write!( - f, - "{} gateway '{}' registered at: {}", - self.typ, self.identity, self.registration - )?; - if let Some(endpoint) = &self.endpoint { - write!(f, " endpoint: {endpoint}")?; - } - - if let Some(wg_tun_address) = &self.wg_tun_address { - write!(f, " wg tun address: {wg_tun_address}")?; - } - Ok(()) - } -} - pub async fn list_gateways(args: A) -> Result where A: AsRef, diff --git a/common/client-core/src/cli_helpers/mod.rs b/common/client-core/src/cli_helpers/mod.rs index e2a018cb18..5ab51b8b4c 100644 --- a/common/client-core/src/cli_helpers/mod.rs +++ b/common/client-core/src/cli_helpers/mod.rs @@ -1,12 +1,14 @@ // Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +pub mod client_add_gateway; pub mod client_import_credential; pub mod client_init; pub mod client_list_gateways; pub mod client_run; pub mod client_switch_gateway; pub mod traits; +mod types; pub use client_init::InitialisableClient; pub use traits::{CliClient, CliClientConfig}; diff --git a/common/client-core/src/cli_helpers/types.rs b/common/client-core/src/cli_helpers/types.rs new file mode 100644 index 0000000000..4a351f38ef --- /dev/null +++ b/common/client-core/src/cli_helpers/types.rs @@ -0,0 +1,40 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use nym_crypto::asymmetric::identity; +use serde::{Deserialize, Serialize}; +use std::fmt::{Display, Formatter}; +use time::OffsetDateTime; +use url::Url; + +#[derive(Serialize, Deserialize)] +pub struct GatewayInfo { + pub registration: OffsetDateTime, + pub identity: identity::PublicKey, + pub active: bool, + + pub typ: String, + pub endpoint: Option, + pub wg_tun_address: Option, +} + +impl Display for GatewayInfo { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.active { + write!(f, "[ACTIVE] ")?; + } + write!( + f, + "{} gateway '{}' registered at: {}", + self.typ, self.identity, self.registration + )?; + if let Some(endpoint) = &self.endpoint { + write!(f, " endpoint: {endpoint}")?; + } + + if let Some(wg_tun_address) = &self.wg_tun_address { + write!(f, " wg tun address: {wg_tun_address}")?; + } + Ok(()) + } +} diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index d2d391f102..67382c468e 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -198,6 +198,9 @@ pub enum ClientCoreError { source: url::ParseError, }, + #[error("this client (id: '{client_id}') has already been initialised before. If you want to add additional gateway, use `add-gateway` command")] + AlreadyInitialised { client_id: String }, + #[error("this client has already registered with gateway {gateway_id}")] AlreadyRegistered { gateway_id: String }, } diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs new file mode 100644 index 0000000000..fcef40052d --- /dev/null +++ b/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs @@ -0,0 +1,13 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::IdentityKey; + +pub struct NymNode { + /// Network address of this mixnode, for example 1.1.1.1 or foo.nymnode.com + /// that will used for discovering other capabilities of this node. + pub host: String, + + /// Base58-encoded ed25519 EdDSA public key. + pub identity_key: IdentityKey, +} diff --git a/service-providers/ip-packet-router/src/cli/add_gateway.rs b/service-providers/ip-packet-router/src/cli/add_gateway.rs new file mode 100644 index 0000000000..3050233c87 --- /dev/null +++ b/service-providers/ip-packet-router/src/cli/add_gateway.rs @@ -0,0 +1,32 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliIpPacketRouterClient; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; +use nym_ip_packet_router::error::IpPacketRouterError; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/service-providers/ip-packet-router/src/cli/mod.rs b/service-providers/ip-packet-router/src/cli/mod.rs index 912c13cc7a..3de91de6be 100644 --- a/service-providers/ip-packet-router/src/cli/mod.rs +++ b/service-providers/ip-packet-router/src/cli/mod.rs @@ -9,6 +9,7 @@ use nym_ip_packet_router::config::{BaseClientConfig, Config}; use nym_ip_packet_router::error::IpPacketRouterError; use std::sync::OnceLock; +mod add_gateway; mod build_info; mod import_credential; mod init; @@ -69,6 +70,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Add new gateway to this client + AddGateway(add_gateway::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! SwitchGateway(switch_gateway::Args), @@ -126,6 +130,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> { Commands::Run(m) => run::execute(&m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::AddGateway(args) => add_gateway::execute(args).await?, Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::Sign(m) => sign::execute(&m).await?, Commands::BuildInfo(m) => build_info::execute(m), diff --git a/service-providers/network-requester/src/cli/add_gateway.rs b/service-providers/network-requester/src/cli/add_gateway.rs new file mode 100644 index 0000000000..ec4703045b --- /dev/null +++ b/service-providers/network-requester/src/cli/add_gateway.rs @@ -0,0 +1,32 @@ +// Copyright 2024 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use crate::cli::CliNetworkRequesterClient; +use crate::error::NetworkRequesterError; +use nym_bin_common::output_format::OutputFormat; +use nym_client_core::cli_helpers::client_list_gateways::{ + list_gateways, CommonClientListGatewaysArgs, +}; + +#[derive(clap::Args)] +pub(crate) struct Args { + #[command(flatten)] + common_args: CommonClientListGatewaysArgs, + + #[arg(short, long, default_value_t = OutputFormat::default())] + output: OutputFormat, +} + +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientListGatewaysArgs { + &self.common_args + } +} + +pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { + let output = args.output; + let res = list_gateways::(args).await?; + + println!("{}", output.format(&res)); + Ok(()) +} diff --git a/service-providers/network-requester/src/cli/mod.rs b/service-providers/network-requester/src/cli/mod.rs index 7ba2462c61..290c4b8980 100644 --- a/service-providers/network-requester/src/cli/mod.rs +++ b/service-providers/network-requester/src/cli/mod.rs @@ -16,6 +16,7 @@ use nym_client_core::cli_helpers::CliClient; use nym_config::OptionalSet; use std::sync::OnceLock; +mod add_gateway; mod build_info; mod import_credential; mod init; @@ -79,6 +80,9 @@ pub(crate) enum Commands { /// List all registered with gateways ListGateways(list_gateways::Args), + /// Add new gateway to this client + AddGateway(add_gateway::Args), + /// Change the currently active gateway. Note that you must have already registered with the new gateway! SwitchGateway(switch_gateway::Args), @@ -178,6 +182,7 @@ pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> { Commands::Sign(m) => sign::execute(&m).await?, Commands::ImportCredential(m) => import_credential::execute(m).await?, Commands::ListGateways(args) => list_gateways::execute(args).await?, + Commands::AddGateway(args) => add_gateway::execute(args).await?, Commands::SwitchGateway(args) => switch_gateway::execute(args).await?, Commands::BuildInfo(m) => build_info::execute(m), Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name), From f012a1a069462e387b6f9109b7f6bead39f92f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 27 Mar 2024 16:07:07 +0000 Subject: [PATCH 50/56] fixed add gateway commands for nr and ipr --- .../ip-packet-router/src/cli/add_gateway.rs | 12 +++++------- .../network-requester/src/cli/add_gateway.rs | 13 ++++++------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/service-providers/ip-packet-router/src/cli/add_gateway.rs b/service-providers/ip-packet-router/src/cli/add_gateway.rs index 3050233c87..ebfffcf149 100644 --- a/service-providers/ip-packet-router/src/cli/add_gateway.rs +++ b/service-providers/ip-packet-router/src/cli/add_gateway.rs @@ -3,29 +3,27 @@ use crate::cli::CliIpPacketRouterClient; use nym_bin_common::output_format::OutputFormat; -use nym_client_core::cli_helpers::client_list_gateways::{ - list_gateways, CommonClientListGatewaysArgs, -}; +use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs}; use nym_ip_packet_router::error::IpPacketRouterError; #[derive(clap::Args)] pub(crate) struct Args { #[command(flatten)] - common_args: CommonClientListGatewaysArgs, + common_args: CommonClientAddGatewayArgs, #[arg(short, long, default_value_t = OutputFormat::default())] output: OutputFormat, } -impl AsRef for Args { - fn as_ref(&self) -> &CommonClientListGatewaysArgs { +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientAddGatewayArgs { &self.common_args } } pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> { let output = args.output; - let res = list_gateways::(args).await?; + let res = add_gateway::(args).await?; println!("{}", output.format(&res)); Ok(()) diff --git a/service-providers/network-requester/src/cli/add_gateway.rs b/service-providers/network-requester/src/cli/add_gateway.rs index ec4703045b..8b4b102b34 100644 --- a/service-providers/network-requester/src/cli/add_gateway.rs +++ b/service-providers/network-requester/src/cli/add_gateway.rs @@ -4,28 +4,27 @@ use crate::cli::CliNetworkRequesterClient; use crate::error::NetworkRequesterError; use nym_bin_common::output_format::OutputFormat; -use nym_client_core::cli_helpers::client_list_gateways::{ - list_gateways, CommonClientListGatewaysArgs, -}; +use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs}; + #[derive(clap::Args)] pub(crate) struct Args { #[command(flatten)] - common_args: CommonClientListGatewaysArgs, + common_args: CommonClientAddGatewayArgs, #[arg(short, long, default_value_t = OutputFormat::default())] output: OutputFormat, } -impl AsRef for Args { - fn as_ref(&self) -> &CommonClientListGatewaysArgs { +impl AsRef for Args { + fn as_ref(&self) -> &CommonClientAddGatewayArgs { &self.common_args } } pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> { let output = args.output; - let res = list_gateways::(args).await?; + let res = add_gateway::(args).await?; println!("{}", output.format(&res)); Ok(()) From b869c309092922453fe5b1d195de222f8481e18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 27 Mar 2024 16:07:43 +0000 Subject: [PATCH 51/56] added extra alias --- common/client-core/src/cli_helpers/client_add_gateway.rs | 6 +++--- service-providers/network-requester/src/cli/add_gateway.rs | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/common/client-core/src/cli_helpers/client_add_gateway.rs b/common/client-core/src/cli_helpers/client_add_gateway.rs index afcb236ec7..ba37d20523 100644 --- a/common/client-core/src/cli_helpers/client_add_gateway.rs +++ b/common/client-core/src/cli_helpers/client_add_gateway.rs @@ -27,8 +27,8 @@ pub struct CommonClientAddGatewayArgs { /// Explicitly specify id of the gateway to register with. /// If unspecified, a random gateway will be chosen instead. - #[cfg_attr(feature = "cli", clap(long))] - pub gateway: Option, + #[cfg_attr(feature = "cli", clap(long, alias = "gateway"))] + pub gateway_id: Option, /// Specifies whether the client will attempt to enforce tls connection to the desired gateway. #[cfg_attr(feature = "cli", clap(long))] @@ -86,7 +86,7 @@ where } // Attempt to use a user-provided gateway, if possible - let user_chosen_gateway_id = common_args.gateway; + let user_chosen_gateway_id = common_args.gateway_id; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); let selection_spec = GatewaySelectionSpecification::new( diff --git a/service-providers/network-requester/src/cli/add_gateway.rs b/service-providers/network-requester/src/cli/add_gateway.rs index 8b4b102b34..e07f16f46d 100644 --- a/service-providers/network-requester/src/cli/add_gateway.rs +++ b/service-providers/network-requester/src/cli/add_gateway.rs @@ -6,7 +6,6 @@ use crate::error::NetworkRequesterError; use nym_bin_common::output_format::OutputFormat; use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs}; - #[derive(clap::Args)] pub(crate) struct Args { #[command(flatten)] From 8fa213502da054a7edc451ad2d0e4a017ae8be0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 28 Mar 2024 08:11:57 +0000 Subject: [PATCH 52/56] removed force register flag + improved error message on no gateways available --- Cargo.lock | 80 +++++++++---------- .../src/cli_helpers/client_add_gateway.rs | 30 +++---- .../src/cli_helpers/client_init.rs | 1 - common/client-core/src/error.rs | 3 + common/client-core/src/init/mod.rs | 7 +- common/client-core/src/init/types.rs | 6 +- common/wasm/client-core/src/helpers.rs | 1 - nym-connect/desktop/Cargo.lock | 30 +++---- .../desktop/src-tauri/src/config/mod.rs | 1 - sdk/lib/socks5-listener/src/lib.rs | 1 - sdk/rust/nym-sdk/src/mixnet/client.rs | 1 - 11 files changed, 70 insertions(+), 91 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c809facc92..ea89e7ec2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -389,16 +389,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "async-file-watcher" -version = "0.1.0" -dependencies = [ - "futures", - "log", - "notify", - "tokio", -] - [[package]] name = "async-io" version = "1.13.0" @@ -3301,20 +3291,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-api-client" -version = "0.1.0" -dependencies = [ - "async-trait", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tracing", - "url", - "wasmtimer", -] - [[package]] name = "http-body" version = "0.4.5" @@ -3943,17 +3919,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "ledger" -version = "0.1.0" -dependencies = [ - "bip32", - "k256", - "ledger-transport", - "ledger-transport-hid", - "thiserror", -] - [[package]] name = "ledger-apdu" version = "0.10.0" @@ -4596,9 +4561,9 @@ version = "1.3.0-rc.0" dependencies = [ "async-trait", "futures", - "http-api-client", "js-sys", "nym-bin-common", + "nym-http-api-client", "nym-ordered-buffer", "nym-service-providers-common", "nym-socks5-requests", @@ -5073,6 +5038,16 @@ dependencies = [ "ts-rs", ] +[[package]] +name = "nym-async-file-watcher" +version = "0.1.0" +dependencies = [ + "futures", + "log", + "notify", + "tokio", +] + [[package]] name = "nym-bandwidth-controller" version = "0.1.0" @@ -5729,6 +5704,20 @@ dependencies = [ "serde", ] +[[package]] +name = "nym-http-api-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", + "wasmtimer", +] + [[package]] name = "nym-id" version = "0.1.0" @@ -5819,6 +5808,17 @@ dependencies = [ "url", ] +[[package]] +name = "nym-ledger" +version = "0.1.0" +dependencies = [ + "bip32", + "k256", + "ledger-transport", + "ledger-transport-hid", + "thiserror", +] + [[package]] name = "nym-metrics" version = "0.1.0" @@ -5983,7 +5983,6 @@ version = "1.1.33" dependencies = [ "addr", "anyhow", - "async-file-watcher", "async-trait", "bs58 0.5.0", "clap 4.4.7", @@ -5992,6 +5991,7 @@ dependencies = [ "humantime-serde", "ipnetwork 0.20.0", "log", + "nym-async-file-watcher", "nym-bin-common", "nym-client-core", "nym-client-websocket-requests", @@ -6086,10 +6086,10 @@ version = "0.1.0" dependencies = [ "async-trait", "base64 0.21.4", - "http-api-client", "nym-bin-common", "nym-crypto", "nym-exit-policy", + "nym-http-api-client", "nym-wireguard-types", "schemars", "serde", @@ -6667,7 +6667,6 @@ dependencies = [ "eyre", "flate2", "futures", - "http-api-client", "itertools 0.10.5", "log", "nym-api-requests", @@ -6678,6 +6677,7 @@ dependencies = [ "nym-contracts-common", "nym-ephemera-common", "nym-group-contract-common", + "nym-http-api-client", "nym-mixnet-contract-common", "nym-multisig-contract-common", "nym-name-service-common", @@ -6803,7 +6803,6 @@ name = "nymvisor" version = "0.1.0" dependencies = [ "anyhow", - "async-file-watcher", "bytes", "clap 4.4.7", "dotenvy", @@ -6813,6 +6812,7 @@ dependencies = [ "humantime 2.1.0", "humantime-serde", "nix 0.27.1", + "nym-async-file-watcher", "nym-bin-common", "nym-config", "nym-task", diff --git a/common/client-core/src/cli_helpers/client_add_gateway.rs b/common/client-core/src/cli_helpers/client_add_gateway.rs index ba37d20523..f28cbabd59 100644 --- a/common/client-core/src/cli_helpers/client_add_gateway.rs +++ b/common/client-core/src/cli_helpers/client_add_gateway.rs @@ -39,11 +39,6 @@ pub struct CommonClientAddGatewayArgs { #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))] pub latency_based_selection: bool, - /// Force register gateway. WARNING: this will overwrite any existing keys for the given id, - /// potentially causing loss of access. - #[cfg_attr(feature = "cli", clap(long))] - pub force_register_gateway: bool, - /// Specify whether this new gateway should be set as the active one #[cfg_attr(feature = "cli", clap(long, default_value_t = true))] pub set_active: bool, @@ -80,11 +75,6 @@ where let key_store = OnDiskKeys::new(paths.keys.clone()); let details_store = setup_fs_gateways_storage(&paths.gateway_registrations).await?; - let user_wants_force_register = common_args.force_register_gateway; - if user_wants_force_register { - eprintln!("Instructed to force registering gateway. This might overwrite keys!"); - } - // Attempt to use a user-provided gateway, if possible let user_chosen_gateway_id = common_args.gateway_id; log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}"); @@ -101,7 +91,7 @@ where // if user provided gateway id (and we can't overwrite data), make sure we're not trying to register // with a known gateway if let Some(user_chosen) = user_chosen_gateway_id { - if !common_args.force_register_gateway && registered_gateways.contains(&user_chosen) { + if registered_gateways.contains(&user_chosen) { return Err(ClientCoreError::AlreadyRegistered { gateway_id: user_chosen.to_base58_string(), } @@ -126,20 +116,18 @@ where // since we're registering with a brand new gateway, // make sure the list of available gateways doesn't overlap the list of known gateways - let available_gateways = if common_args.force_register_gateway { - // if we're force registering, all bets are off - available_gateways - } else { - available_gateways - .into_iter() - .filter(|g| !registered_gateways.contains(g.identity())) - .collect() - }; + let available_gateways = available_gateways + .into_iter() + .filter(|g| !registered_gateways.contains(g.identity())) + .collect::>(); + + if available_gateways.is_empty() { + return Err(ClientCoreError::NoNewGatewaysAvailable.into()) + } let gateway_setup = GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: common_args.force_register_gateway, wg_tun_address: None, }; diff --git a/common/client-core/src/cli_helpers/client_init.rs b/common/client-core/src/cli_helpers/client_init.rs index f765117d35..019416fb2d 100644 --- a/common/client-core/src/cli_helpers/client_init.rs +++ b/common/client-core/src/cli_helpers/client_init.rs @@ -169,7 +169,6 @@ where let gateway_setup = GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: false, wg_tun_address: None, }; diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index 67382c468e..56b95c2a43 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -38,6 +38,9 @@ pub enum ClientCoreError { #[error("no gateways on network")] NoGatewaysOnNetwork, + + #[error("there are no more new gateways on the network - it seems this client has already registered with all nodes it could have")] + NoNewGatewaysAvailable, #[error("list of nym apis is empty")] ListOfNymApisIsEmpty, diff --git a/common/client-core/src/init/mod.rs b/common/client-core/src/init/mod.rs index 388902045f..a45c87da6a 100644 --- a/common/client-core/src/init/mod.rs +++ b/common/client-core/src/init/mod.rs @@ -50,7 +50,6 @@ where async fn setup_new_gateway( key_store: &K, details_store: &D, - overwrite_data: bool, selection_specification: GatewaySelectionSpecification, available_gateways: Vec, wg_tun_ip_address: Option, @@ -94,8 +93,8 @@ where // check if we already have details associated with this particular gateway // and if so, see if we can overwrite it let selected_id = selected_gateway.gateway_id().to_base58_string(); - if has_gateway_details(details_store, &selected_id).await? && !overwrite_data { - return Err(ClientCoreError::ForbiddenGatewayKeyOverwrite { + if has_gateway_details(details_store, &selected_id).await? { + return Err(ClientCoreError::AlreadyRegistered { gateway_id: selected_id, }); } @@ -208,14 +207,12 @@ where GatewaySetup::New { specification, available_gateways, - overwrite_data, wg_tun_address, } => { log::trace!("GatewaySetup::New with spec: {specification:?}"); setup_new_gateway( key_store, details_store, - overwrite_data, specification, available_gateways, wg_tun_address, diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index f8f5d93fdb..b9c21b128a 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -244,10 +244,7 @@ pub enum GatewaySetup { // TODO: seems to be a bit inefficient to pass them by value available_gateways: Vec, - - /// Specifies whether old data should be overwritten whilst setting up new gateway client. - overwrite_data: bool, - + /// Implicitly specify whether the chosen gateway must use wireguard mode by setting the tun address. /// /// Currently this is imperfect solution as I'd imagine this address could vary from gateway to gateway @@ -287,7 +284,6 @@ impl GatewaySetup { additional_data: None, }, available_gateways: vec![], - overwrite_data: false, wg_tun_address: None, } } diff --git a/common/wasm/client-core/src/helpers.rs b/common/wasm/client-core/src/helpers.rs index a64341907c..80c9e90135 100644 --- a/common/wasm/client-core/src/helpers.rs +++ b/common/wasm/client-core/src/helpers.rs @@ -106,7 +106,6 @@ pub async fn setup_gateway_wasm( GatewaySetup::New { specification: selection_spec, available_gateways: gateways.to_vec(), - overwrite_data: false, wg_tun_address: None, } }; diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 3f3c7fd428..11e7b040c7 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -2844,20 +2844,6 @@ dependencies = [ "itoa 1.0.9", ] -[[package]] -name = "http-api-client" -version = "0.1.0" -dependencies = [ - "async-trait", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tracing", - "url", - "wasmtimer", -] - [[package]] name = "http-body" version = "0.4.5" @@ -4211,6 +4197,20 @@ dependencies = [ "serde", ] +[[package]] +name = "nym-http-api-client" +version = "0.1.0" +dependencies = [ + "async-trait", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tracing", + "url", + "wasmtimer", +] + [[package]] name = "nym-id" version = "0.1.0" @@ -4636,7 +4636,6 @@ dependencies = [ "eyre", "flate2", "futures", - "http-api-client", "itertools", "log", "nym-api-requests", @@ -4647,6 +4646,7 @@ dependencies = [ "nym-contracts-common", "nym-ephemera-common", "nym-group-contract-common", + "nym-http-api-client", "nym-mixnet-contract-common", "nym-multisig-contract-common", "nym-name-service-common", diff --git a/nym-connect/desktop/src-tauri/src/config/mod.rs b/nym-connect/desktop/src-tauri/src/config/mod.rs index 83c72dde79..79b70f814b 100644 --- a/nym-connect/desktop/src-tauri/src/config/mod.rs +++ b/nym-connect/desktop/src-tauri/src/config/mod.rs @@ -220,7 +220,6 @@ pub async fn init_socks5_config(provider_address: String, chosen_gateway_id: Str GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: true, wg_tun_address: None, } } else { diff --git a/sdk/lib/socks5-listener/src/lib.rs b/sdk/lib/socks5-listener/src/lib.rs index a4059a14d8..a0127d713c 100644 --- a/sdk/lib/socks5-listener/src/lib.rs +++ b/sdk/lib/socks5-listener/src/lib.rs @@ -276,7 +276,6 @@ where must_use_tls: false, }, available_gateways: current_gateways(&mut rng, &nym_apis).await?, - overwrite_data: false, wg_tun_address: None, }); diff --git a/sdk/rust/nym-sdk/src/mixnet/client.rs b/sdk/rust/nym-sdk/src/mixnet/client.rs index b59b7d20bb..ec438e40ef 100644 --- a/sdk/rust/nym-sdk/src/mixnet/client.rs +++ b/sdk/rust/nym-sdk/src/mixnet/client.rs @@ -434,7 +434,6 @@ where Ok(GatewaySetup::New { specification: selection_spec, available_gateways, - overwrite_data: !self.config.key_mode.is_keep(), wg_tun_address: self.wireguard_tun_address(), }) } From 4c43935862804fc52b264a27ae2856dbbaf7d41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 28 Mar 2024 08:49:30 +0000 Subject: [PATCH 53/56] change NR+IPR return types --- Cargo.lock | 1 + service-providers/ip-packet-router/Cargo.toml | 1 + service-providers/ip-packet-router/src/main.rs | 5 +++-- service-providers/network-requester/Cargo.toml | 2 +- service-providers/network-requester/src/main.rs | 6 ++++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea89e7ec2a..61a6d6120e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5772,6 +5772,7 @@ dependencies = [ name = "nym-ip-packet-router" version = "0.1.0" dependencies = [ + "anyhow", "bincode", "bs58 0.5.0", "bytes", diff --git a/service-providers/ip-packet-router/Cargo.toml b/service-providers/ip-packet-router/Cargo.toml index 3029a66a61..f36c7b7ed9 100644 --- a/service-providers/ip-packet-router/Cargo.toml +++ b/service-providers/ip-packet-router/Cargo.toml @@ -9,6 +9,7 @@ edition.workspace = true license.workspace = true [dependencies] +anyhow.workspace = true bincode = "1.3.3" bs58 = { workspace = true } bytes = "1.5.0" diff --git a/service-providers/ip-packet-router/src/main.rs b/service-providers/ip-packet-router/src/main.rs index 0412ea62a9..c8f9fd0e1b 100644 --- a/service-providers/ip-packet-router/src/main.rs +++ b/service-providers/ip-packet-router/src/main.rs @@ -3,7 +3,7 @@ mod cli; #[cfg(target_os = "linux")] #[tokio::main] -async fn main() -> Result<(), nym_ip_packet_router::error::IpPacketRouterError> { +async fn main() -> anyhow::Result<()> { use clap::Parser; let args = cli::Cli::parse(); @@ -14,7 +14,8 @@ async fn main() -> Result<(), nym_ip_packet_router::error::IpPacketRouterError> nym_bin_common::logging::maybe_print_banner(clap::crate_name!(), clap::crate_version!()); } - cli::execute(args).await + cli::execute(args).await?; + Ok(()) } #[cfg(not(target_os = "linux"))] diff --git a/service-providers/network-requester/Cargo.toml b/service-providers/network-requester/Cargo.toml index e0aa58d955..63e82dbe58 100644 --- a/service-providers/network-requester/Cargo.toml +++ b/service-providers/network-requester/Cargo.toml @@ -16,6 +16,7 @@ name = "nym_network_requester" path = "src/lib.rs" [dependencies] +anyhow = { workspace = true } addr = "0.15.6" async-trait = { workspace = true } bs58 = { workspace = true } @@ -65,4 +66,3 @@ nym-id = { path = "../../common/nym-id" } [dev-dependencies] tempfile = "3.5.0" -anyhow = { workspace = true } diff --git a/service-providers/network-requester/src/main.rs b/service-providers/network-requester/src/main.rs index 391fe38242..00d62f083b 100644 --- a/service-providers/network-requester/src/main.rs +++ b/service-providers/network-requester/src/main.rs @@ -16,7 +16,7 @@ mod socks5; mod statistics; #[tokio::main] -async fn main() -> Result<(), NetworkRequesterError> { +async fn main() -> anyhow::Result<()> { let args = cli::Cli::parse(); setup_env(args.config_env_file.as_ref()); @@ -25,5 +25,7 @@ async fn main() -> Result<(), NetworkRequesterError> { } setup_logging(); - cli::execute(args).await + cli::execute(args).await?; + + Ok(()) } From 0b46d6486967394369ccba066ed2213f44586090 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 28 Mar 2024 08:57:17 +0000 Subject: [PATCH 54/56] cargo fmt --- common/client-core/src/cli_helpers/client_add_gateway.rs | 2 +- common/client-core/src/error.rs | 2 +- common/client-core/src/init/types.rs | 2 +- service-providers/network-requester/src/main.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common/client-core/src/cli_helpers/client_add_gateway.rs b/common/client-core/src/cli_helpers/client_add_gateway.rs index f28cbabd59..148c947d8a 100644 --- a/common/client-core/src/cli_helpers/client_add_gateway.rs +++ b/common/client-core/src/cli_helpers/client_add_gateway.rs @@ -122,7 +122,7 @@ where .collect::>(); if available_gateways.is_empty() { - return Err(ClientCoreError::NoNewGatewaysAvailable.into()) + return Err(ClientCoreError::NoNewGatewaysAvailable.into()); } let gateway_setup = GatewaySetup::New { diff --git a/common/client-core/src/error.rs b/common/client-core/src/error.rs index 56b95c2a43..bdfecfda5e 100644 --- a/common/client-core/src/error.rs +++ b/common/client-core/src/error.rs @@ -38,7 +38,7 @@ pub enum ClientCoreError { #[error("no gateways on network")] NoGatewaysOnNetwork, - + #[error("there are no more new gateways on the network - it seems this client has already registered with all nodes it could have")] NoNewGatewaysAvailable, diff --git a/common/client-core/src/init/types.rs b/common/client-core/src/init/types.rs index b9c21b128a..74a6a72ab8 100644 --- a/common/client-core/src/init/types.rs +++ b/common/client-core/src/init/types.rs @@ -244,7 +244,7 @@ pub enum GatewaySetup { // TODO: seems to be a bit inefficient to pass them by value available_gateways: Vec, - + /// Implicitly specify whether the chosen gateway must use wireguard mode by setting the tun address. /// /// Currently this is imperfect solution as I'd imagine this address could vary from gateway to gateway diff --git a/service-providers/network-requester/src/main.rs b/service-providers/network-requester/src/main.rs index 00d62f083b..1ab71f0ddc 100644 --- a/service-providers/network-requester/src/main.rs +++ b/service-providers/network-requester/src/main.rs @@ -26,6 +26,6 @@ async fn main() -> anyhow::Result<()> { setup_logging(); cli::execute(args).await?; - + Ok(()) } From c585753d026dc9abefa11635a40815ee132bf3bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 28 Mar 2024 09:10:57 +0000 Subject: [PATCH 55/56] removing unused code --- .../mixnet-contract/src/nym_node.rs | 13 ------------- service-providers/network-requester/src/main.rs | 1 - 2 files changed, 14 deletions(-) delete mode 100644 common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs diff --git a/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs b/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs deleted file mode 100644 index fcef40052d..0000000000 --- a/common/cosmwasm-smart-contracts/mixnet-contract/src/nym_node.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2024 - Nym Technologies SA -// SPDX-License-Identifier: Apache-2.0 - -use crate::IdentityKey; - -pub struct NymNode { - /// Network address of this mixnode, for example 1.1.1.1 or foo.nymnode.com - /// that will used for discovering other capabilities of this node. - pub host: String, - - /// Base58-encoded ed25519 EdDSA public key. - pub identity_key: IdentityKey, -} diff --git a/service-providers/network-requester/src/main.rs b/service-providers/network-requester/src/main.rs index 1ab71f0ddc..edf687e167 100644 --- a/service-providers/network-requester/src/main.rs +++ b/service-providers/network-requester/src/main.rs @@ -2,7 +2,6 @@ // SPDX-License-Identifier: GPL-3.0-only use clap::{crate_name, crate_version, Parser}; -use error::NetworkRequesterError; use nym_bin_common::logging::{maybe_print_banner, setup_logging}; use nym_network_defaults::setup_env; From 91b790accc583c2254ed3863ef000561b7683388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 28 Mar 2024 09:30:27 +0000 Subject: [PATCH 56/56] fixed incorrect ArgGroup naming --- common/client-core/src/cli_helpers/client_add_gateway.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/client-core/src/cli_helpers/client_add_gateway.rs b/common/client-core/src/cli_helpers/client_add_gateway.rs index 148c947d8a..05c367f49a 100644 --- a/common/client-core/src/cli_helpers/client_add_gateway.rs +++ b/common/client-core/src/cli_helpers/client_add_gateway.rs @@ -36,7 +36,7 @@ pub struct CommonClientAddGatewayArgs { /// Specifies whether the new gateway should be determined based by latency as opposed to being chosen /// uniformly. - #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway"))] + #[cfg_attr(feature = "cli", clap(long, conflicts_with = "gateway_id"))] pub latency_based_selection: bool, /// Specify whether this new gateway should be set as the active one