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] 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"))]