From 86831a602104b255dc6f0e16233d917ea43dbf5b Mon Sep 17 00:00:00 2001 From: Manuthor Date: Tue, 15 Oct 2024 22:28:48 +0200 Subject: [PATCH 1/3] feat(findex): add basic REST client instanciation - without Findex Cloud --- .github/workflows/build.yml | 2 +- .github/workflows/ci.yml | 6 - .pre-commit-config.yaml | 8 +- crates/aesgcm/src/lib.rs | 6 +- crates/aesgcm/src/wasm_bindgen/mod.rs | 1 + crates/anonymization/Cargo.toml | 3 + crates/anonymization/src/core/number.rs | 2 +- crates/anonymization/src/ffi/tests.rs | 2 +- crates/anonymization/src/pyo3/py_number.rs | 2 +- crates/anonymization/src/wasm_bindgen/mod.rs | 4 +- crates/cloudproof/Cargo.toml | 2 +- crates/cover_crypt/src/ffi/hybrid_cc_aes.rs | 2 +- crates/cover_crypt/src/pyo3/py_abe_policy.rs | 2 +- crates/cover_crypt/src/wasm_bindgen/mod.rs | 1 + crates/ecies/src/ffi/ecies.rs | 2 +- crates/ecies/src/wasm_bindgen/mod.rs | 1 + crates/findex/Cargo.toml | 15 +- .../python/cloudproof_findex/__init__.pyi | 20 +- crates/findex/python/tests/findex_test.py | 24 +- crates/findex/src/db_interfaces/custom/mod.rs | 2 +- crates/findex/src/db_interfaces/error.rs | 24 +- crates/findex/src/db_interfaces/mod.rs | 3 +- crates/findex/src/db_interfaces/redis.rs | 32 +- .../src/db_interfaces/rest/callback_prefix.rs | 4 +- .../db_interfaces/rest/findex_cloud_stores.rs | 338 ++++++++++++++++++ crates/findex/src/db_interfaces/rest/mod.rs | 15 +- .../src/db_interfaces/rest/rest_stores.rs | 212 +++++++++++ .../findex/src/db_interfaces/rest/stores.rs | 227 ------------ crates/findex/src/db_interfaces/sqlite.rs | 4 +- crates/findex/src/db_interfaces/tests.rs | 7 +- crates/findex/src/instantiation/db_config.rs | 32 +- crates/findex/src/instantiation/findex.rs | 64 +++- crates/findex/src/interfaces/ffi/api.rs | 83 ++++- crates/findex/src/interfaces/python/api.rs | 37 +- crates/findex/src/interfaces/wasm/api.rs | 46 ++- crates/findex/src/lib.rs | 7 + crates/findex/src/ser_de/ffi_ser_de.rs | 20 +- crates/findex/src/ser_de/mod.rs | 2 +- crates/findex/src/ser_de/wasm_ser_de.rs | 1 + crates/fpe/src/core/alphabet.rs | 2 +- crates/fpe/src/core/integer.rs | 2 +- crates/fpe/src/wasm_bindgen/mod.rs | 1 + 42 files changed, 923 insertions(+), 347 deletions(-) create mode 100644 crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs create mode 100644 crates/findex/src/db_interfaces/rest/rest_stores.rs delete mode 100644 crates/findex/src/db_interfaces/rest/stores.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a52d4f3..a22ec8d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -9,7 +9,7 @@ on: jobs: cloudproof_rust: - uses: Cosmian/reusable_workflows/.github/workflows/cloudproof.yml@develop + uses: Cosmian/reusable_workflows/.github/workflows/cloudproof.yml@fix/cloudproof with: project-name: cloudproof_rust toolchain: stable diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2ef70883..4c1b895b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,12 +4,6 @@ name: CI checks on: push jobs: - cargo-nursery-base: - uses: Cosmian/reusable_workflows/.github/workflows/cargo-nursery-base.yml@develop - with: - toolchain: stable - exclusions: --exclude=cloudproof_findex - cargo-doc: uses: Cosmian/reusable_workflows/.github/workflows/cargo-doc.yml@develop with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 09dc6877..3bdc6981 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -122,13 +122,9 @@ repos: rev: v1.0.24 hooks: # - id: dprint-toml-fix + # - id: cargo-upgrade + # - id: cargo-update - id: stable-cargo-format - - id: cargo-upgrade - - id: cargo-update - - id: cargo-audit-deny-warnings - - id: cargo-outdated - - id: cargo-udeps - args: [--exclude=cloudproof_findex] - id: cargo-machete - id: docker-compose-up - id: cargo-tests-all diff --git a/crates/aesgcm/src/lib.rs b/crates/aesgcm/src/lib.rs index f9bc5240..138013d8 100644 --- a/crates/aesgcm/src/lib.rs +++ b/crates/aesgcm/src/lib.rs @@ -1,6 +1,6 @@ -/// The `cloudproof_rust` subcrate `aesgcm` brings the standard AES256 GCM -/// implementation which has been audited by the NCC Group, with no significant -/// findings. Refer to +//! The `cloudproof_rust` subcrate `aesgcm` brings the standard AES256 GCM +//! implementation which has been audited by the NCC Group, with no significant +//! findings. Refer to #[cfg(feature = "ffi")] pub mod ffi; diff --git a/crates/aesgcm/src/wasm_bindgen/mod.rs b/crates/aesgcm/src/wasm_bindgen/mod.rs index 8620af54..747f57bb 100644 --- a/crates/aesgcm/src/wasm_bindgen/mod.rs +++ b/crates/aesgcm/src/wasm_bindgen/mod.rs @@ -1,4 +1,5 @@ mod aesgcm; +#[allow(dead_code)] #[cfg(test)] mod tests; diff --git a/crates/anonymization/Cargo.toml b/crates/anonymization/Cargo.toml index 45ceb0e7..fb8d7962 100644 --- a/crates/anonymization/Cargo.toml +++ b/crates/anonymization/Cargo.toml @@ -21,6 +21,9 @@ wasm = ["js-sys", "wasm-bindgen"] [package.metadata.cargo-udeps.ignore] normal = ["js-sys", "wasm-bindgen"] +[package.metadata.cargo-machete] +ignored = ["tiny-keccak"] + [dependencies] argon2 = "0.5" base64 = { workspace = true } diff --git a/crates/anonymization/src/core/number.rs b/crates/anonymization/src/core/number.rs index 6a01c60a..b57887e0 100644 --- a/crates/anonymization/src/core/number.rs +++ b/crates/anonymization/src/core/number.rs @@ -94,7 +94,7 @@ impl DateAggregator { /// /// * `time_unit`: The unit of time to round the date to. #[must_use] - pub fn new(time_unit: TimeUnit) -> Self { + pub const fn new(time_unit: TimeUnit) -> Self { Self { time_unit } } diff --git a/crates/anonymization/src/ffi/tests.rs b/crates/anonymization/src/ffi/tests.rs index 1842130d..564dac16 100644 --- a/crates/anonymization/src/ffi/tests.rs +++ b/crates/anonymization/src/ffi/tests.rs @@ -1,2 +1,2 @@ #[test] -fn ffi_anonymization() {} +const fn ffi_anonymization() {} diff --git a/crates/anonymization/src/pyo3/py_number.rs b/crates/anonymization/src/pyo3/py_number.rs index 57f284fd..78aef83d 100644 --- a/crates/anonymization/src/pyo3/py_number.rs +++ b/crates/anonymization/src/pyo3/py_number.rs @@ -55,7 +55,7 @@ pub struct NumberScaler(NumberScalerRust); #[pymethods] impl NumberScaler { #[new] - pub fn new(mean: f64, std_dev: f64, scale: f64, translation: f64) -> Self { + pub const fn new(mean: f64, std_dev: f64, scale: f64, translation: f64) -> Self { Self(NumberScalerRust::new(mean, std_dev, scale, translation)) } diff --git a/crates/anonymization/src/wasm_bindgen/mod.rs b/crates/anonymization/src/wasm_bindgen/mod.rs index 599c63f0..9cb3ba2b 100644 --- a/crates/anonymization/src/wasm_bindgen/mod.rs +++ b/crates/anonymization/src/wasm_bindgen/mod.rs @@ -7,6 +7,8 @@ macro_rules! wasm_unwrap { mod hash; mod noise; mod number; +mod word; + +#[allow(dead_code)] #[cfg(test)] mod tests; -mod word; diff --git a/crates/cloudproof/Cargo.toml b/crates/cloudproof/Cargo.toml index 5a0a7ed9..d875c89a 100644 --- a/crates/cloudproof/Cargo.toml +++ b/crates/cloudproof/Cargo.toml @@ -22,6 +22,7 @@ doctest = false [features] findex-redis = ["cloudproof_findex/redis-interface"] findex-sqlite = ["cloudproof_findex/sqlite-interface"] +findex-rest = ["cloudproof_findex/rest-interface"] default = [ "cloudproof_aesgcm/default", "cloudproof_anonymization/default", @@ -59,4 +60,3 @@ cloudproof_ecies = { version = "0.1.4", optional = true } cloudproof_findex = { version = "6.0.2", optional = true } cloudproof_fpe = { version = "0.2.2", optional = true } ###### -cosmian_crypto_core = { workspace = true, features = ["default"] } diff --git a/crates/cover_crypt/src/ffi/hybrid_cc_aes.rs b/crates/cover_crypt/src/ffi/hybrid_cc_aes.rs index 7bd55e76..2a45e3e5 100644 --- a/crates/cover_crypt/src/ffi/hybrid_cc_aes.rs +++ b/crates/cover_crypt/src/ffi/hybrid_cc_aes.rs @@ -483,7 +483,7 @@ pub unsafe extern "C" fn h_decrypt_header( #[no_mangle] /// /// # Safety -pub unsafe extern "C" fn h_symmetric_encryption_overhead() -> i32 { +pub const unsafe extern "C" fn h_symmetric_encryption_overhead() -> i32 { (Aes256Gcm::NONCE_LENGTH + Aes256Gcm::MAC_LENGTH) as i32 } diff --git a/crates/cover_crypt/src/pyo3/py_abe_policy.rs b/crates/cover_crypt/src/pyo3/py_abe_policy.rs index 3425ef2d..61d371d6 100644 --- a/crates/cover_crypt/src/pyo3/py_abe_policy.rs +++ b/crates/cover_crypt/src/pyo3/py_abe_policy.rs @@ -148,7 +148,7 @@ impl PolicyAxis { /// /// Returns: /// bool - pub fn is_hierarchical(&self) -> bool { + pub const fn is_hierarchical(&self) -> bool { self.0.hierarchical } diff --git a/crates/cover_crypt/src/wasm_bindgen/mod.rs b/crates/cover_crypt/src/wasm_bindgen/mod.rs index 22ecadeb..9f52eccc 100644 --- a/crates/cover_crypt/src/wasm_bindgen/mod.rs +++ b/crates/cover_crypt/src/wasm_bindgen/mod.rs @@ -8,5 +8,6 @@ mod abe_policy; mod generate_cc_keys; mod hybrid_cc_aes; +#[allow(dead_code)] #[cfg(test)] mod tests; diff --git a/crates/ecies/src/ffi/ecies.rs b/crates/ecies/src/ffi/ecies.rs index 6b2c8090..491d2779 100644 --- a/crates/ecies/src/ffi/ecies.rs +++ b/crates/ecies/src/ffi/ecies.rs @@ -125,7 +125,7 @@ pub unsafe extern "C" fn h_ecies_salsa_seal_box_encrypt( } #[no_mangle] -pub unsafe extern "C" fn h_ecies_salsa_seal_box_get_encryption_overhead() -> u32 { +pub const unsafe extern "C" fn h_ecies_salsa_seal_box_get_encryption_overhead() -> u32 { EciesSalsaSealBox::ENCRYPTION_OVERHEAD as u32 } diff --git a/crates/ecies/src/wasm_bindgen/mod.rs b/crates/ecies/src/wasm_bindgen/mod.rs index ec7fd7f5..cd22dd84 100644 --- a/crates/ecies/src/wasm_bindgen/mod.rs +++ b/crates/ecies/src/wasm_bindgen/mod.rs @@ -1,4 +1,5 @@ mod ecies; +#[allow(dead_code)] #[cfg(test)] mod tests; diff --git a/crates/findex/Cargo.toml b/crates/findex/Cargo.toml index 99475fc9..c6f6f309 100644 --- a/crates/findex/Cargo.toml +++ b/crates/findex/Cargo.toml @@ -20,13 +20,14 @@ doctest = false [features] # Actual user features. -default = [] +default = ["rest-interface"] # Meta features implicitly activated. serialization = [] ffi = [ "redis-interface", + "findex-cloud", "rest-interface", "cosmian_ffi_utils", "lazy_static", @@ -37,6 +38,7 @@ ffi = [ python = [ "redis-interface", + "findex-cloud", "rest-interface", "sqlite-interface", "futures", @@ -45,6 +47,7 @@ python = [ ] wasm = [ + "findex-cloud", "rest-interface", "js-sys", "log", @@ -56,12 +59,8 @@ wasm = [ ] redis-interface = ["redis"] -rest-interface = [ - "base64", - "cosmian_crypto_core/ser", - "reqwest", - "serialization", -] +findex-cloud = ["base64", "cosmian_crypto_core/ser", "reqwest", "serialization"] +rest-interface = ["base64", "cosmian_crypto_core/ser", "reqwest", "serialization"] sqlite-interface = ["rusqlite"] [dependencies] @@ -71,7 +70,7 @@ async-trait = { workspace = true } base64 = { workspace = true, optional = true } cosmian_crypto_core = { workspace = true } cosmian_ffi_utils = { workspace = true, optional = true } -cosmian_findex = "6.0.0" +cosmian_findex = { git = "https://www.github.com/Cosmian/findex", branch = "fix/missing_some_structs_serialization" } futures = { version = "0.3.30", optional = true } js-sys = { workspace = true, optional = true } lazy_static = { version = "1.4.0", optional = true } diff --git a/crates/findex/python/cloudproof_findex/__init__.pyi b/crates/findex/python/cloudproof_findex/__init__.pyi index 09ac7f59..2e4461c3 100644 --- a/crates/findex/python/cloudproof_findex/__init__.pyi +++ b/crates/findex/python/cloudproof_findex/__init__.pyi @@ -189,7 +189,7 @@ class AuthorizationToken: class Findex: @staticmethod def new_with_sqlite_interface( - key: Key, label: str, entry_path: str, chain_path: Optional[str]=None + key: Key, label: str, entry_path: str, chain_path: Optional[str] = None ) -> Findex: """Instantiate a new Findex instance using an SQLite interface. @@ -198,7 +198,7 @@ class Findex: """ @staticmethod def new_with_redis_interface( - key: Key, label: str, entry_url: str, chain_url: Optional[str]=None + key: Key, label: str, entry_url: str, chain_url: Optional[str] = None ) -> Findex: """Instantiate a new Findex instance using a Redis interface. @@ -206,8 +206,18 @@ class Findex: Findex """ @staticmethod - def new_with_rest_interface(label: str, token: str, entry_url: str, - chain_url: Optional[str]=None) -> Findex: + def new_with_findex_cloud_interface( + label: str, token: str, entry_url: str, chain_url: Optional[str] = None + ) -> Findex: + """Instantiate a new Findex instance using a REST interface. + + Returns: + Findex + """ + @staticmethod + def new_with_rest_interface( + key: Key, label: str, entry_url: str, chain_url: Optional[str] = None + ) -> Findex: """Instantiate a new Findex instance using a REST interface. Returns: @@ -218,7 +228,7 @@ class Findex: key: Key, label: str, entry_callbacks: PythonCallbacks, - chain_callbacks: Optional[PythonCallbacks]=None, + chain_callbacks: Optional[PythonCallbacks] = None, ) -> Findex: """Instantiate a new Findex instance using a custom interface. diff --git a/crates/findex/python/tests/findex_test.py b/crates/findex/python/tests/findex_test.py index a9eedb3f..8a829680 100644 --- a/crates/findex/python/tests/findex_test.py +++ b/crates/findex/python/tests/findex_test.py @@ -119,7 +119,9 @@ def upsert(old_values: dict, new_values: dict): if old_value == current_value: table[uid] = new_value elif not current_value: - raise ValueError('The current value needs to be defined as long as the old value is defined ') + raise ValueError( + 'The current value needs to be defined as long as the old value is defined ' + ) else: res[uid] = current_value return res @@ -187,7 +189,7 @@ class TestFindex(unittest.TestCase): def setUp(self) -> None: # Create structures needed by Findex self.findex_key = Key.random() - self.label = "My label." + self.label = 'My label.' self.db = { 1: ['Martin', 'Sheperd'], @@ -238,11 +240,17 @@ def setUp(self) -> None: self.label, redis_url, ), - 'rest': Findex.new_with_rest_interface(self.label, - str(token), - rest_server_url), + 'findex-cloud': Findex.new_with_findex_cloud_interface( + self.label, str(token), rest_server_url + ), + 'rest': Findex.new_with_findex_cloud_interface( + self.label, str(token), rest_server_url + ), 'custom': Findex.new_with_custom_interface( - self.findex_key, self.label, in_memory_db_interface, in_memory_db_interface + self.findex_key, + self.label, + in_memory_db_interface, + in_memory_db_interface, ), } @@ -343,9 +351,9 @@ def test_compact(self) -> None: instance.add(indexed_values_and_keywords) # removing 2nd db line - new_label = "My renewed label" + new_label = 'My renewed label' - filtered_locations = { Location.from_int(2) } + filtered_locations = {Location.from_int(2)} def filter_obsolete_data(dataset: Set[Location]): res = set() diff --git a/crates/findex/src/db_interfaces/custom/mod.rs b/crates/findex/src/db_interfaces/custom/mod.rs index 3b290a71..eceeced2 100644 --- a/crates/findex/src/db_interfaces/custom/mod.rs +++ b/crates/findex/src/db_interfaces/custom/mod.rs @@ -14,7 +14,7 @@ macro_rules! impl_custom_backend { ($backend_type:ident, $callback_type:ident, $value_length:ident) => { impl $backend_type { #[must_use] - pub fn new(backend: $callback_type) -> Self { + pub const fn new(backend: $callback_type) -> Self { Self(backend) } } diff --git a/crates/findex/src/db_interfaces/error.rs b/crates/findex/src/db_interfaces/error.rs index 0a35f965..5f9c9156 100644 --- a/crates/findex/src/db_interfaces/error.rs +++ b/crates/findex/src/db_interfaces/error.rs @@ -16,7 +16,12 @@ use wasm_bindgen::JsCast; #[cfg(feature = "wasm")] use wasm_bindgen::JsValue; -#[cfg(any(feature = "rest-interface", feature = "wasm", feature = "ffi"))] +#[cfg(any( + feature = "findex-cloud", + feature = "rest-interface", + feature = "wasm", + feature = "ffi" +))] use crate::ser_de::SerializationError; #[derive(Debug)] @@ -30,11 +35,11 @@ pub enum DbInterfaceError { Ffi(String, ErrorCode), #[cfg(feature = "python")] Python(String), - #[cfg(feature = "rest-interface")] + #[cfg(feature = "findex-cloud")] MalformedToken(String), #[cfg(feature = "wasm")] Wasm(String), - #[cfg(feature = "rest-interface")] + #[cfg(feature = "findex-cloud")] MissingPermission(i32), Findex(FindexCoreError), CryptoCore(CryptoCoreError), @@ -55,13 +60,13 @@ impl Display for DbInterfaceError { Self::MissingCallback(err) => write!(f, "unknown callback: {err}"), #[cfg(feature = "ffi")] Self::Ffi(err, code) => write!(f, "{err}: {code}"), - #[cfg(feature = "rest-interface")] + #[cfg(feature = "findex-cloud")] Self::MalformedToken(err) => write!(f, "{err}"), #[cfg(feature = "python")] Self::Python(err) => write!(f, "{err}"), #[cfg(feature = "wasm")] Self::Wasm(err) => write!(f, "wasm callback error: {err}"), - #[cfg(feature = "rest-interface")] + #[cfg(feature = "findex-cloud")] Self::MissingPermission(err) => write!(f, "missing permission: {err}"), Self::CryptoCore(err) => write!(f, "crypto_core: {err}"), Self::Findex(err) => write!(f, "findex: {err}"), @@ -92,7 +97,12 @@ impl From for DbInterfaceError { } } -#[cfg(any(feature = "rest-interface", feature = "wasm", feature = "ffi"))] +#[cfg(any( + feature = "findex-cloud", + feature = "rest-interface", + feature = "wasm", + feature = "ffi" +))] impl From for DbInterfaceError { fn from(e: SerializationError) -> Self { Self::Serialization(e.to_string()) @@ -105,7 +115,7 @@ impl From for DbInterfaceError { } } -#[cfg(feature = "rest-interface")] +#[cfg(any(feature = "findex-cloud", feature = "rest-interface"))] impl From for DbInterfaceError { fn from(e: TryFromSliceError) -> Self { Self::SliceConversion(e) diff --git a/crates/findex/src/db_interfaces/mod.rs b/crates/findex/src/db_interfaces/mod.rs index 2d0d7abd..ba61e052 100644 --- a/crates/findex/src/db_interfaces/mod.rs +++ b/crates/findex/src/db_interfaces/mod.rs @@ -3,7 +3,7 @@ mod error; -#[cfg(feature = "rest-interface")] +#[cfg(any(feature = "findex-cloud", feature = "rest-interface"))] pub mod rest; #[cfg(any(feature = "wasm", feature = "python", feature = "ffi",))] @@ -21,6 +21,7 @@ pub mod sqlite; feature = "ffi", feature = "python", feature = "redis-interface", + feature = "findex-cloud", feature = "rest-interface", feature = "sqlite-interface", feature = "wasm", diff --git a/crates/findex/src/db_interfaces/redis.rs b/crates/findex/src/db_interfaces/redis.rs index 8d99989c..4a786d0d 100644 --- a/crates/findex/src/db_interfaces/redis.rs +++ b/crates/findex/src/db_interfaces/redis.rs @@ -15,16 +15,38 @@ use crate::db_interfaces::DbInterfaceError; /// The length of the prefix of the table name in bytes /// 0x00ee for the entry table /// 0x00ef for the chain table -const TABLE_PREFIX_LENGTH: usize = 2; +pub const TABLE_PREFIX_LENGTH: usize = 2; -#[derive(Copy, Clone)] -enum FindexTable { +#[repr(u8)] +#[derive(Copy, Clone, Debug)] +pub enum FindexTable { Entry = 0xee, Chain = 0xef, } +impl From for u8 { + fn from(table: FindexTable) -> Self { + table as Self + } +} + +impl TryFrom for FindexTable { + type Error = FindexCoreError; + + fn try_from(value: u8) -> Result { + match value { + 0xee => Ok(Self::Entry), + 0xef => Ok(Self::Chain), + _ => Err(FindexCoreError::Conversion(format!( + "{value} is not a valid table" + ))), + } + } +} + /// Generate a key for the entry table or chain table -fn build_key(table: FindexTable, uid: &[u8]) -> Vec { +#[must_use] +pub fn build_key(table: FindexTable, uid: &[u8]) -> Vec { [&[0x00, table as u8], uid].concat() } @@ -78,6 +100,7 @@ impl RedisEntryBackend { /// /// # Warning /// This is definitive + #[allow(dependency_on_unit_never_type_fallback)] pub async fn clear_indexes(&self) -> Result<(), DbInterfaceError> { redis::cmd("FLUSHDB") .query_async(&mut self.manager.clone()) @@ -234,6 +257,7 @@ impl RedisChainBackend { /// /// # Warning /// This is definitive + #[allow(dependency_on_unit_never_type_fallback)] pub async fn clear_indexes(&self) -> Result<(), DbInterfaceError> { redis::cmd("FLUSHDB") .query_async(&mut self.0.clone()) diff --git a/crates/findex/src/db_interfaces/rest/callback_prefix.rs b/crates/findex/src/db_interfaces/rest/callback_prefix.rs index d70c777e..6e75a187 100644 --- a/crates/findex/src/db_interfaces/rest/callback_prefix.rs +++ b/crates/findex/src/db_interfaces/rest/callback_prefix.rs @@ -15,9 +15,9 @@ pub enum CallbackPrefix { } impl CallbackPrefix { - #[cfg(feature = "rest-interface")] + #[cfg(any(feature = "findex-cloud", feature = "rest-interface"))] #[must_use] - pub fn get_uri(self) -> &'static str { + pub const fn get_uri(self) -> &'static str { match self { Self::FetchEntry => "fetch_entries", Self::FetchChain => "fetch_chains", diff --git a/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs b/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs new file mode 100644 index 00000000..05e6fc73 --- /dev/null +++ b/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs @@ -0,0 +1,338 @@ +#[cfg(not(feature = "wasm"))] +use std::time::SystemTime; +use std::{ops::Deref, str::FromStr}; + +use async_trait::async_trait; +use cosmian_crypto_core::bytes_ser_de::Serializable; +use cosmian_findex::{kmac, DbInterface, ENTRY_LENGTH, LINK_LENGTH}; +pub use cosmian_findex::{TokenToEncryptedValueMap, TokenWithEncryptedValueList, Tokens}; +#[cfg(feature = "wasm")] +use js_sys::Date; +use reqwest::Client; + +use super::{upsert_data::UpsertData, AuthorizationToken, CallbackPrefix}; +use crate::{ + db_interfaces::DbInterfaceError, + ser_de::ffi_ser_de::{ + deserialize_edx_lines, deserialize_token_set, serialize_edx_lines, serialize_token_set, + }, +}; + +/// The number of seconds of validity of the requests to the `Findex Cloud` +/// server. After this time, the request cannot be accepted by the backend. This +/// is done to prevent replay attacks. +pub const REQUEST_SIGNATURE_TIMEOUT_AS_SECS: u64 = 60; + +/// Callback signature length. +pub const SIGNATURE_LENGTH: usize = 32; + +/// Parameters needed to instantiate a REST backend. +#[derive(Debug, PartialEq, Eq)] +pub struct FindexCloudParameters { + token: AuthorizationToken, + url: String, +} + +impl FindexCloudParameters { + #[must_use] + pub const fn new(token: AuthorizationToken, url: String) -> Self { + Self { token, url } + } + + pub fn from(token: &str, url: String) -> Result { + let token = AuthorizationToken::from_str(token)?; + Ok(Self { token, url }) + } +} + +#[derive(Debug)] +pub struct FindexCloudChainBackend(FindexCloudParameters); + +impl Deref for FindexCloudChainBackend { + type Target = FindexCloudParameters; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl FindexCloudChainBackend { + #[must_use] + pub const fn new(parameters: FindexCloudParameters) -> Self { + Self(parameters) + } + + /// Post the given `body` signed with the given `callback` key. + async fn post( + &self, + callback: CallbackPrefix, + bytes: &[u8], + ) -> Result, DbInterfaceError> { + let key = { + self.token + .get_key(&self.token.index_id, callback) + .ok_or_else(|| DbInterfaceError::MissingPermission(callback as i32))? + }; + + // SystemTime::now() panics in WASM + #[cfg(feature = "wasm")] + let current_timestamp = (Date::now() / 1000.0) as u64; // Date::now() returns milliseconds + + #[cfg(not(feature = "wasm"))] + let current_timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .map_err(|_| DbInterfaceError::Other("SystemTime is before UNIX_EPOCH".to_string()))? + .as_secs(); + + let expiration_timestamp_bytes = + (current_timestamp + REQUEST_SIGNATURE_TIMEOUT_AS_SECS).to_be_bytes(); + + let signature = kmac!(SIGNATURE_LENGTH, &key, &expiration_timestamp_bytes, bytes); + + let mut body = + Vec::with_capacity(signature.len() + expiration_timestamp_bytes.len() + bytes.len()); + body.extend(&signature); + body.extend(&expiration_timestamp_bytes); + body.extend(bytes); + + let url = { + format!( + "{}/indexes/{}/{}", + &self.url, + self.token.index_id, + callback.get_uri(), + ) + }; + + let response = Client::new() + .post(url) + .body(body) + .send() + .await + .map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to send the request to Findex Cloud: {err}" + )) + })?; + + if !response.status().is_success() { + return Err(DbInterfaceError::Other(format!( + "request to Findex Cloud server failed, status code is {}, response is '{}'", + response.status(), + response + .text() + .await + .unwrap_or_else(|_| "cannot parse response".to_owned()) + ))); + } + + response.bytes().await.map(|r| r.to_vec()).map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to read the returned bytes from Findex Cloud server: {err}" + )) + }) + } +} + +#[async_trait(?Send)] +impl DbInterface for FindexCloudChainBackend { + type Error = DbInterfaceError; + + async fn dump_tokens(&self) -> Result { + let bytes = self.post(CallbackPrefix::DumpTokens, &[]).await?; + deserialize_token_set(&bytes) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn fetch( + &self, + tokens: Tokens, + ) -> Result, Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let res = self + .post((CallbackPrefix::FetchEntry as u8 + 1).try_into()?, &bytes) + .await?; + deserialize_edx_lines(&res) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn upsert( + &self, + old_values: TokenToEncryptedValueMap, + new_values: TokenToEncryptedValueMap, + ) -> Result, Self::Error> { + let modifications = UpsertData::::new(old_values, new_values); + let bytes = modifications.serialize()?; + + let res = self.post(CallbackPrefix::Upsert, &bytes).await?; + + deserialize_edx_lines(&res) + .map(|v| v.into_iter().collect()) + .map_err(Self::Error::from) + } + + async fn insert( + &self, + values: TokenToEncryptedValueMap, + ) -> Result<(), Self::Error> { + let bytes = serialize_edx_lines(&values)?; + let _ = self.post(CallbackPrefix::Insert, &bytes).await?; + Ok(()) + } + + async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let _ = self + .post((CallbackPrefix::DeleteEntry as u8 + 1).try_into()?, &bytes) + .await?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct FindexCloudEntryBackend(FindexCloudParameters); + +impl Deref for FindexCloudEntryBackend { + type Target = FindexCloudParameters; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl FindexCloudEntryBackend { + #[must_use] + pub const fn new(parameters: FindexCloudParameters) -> Self { + Self(parameters) + } + + /// Post the given `body` signed with the given `callback` key. + async fn post( + &self, + callback: CallbackPrefix, + bytes: &[u8], + ) -> Result, DbInterfaceError> { + let key = { + self.token + .get_key(&self.token.index_id, callback) + .ok_or_else(|| DbInterfaceError::MissingPermission(callback as i32))? + }; + + // SystemTime::now() panics in WASM + #[cfg(feature = "wasm")] + let current_timestamp = (Date::now() / 1000.0) as u64; // Date::now() returns milliseconds + + #[cfg(not(feature = "wasm"))] + let current_timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .map_err(|_| DbInterfaceError::Other("SystemTime is before UNIX_EPOCH".to_string()))? + .as_secs(); + + let expiration_timestamp_bytes = + (current_timestamp + REQUEST_SIGNATURE_TIMEOUT_AS_SECS).to_be_bytes(); + + let signature = kmac!(SIGNATURE_LENGTH, &key, &expiration_timestamp_bytes, bytes); + + let mut body = + Vec::with_capacity(signature.len() + expiration_timestamp_bytes.len() + bytes.len()); + body.extend(&signature); + body.extend(&expiration_timestamp_bytes); + body.extend(bytes); + + let url = { + format!( + "{}/indexes/{}/{}", + &self.url, + self.token.index_id, + callback.get_uri(), + ) + }; + + let response = Client::new() + .post(url) + .body(body) + .send() + .await + .map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to send the request to Findex Cloud: {err}" + )) + })?; + + if !response.status().is_success() { + return Err(DbInterfaceError::Other(format!( + "request to Findex Cloud server failed, status code is {}, response is '{}'", + response.status(), + response + .text() + .await + .unwrap_or_else(|_| "cannot parse response".to_owned()) + ))); + } + + response.bytes().await.map(|r| r.to_vec()).map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to read the returned bytes from Findex Cloud server: {err}" + )) + }) + } +} + +#[async_trait(?Send)] +impl DbInterface for FindexCloudEntryBackend { + type Error = DbInterfaceError; + + async fn dump_tokens(&self) -> Result { + let bytes = self.post(CallbackPrefix::DumpTokens, &[]).await?; + deserialize_token_set(&bytes) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn fetch( + &self, + tokens: Tokens, + ) -> Result, Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let res = self + .post((CallbackPrefix::FetchEntry as u8).try_into()?, &bytes) + .await?; + deserialize_edx_lines(&res) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn upsert( + &self, + old_values: TokenToEncryptedValueMap, + new_values: TokenToEncryptedValueMap, + ) -> Result, Self::Error> { + let modifications = UpsertData::::new(old_values, new_values); + let bytes = modifications.serialize()?; + + let res = self.post(CallbackPrefix::Upsert, &bytes).await?; + + deserialize_edx_lines(&res) + .map(|v| v.into_iter().collect()) + .map_err(Self::Error::from) + } + + async fn insert( + &self, + values: TokenToEncryptedValueMap, + ) -> Result<(), Self::Error> { + let bytes = serialize_edx_lines(&values)?; + let _ = self.post(CallbackPrefix::Insert, &bytes).await?; + Ok(()) + } + + async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let _ = self + .post((CallbackPrefix::DeleteEntry as u8).try_into()?, &bytes) + .await?; + Ok(()) + } +} diff --git a/crates/findex/src/db_interfaces/rest/mod.rs b/crates/findex/src/db_interfaces/rest/mod.rs index a4957265..cae32ee2 100644 --- a/crates/findex/src/db_interfaces/rest/mod.rs +++ b/crates/findex/src/db_interfaces/rest/mod.rs @@ -1,8 +1,19 @@ +#[cfg(feature = "rest-interface")] mod callback_prefix; -mod stores; +#[cfg(feature = "findex-cloud")] +mod findex_cloud_stores; +mod rest_stores; +#[cfg(feature = "findex-cloud")] mod token; mod upsert_data; pub use callback_prefix::CallbackPrefix; -pub use stores::{RestChainBackend, RestEntryBackend, RestParameters}; +#[cfg(feature = "findex-cloud")] +pub use findex_cloud_stores::{ + FindexCloudChainBackend, FindexCloudEntryBackend, FindexCloudParameters, +}; +#[cfg(feature = "rest-interface")] +pub use rest_stores::{RestChainBackend, RestEntryBackend}; +#[cfg(feature = "findex-cloud")] pub use token::AuthorizationToken; +pub use upsert_data::UpsertData; diff --git a/crates/findex/src/db_interfaces/rest/rest_stores.rs b/crates/findex/src/db_interfaces/rest/rest_stores.rs new file mode 100644 index 00000000..04c06952 --- /dev/null +++ b/crates/findex/src/db_interfaces/rest/rest_stores.rs @@ -0,0 +1,212 @@ +use async_trait::async_trait; +use cosmian_crypto_core::bytes_ser_de::Serializable; +use cosmian_findex::{DbInterface, ENTRY_LENGTH, LINK_LENGTH}; +pub use cosmian_findex::{TokenToEncryptedValueMap, TokenWithEncryptedValueList, Tokens}; +use reqwest::Client; + +use super::{upsert_data::UpsertData, CallbackPrefix}; +use crate::{ + db_interfaces::DbInterfaceError, + ser_de::ffi_ser_de::{ + deserialize_edx_lines, deserialize_token_set, serialize_edx_lines, serialize_token_set, + }, +}; + +#[derive(Debug)] +pub struct RestEntryBackend { + pub client: Client, + pub url: String, +} + +impl RestEntryBackend { + async fn post( + &self, + callback: CallbackPrefix, + body: &[u8], + ) -> Result, DbInterfaceError> { + let url = { format!("{}/indexes/{}", &self.url, callback.get_uri(),) }; + let response = self + .client + .post(url) + .body(body.to_vec()) + .send() + .await + .map_err(|err| { + DbInterfaceError::Other(format!("Unable to send the request to Findex REST: {err}")) + })?; + + if !response.status().is_success() { + return Err(DbInterfaceError::Other(format!( + "request to Findex REST server failed, status code is {}, response is '{}'", + response.status(), + response + .text() + .await + .unwrap_or_else(|_| "cannot parse response".to_owned()) + ))); + } + + response.bytes().await.map(|r| r.to_vec()).map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to read the returned bytes from Findex REST server: {err}" + )) + }) + } +} + +#[async_trait(?Send)] +impl DbInterface for RestEntryBackend { + type Error = DbInterfaceError; + + async fn dump_tokens(&self) -> Result { + let bytes = self.post(CallbackPrefix::DumpTokens, &[]).await?; + deserialize_token_set(&bytes) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn fetch( + &self, + tokens: Tokens, + ) -> Result, Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let res = self + .post((CallbackPrefix::FetchEntry as u8).try_into()?, &bytes) + .await?; + deserialize_edx_lines(&res) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn upsert( + &self, + old_values: TokenToEncryptedValueMap, + new_values: TokenToEncryptedValueMap, + ) -> Result, Self::Error> { + let modifications = UpsertData::::new(old_values, new_values); + let bytes = modifications.serialize()?; + + let res = self.post(CallbackPrefix::Upsert, &bytes).await?; + + deserialize_edx_lines(&res) + .map(|v| v.into_iter().collect()) + .map_err(Self::Error::from) + } + + async fn insert( + &self, + values: TokenToEncryptedValueMap, + ) -> Result<(), Self::Error> { + let bytes = serialize_edx_lines(&values)?; + let _ = self.post(CallbackPrefix::Insert, &bytes).await?; + Ok(()) + } + + async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let _ = self + .post((CallbackPrefix::DeleteEntry as u8).try_into()?, &bytes) + .await?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct RestChainBackend { + pub client: Client, + pub url: String, +} + +impl RestChainBackend { + async fn post( + &self, + callback: CallbackPrefix, + body: &[u8], + ) -> Result, DbInterfaceError> { + let url = { format!("{}/indexes/{}", &self.url, callback.get_uri(),) }; + + let response = self + .client + .post(url) + .body(body.to_vec()) + .send() + .await + .map_err(|err| { + DbInterfaceError::Other(format!("Unable to send the request to Findex REST: {err}")) + })?; + + if !response.status().is_success() { + return Err(DbInterfaceError::Other(format!( + "request to Findex REST server failed, status code is {}, response is '{}'", + response.status(), + response + .text() + .await + .unwrap_or_else(|_| "cannot parse response".to_owned()) + ))); + } + + response.bytes().await.map(|r| r.to_vec()).map_err(|err| { + DbInterfaceError::Other(format!( + "Unable to read the returned bytes from Findex REST server: {err}" + )) + }) + } +} + +#[async_trait(?Send)] +impl DbInterface for RestChainBackend { + type Error = DbInterfaceError; + + async fn dump_tokens(&self) -> Result { + let bytes = self.post(CallbackPrefix::DumpTokens, &[]).await?; + deserialize_token_set(&bytes) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn fetch( + &self, + tokens: Tokens, + ) -> Result, Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let res = self + .post((CallbackPrefix::FetchEntry as u8 + 1).try_into()?, &bytes) + .await?; + deserialize_edx_lines(&res) + .map_err(Self::Error::from) + .map(Into::into) + } + + async fn upsert( + &self, + old_values: TokenToEncryptedValueMap, + new_values: TokenToEncryptedValueMap, + ) -> Result, Self::Error> { + let modifications = UpsertData::::new(old_values, new_values); + let bytes = modifications.serialize()?; + + let res = self.post(CallbackPrefix::Upsert, &bytes).await?; + + deserialize_edx_lines(&res) + .map(|v| v.into_iter().collect()) + .map_err(Self::Error::from) + } + + async fn insert( + &self, + values: TokenToEncryptedValueMap, + ) -> Result<(), Self::Error> { + let bytes = serialize_edx_lines(&values)?; + let _ = self.post(CallbackPrefix::Insert, &bytes).await?; + Ok(()) + } + + async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { + let bytes = serialize_token_set(&tokens)?; + let _ = self + .post((CallbackPrefix::DeleteEntry as u8 + 1).try_into()?, &bytes) + .await?; + Ok(()) + } +} diff --git a/crates/findex/src/db_interfaces/rest/stores.rs b/crates/findex/src/db_interfaces/rest/stores.rs deleted file mode 100644 index 24bafe31..00000000 --- a/crates/findex/src/db_interfaces/rest/stores.rs +++ /dev/null @@ -1,227 +0,0 @@ -#[cfg(not(feature = "wasm"))] -use std::time::SystemTime; -use std::{ops::Deref, str::FromStr}; - -use async_trait::async_trait; -use cosmian_crypto_core::bytes_ser_de::Serializable; -use cosmian_findex::{kmac, DbInterface, ENTRY_LENGTH, LINK_LENGTH}; -pub use cosmian_findex::{TokenToEncryptedValueMap, TokenWithEncryptedValueList, Tokens}; -#[cfg(feature = "wasm")] -use js_sys::Date; -use reqwest::Client; - -use super::{upsert_data::UpsertData, AuthorizationToken, CallbackPrefix}; -use crate::{ - db_interfaces::DbInterfaceError, - ser_de::ffi_ser_de::{ - deserialize_edx_lines, deserialize_token_set, serialize_edx_lines, serialize_token_set, - }, -}; - -/// The number of seconds of validity of the requests to the `FindexREST` -/// server. After this time, the request cannot be accepted by the backend. This -/// is done to prevent replay attacks. -pub const REQUEST_SIGNATURE_TIMEOUT_AS_SECS: u64 = 60; - -/// Callback signature length. -pub const SIGNATURE_LENGTH: usize = 32; - -macro_rules! impl_rest_backend { - ($type:ident, $value_length:ident, $name:literal, $table_bit:expr) => { - impl Deref for $type { - type Target = RestParameters; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl $type { - #[must_use] - pub fn new(parameters: RestParameters) -> Self { - Self(parameters) - } - - /// Post the given `body` signed with the given `callback` key. - async fn post( - &self, - callback: CallbackPrefix, - bytes: &[u8], - ) -> Result, DbInterfaceError> { - let key = { - self.token - .get_key(&self.token.index_id, callback) - .ok_or_else(|| DbInterfaceError::MissingPermission(callback as i32))? - }; - - // SystemTime::now() panics in WASM - #[cfg(feature = "wasm")] - let current_timestamp = (Date::now() / 1000.0) as u64; // Date::now() returns milliseconds - - #[cfg(not(feature = "wasm"))] - let current_timestamp = SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| { - DbInterfaceError::Other("SystemTime is before UNIX_EPOCH".to_string()) - })? - .as_secs(); - - let expiration_timestamp_bytes = - (current_timestamp + REQUEST_SIGNATURE_TIMEOUT_AS_SECS).to_be_bytes(); - - let signature = kmac!(SIGNATURE_LENGTH, &key, &expiration_timestamp_bytes, bytes); - - let mut body = Vec::with_capacity( - signature.len() + expiration_timestamp_bytes.len() + bytes.len(), - ); - body.extend(&signature); - body.extend(&expiration_timestamp_bytes); - body.extend(bytes); - - let url = { - format!( - "{}/indexes/{}/{}", - &self.url, - self.token.index_id, - callback.get_uri(), - ) - }; - - let response = Client::new() - .post(url) - .body(body) - .send() - .await - .map_err(|err| { - DbInterfaceError::Other(format!( - "Unable to send the request to FindexREST: {err}" - )) - })?; - - if !response.status().is_success() { - return Err(DbInterfaceError::Other(format!( - "request to FindexREST server failed, status code is {}, response is {}", - response.status(), - response - .text() - .await - .unwrap_or_else(|_| "cannot parse response".to_owned()) - ))); - } - - response.bytes().await.map(|r| r.to_vec()).map_err(|err| { - DbInterfaceError::Other(format!( - "Impossible to read the returned bytes from FindexREST server: {err}" - )) - }) - } - } - - #[async_trait(?Send)] - impl DbInterface<$value_length> for $type { - type Error = DbInterfaceError; - - async fn dump_tokens(&self) -> Result { - let bytes = self.post(CallbackPrefix::DumpTokens, &[]).await?; - deserialize_token_set(&bytes) - .map_err(Self::Error::from) - .map(Into::into) - } - - async fn fetch( - &self, - tokens: $crate::db_interfaces::rest::stores::Tokens, - ) -> Result< - $crate::db_interfaces::rest::stores::TokenWithEncryptedValueList<$value_length>, - Self::Error, - > { - let bytes = serialize_token_set(&tokens.into())?; - let res = self - .post( - (CallbackPrefix::FetchEntry as u8 + $table_bit).try_into()?, - &bytes, - ) - .await?; - deserialize_edx_lines(&res) - .map_err(Self::Error::from) - .map(Into::into) - } - - async fn upsert( - &self, - old_values: $crate::db_interfaces::rest::stores::TokenToEncryptedValueMap< - $value_length, - >, - new_values: $crate::db_interfaces::rest::stores::TokenToEncryptedValueMap< - $value_length, - >, - ) -> Result< - $crate::db_interfaces::rest::stores::TokenToEncryptedValueMap<$value_length>, - Self::Error, - > { - let modifications = UpsertData::<$value_length>::new(old_values, new_values); - let bytes = modifications.serialize()?; - - let res = self.post(CallbackPrefix::Upsert, &bytes).await?; - - deserialize_edx_lines(&res) - .map(|v| v.into_iter().collect()) - .map_err(Self::Error::from) - } - - async fn insert( - &self, - values: $crate::db_interfaces::rest::stores::TokenToEncryptedValueMap< - $value_length, - >, - ) -> Result<(), Self::Error> { - let bytes = serialize_edx_lines(&values.into())?; - let _ = self.post(CallbackPrefix::Insert, &bytes).await?; - Ok(()) - } - - async fn delete( - &self, - tokens: $crate::db_interfaces::rest::stores::Tokens, - ) -> Result<(), Self::Error> { - let bytes = serialize_token_set(&tokens.into())?; - let _ = self - .post( - (CallbackPrefix::DeleteEntry as u8 + $table_bit).try_into()?, - &bytes, - ) - .await?; - Ok(()) - } - } - }; -} - -/// Parameters needed to instantiate a REST backend. -#[derive(Debug, PartialEq, Eq)] -pub struct RestParameters { - token: AuthorizationToken, - url: String, -} - -impl RestParameters { - #[must_use] - pub fn new(token: AuthorizationToken, url: String) -> Self { - Self { token, url } - } - - pub fn from(token: &str, url: String) -> Result { - let token = AuthorizationToken::from_str(token)?; - Ok(Self { token, url }) - } -} - -#[derive(Debug)] -pub struct RestEntryBackend(RestParameters); - -impl_rest_backend!(RestEntryBackend, ENTRY_LENGTH, "entry_table", 0); - -#[derive(Debug)] -pub struct RestChainBackend(RestParameters); - -impl_rest_backend!(RestChainBackend, LINK_LENGTH, "entry_table", 1); diff --git a/crates/findex/src/db_interfaces/sqlite.rs b/crates/findex/src/db_interfaces/sqlite.rs index 03694bb6..f6b66a90 100644 --- a/crates/findex/src/db_interfaces/sqlite.rs +++ b/crates/findex/src/db_interfaces/sqlite.rs @@ -82,8 +82,8 @@ macro_rules! impl_sqlite_backend { )?; rows.map(|res| { - // TODO: this fix is needed since error from conversion to encrypted value is not - // easily convertible inside the `query_map`. + // TODO: this fix is needed since error from conversion to encrypted value is + // not easily convertible inside the `query_map`. // // Two paths to go forward: // - find a way to convert the error inside `query_map` diff --git a/crates/findex/src/db_interfaces/tests.rs b/crates/findex/src/db_interfaces/tests.rs index fe48a6b8..bb573ef8 100644 --- a/crates/findex/src/db_interfaces/tests.rs +++ b/crates/findex/src/db_interfaces/tests.rs @@ -81,8 +81,8 @@ fn get_users() -> Result, DbInterfaceError> { .map_err(|e| DbInterfaceError::Serialization(e.to_string())) } -/// Generate the key used in the tests. In case the test is a non-regression, the key from -/// `dataset` is used. Otherwise a new random key is generated. +/// Generate the key used in the tests. In case the test is a non-regression, +/// the key from `dataset` is used. Otherwise a new random key is generated. fn get_key(is_non_regression: bool) -> UserKey { if is_non_regression { let bytes = general_purpose::STANDARD @@ -194,7 +194,8 @@ async fn find_users(findex: &InstantiatedFindex, key: &UserKey, label: &Label) { /// 3. Asserts that compact operations can be run on the backend. /// 4. Asserts that the correctness of the search as defined in step 2. /// -/// The `.db` file produced by this test should be okay to use in the non-regression test. +/// The `.db` file produced by this test should be okay to use in the +/// non-regression test. pub async fn test_backend(config: Configuration) { let is_non_regression = false; diff --git a/crates/findex/src/instantiation/db_config.rs b/crates/findex/src/instantiation/db_config.rs index 7eb501a4..64c121c7 100644 --- a/crates/findex/src/instantiation/db_config.rs +++ b/crates/findex/src/instantiation/db_config.rs @@ -1,10 +1,12 @@ +use reqwest::Client; + #[cfg(feature = "ffi")] use crate::db_interfaces::custom::ffi::FfiCallbacks; #[cfg(feature = "python")] use crate::db_interfaces::custom::python::PythonCallbacks; #[cfg(feature = "wasm")] use crate::db_interfaces::custom::wasm::WasmCallbacks; -#[cfg(feature = "rest-interface")] +#[cfg(feature = "findex-cloud")] use crate::db_interfaces::rest::AuthorizationToken; /// Contains all parameters needed to instantiate the corresponding interfaces. @@ -13,23 +15,29 @@ use crate::db_interfaces::rest::AuthorizationToken; /// Entry Table while the second ones are used to instantiate the Chain Table. #[derive(Clone)] pub enum Configuration { - /// REST DB interface requires an authorization token and a server URL for the Entry and the - /// Chain tables. + /// Findex Cloud DB interface requires an authorization token and a server + /// URL for the Entry and the Chain tables. + #[cfg(feature = "findex-cloud")] + FindexCloud(AuthorizationToken, String, String), + + /// REST DB interface requires an authorization token and a server URL for + /// the Entry and the Chain tables. #[cfg(feature = "rest-interface")] - Rest(AuthorizationToken, String, String), + Rest(Client, String, String), - /// FFI DB interface requests FFI functions corresponding to the APIs used by the - /// Entry/Chain tables. + /// FFI DB interface requests FFI functions corresponding to the APIs used + /// by the Entry/Chain tables. #[cfg(feature = "ffi")] Ffi(FfiCallbacks, FfiCallbacks), - /// Python DB interface requests Python functions corresponding to the APIs used - /// by the Entry/Chain tables. + /// Python DB interface requests Python functions corresponding to the APIs + /// used by the Entry/Chain tables. #[cfg(feature = "python")] Python(PythonCallbacks, PythonCallbacks), - /// SQLite DB interface requests a valid [`Connection`](rusqlite::Connection) - /// pointing to valid Entry/Chain tables. + /// `SQLite` DB interface requests a valid + /// [`Connection`](rusqlite::Connection) pointing to valid Entry/Chain + /// tables. #[cfg(feature = "sqlite-interface")] Sqlite(String, String), @@ -37,8 +45,8 @@ pub enum Configuration { #[cfg(feature = "redis-interface")] Redis(String, String), - /// WASM DB interface requests WASM functions corresponding to the APIs used by - /// the Entry/Chain tables. + /// WASM DB interface requests WASM functions corresponding to the APIs used + /// by the Entry/Chain tables. #[cfg(feature = "wasm")] Wasm(WasmCallbacks, WasmCallbacks), } diff --git a/crates/findex/src/instantiation/findex.rs b/crates/findex/src/instantiation/findex.rs index fbf1cec2..54e5e00a 100644 --- a/crates/findex/src/instantiation/findex.rs +++ b/crates/findex/src/instantiation/findex.rs @@ -17,8 +17,12 @@ use crate::db_interfaces::custom::python::{PythonChainBackend, PythonEntryBacken use crate::db_interfaces::custom::wasm::{WasmChainBackend, WasmEntryBackend}; #[cfg(feature = "redis-interface")] use crate::db_interfaces::redis::{RedisChainBackend, RedisEntryBackend}; +#[cfg(feature = "findex-cloud")] +use crate::db_interfaces::rest::{ + FindexCloudChainBackend, FindexCloudEntryBackend, FindexCloudParameters, +}; #[cfg(feature = "rest-interface")] -use crate::db_interfaces::rest::{RestChainBackend, RestEntryBackend, RestParameters}; +use crate::db_interfaces::rest::{RestChainBackend, RestEntryBackend}; #[cfg(feature = "sqlite-interface")] use crate::db_interfaces::sqlite::{SqlChainBackend, SqlEntryBackend}; use crate::{db_interfaces::DbInterfaceError, Configuration}; @@ -70,6 +74,15 @@ pub enum InstantiatedFindex { >, ), + #[cfg(feature = "findex-cloud")] + FindexCloud( + Findex< + DbInterfaceError, + EntryTable, + ChainTable, + >, + ), + #[cfg(feature = "rest-interface")] Rest( Findex< @@ -96,13 +109,29 @@ impl InstantiatedFindex { ChainTable::setup(RedisChainBackend::connect(&chain_params).await?), )), + #[cfg(feature = "findex-cloud")] + Configuration::FindexCloud(token, entry_url, chain_url) => { + Self::FindexCloud(Findex::new( + EntryTable::setup(FindexCloudEntryBackend::new(FindexCloudParameters::new( + token.clone(), + entry_url, + ))), + ChainTable::setup(FindexCloudChainBackend::new(FindexCloudParameters::new( + token, chain_url, + ))), + )) + } + #[cfg(feature = "rest-interface")] - Configuration::Rest(token, entry_url, chain_url) => Self::Rest(Findex::new( - EntryTable::setup(RestEntryBackend::new(RestParameters::new( - token.clone(), - entry_url, - ))), - ChainTable::setup(RestChainBackend::new(RestParameters::new(token, chain_url))), + Configuration::Rest(client, entry_url, chain_url) => Self::Rest(Findex::new( + EntryTable::setup(RestEntryBackend { + client: client.clone(), + url: entry_url, + }), + ChainTable::setup(RestChainBackend { + client, + url: chain_url, + }), )), #[cfg(feature = "ffi")] @@ -141,6 +170,8 @@ impl InstantiatedFindex { Self::Python(findex) => findex.keygen(), #[cfg(feature = "wasm")] Self::Wasm(findex) => findex.keygen(), + #[cfg(feature = "findex-cloud")] + Self::FindexCloud(findex) => findex.keygen(), #[cfg(feature = "rest-interface")] Self::Rest(findex) => findex.keygen(), } @@ -158,6 +189,8 @@ impl InstantiatedFindex { interrupt: &Interrupt, ) -> Result> { match self { + #[cfg(feature = "findex-cloud")] + Self::FindexCloud(findex) => findex.search(key, label, keywords, interrupt).await, #[cfg(feature = "rest-interface")] Self::Rest(findex) => findex.search(key, label, keywords, interrupt).await, #[cfg(feature = "ffi")] @@ -191,6 +224,8 @@ impl InstantiatedFindex { Self::Python(findex) => findex.add(key, label, additions).await, #[cfg(feature = "wasm")] Self::Wasm(findex) => findex.add(key, label, additions).await, + #[cfg(feature = "findex-cloud")] + Self::FindexCloud(findex) => findex.add(key, label, additions).await, #[cfg(feature = "rest-interface")] Self::Rest(findex) => findex.add(key, label, additions).await, } @@ -214,6 +249,8 @@ impl InstantiatedFindex { Self::Python(findex) => findex.delete(key, label, deletions).await, #[cfg(feature = "wasm")] Self::Wasm(findex) => findex.delete(key, label, deletions).await, + #[cfg(feature = "findex-cloud")] + Self::FindexCloud(findex) => findex.delete(key, label, deletions).await, #[cfg(feature = "rest-interface")] Self::Rest(findex) => findex.delete(key, label, deletions).await, } @@ -298,6 +335,19 @@ impl InstantiatedFindex { ) .await } + #[cfg(feature = "findex-cloud")] + Self::FindexCloud(findex) => { + findex + .compact( + old_key, + new_key, + old_label, + new_label, + compacting_rate, + data_filter, + ) + .await + } #[cfg(feature = "rest-interface")] Self::Rest(findex) => { findex diff --git a/crates/findex/src/interfaces/ffi/api.rs b/crates/findex/src/interfaces/ffi/api.rs index a3bb6595..e42f9033 100644 --- a/crates/findex/src/interfaces/ffi/api.rs +++ b/crates/findex/src/interfaces/ffi/api.rs @@ -131,7 +131,7 @@ pub unsafe extern "C" fn h_instantiate_with_custom_interface( ErrorCode::Success.into() } -/// Instantiate a Findex using a REST backend. +/// Instantiate a Findex using a Findex Cloud backend. /// /// # Parameters /// @@ -144,7 +144,7 @@ pub unsafe extern "C" fn h_instantiate_with_custom_interface( /// Cannot be safe since using FFI. #[no_mangle] #[tracing::instrument(ret, skip_all)] -pub unsafe extern "C" fn h_instantiate_with_rest_interface( +pub unsafe extern "C" fn h_instantiate_with_findex_cloud_interface( findex_handle: *mut i32, label_ptr: *const i8, token_ptr: *const i8, @@ -177,7 +177,7 @@ pub unsafe extern "C" fn h_instantiate_with_rest_interface( } else { ffi_read_string!("REST server Chain Table URL", chain_url_ptr) }; - let config = Configuration::Rest(authorization_token.clone(), entry_url, chain_url); + let config = Configuration::FindexCloud(authorization_token.clone(), entry_url, chain_url); let rt = ffi_unwrap!( tokio::runtime::Runtime::new(), @@ -205,6 +205,81 @@ pub unsafe extern "C" fn h_instantiate_with_rest_interface( ErrorCode::Success.into() } +/// Instantiate a Findex using a REST backend. +/// +/// # Parameters +/// +/// - `label` : label used by Findex +/// - `token` : token containing authentication keys +/// - `url` : REST server URL +/// +/// # Safety +/// +/// Cannot be safe since using FFI. +#[no_mangle] +#[tracing::instrument(ret, skip_all)] +pub unsafe extern "C" fn h_instantiate_with_rest_interface( + findex_handle: *mut i32, + key_ptr: *const u8, + key_len: i32, + label_ptr: *const i8, + entry_url_ptr: *const i8, + chain_url_ptr: *const i8, +) -> i32 { + #[cfg(debug_assertions)] + log_init(); + + let key_bytes = ffi_read_bytes!("key", key_ptr, key_len); + let key = ffi_unwrap!( + SymmetricKey::try_from_slice(key_bytes), + "error deserializing findex key", + ErrorCode::Serialization + ); + trace!("Key successfully parsed"); + + let label_bytes = ffi_read_string!("label", label_ptr); + let label = Label::from(label_bytes.as_str()); + trace!("Label successfully parsed: label: {label}"); + + let entry_url = if entry_url_ptr.is_null() { + String::new() + } else { + ffi_read_string!("REST server Entry Table URL", entry_url_ptr) + }; + + let chain_url = if chain_url_ptr.is_null() { + String::new() + } else { + ffi_read_string!("REST server Chain Table URL", chain_url_ptr) + }; + let config = Configuration::Rest(reqwest::Client::new(), entry_url, chain_url); + + let rt = ffi_unwrap!( + tokio::runtime::Runtime::new(), + "error creating Tokio runtime", + ErrorCode::Tokio + ); + let findex = ffi_unwrap!( + rt.block_on(InstantiatedFindex::new(config)), + "error instantiating Findex with REST backend", + ErrorCode::Backend + ); + + let mut cache = FINDEX_INSTANCES + .lock() + .expect("Findex instance cache lock poisoned."); + let handle = ffi_unwrap!( + ::try_from(cache.len()), + "findex instance cache capacity overflow", + ErrorCode::Findex + ); + cache.insert(handle, (key, label, findex)); + + *findex_handle = handle; + + ErrorCode::Success.into() +} + /// Instantiate a Findex using a Redis backend. /// /// # Parameters @@ -592,7 +667,7 @@ pub unsafe extern "C" fn h_delete( /// indexes every night this is the number of days to wait before /// being sure that a big portion of the indexes were checked /// (see the coupon problem to understand why it's not 100% sure) - +/// /// # Safety /// /// Cannot be safe since using FFI. diff --git a/crates/findex/src/interfaces/python/api.rs b/crates/findex/src/interfaces/python/api.rs index eadbdaaa..2628b020 100644 --- a/crates/findex/src/interfaces/python/api.rs +++ b/crates/findex/src/interfaces/python/api.rs @@ -104,7 +104,7 @@ impl Findex { ); let instance = pyo3_unwrap!( runtime.block_on(InstantiatedFindex::new(configuration)), - "error instantiating Findex with Redis backend" + "error instantiating Findex with custom backend" ); Ok(Self { key: UserKey::try_from_bytes(key.0.to_bytes()) @@ -117,7 +117,7 @@ impl Findex { /// Instantiates Findex with a REST backend. #[staticmethod] - pub fn new_with_rest_interface( + pub fn new_with_findex_cloud_interface( label: String, token: String, entry_url: String, @@ -134,12 +134,12 @@ impl Findex { let key = UserKey::try_from_slice(&token.findex_key) .expect("the bytes passed represent a correct key"); let instance = pyo3_unwrap!( - runtime.block_on(InstantiatedFindex::new(Configuration::Rest( + runtime.block_on(InstantiatedFindex::new(Configuration::FindexCloud( token, entry_url.clone(), chain_url.unwrap_or(entry_url) ))), - "error instantiating Findex with Redis backend" + "error instantiating Findex with Findex Cloud backend" ); Ok(Self { key, @@ -149,6 +149,35 @@ impl Findex { }) } + /// Instantiates Findex with a REST backend. + #[staticmethod] + pub fn new_with_rest_interface( + key: &KeyPy, + label: String, + entry_url: String, + chain_url: Option, + ) -> PyResult { + let runtime = pyo3_unwrap!( + tokio::runtime::Runtime::new(), + "error creating Tokio runtime" + ); + let instance = pyo3_unwrap!( + runtime.block_on(InstantiatedFindex::new(Configuration::Rest( + reqwest::Client::new(), + entry_url.clone(), + chain_url.unwrap_or(entry_url) + ))), + "error instantiating Findex with REST backend" + ); + Ok(Self { + key: UserKey::try_from_bytes(key.0.to_bytes()) + .expect("the bytes passed represent a correct key"), + label: Label::from(label.as_str()), + runtime, + instance, + }) + } + /// Adds the given associations to the index. /// /// Any subsequent search for such a keyword will result in finding (at diff --git a/crates/findex/src/interfaces/wasm/api.rs b/crates/findex/src/interfaces/wasm/api.rs index e81dbf29..d7925f74 100644 --- a/crates/findex/src/interfaces/wasm/api.rs +++ b/crates/findex/src/interfaces/wasm/api.rs @@ -45,15 +45,30 @@ impl WasmFindex { .map_err(JsError::from) } - /// Instantiates a Findex object using REST interfaces, using the given token - /// and URLs. - pub async fn new_with_rest_interface( + /// Instantiates a Findex object using REST interfaces, using the given + /// token and URLs. + pub async fn new_with_findex_cloud_interface( token: String, entry_url: String, chain_url: String, ) -> Result { let config = - Configuration::Rest(AuthorizationToken::from_str(&token)?, entry_url, chain_url); + Configuration::FindexCloud(AuthorizationToken::from_str(&token)?, entry_url, chain_url); + + InstantiatedFindex::new(config) + .await + .map(Self) + .map_err(WasmError::from) + .map_err(JsError::from) + } + + /// Instantiates a Findex object using REST interfaces, using the given + /// token and URLs. + pub async fn new_with_rest_interface( + entry_url: String, + chain_url: String, + ) -> Result { + let config = Configuration::Rest(reqwest::Client::new(), entry_url, chain_url); InstantiatedFindex::new(config) .await @@ -94,7 +109,7 @@ impl WasmFindex { let res = ::try_from(res).map_err(|e| { format!( "Findex search: failed converting input of user interrupt into Js object: \ - {e:?}" + {e:?}" ) })?; let res = interrupt @@ -103,13 +118,15 @@ impl WasmFindex { let interruption_flag = JsFuture::from(Promise::resolve(&res)).await.map_err(|e| { format!( - "Findex search: failed getting the promised results from user interrupt: {e:?}" - ) + "Findex search: failed getting the promised results from user \ + interrupt: {e:?}" + ) })?; interruption_flag.as_bool().ok_or_else(|| { format!( - "Findex search: user interrupt does not return a boolean value: {interrupt:?}" - ) + "Findex search: user interrupt does not return a boolean value: \ + {interrupt:?}" + ) }) } else { Ok(false) @@ -221,15 +238,16 @@ impl WasmFindex { })?); let filtered_data = JsFuture::from(promise).await.map_err(|e| { format!( - "Findex compact: failed getting the promised results from the obsolete data \ - filter: {e:?}" - ) + "Findex compact: failed getting the promised results from the obsolete \ + data filter: {e:?}" + ) })?; let filtered_data = >::try_from(IndexedData::from(filtered_data)) .map_err(|e| { format!( - "Findex compact: failed converting Js array back to filtered data: {e:?}" - ) + "Findex compact: failed converting Js array back to filtered data: \ + {e:?}" + ) })?; Ok(filtered_data) } else { diff --git a/crates/findex/src/lib.rs b/crates/findex/src/lib.rs index 1ec52914..20e924d3 100644 --- a/crates/findex/src/lib.rs +++ b/crates/findex/src/lib.rs @@ -6,6 +6,7 @@ pub mod db_interfaces; feature = "ffi", feature = "python", feature = "redis-interface", + feature = "findex-cloud", feature = "rest-interface", feature = "sqlite-interface", feature = "wasm", @@ -25,8 +26,14 @@ pub mod ser_de; feature = "ffi", feature = "python", feature = "redis-interface", + feature = "findex-cloud", feature = "rest-interface", feature = "sqlite-interface", feature = "wasm", ))] pub use instantiation::{Configuration, InstantiatedFindex}; + +pub mod reexport { + pub use cosmian_crypto_core; + pub use cosmian_findex; +} diff --git a/crates/findex/src/ser_de/ffi_ser_de.rs b/crates/findex/src/ser_de/ffi_ser_de.rs index 5fee5d06..9eac6c25 100644 --- a/crates/findex/src/ser_de/ffi_ser_de.rs +++ b/crates/findex/src/ser_de/ffi_ser_de.rs @@ -29,15 +29,16 @@ pub const fn get_serialized_edx_lines_size_bound( pub fn get_upsert_output_size( modifications: &HashMap, Keywords>, ) -> usize { - // Since `h_add` (resp. `h_delete`) returns the set of keywords that have been inserted (resp. - // deleted), caller MUST know in advance how much memory is needed before calling `h_add` - // (resp. `h_delete`). + // Since `h_add` (resp. `h_delete`) returns the set of keywords that have been + // inserted (resp. deleted), caller MUST know in advance how much memory is + // needed before calling `h_add` (resp. `h_delete`). // - // In order to centralize into Rust the computation of the allocation size, 2 calls to - // `h_upsert` are required: + // In order to centralize into Rust the computation of the allocation size, 2 + // calls to `h_upsert` are required: // - // - the first call is made with `results_len` with a 0 value. No indexation at all is done. It - // simply returns an upper bound estimation of the allocation needed store the results. + // - the first call is made with `results_len` with a 0 value. No indexation at + // all is done. It simply returns an upper bound estimation of the allocation + // needed store the results. // - the second call takes this returned value for `results_len` modifications .values() @@ -136,8 +137,9 @@ pub fn deserialize_edx_lines( let mut items = Vec::with_capacity(length); for _ in 0..length { let key = Token::from(de.read_array()?); - // TODO: since constant generics cannot be used as constant values, there is no way to use - // `de.read_array<{ EncryptedValue::::LENGTH }>()` for now. + // TODO: since constant generics cannot be used as constant values, there is no + // way to use `de.read_array<{ EncryptedValue::::LENGTH + // }>()` for now. let value = EncryptedValue::::try_from(de.read_vec()?.as_slice())?; items.push((key, value)); } diff --git a/crates/findex/src/ser_de/mod.rs b/crates/findex/src/ser_de/mod.rs index 28893337..d4622266 100644 --- a/crates/findex/src/ser_de/mod.rs +++ b/crates/findex/src/ser_de/mod.rs @@ -61,7 +61,7 @@ impl From for SerializationError { } } -#[cfg(any(feature = "ffi", feature = "rest-interface"))] +#[cfg(any(feature = "ffi", feature = "findex-cloud", feature = "rest-interface"))] pub mod ffi_ser_de; #[cfg(feature = "wasm")] pub mod wasm_ser_de; diff --git a/crates/findex/src/ser_de/wasm_ser_de.rs b/crates/findex/src/ser_de/wasm_ser_de.rs index 31499729..7043c222 100644 --- a/crates/findex/src/ser_de/wasm_ser_de.rs +++ b/crates/findex/src/ser_de/wasm_ser_de.rs @@ -124,6 +124,7 @@ pub fn edx_lines_to_js_array( Ok(res) } +#[allow(dead_code)] #[cfg(test)] mod tests { diff --git a/crates/fpe/src/core/alphabet.rs b/crates/fpe/src/core/alphabet.rs index b9045255..8cceae49 100644 --- a/crates/fpe/src/core/alphabet.rs +++ b/crates/fpe/src/core/alphabet.rs @@ -128,7 +128,7 @@ impl Alphabet { /// secure. The minimum length is calculated based on the number of /// characters in the alphabet and recommended security thresholds. #[must_use] - pub fn minimum_plaintext_length(&self) -> usize { + pub const fn minimum_plaintext_length(&self) -> usize { self.min_text_length } diff --git a/crates/fpe/src/core/integer.rs b/crates/fpe/src/core/integer.rs index 45a862a3..f29e004e 100644 --- a/crates/fpe/src/core/integer.rs +++ b/crates/fpe/src/core/integer.rs @@ -267,7 +267,7 @@ impl Integer { /// The number of digits of the max value /// that is the same as the `radix^digits - 1` #[must_use] - pub fn digits(&self) -> usize { + pub const fn digits(&self) -> usize { self.digits } } diff --git a/crates/fpe/src/wasm_bindgen/mod.rs b/crates/fpe/src/wasm_bindgen/mod.rs index 0139d6c7..51e81ee4 100644 --- a/crates/fpe/src/wasm_bindgen/mod.rs +++ b/crates/fpe/src/wasm_bindgen/mod.rs @@ -2,5 +2,6 @@ mod alphabet; mod float; mod integer; +#[allow(dead_code)] #[cfg(test)] mod tests; From e61e161d2b45fda5fc8205dfc80b4b086c7d661c Mon Sep 17 00:00:00 2001 From: Manuthor Date: Sun, 27 Oct 2024 06:14:33 +0100 Subject: [PATCH 2/3] fix(findex): remove useless try_into in REST interfaces --- crates/findex/Cargo.toml | 1 + .../db_interfaces/rest/findex_cloud_stores.rs | 16 ++++------------ .../findex/src/db_interfaces/rest/rest_stores.rs | 16 ++++------------ 3 files changed, 9 insertions(+), 24 deletions(-) diff --git a/crates/findex/Cargo.toml b/crates/findex/Cargo.toml index c6f6f309..7f0045f1 100644 --- a/crates/findex/Cargo.toml +++ b/crates/findex/Cargo.toml @@ -71,6 +71,7 @@ base64 = { workspace = true, optional = true } cosmian_crypto_core = { workspace = true } cosmian_ffi_utils = { workspace = true, optional = true } cosmian_findex = { git = "https://www.github.com/Cosmian/findex", branch = "fix/missing_some_structs_serialization" } +# cosmian_findex = { path = "../../../findex" } futures = { version = "0.3.30", optional = true } js-sys = { workspace = true, optional = true } lazy_static = { version = "1.4.0", optional = true } diff --git a/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs b/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs index 05e6fc73..eb49f07c 100644 --- a/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs +++ b/crates/findex/src/db_interfaces/rest/findex_cloud_stores.rs @@ -150,9 +150,7 @@ impl DbInterface for FindexCloudChainBackend { tokens: Tokens, ) -> Result, Self::Error> { let bytes = serialize_token_set(&tokens)?; - let res = self - .post((CallbackPrefix::FetchEntry as u8 + 1).try_into()?, &bytes) - .await?; + let res = self.post(CallbackPrefix::FetchChain, &bytes).await?; deserialize_edx_lines(&res) .map_err(Self::Error::from) .map(Into::into) @@ -184,9 +182,7 @@ impl DbInterface for FindexCloudChainBackend { async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { let bytes = serialize_token_set(&tokens)?; - let _ = self - .post((CallbackPrefix::DeleteEntry as u8 + 1).try_into()?, &bytes) - .await?; + let _ = self.post(CallbackPrefix::DeleteChain, &bytes).await?; Ok(()) } } @@ -296,9 +292,7 @@ impl DbInterface for FindexCloudEntryBackend { tokens: Tokens, ) -> Result, Self::Error> { let bytes = serialize_token_set(&tokens)?; - let res = self - .post((CallbackPrefix::FetchEntry as u8).try_into()?, &bytes) - .await?; + let res = self.post(CallbackPrefix::FetchEntry, &bytes).await?; deserialize_edx_lines(&res) .map_err(Self::Error::from) .map(Into::into) @@ -330,9 +324,7 @@ impl DbInterface for FindexCloudEntryBackend { async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { let bytes = serialize_token_set(&tokens)?; - let _ = self - .post((CallbackPrefix::DeleteEntry as u8).try_into()?, &bytes) - .await?; + let _ = self.post(CallbackPrefix::DeleteEntry, &bytes).await?; Ok(()) } } diff --git a/crates/findex/src/db_interfaces/rest/rest_stores.rs b/crates/findex/src/db_interfaces/rest/rest_stores.rs index 04c06952..711d2f6d 100644 --- a/crates/findex/src/db_interfaces/rest/rest_stores.rs +++ b/crates/findex/src/db_interfaces/rest/rest_stores.rs @@ -70,9 +70,7 @@ impl DbInterface for RestEntryBackend { tokens: Tokens, ) -> Result, Self::Error> { let bytes = serialize_token_set(&tokens)?; - let res = self - .post((CallbackPrefix::FetchEntry as u8).try_into()?, &bytes) - .await?; + let res = self.post(CallbackPrefix::FetchEntry, &bytes).await?; deserialize_edx_lines(&res) .map_err(Self::Error::from) .map(Into::into) @@ -104,9 +102,7 @@ impl DbInterface for RestEntryBackend { async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { let bytes = serialize_token_set(&tokens)?; - let _ = self - .post((CallbackPrefix::DeleteEntry as u8).try_into()?, &bytes) - .await?; + let _ = self.post(CallbackPrefix::DeleteEntry, &bytes).await?; Ok(()) } } @@ -170,9 +166,7 @@ impl DbInterface for RestChainBackend { tokens: Tokens, ) -> Result, Self::Error> { let bytes = serialize_token_set(&tokens)?; - let res = self - .post((CallbackPrefix::FetchEntry as u8 + 1).try_into()?, &bytes) - .await?; + let res = self.post(CallbackPrefix::FetchChain, &bytes).await?; deserialize_edx_lines(&res) .map_err(Self::Error::from) .map(Into::into) @@ -204,9 +198,7 @@ impl DbInterface for RestChainBackend { async fn delete(&self, tokens: Tokens) -> Result<(), Self::Error> { let bytes = serialize_token_set(&tokens)?; - let _ = self - .post((CallbackPrefix::DeleteEntry as u8 + 1).try_into()?, &bytes) - .await?; + let _ = self.post(CallbackPrefix::DeleteChain, &bytes).await?; Ok(()) } } From cd1649c39d0e0c89e4815aa25f867d11721c4ce5 Mon Sep 17 00:00:00 2001 From: Manuthor Date: Sun, 3 Nov 2024 08:16:34 +0100 Subject: [PATCH 3/3] feat: prefix route with an index ID --- .../src/db_interfaces/rest/rest_stores.rs | 20 +++++++++++++++++-- crates/findex/src/instantiation/db_config.rs | 4 ++-- crates/findex/src/instantiation/findex.rs | 4 +++- crates/findex/src/interfaces/python/api.rs | 4 +++- crates/findex/src/interfaces/wasm/api.rs | 3 ++- 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/crates/findex/src/db_interfaces/rest/rest_stores.rs b/crates/findex/src/db_interfaces/rest/rest_stores.rs index 711d2f6d..02960c02 100644 --- a/crates/findex/src/db_interfaces/rest/rest_stores.rs +++ b/crates/findex/src/db_interfaces/rest/rest_stores.rs @@ -16,6 +16,7 @@ use crate::{ pub struct RestEntryBackend { pub client: Client, pub url: String, + pub index_id: String, } impl RestEntryBackend { @@ -24,7 +25,14 @@ impl RestEntryBackend { callback: CallbackPrefix, body: &[u8], ) -> Result, DbInterfaceError> { - let url = { format!("{}/indexes/{}", &self.url, callback.get_uri(),) }; + let url = { + format!( + "{}/indexes/{}/{}", + &self.url, + self.index_id, + callback.get_uri(), + ) + }; let response = self .client .post(url) @@ -111,6 +119,7 @@ impl DbInterface for RestEntryBackend { pub struct RestChainBackend { pub client: Client, pub url: String, + pub index_id: String, } impl RestChainBackend { @@ -119,7 +128,14 @@ impl RestChainBackend { callback: CallbackPrefix, body: &[u8], ) -> Result, DbInterfaceError> { - let url = { format!("{}/indexes/{}", &self.url, callback.get_uri(),) }; + let url = { + format!( + "{}/indexes/{}/{}", + &self.url, + self.index_id, + callback.get_uri(), + ) + }; let response = self .client diff --git a/crates/findex/src/instantiation/db_config.rs b/crates/findex/src/instantiation/db_config.rs index 64c121c7..85fdeb6a 100644 --- a/crates/findex/src/instantiation/db_config.rs +++ b/crates/findex/src/instantiation/db_config.rs @@ -21,9 +21,9 @@ pub enum Configuration { FindexCloud(AuthorizationToken, String, String), /// REST DB interface requires an authorization token and a server URL for - /// the Entry and the Chain tables. + /// the Entry and the Chain tables and the index ID. #[cfg(feature = "rest-interface")] - Rest(Client, String, String), + Rest(Client, String, String, String), /// FFI DB interface requests FFI functions corresponding to the APIs used /// by the Entry/Chain tables. diff --git a/crates/findex/src/instantiation/findex.rs b/crates/findex/src/instantiation/findex.rs index 54e5e00a..af69dfa2 100644 --- a/crates/findex/src/instantiation/findex.rs +++ b/crates/findex/src/instantiation/findex.rs @@ -123,14 +123,16 @@ impl InstantiatedFindex { } #[cfg(feature = "rest-interface")] - Configuration::Rest(client, entry_url, chain_url) => Self::Rest(Findex::new( + Configuration::Rest(client, entry_url, chain_url, index_id) => Self::Rest(Findex::new( EntryTable::setup(RestEntryBackend { client: client.clone(), url: entry_url, + index_id: index_id.clone(), }), ChainTable::setup(RestChainBackend { client, url: chain_url, + index_id, }), )), diff --git a/crates/findex/src/interfaces/python/api.rs b/crates/findex/src/interfaces/python/api.rs index 2628b020..f65ab76b 100644 --- a/crates/findex/src/interfaces/python/api.rs +++ b/crates/findex/src/interfaces/python/api.rs @@ -154,6 +154,7 @@ impl Findex { pub fn new_with_rest_interface( key: &KeyPy, label: String, + index_id: String, entry_url: String, chain_url: Option, ) -> PyResult { @@ -165,7 +166,8 @@ impl Findex { runtime.block_on(InstantiatedFindex::new(Configuration::Rest( reqwest::Client::new(), entry_url.clone(), - chain_url.unwrap_or(entry_url) + chain_url.unwrap_or(entry_url), + index_id, ))), "error instantiating Findex with REST backend" ); diff --git a/crates/findex/src/interfaces/wasm/api.rs b/crates/findex/src/interfaces/wasm/api.rs index d7925f74..88bc919f 100644 --- a/crates/findex/src/interfaces/wasm/api.rs +++ b/crates/findex/src/interfaces/wasm/api.rs @@ -67,8 +67,9 @@ impl WasmFindex { pub async fn new_with_rest_interface( entry_url: String, chain_url: String, + index_id: String, ) -> Result { - let config = Configuration::Rest(reqwest::Client::new(), entry_url, chain_url); + let config = Configuration::Rest(reqwest::Client::new(), entry_url, chain_url, index_id); InstantiatedFindex::new(config) .await