diff --git a/Cargo.toml b/Cargo.toml index 378272c4..4197f19e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,45 @@ resolver = "2" members = [ "core", "meta-server-emulator", - "meta-test", "core-swift-lib", "wasm" ] exclude = [ "meta-server-serverless" -] \ No newline at end of file +] + +[workspace.dependencies] +# Error handling +thiserror = "1.0.49" +anyhow = "1.0.75" + +# Logging and tracing +tracing = "0.1" +tracing-subscriber = { version = "0.3" } + +# Json +serde = { version = "1.0.188", features = ["derive"] } +serde_json = "1.0.107" +serde_derive = "1.0.188" + +# Async utils +async-std = { version = "1.12.0" } +async-trait = "0.1" +flume = "0.11" +async-mutex = "1.4" + +# Cryptography +ed25519-dalek = "1.0.1" +crypto_box = { version = "0.8.2", features = ["std"] } +rand = "0.8.5" +getrandom = { version = "0.2.8", features = ["js"] } +sha2 = { version = "0.10.6", features = ["oid"] } +base64 = "0.20.0" +hex = "0.4" +#https://github.com/dsprenkels/sss-rs +shamirsecretsharing = "0.1" + +# Sql +diesel = { version = "2.0.0" } +diesel_migrations = { version = "2.0.0" } \ No newline at end of file diff --git a/core-swift-lib/Cargo.toml b/core-swift-lib/Cargo.toml index 886010d6..9d296bd2 100644 --- a/core-swift-lib/Cargo.toml +++ b/core-swift-lib/Cargo.toml @@ -9,11 +9,15 @@ name = "meta_secret_core_swift" [dependencies] meta-secret-core = { path = "../core"} -serde_json = "1.0.87" -serde = { version = "1.0", features = ["derive"] } -ed25519-dalek = "1.0" -crypto_box = "0.8.1" -base64 = "0.20.0-alpha.1" -sha2 = "0.10.6" -hex = "0.4" -anyhow = "1.0.66" + +anyhow.workspace = true + +serde.workspace = true +serde_json.workspace = true +serde_derive.workspace = true + +ed25519-dalek.workspace = true +crypto_box.workspace = true +base64.workspace = true +sha2.workspace = true +hex.workspace = true diff --git a/core-swift-lib/src/swift_to_rust.rs b/core-swift-lib/src/swift_to_rust.rs index 878b9260..c9b4d37a 100644 --- a/core-swift-lib/src/swift_to_rust.rs +++ b/core-swift-lib/src/swift_to_rust.rs @@ -1,7 +1,6 @@ use anyhow::Context; -use meta_secret_core::crypto::keys::KeyManager; +use meta_secret_core::crypto::keys::{KeyManager, SecretBox}; use meta_secret_core::errors::CoreError; -use meta_secret_core::models::{Base64EncodedText, SecretDistributionDocData, SerializedKeyManager}; use meta_secret_core::recover_from_shares; use meta_secret_core::secret::data_block::common::SharedSecretConfig; use meta_secret_core::secret::shared_secret::UserShareDto; @@ -11,6 +10,8 @@ use std::ffi::CString; use std::os::raw::c_char; use std::slice; use std::str; +use meta_secret_core::crypto::encoding::base64::Base64Text; +use meta_secret_core::node::common::model::secret::SecretDistributionData; type SizeT = usize; @@ -73,13 +74,13 @@ fn to_c_str(str: String) -> *mut c_char { } mod internal { + use meta_secret_core::node::common::model::crypto::{AeadCipherText, AeadPlainText, EncryptedMessage}; + use meta_secret_core::node::common::model::secret::MetaPasswordId; use super::*; - use meta_secret_core::models::{AeadCipherText, AeadPlainText, MetaPasswordId}; use meta_secret_core::secret; pub fn generate_security_box(vault_name_bytes: *const u8, len: SizeT) -> CoreResult { - let device_name = data_to_string(vault_name_bytes, len)?; - let security_box = KeyManager::generate_security_box(device_name); + let security_box = KeyManager::generate_secret_box(); let user = serde_json::to_string_pretty(&security_box)?; Ok(user) } @@ -132,10 +133,11 @@ mod internal { println!("restore_task {:?}", restore_task.doc); // Decrypt shares + let EncryptedMessage::CipherShare { share, ..} = restore_task.doc.secret_message; let share_json: AeadPlainText = key_manager .transport_key_pair - .decrypt(&restore_task.doc.secret_message.encrypted_text)?; - let share_json = UserShareDto::try_from(share_json.msg.as_ref())?; + .decrypt(&share)?; + let share_json = UserShareDto::try_from(&share_json.msg)?; // Decrypted Share to JSon let result_json = serde_json::to_string_pretty(&share_json)?; @@ -147,16 +149,18 @@ mod internal { let restore_task = RestoreTask::try_from(&data_string)?; let key_manager = KeyManager::try_from(&restore_task.key_manager)?; + let EncryptedMessage::CipherShare { share: second_share, ..} = restore_task.doc_two.secret_message; let share_from_device_2_json: AeadPlainText = key_manager .transport_key_pair - .decrypt(&restore_task.doc_two.secret_message.encrypted_text)?; - let share_from_device_2_json = UserShareDto::try_from(share_from_device_2_json.msg.as_ref())?; + .decrypt(&second_share)?; + let share_from_device_2_json = UserShareDto::try_from(&share_from_device_2_json.msg)?; + let EncryptedMessage::CipherShare { share: first_share, ..} = restore_task.doc_one.secret_message; let share_from_device_1_json: AeadPlainText = key_manager .transport_key_pair - .decrypt(&restore_task.doc_one.secret_message.encrypted_text)?; + .decrypt(&first_share)?; - let share_from_device_1_json = UserShareDto::try_from(share_from_device_1_json.msg.as_ref())?; + let share_from_device_1_json = UserShareDto::try_from(&share_from_device_1_json.msg)?; // Restored Password to JSon let password = recover_from_shares(vec![share_from_device_2_json, share_from_device_1_json])?; @@ -186,8 +190,8 @@ fn data_to_string(bytes: *const u8, len: SizeT) -> CoreResult { #[derive(Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct JsonMappedData { - sender_key_manager: SerializedKeyManager, - receiver_pub_key: Base64EncodedText, + sender_key_manager: SecretBox, + receiver_pub_key: Base64Text, secret: String, } @@ -203,16 +207,16 @@ impl TryFrom<&String> for JsonMappedData { #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct RestoreTask { - key_manager: SerializedKeyManager, - doc_one: SecretDistributionDocData, - doc_two: SecretDistributionDocData, + key_manager: SecretBox, + doc_one: SecretDistributionData, + doc_two: SecretDistributionData, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] struct DecryptTask { - key_manager: SerializedKeyManager, - doc: SecretDistributionDocData, + key_manager: SecretBox, + doc: SecretDistributionData, } impl TryFrom<&String> for RestoreTask { @@ -238,10 +242,10 @@ impl TryFrom<&String> for DecryptTask { pub mod test { use meta_secret_core::crypto::key_pair::KeyPair; use meta_secret_core::crypto::keys::KeyManager; - use meta_secret_core::models::AeadCipherText; use meta_secret_core::secret::data_block::common::SharedSecretConfig; use meta_secret_core::secret::shared_secret::UserShareDto; use meta_secret_core::{secret, CoreResult}; + use meta_secret_core::node::common::model::crypto::AeadCipherText; #[test] fn split_and_encrypt() -> CoreResult<()> { diff --git a/core/Cargo.toml b/core/Cargo.toml index bc7e295a..d669e764 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -3,55 +3,52 @@ name = "meta-secret-core" version = "2.0.0" edition = "2021" license = "Apache-2.0" -description = "Meta Secret core module" +description = "Meta Secret Core Module" homepage = "https://github.com/meta-secret/meta-secret-core" documentation = "https://github.com/meta-secret/meta-secret-core/blob/main/core/README.md" repository = "https://github.com/meta-secret/meta-secret-core" readme = "README.md" +[features] +test_utils = [] + [lib] crate-type = ["cdylib", "lib", "staticlib"] name = "meta_secret_core" [dependencies] -chrono = "0.4.31" - -thiserror = "1.0.40" -anyhow = "1.0.66" - -tracing = {version = "0.1.37" } -tracing-subscriber = {version = "0.3.17", features = ["json", "env-filter"]} - -async-mutex = "1.4.0" - -async-trait = "0.1" -flume = "0.11.0" - -reqwest = { version = "0.11.13", features = ["json"] } -async-std = { version = "1.12.0", features = ["unstable"] } - -ed25519-dalek = "1.0.1" -crypto_box = { version = "0.8.2", features = ["std"] } -rand = "0.8.5" -getrandom = { version = "0.2.8", features = ["js"] } -sha2 = { version = "0.10.6", features = ["oid"] } -base64 = "0.20.0" - -hex = "0.4" - +thiserror.workspace = true +anyhow.workspace = true + +async-trait.workspace = true +flume.workspace = true +async-mutex.workspace = true +async-std = { workspace = true, features = ["unstable"] } + +serde.workspace = true +serde_json.workspace = true +serde_derive.workspace = true + +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["json", "env-filter"] } +tracing-attributes = "0.1.27" + +ed25519-dalek.workspace = true +crypto_box.workspace = true +rand.workspace = true +getrandom.workspace = true +sha2.workspace = true +base64.workspace = true +hex.workspace = true #https://github.com/dsprenkels/sss-rs -shamirsecretsharing = "0.1" +shamirsecretsharing.workspace = true -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" serde_bytes = "0.11" serde-big-array = "0.4" -serde_derive = "^1.0" qrcode-generator = "4.1.6" rqrr = "0.5" image = "0.24" -log = "0.4.20" [dependencies.uuid] version = "1.3.0" @@ -61,7 +58,6 @@ features = [ "macro-diagnostics", # Enable better diagnostics for compile-time UUIDs ] - [dev-dependencies] -tokio = { version = "1.20.1", features = ["macros"] } -pretty_assertions = "1" \ No newline at end of file +tokio = { version = "1.20.1", features = ["full"] } +pretty_assertions = "1" diff --git a/core/src/crypto/encoding.rs b/core/src/crypto/encoding.rs index 863f6874..8a0abf24 100644 --- a/core/src/crypto/encoding.rs +++ b/core/src/crypto/encoding.rs @@ -6,22 +6,28 @@ pub type Array256Bit = [u8; KEY_SIZE_32_BYTES]; pub mod base64 { extern crate base64; + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct Base64Text { + pub base64_text: String, + } + pub mod encoder { use base64::alphabet::URL_SAFE; use base64::engine::fast_portable::{FastPortable, NO_PAD}; use crate::crypto::encoding::Array256Bit; - use crate::models::Base64EncodedText; + use crate::crypto::encoding::base64::Base64Text; const URL_SAFE_ENGINE: FastPortable = FastPortable::from(&URL_SAFE, NO_PAD); - impl From> for Base64EncodedText { + impl From> for Base64Text { fn from(data: Vec) -> Self { - Base64EncodedText::from(data.as_slice()) + Base64Text::from(data.as_slice()) } } - impl From<&[u8]> for Base64EncodedText { + impl From<&[u8]> for Base64Text { fn from(data: &[u8]) -> Self { Self { base64_text: base64::encode_engine(data, &URL_SAFE_ENGINE), @@ -29,21 +35,21 @@ pub mod base64 { } } - impl From for Base64EncodedText { + impl From for Base64Text { fn from(data: String) -> Self { - Base64EncodedText::from(data.as_bytes()) + Base64Text::from(data.as_bytes()) } } - impl From<&str> for Base64EncodedText { + impl From<&str> for Base64Text { fn from(data: &str) -> Self { - Base64EncodedText::from(data.as_bytes()) + Base64Text::from(data.as_bytes()) } } - impl From<&Array256Bit> for Base64EncodedText { + impl From<&Array256Bit> for Base64Text { fn from(data: &Array256Bit) -> Self { - Base64EncodedText::from(data.as_slice()) + Base64Text::from(data.as_slice()) } } } @@ -53,24 +59,24 @@ pub mod base64 { use base64::engine::fast_portable::{FastPortable, NO_PAD}; use crate::crypto::encoding::Array256Bit; + use crate::crypto::encoding::base64::Base64Text; use crate::errors::CoreError; - use crate::models::Base64EncodedText; const URL_SAFE_ENGINE: FastPortable = FastPortable::from(&URL_SAFE, NO_PAD); - impl TryFrom<&Base64EncodedText> for Vec { + impl TryFrom<&Base64Text> for Vec { type Error = CoreError; - fn try_from(base64: &Base64EncodedText) -> Result { + fn try_from(base64: &Base64Text) -> Result { let data = base64::decode_engine(&base64.base64_text, &URL_SAFE_ENGINE)?; Ok(data) } } - impl TryFrom<&Base64EncodedText> for Array256Bit { + impl TryFrom<&Base64Text> for Array256Bit { type Error = CoreError; - fn try_from(encoded: &Base64EncodedText) -> Result { + fn try_from(encoded: &Base64Text) -> Result { //decode base64 string let bytes_vec = Vec::try_from(encoded)?; //try to cast an array to a fixed size array @@ -82,15 +88,15 @@ pub mod base64 { #[cfg(test)] mod test { - use crate::models::Base64EncodedText; + use crate::crypto::encoding::base64::Base64Text; const TEST_STR: &str = "kjsfdbkjsfhdkjhsfdkjhsfdkjhksfdjhksjfdhksfd"; const ENCODED_URL_SAFE_TEST_STR: &str = "a2pzZmRia2pzZmhka2poc2Zka2poc2Zka2poa3NmZGpoa3NqZmRoa3NmZA"; #[test] fn from_vec() { - let encoded = Base64EncodedText::from(vec![65, 65, 65]); - let expected = Base64EncodedText { + let encoded = Base64Text::from(vec![65, 65, 65]); + let expected = Base64Text { base64_text: "QUFB".to_string(), }; assert_eq!(encoded, expected); @@ -98,8 +104,8 @@ pub mod base64 { #[test] fn from_bytes() { - let encoded = Base64EncodedText::from(TEST_STR.as_bytes()); - let expected = Base64EncodedText { + let encoded = Base64Text::from(TEST_STR.as_bytes()); + let expected = Base64Text { base64_text: ENCODED_URL_SAFE_TEST_STR.to_string(), }; assert_eq!(encoded, expected); @@ -108,23 +114,20 @@ pub mod base64 { } pub mod serialized_key_manager { - use crate::models::Base64EncodedText; pub mod encoder { use ed25519_dalek::ed25519::signature::Signature; + use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::{DalekPublicKey, DalekSignature, DsaKeyPair, KeyPair, TransportDsaKeyPair}; - use crate::crypto::keys::KeyManager; - use crate::models::{SerializedDsaKeyPair, SerializedKeyManager, SerializedTransportKeyPair}; - - use super::Base64EncodedText; + use crate::crypto::keys::{KeyManager, SecretBox, SerializedDsaKeyPair, SerializedTransportKeyPair}; - // KeyManager -> SerializedKeyManager - impl From<&KeyManager> for SerializedKeyManager { - fn from(key_manager: &KeyManager) -> Self { + // KeyManager -> SecretBox + impl From for SecretBox { + fn from(key_manager: KeyManager) -> Self { Self { - dsa: Box::from(SerializedDsaKeyPair::from(&key_manager.dsa)), - transport: Box::from(SerializedTransportKeyPair::from(&key_manager.transport_key_pair)), + dsa:SerializedDsaKeyPair::from(&key_manager.dsa), + transport: SerializedTransportKeyPair::from(&key_manager.transport_key_pair), } } } @@ -132,8 +135,8 @@ pub mod serialized_key_manager { impl From<&TransportDsaKeyPair> for SerializedTransportKeyPair { fn from(transport: &TransportDsaKeyPair) -> Self { Self { - secret_key: Box::from(transport.secret_key()), - public_key: Box::from(transport.public_key()), + secret_key: transport.secret_key(), + public_key: transport.public_key(), } } } @@ -141,61 +144,59 @@ pub mod serialized_key_manager { impl From<&DsaKeyPair> for SerializedDsaKeyPair { fn from(dsa: &DsaKeyPair) -> Self { Self { - key_pair: Box::from(dsa.encode_key_pair()), - public_key: Box::from(dsa.public_key()), + key_pair: dsa.encode_key_pair(), + public_key: dsa.public_key(), } } } - impl From<&DalekPublicKey> for Base64EncodedText { + impl From<&DalekPublicKey> for Base64Text { fn from(pk: &DalekPublicKey) -> Self { - Base64EncodedText::from(&pk.to_bytes()) + Base64Text::from(&pk.to_bytes()) } } - impl From<&DalekSignature> for Base64EncodedText { + impl From<&DalekSignature> for Base64Text { fn from(sig: &DalekSignature) -> Self { - Base64EncodedText::from(sig.as_bytes()) + Base64Text::from(sig.as_bytes()) } } } pub mod decoder { use crate::crypto::encoding::Array256Bit; + use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::{ CryptoBoxPublicKey, CryptoBoxSecretKey, DalekKeyPair, DalekPublicKey, DalekSignature, DsaKeyPair, TransportDsaKeyPair, }; - use crate::crypto::keys::KeyManager; + use crate::crypto::keys::{KeyManager, SecretBox, SerializedDsaKeyPair, SerializedTransportKeyPair}; use crate::errors::CoreError; - use crate::models::{SerializedDsaKeyPair, SerializedKeyManager, SerializedTransportKeyPair}; - - use super::Base64EncodedText; impl TryFrom<&SerializedDsaKeyPair> for DsaKeyPair { type Error = CoreError; fn try_from(serialized_dsa: &SerializedDsaKeyPair) -> Result { - let key_pair_vec: Vec = Vec::try_from(serialized_dsa.key_pair.as_ref())?; + let key_pair_vec: Vec = Vec::try_from(&serialized_dsa.key_pair)?; let key_pair = DalekKeyPair::from_bytes(key_pair_vec.as_slice())?; Ok(Self { key_pair }) } } - impl TryFrom<&Base64EncodedText> for DalekPublicKey { + impl TryFrom<&Base64Text> for DalekPublicKey { type Error = CoreError; - fn try_from(base64_text: &Base64EncodedText) -> Result { + fn try_from(base64_text: &Base64Text) -> Result { let bytes = Array256Bit::try_from(base64_text)?; let pk = DalekPublicKey::from_bytes(&bytes)?; Ok(pk) } } - impl TryFrom<&Base64EncodedText> for DalekSignature { + impl TryFrom<&Base64Text> for DalekSignature { type Error = CoreError; - fn try_from(base64: &Base64EncodedText) -> Result { + fn try_from(base64: &Base64Text) -> Result { let bytes_vec: Vec = Vec::try_from(base64)?; let sign = DalekSignature::from_bytes(bytes_vec.as_slice())?; Ok(sign) @@ -206,9 +207,9 @@ pub mod serialized_key_manager { type Error = CoreError; fn try_from(serialized_transport: &SerializedTransportKeyPair) -> Result { - let sk_bytes = Array256Bit::try_from(serialized_transport.secret_key.as_ref())?; + let sk_bytes = Array256Bit::try_from(&serialized_transport.secret_key)?; let secret_key = CryptoBoxSecretKey::from(sk_bytes); - let pk_bytes = Array256Bit::try_from(serialized_transport.public_key.as_ref())?; + let pk_bytes = Array256Bit::try_from(&serialized_transport.public_key)?; let public_key = CryptoBoxPublicKey::from(pk_bytes); let key_pair = Self { secret_key, public_key }; @@ -217,12 +218,12 @@ pub mod serialized_key_manager { } } - impl TryFrom<&SerializedKeyManager> for KeyManager { + impl TryFrom<&SecretBox> for KeyManager { type Error = CoreError; - fn try_from(serialized_km: &SerializedKeyManager) -> Result { - let dsa = DsaKeyPair::try_from(serialized_km.dsa.as_ref())?; - let transport_key_pair = TransportDsaKeyPair::try_from(serialized_km.transport.as_ref())?; + fn try_from(serialized_km: &SecretBox) -> Result { + let dsa = DsaKeyPair::try_from(&serialized_km.dsa)?; + let transport_key_pair = TransportDsaKeyPair::try_from(&serialized_km.transport)?; let key_manager = Self { dsa, transport_key_pair, @@ -234,10 +235,10 @@ pub mod serialized_key_manager { #[cfg(test)] pub mod test { + use crate::CoreResult; + use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::{DalekPublicKey, DalekSignature, KeyPair}; use crate::crypto::keys::KeyManager; - use crate::models::Base64EncodedText; - use crate::CoreResult; #[test] fn from_base64_to_dalek_public_key() -> CoreResult<()> { @@ -253,7 +254,7 @@ pub mod serialized_key_manager { let km = KeyManager::generate(); let serialized_sign = km.dsa.sign("text".to_string()); let deserialized_sign = DalekSignature::try_from(&serialized_sign)?; - let serialized_sign_2nd_time = Base64EncodedText::from(&deserialized_sign); + let serialized_sign_2nd_time = Base64Text::from(&deserialized_sign); assert_eq!(serialized_sign, serialized_sign_2nd_time); Ok(()) @@ -267,32 +268,32 @@ pub mod cryptobox { use crypto_box::Nonce; use crate::crypto::encoding::Array256Bit; + use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::{CryptoBoxPublicKey, CryptoBoxSecretKey}; use crate::errors::CoreError; - use crate::models::Base64EncodedText; - impl TryFrom<&Base64EncodedText> for CryptoBoxPublicKey { + impl TryFrom<&Base64Text> for CryptoBoxPublicKey { type Error = CoreError; - fn try_from(encoded: &Base64EncodedText) -> Result { + fn try_from(encoded: &Base64Text) -> Result { let byte_array = Array256Bit::try_from(encoded)?; Ok(CryptoBoxPublicKey::from(byte_array)) } } - impl TryFrom<&Base64EncodedText> for CryptoBoxSecretKey { + impl TryFrom<&Base64Text> for CryptoBoxSecretKey { type Error = CoreError; - fn try_from(encoded: &Base64EncodedText) -> Result { + fn try_from(encoded: &Base64Text) -> Result { let byte_array = Array256Bit::try_from(encoded)?; Ok(CryptoBoxSecretKey::from(byte_array)) } } - impl TryFrom<&Base64EncodedText> for Nonce { + impl TryFrom<&Base64Text> for Nonce { type Error = CoreError; - fn try_from(encoded: &Base64EncodedText) -> Result { + fn try_from(encoded: &Base64Text) -> Result { let vec = Vec::try_from(encoded)?; let byte_array: [u8; 24] = vec.as_slice().try_into()?; Ok(Nonce::from(byte_array)) diff --git a/core/src/crypto/key_pair.rs b/core/src/crypto/key_pair.rs index c0c979fc..9dc78fe7 100644 --- a/core/src/crypto/key_pair.rs +++ b/core/src/crypto/key_pair.rs @@ -1,16 +1,18 @@ -use crypto_box::aead::AeadCore; + use crypto_box::{ aead::{Aead, OsRng as CryptoBoxOsRng, Payload}, ChaChaBox, Nonce, }; +use crypto_box::aead::AeadCore; use ed25519_dalek::{Keypair, Signer}; use image::EncodableLayout; -use rand::rngs::OsRng as RandOsRng; use rand::RngCore; +use rand::rngs::OsRng as RandOsRng; -use crate::errors::CoreError; -use crate::models::{AeadAuthData, AeadCipherText, AeadPlainText, Base64EncodedText, CommunicationChannel}; use crate::CoreResult; +use crate::crypto::encoding::base64::Base64Text; +use crate::errors::CoreError; +use crate::node::common::model::crypto::{AeadAuthData, AeadCipherText, AeadPlainText, CommunicationChannel}; pub type CryptoBoxPublicKey = crypto_box::PublicKey; pub type CryptoBoxSecretKey = crypto_box::SecretKey; @@ -22,8 +24,8 @@ pub type DalekSignature = ed25519_dalek::Signature; pub trait KeyPair { fn generate() -> Self; - fn public_key(&self) -> Base64EncodedText; - fn secret_key(&self) -> Base64EncodedText; + fn public_key(&self) -> Base64Text; + fn secret_key(&self) -> Base64Text; } pub struct DsaKeyPair { @@ -31,13 +33,13 @@ pub struct DsaKeyPair { } impl DsaKeyPair { - pub fn sign(&self, text: String) -> Base64EncodedText { + pub fn sign(&self, text: String) -> Base64Text { let signature: DalekSignature = self.key_pair.sign(text.as_bytes()); - Base64EncodedText::from(&signature) + Base64Text::from(&signature) } - pub fn encode_key_pair(&self) -> Base64EncodedText { - Base64EncodedText::from(self.key_pair.to_bytes().as_slice()) + pub fn encode_key_pair(&self) -> Base64Text { + Base64Text::from(self.key_pair.to_bytes().as_slice()) } } @@ -56,12 +58,12 @@ impl KeyPair for DsaKeyPair { } } - fn public_key(&self) -> Base64EncodedText { - Base64EncodedText::from(&self.key_pair.public) + fn public_key(&self) -> Base64Text { + Base64Text::from(&self.key_pair.public) } - fn secret_key(&self) -> Base64EncodedText { - Base64EncodedText::from(&self.key_pair.secret.to_bytes()) + fn secret_key(&self) -> Base64Text { + Base64Text::from(&self.key_pair.secret.to_bytes()) } } @@ -78,12 +80,12 @@ impl KeyPair for TransportDsaKeyPair { Self { secret_key, public_key } } - fn public_key(&self) -> Base64EncodedText { - Base64EncodedText::from(self.public_key.as_bytes()) + fn public_key(&self) -> Base64Text { + Base64Text::from(self.public_key.as_bytes()) } - fn secret_key(&self) -> Base64EncodedText { - Base64EncodedText::from(self.secret_key.as_bytes()) + fn secret_key(&self) -> Base64Text { + Base64Text::from(self.secret_key.as_bytes()) } } @@ -92,19 +94,19 @@ impl TransportDsaKeyPair { ChaChaBox::new(their_pk, &self.secret_key) } - pub fn encrypt_string(&self, plain_text: String, receiver_pk: Base64EncodedText) -> CoreResult { + pub fn encrypt_string(&self, plain_text: String, receiver_pk: Base64Text) -> CoreResult { let channel = CommunicationChannel { - sender: Box::from(self.public_key()), - receiver: Box::from(receiver_pk), + sender: self.public_key(), + receiver: receiver_pk, }; let auth_data = AeadAuthData { associated_data: "checksum".to_string(), - channel: Box::from(channel), - nonce: Box::from(self.generate_nonce()), + channel, + nonce: self.generate_nonce(), }; let aead_text = AeadPlainText { - msg: Box::from(Base64EncodedText::from(plain_text.as_bytes())), - auth_data: Box::from(auth_data), + msg: Base64Text::from(plain_text.as_bytes()), + auth_data, }; self.encrypt(&aead_text) @@ -112,18 +114,21 @@ impl TransportDsaKeyPair { pub fn encrypt(&self, plain_text: &AeadPlainText) -> CoreResult { let auth_data = &plain_text.auth_data; - let their_pk = CryptoBoxPublicKey::try_from(auth_data.channel.receiver.as_ref())?; + + let their_pk = CryptoBoxPublicKey::try_from(&auth_data.channel.receiver)?; + let crypto_box = self.build_cha_cha_box(&their_pk); - let nonce = &Nonce::try_from(auth_data.nonce.as_ref())?; - let msg = Vec::try_from(plain_text.msg.as_ref())?; + + let nonce = Nonce::try_from(&auth_data.nonce)?; + let msg = Vec::try_from(&plain_text.msg)?; let payload = Payload { msg: msg.as_bytes(), // your message to encrypt aad: auth_data.associated_data.as_bytes(), // not encrypted, but authenticated in tag }; - let cipher_text = crypto_box.encrypt(nonce, payload)?; + let cipher_text = crypto_box.encrypt(&nonce, payload)?; let cipher_text = AeadCipherText { - msg: Box::from(Base64EncodedText::from(cipher_text)), + msg: Base64Text::from(cipher_text), auth_data: plain_text.auth_data.clone(), }; @@ -138,48 +143,49 @@ impl TransportDsaKeyPair { let their_pk = match owner_pk { pk if pk.base64_text == channel.sender.base64_text => { - CryptoBoxPublicKey::try_from(channel.receiver.as_ref()) + CryptoBoxPublicKey::try_from(&channel.receiver) } pk if pk.base64_text == channel.receiver.base64_text => { - CryptoBoxPublicKey::try_from(channel.sender.as_ref()) + CryptoBoxPublicKey::try_from(&channel.sender) } _ => Err(CoreError::ThirdPartyEncryptionError { key_manager_pk: owner_pk, - channel: channel.as_ref().clone(), + channel: channel.clone(), }), }?; let crypto_box = self.build_cha_cha_box(&their_pk); - let msg_vec: Vec = Vec::try_from(cipher_text.msg.as_ref())?; - let nonce = &Nonce::try_from(auth_data.nonce.as_ref())?; + let msg_vec: Vec = Vec::try_from(&cipher_text.msg)?; + let nonce = Nonce::try_from(&auth_data.nonce)?; let payload = Payload { msg: msg_vec.as_bytes(), aad: auth_data.associated_data.as_bytes(), }; - let decrypted_plaintext = crypto_box.decrypt(nonce, payload)?; + let decrypted_plaintext = crypto_box.decrypt(&nonce, payload)?; let plain_text = AeadPlainText { - msg: Box::from(Base64EncodedText::from(decrypted_plaintext)), + msg: Base64Text::from(decrypted_plaintext), auth_data: cipher_text.auth_data.clone(), }; Ok(plain_text) } - pub fn generate_nonce(&self) -> Base64EncodedText { + pub fn generate_nonce(&self) -> Base64Text { let nonce: Nonce = ChaChaBox::generate_nonce(&mut CryptoBoxOsRng); - Base64EncodedText::from(nonce.as_slice()) + Base64Text::from(nonce.as_slice()) } } #[cfg(test)] pub mod test { + use crate::CoreResult; + use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::KeyPair; use crate::crypto::keys::KeyManager; use crate::errors::CoreError; - use crate::models::{AeadAuthData, AeadCipherText, AeadPlainText, Base64EncodedText, CommunicationChannel}; - use crate::CoreResult; + use crate::node::common::model::crypto::{AeadAuthData, AeadCipherText, AeadPlainText, CommunicationChannel}; #[test] fn single_person_encryption() -> CoreResult<()> { @@ -192,7 +198,7 @@ pub mod test { let plain_text = alice_km.transport_key_pair.decrypt(&cipher_text)?; assert_eq!( - Base64EncodedText::from(password.as_bytes()).base64_text, + Base64Text::from(password.as_bytes()).base64_text, plain_text.msg.base64_text ); @@ -205,20 +211,26 @@ pub mod test { let bob_km = KeyManager::generate(); let channel = CommunicationChannel { - sender: Box::from(alice_km.transport_key_pair.public_key()), - receiver: Box::from(bob_km.transport_key_pair.public_key()), + sender: alice_km.transport_key_pair.public_key(), + receiver: bob_km.transport_key_pair.public_key(), }; - let nonce = Box::from(alice_km.transport_key_pair.generate_nonce()); - let auth_data = AeadAuthData { - associated_data: "checksum".to_string(), - channel: Box::from(channel), - nonce, - }; - let plain_text = AeadPlainText { - msg: Box::from(Base64EncodedText::from("t0p$3cr3t")), - auth_data: Box::from(auth_data), + + let plain_text = { + let nonce = alice_km.transport_key_pair.generate_nonce(); + + let auth_data = AeadAuthData { + associated_data: "checksum".to_string(), + channel, + nonce, + }; + + AeadPlainText { + msg: Base64Text::from("t0p$3cr3t"), + auth_data, + } }; - let cipher_text: AeadCipherText = alice_km.transport_key_pair.encrypt(&plain_text)?; + + let cipher_text = alice_km.transport_key_pair.encrypt(&plain_text)?; let decrypted_text = bob_km.transport_key_pair.decrypt(&cipher_text)?; assert_eq!(plain_text, decrypted_text); @@ -228,11 +240,11 @@ pub mod test { let cipher_text = AeadCipherText { msg: cipher_text.msg, - auth_data: Box::from(AeadAuthData { + auth_data: AeadAuthData { associated_data: cipher_text.auth_data.associated_data, - channel: Box::from(cipher_text.auth_data.channel.inverse()), + channel: cipher_text.auth_data.channel.inverse(), nonce: cipher_text.auth_data.nonce, - }), + } }; let decrypted_text = bob_km.transport_key_pair.decrypt(&cipher_text)?; @@ -260,7 +272,7 @@ pub mod test { channel, } => { assert_eq!(key_manager_pk, bob_km.transport_key_pair.public_key()); - assert_eq!(channel, *cipher_text.auth_data.channel) + assert_eq!(channel, cipher_text.auth_data.channel) } _ => panic!("Critical error"), } diff --git a/core/src/crypto/keys.rs b/core/src/crypto/keys.rs index 8852dfb0..28fd028f 100644 --- a/core/src/crypto/keys.rs +++ b/core/src/crypto/keys.rs @@ -1,13 +1,50 @@ +use crate::crypto::encoding::base64::Base64Text; use crate::crypto::key_pair::{DsaKeyPair, KeyPair, TransportDsaKeyPair}; -use crate::models::{ - CommunicationChannel, DeviceInfo, MetaVault, SerializedKeyManager, UserSecurityBox, UserSignature, -}; pub struct KeyManager { pub dsa: DsaKeyPair, pub transport_key_pair: TransportDsaKeyPair, } +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct OpenBox { + pub dsa_pk: Base64Text, + pub transport_pk: Base64Text, +} + +/// Serializable version of KeyManager +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SecretBox { + pub dsa: SerializedDsaKeyPair, + pub transport: SerializedTransportKeyPair, +} + +impl From<&SecretBox> for OpenBox { + fn from(secret_box: &SecretBox) -> Self { + Self { + dsa_pk: secret_box.dsa.public_key.clone(), + transport_pk: secret_box.transport.public_key.clone(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SerializedDsaKeyPair { + pub key_pair: Base64Text, + pub public_key: Base64Text, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SerializedTransportKeyPair { + pub secret_key: Base64Text, + pub public_key: Base64Text, +} + + /// Key manager can be used only with a single vault name (in the future they will be independent entities) impl KeyManager { pub fn generate() -> KeyManager { @@ -17,38 +54,8 @@ impl KeyManager { } } - pub fn generate_security_box(vault_name: String) -> UserSecurityBox { + pub fn generate_secret_box() -> SecretBox { let key_manager = KeyManager::generate(); - - let signature = Box::from(key_manager.dsa.sign(vault_name.clone())); - UserSecurityBox { - vault_name, - signature, - key_manager: Box::from(SerializedKeyManager::from(&key_manager)), - } - } -} - -impl UserSecurityBox { - pub fn get_user_sig(&self, device: &DeviceInfo) -> UserSignature { - let key_manager: KeyManager = KeyManager::try_from(self.key_manager.as_ref()).unwrap(); - - UserSignature { - vault: Box::new(MetaVault { - name: self.vault_name.clone(), - device: Box::from(device.clone()), - }), - public_key: Box::from(key_manager.dsa.public_key()), - transport_public_key: Box::from(key_manager.transport_key_pair.public_key()), - } - } -} - -impl CommunicationChannel { - pub fn inverse(self) -> Self { - Self { - sender: self.receiver, - receiver: self.sender, - } + SecretBox::from(key_manager) } } diff --git a/core/src/crypto/utils.rs b/core/src/crypto/utils.rs index 4df73f9d..0120b578 100644 --- a/core/src/crypto/utils.rs +++ b/core/src/crypto/utils.rs @@ -2,7 +2,8 @@ use rand::{distributions::Alphanumeric, Rng}; use sha2::{Digest, Sha256}; use uuid::Uuid; -use crate::models::Base64EncodedText; +use crate::crypto::encoding::base64::Base64Text; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptorFqdn, ObjectDescriptorId}; const SEED_LENGTH: usize = 64; @@ -20,64 +21,41 @@ pub fn generate_hash() -> String { } /// Generate random uuid encoded with base64 url encoding -pub fn rand_uuid_b64_url_enc() -> Base64EncodedText { +pub fn rand_uuid_b64_url_enc() -> Base64Text { let uuid = Uuid::new_v4(); let uuid_bytes = uuid.as_bytes().as_slice(); - Base64EncodedText::from(uuid_bytes) + Base64Text::from(uuid_bytes) } -pub fn rand_64bit_b64_url_enc() -> Base64EncodedText { +pub fn rand_64bit_b64_url_enc() -> Base64Text { let uuid = Uuid::new_v4().as_u64_pair().0.to_le_bytes().to_vec(); - Base64EncodedText::from(uuid) + Base64Text::from(uuid) } pub fn generate_uuid_b64_url_enc(value: String) -> String { let hash = Sha256::digest(value.as_bytes()); let uuid = Uuid::from_slice(&hash.as_slice()[..16]).unwrap(); - Base64EncodedText::from(uuid.as_bytes().as_slice()).base64_text + Base64Text::from(uuid.as_bytes().as_slice()).base64_text } -/// Convert a string to a base64 url encoded uuid -pub fn to_id(str: &str) -> String { - //let hash = Sha256::digest(str.as_bytes()); - //let uuid = Uuid::from_slice(&hash.as_slice()[..16]).unwrap(); - //Base64EncodedText::from(uuid.as_bytes().as_slice()) - //Base64EncodedText::from(uuid.as_bytes().as_slice()) - let next = if str.contains("::") { - let parts: Vec<&str> = str.split("::").collect(); - let next_counter: usize = parts[1].parse().unwrap(); - format!("{}::{:?}", parts[0], next_counter + 1) - } else { - format!("{}::{}", str, 0) - }; - - //Base64EncodedText::from(next) - next +pub trait NextId { + fn next_id(self) -> ObjectDescriptorId; } -#[cfg(test)] -mod test { - use crate::crypto::utils::to_id; - - #[test] - fn to_id_test() { - //let id = to_id("yay"); - //let expected_uuid = uuid!("f6078ebe-0c2f-08c2-25c0-349aef2fe062").as_ref().as_bytes(); - //let expected_uuid = String::from_utf8(expected_uuid.to_vec()).unwrap(); - //let expected_uuid = Base64EncodedText::from(expected_uuid.as_ref()); - //assert_eq!(expected_uuid, id) +impl NextId for ObjectDescriptorFqdn { + fn next_id(self) -> ObjectDescriptorId { + ObjectDescriptorId { + fqdn: self.clone(), + id: 0, + } + } +} - let id_0 = to_id("qwe:qwe"); - println!("{}", id_0); - let id_0 = to_id(id_0.as_str()); - println!("{}", id_0); - let id_0 = to_id(id_0.as_str()); - println!("{}", id_0); - let id_0 = to_id(id_0.as_str()); - println!("{}", id_0); - let id_0 = to_id(id_0.as_str()); - println!("{}", id_0); - let id_0 = to_id(id_0.as_str()); - println!("{}", id_0); +impl NextId for ObjectDescriptorId { + fn next_id(self) -> ObjectDescriptorId { + ObjectDescriptorId { + id: self.id + 1, + ..self + } } } diff --git a/core/src/errors/mod.rs b/core/src/errors/mod.rs index af97d8a6..01bce16c 100644 --- a/core/src/errors/mod.rs +++ b/core/src/errors/mod.rs @@ -3,7 +3,8 @@ use std::string::FromUtf8Error; use shamirsecretsharing::SSSError; -use crate::models::{Base64EncodedText, CommunicationChannel}; +use crate::crypto::encoding::base64::Base64Text; +use crate::node::common::model::crypto::CommunicationChannel; use crate::secret::data_block::common::DataBlockParserError; #[derive(thiserror::Error, Debug)] @@ -46,7 +47,7 @@ pub enum CoreError { #[error("The key manager: {key_manager_pk:?} is not a component of the secure communication channel: {channel:?}")] ThirdPartyEncryptionError { - key_manager_pk: Base64EncodedText, + key_manager_pk: Base64Text, channel: CommunicationChannel, }, diff --git a/core/src/lib.rs b/core/src/lib.rs index 2f665ecf..f96b21cc 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -4,17 +4,17 @@ extern crate serde; extern crate serde_derive; extern crate serde_json; +use std::{fs, io}; use std::ffi::OsStr; use std::fs::File; use std::io::BufReader; use std::path::Path; -use std::{fs, io}; use image::ImageError; use rqrr::DeQRError; -use errors::RecoveryError::EmptyInput; use errors::{RecoveryError, SharesLoaderError, SplitError}; +use errors::RecoveryError::EmptyInput; use crate::errors::CoreError; use crate::secret::data_block::common::SharedSecretConfig; @@ -23,9 +23,7 @@ use crate::secret::shared_secret::{PlainText, SharedSecret, SharedSecretEncrypti pub mod crypto; pub mod errors; -pub mod models; pub mod node; -pub mod sdk; pub mod secret; pub type CoreResult = std::result::Result; diff --git a/core/src/models/aead_auth_data.rs b/core/src/models/aead_auth_data.rs deleted file mode 100644 index 65145a7d..00000000 --- a/core/src/models/aead_auth_data.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct AeadAuthData { - #[serde(rename = "associatedData")] - pub associated_data: String, - #[serde(rename = "channel")] - pub channel: Box, - #[serde(rename = "nonce")] - pub nonce: Box, -} - -impl AeadAuthData { - pub fn new( - associated_data: String, - channel: crate::models::CommunicationChannel, - nonce: crate::models::Base64EncodedText, - ) -> AeadAuthData { - AeadAuthData { - associated_data, - channel: Box::new(channel), - nonce: Box::new(nonce), - } - } -} diff --git a/core/src/models/aead_cipher_text.rs b/core/src/models/aead_cipher_text.rs deleted file mode 100644 index d7e90009..00000000 --- a/core/src/models/aead_cipher_text.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct AeadCipherText { - #[serde(rename = "msg")] - pub msg: Box, - #[serde(rename = "authData")] - pub auth_data: Box, -} - -impl AeadCipherText { - pub fn new(msg: crate::models::Base64EncodedText, auth_data: crate::models::AeadAuthData) -> AeadCipherText { - AeadCipherText { - msg: Box::new(msg), - auth_data: Box::new(auth_data), - } - } -} diff --git a/core/src/models/aead_plain_text.rs b/core/src/models/aead_plain_text.rs deleted file mode 100644 index 40c93191..00000000 --- a/core/src/models/aead_plain_text.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct AeadPlainText { - #[serde(rename = "msg")] - pub msg: Box, - #[serde(rename = "authData")] - pub auth_data: Box, -} - -impl AeadPlainText { - pub fn new(msg: crate::models::Base64EncodedText, auth_data: crate::models::AeadAuthData) -> AeadPlainText { - AeadPlainText { - msg: Box::new(msg), - auth_data: Box::new(auth_data), - } - } -} diff --git a/core/src/models/application_state.rs b/core/src/models/application_state.rs deleted file mode 100644 index 257eb575..00000000 --- a/core/src/models/application_state.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct ApplicationState { - #[serde(rename = "metaVault", skip_serializing_if = "Option::is_none")] - pub meta_vault: Option>, - #[serde(rename = "vault", skip_serializing_if = "Option::is_none")] - pub vault: Option>, - #[serde(rename = "metaPasswords")] - pub meta_passwords: Vec, - #[serde(rename = "joinComponent")] - pub join_component: bool, -} - -impl ApplicationState { - pub fn new(meta_passwords: Vec, join_component: bool) -> ApplicationState { - ApplicationState { - meta_vault: None, - vault: None, - meta_passwords, - join_component, - } - } -} diff --git a/core/src/models/base64_encoded_text.rs b/core/src/models/base64_encoded_text.rs deleted file mode 100644 index 5ed05559..00000000 --- a/core/src/models/base64_encoded_text.rs +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct Base64EncodedText { - #[serde(rename = "base64Text")] - pub base64_text: String, -} - -impl Base64EncodedText { - pub fn new(base64_text: String) -> Base64EncodedText { - Base64EncodedText { base64_text } - } -} diff --git a/core/src/models/communication_channel.rs b/core/src/models/communication_channel.rs deleted file mode 100644 index cdcbbcd2..00000000 --- a/core/src/models/communication_channel.rs +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// CommunicationChannel : Represents virtual encrypted communication channel between two points. - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct CommunicationChannel { - #[serde(rename = "sender")] - pub sender: Box, - #[serde(rename = "receiver")] - pub receiver: Box, -} - -impl CommunicationChannel { - /// Represents virtual encrypted communication channel between two points. - pub fn new( - sender: crate::models::Base64EncodedText, - receiver: crate::models::Base64EncodedText, - ) -> CommunicationChannel { - CommunicationChannel { - sender: Box::new(sender), - receiver: Box::new(receiver), - } - } -} diff --git a/core/src/models/device_info.rs b/core/src/models/device_info.rs deleted file mode 100644 index 2829d8ab..00000000 --- a/core/src/models/device_info.rs +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct DeviceInfo { - #[serde(rename = "deviceId")] - pub device_id: String, - #[serde(rename = "deviceName")] - pub device_name: String, -} - -impl DeviceInfo { - pub fn new(device_id: String, device_name: String) -> DeviceInfo { - DeviceInfo { device_id, device_name } - } -} diff --git a/core/src/models/encrypted_message.rs b/core/src/models/encrypted_message.rs deleted file mode 100644 index c3683854..00000000 --- a/core/src/models/encrypted_message.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct EncryptedMessage { - #[serde(rename = "receiver")] - pub receiver: Box, - #[serde(rename = "encryptedText")] - pub encrypted_text: Box, -} - -impl EncryptedMessage { - pub fn new( - receiver: crate::models::UserSignature, - encrypted_text: crate::models::AeadCipherText, - ) -> EncryptedMessage { - EncryptedMessage { - receiver: Box::new(receiver), - encrypted_text: Box::new(encrypted_text), - } - } -} diff --git a/core/src/models/find_shares_request.rs b/core/src/models/find_shares_request.rs deleted file mode 100644 index 712e0a4d..00000000 --- a/core/src/models/find_shares_request.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct FindSharesRequest { - #[serde(rename = "userRequestType")] - pub user_request_type: crate::models::SecretDistributionType, - #[serde(rename = "userSignature")] - pub user_signature: Box, -} - -impl FindSharesRequest { - pub fn new( - user_request_type: crate::models::SecretDistributionType, - user_signature: crate::models::UserSignature, - ) -> FindSharesRequest { - FindSharesRequest { - user_request_type, - user_signature: Box::new(user_signature), - } - } -} diff --git a/core/src/models/find_shares_result.rs b/core/src/models/find_shares_result.rs deleted file mode 100644 index 665eb475..00000000 --- a/core/src/models/find_shares_result.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct FindSharesResult { - #[serde(rename = "userRequestType")] - pub user_request_type: crate::models::SecretDistributionType, - #[serde(rename = "shares")] - pub shares: Vec, -} - -impl FindSharesResult { - pub fn new( - user_request_type: crate::models::SecretDistributionType, - shares: Vec, - ) -> FindSharesResult { - FindSharesResult { - user_request_type, - shares, - } - } -} diff --git a/core/src/models/join_request.rs b/core/src/models/join_request.rs deleted file mode 100644 index f41e5bdf..00000000 --- a/core/src/models/join_request.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct JoinRequest { - #[serde(rename = "member")] - pub member: Box, - #[serde(rename = "candidate")] - pub candidate: Box, -} - -impl JoinRequest { - pub fn new(member: crate::models::UserSignature, candidate: crate::models::UserSignature) -> JoinRequest { - JoinRequest { - member: Box::new(member), - candidate: Box::new(candidate), - } - } -} diff --git a/core/src/models/membership_request_type.rs b/core/src/models/membership_request_type.rs deleted file mode 100644 index 72f30173..00000000 --- a/core/src/models/membership_request_type.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum MembershipRequestType { - #[serde(rename = "Accept")] - Accept, - #[serde(rename = "Decline")] - Decline, -} - -impl ToString for MembershipRequestType { - fn to_string(&self) -> String { - match self { - Self::Accept => String::from("Accept"), - Self::Decline => String::from("Decline"), - } - } -} - -impl Default for MembershipRequestType { - fn default() -> MembershipRequestType { - Self::Accept - } -} diff --git a/core/src/models/membership_status.rs b/core/src/models/membership_status.rs deleted file mode 100644 index 02c3b106..00000000 --- a/core/src/models/membership_status.rs +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// MembershipStatus : `AlreadyMember`: Device is a member of a vault already. `Finished`: Operation finished successfully. - -/// `AlreadyMember`: Device is a member of a vault already. `Finished`: Operation finished successfully. -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum MembershipStatus { - #[serde(rename = "VaultNotFound")] - VaultNotFound, - #[serde(rename = "AlreadyMember")] - AlreadyMember, - #[serde(rename = "Finished")] - Finished, -} - -impl ToString for MembershipStatus { - fn to_string(&self) -> String { - match self { - Self::VaultNotFound => String::from("VaultNotFound"), - Self::AlreadyMember => String::from("AlreadyMember"), - Self::Finished => String::from("Finished"), - } - } -} - -impl Default for MembershipStatus { - fn default() -> MembershipStatus { - Self::VaultNotFound - } -} diff --git a/core/src/models/meta_password_doc.rs b/core/src/models/meta_password_doc.rs deleted file mode 100644 index 10775397..00000000 --- a/core/src/models/meta_password_doc.rs +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MetaPasswordDoc { - #[serde(rename = "id")] - pub id: Box, - #[serde(rename = "vault")] - pub vault: Box, -} - -impl MetaPasswordDoc { - pub fn new(id: crate::models::MetaPasswordId, vault: crate::models::VaultDoc) -> MetaPasswordDoc { - MetaPasswordDoc { - id: Box::new(id), - vault: Box::new(vault), - } - } -} diff --git a/core/src/models/meta_password_id.rs b/core/src/models/meta_password_id.rs deleted file mode 100644 index 66606f3e..00000000 --- a/core/src/models/meta_password_id.rs +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MetaPasswordId { - /// SHA256 hash of a salt - #[serde(rename = "id")] - pub id: String, - /// Random String up to 30 characters, must be unique - #[serde(rename = "salt")] - pub salt: String, - /// Human readable name given to the password - #[serde(rename = "name")] - pub name: String, -} - -impl MetaPasswordId { - pub fn new(id: String, salt: String, name: String) -> MetaPasswordId { - MetaPasswordId { id, salt, name } - } -} diff --git a/core/src/models/meta_password_request.rs b/core/src/models/meta_password_request.rs deleted file mode 100644 index 7761dec5..00000000 --- a/core/src/models/meta_password_request.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MetaPasswordRequest { - #[serde(rename = "userSig")] - pub user_sig: Box, - #[serde(rename = "metaPassword")] - pub meta_password: Box, -} - -impl MetaPasswordRequest { - pub fn new( - user_sig: crate::models::UserSignature, - meta_password: crate::models::MetaPasswordDoc, - ) -> MetaPasswordRequest { - MetaPasswordRequest { - user_sig: Box::new(user_sig), - meta_password: Box::new(meta_password), - } - } -} diff --git a/core/src/models/meta_passwords_data.rs b/core/src/models/meta_passwords_data.rs deleted file mode 100644 index 1f0d246a..00000000 --- a/core/src/models/meta_passwords_data.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MetaPasswordsData { - #[serde(rename = "passwordStatus")] - pub password_status: crate::models::MetaPasswordsStatus, - #[serde(rename = "passwords")] - pub passwords: Vec, -} - -impl MetaPasswordsData { - pub fn new( - password_status: crate::models::MetaPasswordsStatus, - passwords: Vec, - ) -> MetaPasswordsData { - MetaPasswordsData { - password_status, - passwords, - } - } -} diff --git a/core/src/models/meta_passwords_status.rs b/core/src/models/meta_passwords_status.rs deleted file mode 100644 index 5c48ce0a..00000000 --- a/core/src/models/meta_passwords_status.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum MetaPasswordsStatus { - #[serde(rename = "Ok")] - Ok, - #[serde(rename = "VaultNotFound")] - VaultNotFound, -} - -impl ToString for MetaPasswordsStatus { - fn to_string(&self) -> String { - match self { - Self::Ok => String::from("Ok"), - Self::VaultNotFound => String::from("VaultNotFound"), - } - } -} - -impl Default for MetaPasswordsStatus { - fn default() -> MetaPasswordsStatus { - Self::Ok - } -} diff --git a/core/src/models/meta_vault.rs b/core/src/models/meta_vault.rs deleted file mode 100644 index 6dda3d14..00000000 --- a/core/src/models/meta_vault.rs +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// MetaVault : It keeps the information about a vault. It's the origin of the objects generated to create a user vault and generate all necessary credentials and user signatures. MetaVault -> KeyManager -> UserSignature - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct MetaVault { - /// vault name - #[serde(rename = "name")] - pub name: String, - #[serde(rename = "device")] - pub device: Box, -} - -impl MetaVault { - /// It keeps the information about a vault. It's the origin of the objects generated to create a user vault and generate all necessary credentials and user signatures. MetaVault -> KeyManager -> UserSignature - pub fn new(name: String, device: crate::models::DeviceInfo) -> MetaVault { - MetaVault { - name, - device: Box::new(device), - } - } -} diff --git a/core/src/models/mod.rs b/core/src/models/mod.rs deleted file mode 100644 index fe3f4a48..00000000 --- a/core/src/models/mod.rs +++ /dev/null @@ -1,60 +0,0 @@ -pub mod aead_auth_data; -pub use self::aead_auth_data::AeadAuthData; -pub mod aead_cipher_text; -pub use self::aead_cipher_text::AeadCipherText; -pub mod aead_plain_text; -pub use self::aead_plain_text::AeadPlainText; -pub mod application_state; -pub use self::application_state::ApplicationState; -pub mod base64_encoded_text; -pub use self::base64_encoded_text::Base64EncodedText; -pub mod communication_channel; -pub use self::communication_channel::CommunicationChannel; -pub mod device_info; -pub use self::device_info::DeviceInfo; -pub mod encrypted_message; -pub use self::encrypted_message::EncryptedMessage; -pub mod find_shares_request; -pub use self::find_shares_request::FindSharesRequest; -pub mod find_shares_result; -pub use self::find_shares_result::FindSharesResult; -pub mod join_request; -pub use self::join_request::JoinRequest; -pub mod membership_request_type; -pub use self::membership_request_type::MembershipRequestType; -pub mod membership_status; -pub use self::membership_status::MembershipStatus; -pub mod meta_password_doc; -pub use self::meta_password_doc::MetaPasswordDoc; -pub mod meta_password_id; -pub use self::meta_password_id::MetaPasswordId; -pub mod meta_password_request; -pub use self::meta_password_request::MetaPasswordRequest; -pub mod meta_passwords_data; -pub use self::meta_passwords_data::MetaPasswordsData; -pub mod meta_passwords_status; -pub use self::meta_passwords_status::MetaPasswordsStatus; -pub mod meta_vault; -pub use self::meta_vault::MetaVault; -pub mod password_recovery_request; -pub use self::password_recovery_request::PasswordRecoveryRequest; -pub mod registration_status; -pub use self::registration_status::RegistrationStatus; -pub mod secret_distribution_doc_data; -pub use self::secret_distribution_doc_data::SecretDistributionDocData; -pub mod secret_distribution_type; -pub use self::secret_distribution_type::SecretDistributionType; -pub mod serialized_dsa_key_pair; -pub use self::serialized_dsa_key_pair::SerializedDsaKeyPair; -pub mod serialized_key_manager; -pub use self::serialized_key_manager::SerializedKeyManager; -pub mod serialized_transport_key_pair; -pub use self::serialized_transport_key_pair::SerializedTransportKeyPair; -pub mod user_credentials; -pub use self::user_credentials::UserCredentials; -pub mod user_security_box; -pub use self::user_security_box::UserSecurityBox; -pub mod user_signature; -pub use self::user_signature::UserSignature; -pub mod vault_doc; -pub use self::vault_doc::VaultDoc; diff --git a/core/src/models/password_recovery_request.rs b/core/src/models/password_recovery_request.rs deleted file mode 100644 index 4cb08a20..00000000 --- a/core/src/models/password_recovery_request.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct PasswordRecoveryRequest { - #[serde(rename = "id")] - pub id: Box, - #[serde(rename = "consumer")] - pub consumer: Box, - #[serde(rename = "provider")] - pub provider: Box, -} - -impl PasswordRecoveryRequest { - pub fn new( - id: crate::models::MetaPasswordId, - consumer: crate::models::UserSignature, - provider: crate::models::UserSignature, - ) -> PasswordRecoveryRequest { - PasswordRecoveryRequest { - id: Box::new(id), - consumer: Box::new(consumer), - provider: Box::new(provider), - } - } -} diff --git a/core/src/models/registration_status.rs b/core/src/models/registration_status.rs deleted file mode 100644 index 00295b8f..00000000 --- a/core/src/models/registration_status.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum RegistrationStatus { - #[serde(rename = "Registered")] - Registered, - #[serde(rename = "AlreadyExists")] - AlreadyExists, -} - -impl ToString for RegistrationStatus { - fn to_string(&self) -> String { - match self { - Self::Registered => String::from("Registered"), - Self::AlreadyExists => String::from("AlreadyExists"), - } - } -} - -impl Default for RegistrationStatus { - fn default() -> RegistrationStatus { - Self::Registered - } -} diff --git a/core/src/models/secret_distribution_doc_data.rs b/core/src/models/secret_distribution_doc_data.rs deleted file mode 100644 index 0986f618..00000000 --- a/core/src/models/secret_distribution_doc_data.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SecretDistributionDocData { - #[serde(rename = "distributionType")] - pub distribution_type: crate::models::SecretDistributionType, - #[serde(rename = "metaPassword")] - pub meta_password: Box, - #[serde(rename = "secretMessage")] - pub secret_message: Box, -} - -impl SecretDistributionDocData { - pub fn new( - distribution_type: crate::models::SecretDistributionType, - meta_password: crate::models::MetaPasswordRequest, - secret_message: crate::models::EncryptedMessage, - ) -> SecretDistributionDocData { - SecretDistributionDocData { - distribution_type, - meta_password: Box::new(meta_password), - secret_message: Box::new(secret_message), - } - } -} diff --git a/core/src/models/secret_distribution_type.rs b/core/src/models/secret_distribution_type.rs deleted file mode 100644 index 26487859..00000000 --- a/core/src/models/secret_distribution_type.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -/// -#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -pub enum SecretDistributionType { - #[serde(rename = "Split")] - Split, - #[serde(rename = "Recover")] - Recover, -} - -impl ToString for SecretDistributionType { - fn to_string(&self) -> String { - match self { - Self::Split => String::from("Split"), - Self::Recover => String::from("Recover"), - } - } -} - -impl Default for SecretDistributionType { - fn default() -> SecretDistributionType { - Self::Split - } -} diff --git a/core/src/models/serialized_dsa_key_pair.rs b/core/src/models/serialized_dsa_key_pair.rs deleted file mode 100644 index a2f633e4..00000000 --- a/core/src/models/serialized_dsa_key_pair.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SerializedDsaKeyPair { - #[serde(rename = "keyPair")] - pub key_pair: Box, - #[serde(rename = "publicKey")] - pub public_key: Box, -} - -impl SerializedDsaKeyPair { - pub fn new( - key_pair: crate::models::Base64EncodedText, - public_key: crate::models::Base64EncodedText, - ) -> SerializedDsaKeyPair { - SerializedDsaKeyPair { - key_pair: Box::new(key_pair), - public_key: Box::new(public_key), - } - } -} diff --git a/core/src/models/serialized_key_manager.rs b/core/src/models/serialized_key_manager.rs deleted file mode 100644 index f6e8e9b9..00000000 --- a/core/src/models/serialized_key_manager.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SerializedKeyManager { - #[serde(rename = "dsa")] - pub dsa: Box, - #[serde(rename = "transport")] - pub transport: Box, -} - -impl SerializedKeyManager { - pub fn new( - dsa: crate::models::SerializedDsaKeyPair, - transport: crate::models::SerializedTransportKeyPair, - ) -> SerializedKeyManager { - SerializedKeyManager { - dsa: Box::new(dsa), - transport: Box::new(transport), - } - } -} diff --git a/core/src/models/serialized_transport_key_pair.rs b/core/src/models/serialized_transport_key_pair.rs deleted file mode 100644 index c331d1d4..00000000 --- a/core/src/models/serialized_transport_key_pair.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SerializedTransportKeyPair { - #[serde(rename = "secretKey")] - pub secret_key: Box, - #[serde(rename = "publicKey")] - pub public_key: Box, -} - -impl SerializedTransportKeyPair { - pub fn new( - secret_key: crate::models::Base64EncodedText, - public_key: crate::models::Base64EncodedText, - ) -> SerializedTransportKeyPair { - SerializedTransportKeyPair { - secret_key: Box::new(secret_key), - public_key: Box::new(public_key), - } - } -} diff --git a/core/src/models/user_credentials.rs b/core/src/models/user_credentials.rs deleted file mode 100644 index 3df347b1..00000000 --- a/core/src/models/user_credentials.rs +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct UserCredentials { - #[serde(rename = "securityBox")] - pub security_box: Box, - #[serde(rename = "userSig")] - pub user_sig: Box, -} - -impl UserCredentials { - pub fn new( - security_box: crate::models::UserSecurityBox, - user_sig: crate::models::UserSignature, - ) -> UserCredentials { - UserCredentials { - security_box: Box::new(security_box), - user_sig: Box::new(user_sig), - } - } -} diff --git a/core/src/models/user_security_box.rs b/core/src/models/user_security_box.rs deleted file mode 100644 index 721faa81..00000000 --- a/core/src/models/user_security_box.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct UserSecurityBox { - #[serde(rename = "vaultName")] - pub vault_name: String, - #[serde(rename = "signature")] - pub signature: Box, - #[serde(rename = "keyManager")] - pub key_manager: Box, -} - -impl UserSecurityBox { - pub fn new( - vault_name: String, - signature: crate::models::Base64EncodedText, - key_manager: crate::models::SerializedKeyManager, - ) -> UserSecurityBox { - UserSecurityBox { - vault_name, - signature: Box::new(signature), - key_manager: Box::new(key_manager), - } - } -} diff --git a/core/src/models/user_signature.rs b/core/src/models/user_signature.rs deleted file mode 100644 index 089a7e98..00000000 --- a/core/src/models/user_signature.rs +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct UserSignature { - #[serde(rename = "vault")] - pub vault: Box, - #[serde(rename = "publicKey")] - pub public_key: Box, - #[serde(rename = "transportPublicKey")] - pub transport_public_key: Box, -} - -impl UserSignature { - pub fn new( - vault: crate::models::MetaVault, - public_key: crate::models::Base64EncodedText, - transport_public_key: crate::models::Base64EncodedText, - ) -> UserSignature { - UserSignature { - vault: Box::new(vault), - public_key: Box::new(public_key), - transport_public_key: Box::new(transport_public_key), - } - } -} diff --git a/core/src/models/vault_doc.rs b/core/src/models/vault_doc.rs deleted file mode 100644 index d6bd1263..00000000 --- a/core/src/models/vault_doc.rs +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Meta Secret Core Models - * - * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) - * - * The version of the OpenAPI document: 1.0.0 - * - * Generated by: https://openapi-generator.tech - */ - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct VaultDoc { - #[serde(rename = "vaultName")] - pub vault_name: String, - #[serde(rename = "signatures")] - pub signatures: Vec, - #[serde(rename = "pendingJoins")] - pub pending_joins: Vec, - #[serde(rename = "declinedJoins")] - pub declined_joins: Vec, -} - -impl VaultDoc { - pub fn new( - vault_name: String, - signatures: Vec, - pending_joins: Vec, - declined_joins: Vec, - ) -> VaultDoc { - VaultDoc { - vault_name, - signatures, - pending_joins, - declined_joins, - } - } -} diff --git a/core/src/node/app/app_state_update_manager.rs b/core/src/node/app/app_state_update_manager.rs index c2e32ecc..6911a833 100644 --- a/core/src/node/app/app_state_update_manager.rs +++ b/core/src/node/app/app_state_update_manager.rs @@ -1,9 +1,11 @@ -use crate::models::ApplicationState; -use crate::node::db::generic_db::KvLogEventRepo; -use async_trait::async_trait; -use log::debug; use std::sync::Arc; +use async_trait::async_trait; +use tracing::debug; + +use crate::node::common::model::ApplicationState; +use crate::node::db::repo::generic_db::KvLogEventRepo; + #[async_trait(? Send)] pub trait JsAppStateManager { async fn update_js_state(&self, new_state: ApplicationState); diff --git a/core/src/node/app/client_meta_app.rs b/core/src/node/app/client_meta_app.rs deleted file mode 100644 index 76776a08..00000000 --- a/core/src/node/app/client_meta_app.rs +++ /dev/null @@ -1,230 +0,0 @@ -use std::sync::Arc; - -use anyhow::anyhow; -use log::error; -use tracing::{debug, info, instrument, Instrument}; - -use crate::crypto::keys::KeyManager; -use crate::models::{MetaVault, UserCredentials}; -use crate::node::app::meta_app::app_state::{ConfiguredAppState, GenericAppState, JoinedAppState}; -use crate::node::app::meta_vault_manager::{MetaVaultManager, UserCredentialsManager}; -use crate::node::db::actions::sign_up::SignUpRequest; -use crate::node::db::events::common::{MemPoolObject, VaultInfo}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::meta_db_service::MetaDbServiceProxy; -use crate::node::db::objects::persistent_object::PersistentObject; -use crate::secret::MetaDistributor; - -pub struct MetaClient { - pub persistent_obj: Arc>, - pub meta_db_service_proxy: Arc, -} - -impl MetaClient { - pub async fn find_user_creds(&self, curr_state: &GenericAppState) -> anyhow::Result> { - let maybe_creds = self.persistent_obj.repo.find_user_creds().in_current_span().await?; - - match maybe_creds { - None => Ok(None), - Some(creds) => Ok(Some(ConfiguredAppState { - app_state: curr_state.get_state(), - creds, - })), - } - } - - #[instrument(skip_all)] - pub async fn get_or_create_local_vault( - &self, - vault_name: &str, - device_name: &str, - ) -> anyhow::Result { - let meta_vault = self - .create_meta_vault(vault_name, device_name) - .in_current_span() - .await?; - let creds = self.generate_user_credentials(meta_vault).in_current_span().await?; - Ok(creds) - } - - async fn create_meta_vault(&self, vault_name: &str, device_name: &str) -> anyhow::Result { - info!("Create a meta vault"); - - let maybe_meta_vault = self.persistent_obj.repo.find_meta_vault().await?; - - match maybe_meta_vault { - None => { - self.persistent_obj - .repo - .create_meta_vault(vault_name.to_string(), device_name.to_string()) - .await - } - Some(meta_vault) => { - if meta_vault.name != vault_name || meta_vault.device.device_name != device_name { - Err(anyhow!("Another meta vault already exists in the database")) - } else { - Ok(meta_vault) - } - } - } - } - - #[instrument(skip(self))] - async fn generate_user_credentials(&self, meta_vault: MetaVault) -> anyhow::Result { - info!("generate_user_credentials: generate a new security box"); - - let maybe_creds = self.persistent_obj.repo.find_user_creds().in_current_span().await?; - - match maybe_creds { - None => { - let security_box = KeyManager::generate_security_box(meta_vault.name); - let user_sig = security_box.get_user_sig(&meta_vault.device); - let creds = UserCredentials::new(security_box, user_sig); - self.persistent_obj.repo.save_user_creds(&creds).await?; - - info!( - "User creds has been generated. Pk: {}", - creds.user_sig.public_key.base64_text - ); - Ok(creds) - } - Some(creds) => Ok(creds), - } - } -} - -impl MetaClient { - #[instrument(skip_all)] - pub async fn sign_up(&self, curr_state: &ConfiguredAppState) -> JoinedAppState { - let join = curr_state.app_state.join_component; - - if join { - //TODO we need to know if the user in pending state (waiting for approval) - info!("Join to cluster: {:?}", curr_state.creds.user_sig.vault.name.clone()); - self.join_cluster(curr_state.clone()).in_current_span().await; - } else { - let vault_info = self.get_vault(curr_state.creds.user_sig.vault.name.clone()).await; - self.sign_up_action(&vault_info, curr_state).await; - } - - let mut updated_app_state = curr_state.app_state.clone(); - - let vault_info = self.get_vault(curr_state.creds.user_sig.vault.name.clone()).await; - if let VaultInfo::Member { vault } = &vault_info { - updated_app_state.vault = Some(Box::new(vault.clone())) - } - - JoinedAppState { - app_state: updated_app_state, - creds: curr_state.creds.clone(), - vault_info, - } - } - - async fn join_cluster(&self, curr_state: ConfiguredAppState) { - info!("Registration: Join cluster"); - - let mem_pool_tail_id = self - .persistent_obj - .find_tail_id_by_obj_desc(&ObjectDescriptor::MemPool) - .await - .unwrap_or(ObjectId::mempool_unit()); - - let join_request = GenericKvLogEvent::MemPool(MemPoolObject::JoinRequest { - event: KvLogEvent { - key: KvKey { - obj_id: mem_pool_tail_id, - obj_desc: ObjectDescriptor::MemPool, - }, - value: curr_state.creds.user_sig.as_ref().clone(), - }, - }); - - let _ = self.persistent_obj.repo.save_event(join_request).await; - } - - #[instrument(skip_all)] - async fn sign_up_action(&self, vault_info: &VaultInfo, curr_state: &ConfiguredAppState) { - match vault_info { - VaultInfo::Member { .. } => { - info!("The client is already signed up") - } - VaultInfo::Pending => { - info!("Pending is not expected here"); - } - VaultInfo::Declined => { - info!("Declined - is not expected here"); - } - VaultInfo::NotFound => { - info!("Register a new vault: {:?}", curr_state.creds.user_sig.vault); - - let reg_res = self.register(&curr_state.creds).in_current_span().await; - - match reg_res { - Ok(vault_info) => { - info!("Successful registration, vault: {:?}", vault_info); - } - Err(err) => { - error!("Error. Registration failed: {:?}", err); - } - } - } - VaultInfo::NotMember => { - panic!("Invalid state: sign_up action. The client is not a member of a vault.") - } - } - } - - #[instrument(skip_all)] - async fn register(&self, creds: &UserCredentials) -> anyhow::Result { - info!("Register. Sign up"); - - let sign_up_request_factory = SignUpRequest {}; - let sign_up_request = sign_up_request_factory.generic_request(&creds.user_sig); - - self.persistent_obj - .repo - .save_event(sign_up_request) - .in_current_span() - .await?; - - Ok(VaultInfo::Pending) - } - - #[instrument(skip_all)] - pub async fn get_vault(&self, vault_name: String) -> VaultInfo { - debug!("Get vault"); - - self.meta_db_service_proxy - .get_vault_info(vault_name) - .in_current_span() - .await - .unwrap() - } -} - -impl MetaClient -where - Repo: KvLogEventRepo, -{ - pub async fn cluster_distribution(&self, pass_id: &str, pass: &str, app_state: &JoinedAppState) { - info!("Cluster distribution. App state: {:?}", app_state); - - if let VaultInfo::Member { vault } = &app_state.vault_info { - let distributor = MetaDistributor { - persistent_obj: self.persistent_obj.clone(), - vault: vault.clone(), - user_creds: Arc::new(app_state.creds.clone()), - }; - - distributor.distribute(pass_id.to_string(), pass.to_string()).await; - } else { - error!("Password distribution is not available. The user is not a member of the vault"); - panic!(); - } - } -} diff --git a/core/src/node/app/meta_app/app_state.rs b/core/src/node/app/meta_app/app_state.rs deleted file mode 100644 index fffce151..00000000 --- a/core/src/node/app/meta_app/app_state.rs +++ /dev/null @@ -1,56 +0,0 @@ -use crate::models::{ApplicationState, UserCredentials}; -use crate::node::db::events::common::VaultInfo; - -#[derive(Clone, Debug)] -pub enum GenericAppState { - Empty(EmptyAppState), - Configured(ConfiguredAppState), - Joined(JoinedAppState), -} - -impl GenericAppState { - pub fn get_state(&self) -> ApplicationState { - match self { - GenericAppState::Empty(EmptyAppState { app_state }) => app_state.clone(), - GenericAppState::Configured(ConfiguredAppState { app_state, .. }) => app_state.clone(), - GenericAppState::Joined(JoinedAppState { app_state, .. }) => app_state.clone(), - } - } -} - -impl GenericAppState { - pub fn empty() -> Self { - GenericAppState::Empty(EmptyAppState::default()) - } -} - -#[derive(Clone, Debug)] -pub struct EmptyAppState { - pub app_state: ApplicationState, -} - -impl Default for EmptyAppState { - fn default() -> Self { - EmptyAppState { - app_state: ApplicationState { - meta_vault: None, - vault: None, - meta_passwords: vec![], - join_component: false, - }, - } - } -} - -#[derive(Clone, Debug)] -pub struct ConfiguredAppState { - pub app_state: ApplicationState, - pub creds: UserCredentials, -} - -#[derive(Clone, Debug)] -pub struct JoinedAppState { - pub app_state: ApplicationState, - pub creds: UserCredentials, - pub vault_info: VaultInfo, -} diff --git a/core/src/node/app/meta_app/messaging.rs b/core/src/node/app/meta_app/messaging.rs index 61f2c1d6..279eb3fe 100644 --- a/core/src/node/app/meta_app/messaging.rs +++ b/core/src/node/app/meta_app/messaging.rs @@ -1,23 +1,11 @@ -use crate::models::MetaPasswordId; +use crate::node::common::model::secret::MetaPasswordId; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -#[serde(tag = "__app_state_request")] pub enum GenericAppStateRequest { - SignUp(SignUpRequest), - Recover(RecoveryRequest), + SignUp, ClusterDistribution(ClusterDistributionRequest), -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SignUpRequest { - pub vault_name: String, - pub device_name: String, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct RecoveryRequest { - pub meta_pass_id: MetaPasswordId, + Recover(MetaPasswordId), } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -27,4 +15,4 @@ pub struct ClusterDistributionRequest { } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum GenericAppStateResponse {} +pub enum GenericAppStateResponse {} \ No newline at end of file diff --git a/core/src/node/app/meta_app/meta_app_service.rs b/core/src/node/app/meta_app/meta_app_service.rs deleted file mode 100644 index f3428e0d..00000000 --- a/core/src/node/app/meta_app/meta_app_service.rs +++ /dev/null @@ -1,296 +0,0 @@ -use std::sync::Arc; - -use async_trait::async_trait; -use tracing::{error, info, instrument, Instrument}; - -use crate::models::{ApplicationState, UserCredentials}; -use crate::node::app::app_state_update_manager::JsAppStateManager; -use crate::node::app::client_meta_app::MetaClient; -use crate::node::app::meta_app::app_state::{ConfiguredAppState, EmptyAppState, GenericAppState, JoinedAppState}; -use crate::node::app::meta_app::messaging::{ - ClusterDistributionRequest, GenericAppStateRequest, GenericAppStateResponse, RecoveryRequest, SignUpRequest, -}; -use crate::node::app::sync_gateway::SyncGateway; -use crate::node::common::actor::{ActionHandler, ServiceState}; -use crate::node::common::data_transfer::MpscDataTransfer; -use crate::node::db::actions::recover::RecoveryAction; -use crate::node::db::events::common::VaultInfo; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::store::meta_pass_store::MetaPassStore; - -pub struct MetaClientService { - pub data_transfer: Arc, - pub meta_client: Arc>, - pub state_manager: Arc, - pub sync_gateway: Arc>, -} - -pub struct MetaClientDataTransfer { - pub dt: MpscDataTransfer, -} - -/// SignUp handler -#[async_trait(? Send)] -impl ActionHandler for MetaClientService -where - Repo: KvLogEventRepo, - StateManager: JsAppStateManager, -{ - #[instrument(skip_all)] - async fn handle(&self, request: SignUpRequest, state: &mut ServiceState) { - match &state.state { - GenericAppState::Empty(EmptyAppState { app_state }) => { - let creds_result = self - .meta_client - .get_or_create_local_vault(request.vault_name.as_str(), request.device_name.as_str()) - .in_current_span() - .await; - - self.sync_gateway.sync().in_current_span().await; - - if let Ok(creds) = creds_result { - let new_app_state = self.update_app_state(app_state, &creds).await; - - let new_generic_app_state = ConfiguredAppState { - app_state: new_app_state, - creds, - }; - - state.state = GenericAppState::Configured(new_generic_app_state); - } - } - GenericAppState::Configured(configured) => { - let joined_app_state = self.meta_client.sign_up(configured).in_current_span().await; - state.state = GenericAppState::Joined(joined_app_state); - } - GenericAppState::Joined(_) => { - error!("ignore sign up requests (device has been already joined"); - } - } - } -} - -impl MetaClientService -where - Repo: KvLogEventRepo, - StateManager: JsAppStateManager, -{ - async fn update_app_state(&self, app_state: &ApplicationState, creds: &UserCredentials) -> ApplicationState { - let mut new_app_state = app_state.clone(); - new_app_state.meta_vault = Some(creds.user_sig.vault.clone()); - - let vault_info = self - .meta_client - .get_vault(creds.user_sig.vault.name.clone()) - .in_current_span() - .await; - - match vault_info { - VaultInfo::Member { vault } => { - let vault_name = vault.vault_name.clone(); - - new_app_state.vault = Some(Box::new(vault)); - - let meta_pass_store = self - .meta_client - .meta_db_service_proxy - .get_meta_pass_store(vault_name) - .await - .unwrap(); - new_app_state.meta_passwords = meta_pass_store.passwords(); - } - VaultInfo::Pending => {} - VaultInfo::Declined => {} - VaultInfo::NotFound => {} - VaultInfo::NotMember => { - new_app_state.join_component = true; - } - } - - new_app_state - } -} - -#[async_trait(? Send)] -impl ActionHandler for MetaClientService -where - Repo: KvLogEventRepo, - - StateManager: JsAppStateManager, -{ - #[instrument(skip_all)] - async fn handle(&self, request: RecoveryRequest, state: &mut ServiceState) { - if let GenericAppState::Joined(app_state) = &state.state { - let recovery_action = RecoveryAction { - persistent_obj: self.meta_client.persistent_obj.clone(), - }; - recovery_action - .recovery_request(request.meta_pass_id, app_state) - .in_current_span() - .await; - } else { - panic!("Invalid request. Recovery request not allowed when the state is not 'Joined'"); - } - } -} - -#[async_trait(? Send)] -impl ActionHandler - for MetaClientService -where - Repo: KvLogEventRepo, - - StateManager: JsAppStateManager, -{ - #[instrument(skip_all)] - async fn handle(&self, request: ClusterDistributionRequest, state: &mut ServiceState) { - if let GenericAppState::Joined(app_state) = &state.state { - self.meta_client - .cluster_distribution(request.pass_id.as_str(), request.pass.as_str(), app_state) - .await; - - let passwords = { - let pass_store = self - .meta_client - .meta_db_service_proxy - .get_meta_pass_store(app_state.creds.user_sig.vault.name.clone()) - .await - .unwrap(); - match pass_store { - MetaPassStore::Store { passwords, .. } => passwords.clone(), - _ => { - vec![] - } - } - }; - - let mut app_state = state.state.get_state(); - app_state.meta_passwords.clear(); - app_state.meta_passwords = passwords; - } else { - panic!("Invalid request. Distribution request not allowed if the state is not 'Joined'") - } - } -} - -impl MetaClientService -where - Repo: KvLogEventRepo, - StateManager: JsAppStateManager, -{ - #[instrument(skip_all)] - pub async fn run(&self) { - info!("Run meta_app service"); - - let mut service_state = self.build_service_state().await; - - while let Ok(request) = self.data_transfer.dt.service_receive().await { - info!( - "Action execution. Request {:?}, state: {:?}", - &request, &service_state.state - ); - - self.sync_gateway.sync().in_current_span().await; - - match &mut service_state.state { - GenericAppState::Empty(_) => {} - GenericAppState::Configured(configured_app_state) => { - let new_app_state = self - .update_app_state(&configured_app_state.app_state, &configured_app_state.creds) - .await; - - configured_app_state.app_state = new_app_state; - } - GenericAppState::Joined(joined_app_state) => { - let new_app_state = self - .update_app_state(&joined_app_state.app_state, &joined_app_state.creds) - .await; - - joined_app_state.app_state = new_app_state; - joined_app_state.vault_info = self - .meta_client - .get_vault(joined_app_state.creds.user_sig.vault.name.clone()) - .await - } - } - - match request { - GenericAppStateRequest::SignUp(sign_up_request) => { - self.handle(sign_up_request, &mut service_state).await; - } - - GenericAppStateRequest::Recover(recovery_request) => { - self.handle(recovery_request, &mut service_state).await - } - - GenericAppStateRequest::ClusterDistribution(request) => { - self.handle(request, &mut service_state).await; - } - } - - self.on_update(&service_state.state.get_state()).await; - } - } - - async fn build_service_state(&self) -> ServiceState { - let mut service_state = ServiceState { - state: GenericAppState::empty(), - }; - - let maybe_configured_app_state = self.meta_client.find_user_creds(&service_state.state).await; - - let app_state = service_state.state.get_state(); - - if let Ok(Some(configured_app_state)) = maybe_configured_app_state { - let new_app_state = self.update_app_state(&app_state, &configured_app_state.creds).await; - - let vault_info = self - .meta_client - .get_vault(configured_app_state.creds.user_sig.vault.name.clone()) - .await; - - if let VaultInfo::Member { vault } = &vault_info { - let vault_name = vault.vault_name.clone(); - - service_state.state = GenericAppState::Joined(JoinedAppState { - app_state: new_app_state, - creds: configured_app_state.creds, - vault_info, - }); - - let meta_pass_store = self - .meta_client - .meta_db_service_proxy - .get_meta_pass_store(vault_name) - .await - .unwrap(); - - service_state.state.get_state().meta_passwords = meta_pass_store.passwords(); - } else { - service_state.state = GenericAppState::Configured(configured_app_state); - } - } - - self.on_update(&service_state.state.get_state()).await; - service_state - } - - pub async fn on_update(&self, app_state: &ApplicationState) { - // update app state in the external system (for instance, vue js) - self.state_manager.update_js_state(app_state.clone()).await - } - - pub async fn send_request(&self, request: GenericAppStateRequest) { - self.data_transfer.dt.send_to_service(request).await - } -} - -pub struct MetaClientAccessProxy { - pub dt: Arc, -} - -impl MetaClientAccessProxy { - pub async fn send_request(&self, request: GenericAppStateRequest) { - self.dt.dt.send_to_service(request).await - } -} diff --git a/core/src/node/app/meta_app/meta_client_service.rs b/core/src/node/app/meta_app/meta_client_service.rs new file mode 100644 index 00000000..9d0b57c6 --- /dev/null +++ b/core/src/node/app/meta_app/meta_client_service.rs @@ -0,0 +1,182 @@ +use std::sync::Arc; + +use anyhow::anyhow; +use tracing::{info, instrument}; + +use crate::node::app::app_state_update_manager::JsAppStateManager; +use crate::node::app::meta_app::messaging::{GenericAppStateRequest, GenericAppStateResponse}; +use crate::node::app::sync_gateway::SyncGateway; +use crate::node::common::actor::ServiceState; +use crate::node::common::data_transfer::MpscDataTransfer; +use crate::node::common::model::ApplicationState; +use crate::node::common::model::user::UserDataOutsiderStatus; +use crate::node::common::model::vault::VaultStatus; +use crate::node::db::actions::recover::RecoveryAction; +use crate::node::db::events::local::CredentialsObject; +use crate::node::db::objects::device_log::PersistentDeviceLog; +use crate::node::db::objects::shared_secret::PersistentSharedSecret; +use crate::node::db::objects::vault::PersistentVault; +use crate::node::db::repo::credentials_repo::CredentialsRepo; +use crate::node::db::repo::generic_db::KvLogEventRepo; +use crate::secret::MetaDistributor; + +pub struct MetaClientService { + pub data_transfer: Arc, + pub state_manager: Arc, + pub sync_gateway: Arc>, +} + +pub struct MetaClientDataTransfer { + pub dt: MpscDataTransfer, +} + +impl MetaClientService + where + Repo: KvLogEventRepo, + StateManager: JsAppStateManager +{ + #[instrument(skip_all)] + pub async fn run(&self) -> anyhow::Result<()> { + info!("Run meta_app service"); + + let mut service_state = self.build_service_state().await?; + + while let Ok(request) = self.data_transfer.dt.service_receive().await { + info!( + "Action execution. Request {:?}, state: {:?}", + &request, &service_state.state + ); + + self.sync_gateway.sync().await?; + + match request { + GenericAppStateRequest::SignUp => { + let vault_status = self.sign_up().await?; + service_state.state.vault = Some(vault_status); + } + + GenericAppStateRequest::ClusterDistribution(request) => { + let creds_repo = CredentialsRepo { + p_obj: self.sync_gateway.persistent_object.clone() + }; + + let user_creds = creds_repo.get_user_creds().await?; + + let vault_repo = PersistentVault { + p_obj: self.sync_gateway.persistent_object.clone() + }; + let vault = vault_repo.get_vault().await?; + + let distributor = MetaDistributor { + persistent_obj: self.sync_gateway.persistent_object.clone(), + vault, + user_creds: Arc::new(user_creds), + }; + + distributor.distribute(request.pass_id, request.pass).await?; + } + + GenericAppStateRequest::Recover(meta_pass_id) => { + let recovery_action = RecoveryAction { + persistent_obj: self.sync_gateway.persistent_object.clone(), + }; + recovery_action + .recovery_request(meta_pass_id, &service_state.state) + .await?; + } + } + + self.on_update(&service_state.state).await; + } + + Ok(()) + } + + async fn build_service_state(&self) -> anyhow::Result> { + let mut service_state = ServiceState { + state: ApplicationState::default() + }; + + let maybe_creds_event = { + let creds_repo = CredentialsRepo { + p_obj: self.sync_gateway.persistent_object.clone(), + }; + creds_repo.find().await? + }; + + service_state.state.device = maybe_creds_event.map(|creds| creds.device()); + + self.on_update(&service_state.state).await; + Ok(service_state) + } + + pub async fn on_update(&self, app_state: &ApplicationState) { + // update app state in the external system (for instance, vue js) + self.state_manager.update_js_state(app_state.clone()).await + } + + pub async fn send_request(&self, request: GenericAppStateRequest) { + self.data_transfer.dt.send_to_service(request).await + } + + async fn sign_up(&self) -> anyhow::Result { + let creds = { + let creds_repo = CredentialsRepo { + p_obj: self.sync_gateway.persistent_object.clone(), + }; + creds_repo.get().await? + }; + + match creds { + CredentialsObject::Device { .. } => { + Err(anyhow!("User credentials not found")) + } + CredentialsObject::DefaultUser(event) => { + let user = event.value.user(); + + //get vault status, if not member, then create request to join + let p_vault = PersistentVault { + p_obj: self.sync_gateway.persistent_object.clone(), + }; + + let vault_status = p_vault + .find(user.clone()) + .await?; + + if let VaultStatus::Outsider(outsider) = vault_status { + if let UserDataOutsiderStatus::Unknown = outsider.status { + let p_device_log = PersistentDeviceLog { + p_obj: self.sync_gateway.persistent_object.clone(), + }; + + p_device_log + .accept_join_cluster_request(user.clone()) + .await?; + + //Init SSDeviceLog + let p_ss_device_log = PersistentSharedSecret { + p_obj: self.sync_gateway.persistent_object.clone(), + }; + + p_ss_device_log.init(user.clone()).await?; + + self.sync_gateway.sync().await?; + } + } + + let vault_status = p_vault.find(user).await?; + Ok(vault_status) + } + } + } +} + +pub struct MetaClientAccessProxy { + pub dt: Arc, +} + +impl MetaClientAccessProxy { + pub async fn send_request(&self, request: GenericAppStateRequest) { + self.dt.dt.send_to_service(request).await + } +} diff --git a/core/src/node/app/meta_app/mod.rs b/core/src/node/app/meta_app/mod.rs index 7f1ed202..ebc78064 100644 --- a/core/src/node/app/meta_app/mod.rs +++ b/core/src/node/app/meta_app/mod.rs @@ -1,3 +1,2 @@ -pub mod app_state; pub mod messaging; -pub mod meta_app_service; +pub mod meta_client_service; diff --git a/core/src/node/app/meta_vault_manager.rs b/core/src/node/app/meta_vault_manager.rs deleted file mode 100644 index 19e98de9..00000000 --- a/core/src/node/app/meta_vault_manager.rs +++ /dev/null @@ -1,124 +0,0 @@ -use async_trait::async_trait; -use tracing::{instrument, Instrument}; - -use crate::crypto::keys::KeyManager; -use crate::models::meta_vault::MetaVault; -use crate::models::user_credentials::UserCredentials; -use crate::models::DeviceInfo; -use crate::node::db::events::common::ObjectCreator; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::local::KvLogEventLocal; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::generic_db::KvLogEventRepo; - -#[async_trait(? Send)] -pub trait MetaVaultManager { - async fn create_meta_vault(&self, vault_name: String, device_name: String) -> anyhow::Result; - async fn find_meta_vault(&self) -> anyhow::Result>; -} - -#[async_trait(? Send)] -impl MetaVaultManager for T -where - T: KvLogEventRepo, -{ - async fn create_meta_vault(&self, vault_name: String, device_name: String) -> anyhow::Result { - let meta_vault = MetaVault { - name: vault_name.to_string(), - device: Box::new(DeviceInfo::from(device_name.to_string())), - }; - - let key = KvKey::unit(&ObjectDescriptor::MetaVault); - let event: KvLogEvent = KvLogEvent { - key, - value: meta_vault.clone(), - }; - - let db_event = GenericKvLogEvent::LocalEvent(KvLogEventLocal::MetaVault { event: Box::new(event) }); - - self.save(ObjectId::meta_vault_index(), db_event).await?; - - Ok(meta_vault) - } - - async fn find_meta_vault(&self) -> anyhow::Result> { - let maybe_meta_vault = self.find_one(ObjectId::meta_vault_index()).await?; - - match maybe_meta_vault { - None => Ok(None), - Some(meta_vault) => match meta_vault { - GenericKvLogEvent::LocalEvent(KvLogEventLocal::MetaVault { event }) => Ok(Some(event.value)), - - _ => { - let err_msg = "Meta vault index: Invalid data"; - panic!("{}", err_msg) - } - }, - } - } -} - -#[async_trait(? Send)] -pub trait UserCredentialsManager: KvLogEventRepo { - async fn save_user_creds(&self, creds: &UserCredentials) -> anyhow::Result; - async fn find_user_creds(&self) -> anyhow::Result>; - async fn generate_user_creds(&self, vault_name: String, device_name: String) -> UserCredentials; - async fn get_or_generate_user_creds(&self, vault_name: String, device_name: String) -> UserCredentials; -} - -#[async_trait(? Send)] -impl UserCredentialsManager for T -where - T: KvLogEventRepo, -{ - async fn save_user_creds(&self, creds: &UserCredentials) -> anyhow::Result { - let event = KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::UserCreds), - value: creds.clone(), - }; - let generic_event = GenericKvLogEvent::LocalEvent(KvLogEventLocal::UserCredentials { event: Box::new(event) }); - - self.save_event(generic_event).await - } - - #[instrument(skip_all)] - async fn find_user_creds(&self) -> anyhow::Result> { - let obj_id = ObjectId::unit(&ObjectDescriptor::UserCreds); - let maybe_creds = self.find_one(obj_id).in_current_span().await?; - match maybe_creds { - None => Ok(None), - Some(user_creds) => match user_creds { - GenericKvLogEvent::LocalEvent(KvLogEventLocal::UserCredentials { event }) => Ok(Some(event.value)), - _ => { - panic!("Meta vault index: Invalid data") - } - }, - } - } - - async fn generate_user_creds(&self, vault_name: String, device_name: String) -> UserCredentials { - let meta_vault = self.create_meta_vault(vault_name, device_name).await.unwrap(); - - let security_box = KeyManager::generate_security_box(meta_vault.name); - let user_sig = security_box.get_user_sig(&meta_vault.device); - let creds = UserCredentials::new(security_box, user_sig); - - self.save_user_creds(&creds).await.unwrap(); - - creds - } - - async fn get_or_generate_user_creds(&self, vault_name: String, device_name: String) -> UserCredentials { - let server_creds_result = self.find_user_creds().await; - - match server_creds_result { - Ok(maybe_creds) => match maybe_creds { - None => self.generate_user_creds(vault_name, device_name).await, - Some(creds) => creds, - }, - Err(_) => self.generate_user_creds(vault_name, device_name).await, - } - } -} diff --git a/core/src/node/app/mod.rs b/core/src/node/app/mod.rs index a193b7c6..28a82da7 100644 --- a/core/src/node/app/mod.rs +++ b/core/src/node/app/mod.rs @@ -1,6 +1,4 @@ pub mod app_state_update_manager; -pub mod client_meta_app; pub mod meta_app; -pub mod meta_vault_manager; pub mod sync_gateway; pub mod virtual_device; diff --git a/core/src/node/app/sync_gateway.rs b/core/src/node/app/sync_gateway.rs index 14c098b2..cc72ca6d 100644 --- a/core/src/node/app/sync_gateway.rs +++ b/core/src/node/app/sync_gateway.rs @@ -1,31 +1,34 @@ use std::sync::Arc; use std::time::Duration; -use tracing::{debug, error, info, instrument, Instrument}; - -use crate::models::UserCredentials; -use crate::node::app::meta_vault_manager::UserCredentialsManager; -use crate::node::db::events::common::{LogEventKeyBasedRecord, ObjectCreator, SharedSecretObject}; -use crate::node::db::events::db_tail::{DbTail, DbTailObject}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use anyhow::anyhow; +use tracing::{debug, error, info, instrument}; + +use crate::node::common::model::device::{DeviceData, DeviceLinkBuilder}; +use crate::node::common::model::user::{UserCredentials, UserDataMember}; +use crate::node::common::model::vault::VaultStatus; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptor, ToObjectDescriptor}; +use crate::node::db::descriptors::shared_secret::{SharedSecretDescriptor, SharedSecretEventId}; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::db_tail::DbTail; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, KeyExtractor, ToGenericEvent}; +use crate::node::db::events::global_index::GlobalIndexObject; use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::local::KvLogEventLocal; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, ObjectId}; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::meta_db_service::MetaDbServiceProxy; -use crate::node::db::meta_db::store::vault_store::VaultStore; +use crate::node::db::events::local::{CredentialsObject, DbTailObject}; +use crate::node::db::events::vault_event::VaultMembershipObject; use crate::node::db::objects::persistent_object::PersistentObject; -use crate::node::server::data_sync::DataSyncMessage; -use crate::node::server::request::SyncRequest; +use crate::node::db::objects::vault::PersistentVault; +use crate::node::db::repo::credentials_repo::CredentialsRepo; +use crate::node::db::repo::generic_db::KvLogEventRepo; +use crate::node::server::data_sync::DataSyncRequest; +use crate::node::server::request::{GlobalIndexRequest, SharedSecretRequest, SyncRequest, VaultRequest}; use crate::node::server::server_app::ServerDataTransfer; pub struct SyncGateway { pub id: String, - pub repo: Arc, pub persistent_object: Arc>, pub server_dt: Arc, - pub meta_db_service_proxy: Arc, } impl SyncGateway { @@ -34,300 +37,234 @@ impl SyncGateway { info!("Run sync gateway"); loop { - self.sync().in_current_span().await; + let result = self.sync().await; + if let Err(err) = result { + error!("Sync error: {:?}", err); + } async_std::task::sleep(Duration::from_millis(300)).await; } } - pub async fn sync(&self) { - let creds_result = self.repo.find_user_creds().in_current_span().await; + ///Levels of synchronization: + /// - global index, server PK - when user has no account + /// - vault, shared secret... - user has been registered, we can sync vault related events + #[instrument(skip_all)] + pub async fn sync(&self) -> anyhow::Result<()> { + let creds_repo = CredentialsRepo { + p_obj: self.persistent_object.clone() + }; - match creds_result { - Err(_) => { - debug!("Gw type: {:?}, Error. User credentials db error. Skip", self.id); - //skip - } + let maybe_creds_event = creds_repo.find().await?; - Ok(None) => { - debug!("Gw type: {:?}, Error. Empty user credentials. Skip", self.id); - //skip - } + let Some(creds_obj) = maybe_creds_event else { + return Ok(()); + }; - Ok(Some(client_creds)) => { - let vault_name = client_creds.user_sig.vault.name.as_str(); - let db_tail_result = self.persistent_object.get_db_tail(vault_name).in_current_span().await; + self.sync_global_index(creds_obj.device()).await?; - match db_tail_result { - Ok(db_tail) => { - let new_gi_tail = self.get_new_tail_for_global_index(&db_tail).in_current_span().await; + let CredentialsObject::DefaultUser(user_creds_event) = creds_obj else { + return Ok(()); + }; - let new_vault_tail_id = self.get_new_tail_for_an_obj(&db_tail.vault_id).in_current_span().await; + //Vault synchronization + let user_creds = user_creds_event.value; + let sender = user_creds.user(); - let new_meta_pass_tail_id = self - .get_new_tail_for_an_obj(&db_tail.meta_pass_id) - .in_current_span() - .await; + let vault_status_obj_desc = VaultDescriptor::VaultStatus(user_creds.user_id()) + .to_obj_desc(); - let new_mem_pool_tail_id = self.get_new_tail_for_mem_pool(&db_tail).in_current_span().await; + let maybe_vault_status = self + .persistent_object + .find_tail_event(vault_status_obj_desc) + .await?; - let new_audit_tail = self.sync_shared_secrets(vault_name, &client_creds, &db_tail).await; + let Some(vault_status_event) = maybe_vault_status else { + return Ok(()); + }; - let new_db_tail = DbTail { - vault_id: new_vault_tail_id, - meta_pass_id: new_meta_pass_tail_id, + let vault_status_object = VaultMembershipObject::try_from(vault_status_event)?; - maybe_global_index_id: new_gi_tail, - maybe_mem_pool_id: new_mem_pool_tail_id.clone(), - s_s_audit: new_audit_tail.clone(), - }; + if vault_status_object.is_not_member() { + return Ok(()); + }; - self.save_updated_db_tail(db_tail, new_db_tail.clone()) - .in_current_span() - .await; + // Local device has less events than the server + let sync_request = { + let vault_name = user_creds.vault_name.clone(); + + let vault_log_free_id = { + let obj_desc = VaultDescriptor::vault_log(vault_name.clone()); + self.persistent_object.find_free_id_by_obj_desc(obj_desc).await? + }; + + let vault_free_id = { + let obj_desc = VaultDescriptor::vault(vault_name.clone()); + self.persistent_object.find_free_id_by_obj_desc(obj_desc).await? + }; + + let vault_status_free_id = { + let obj_desc = VaultDescriptor::vault_status(user_creds.user_id()); + self.persistent_object.find_free_id_by_obj_desc(obj_desc).await? + }; + + SyncRequest::Vault(VaultRequest { + sender, + vault_log: vault_log_free_id, + vault: vault_free_id, + vault_status: vault_status_free_id, + }) + }; - let sync_request = { - let vault_id_request = match &new_db_tail.vault_id { - DbTailObject::Empty { unit_id } => unit_id.clone(), - DbTailObject::Id { tail_id } => tail_id.next(), - }; - - let meta_pass_id_request = match &new_db_tail.meta_pass_id { - DbTailObject::Empty { unit_id } => unit_id.clone(), - DbTailObject::Id { tail_id } => tail_id.next(), - }; - - SyncRequest { - sender: client_creds.user_sig.as_ref().clone(), - global_index: new_db_tail.maybe_global_index_id.clone().map(|gi| gi.next()), - vault_tail_id: Some(vault_id_request), - meta_pass_tail_id: Some(meta_pass_id_request), - s_s_audit: new_audit_tail.clone(), - } - }; - - let mut latest_gi = new_db_tail.maybe_global_index_id.clone(); - let mut latest_vault_id = new_db_tail.vault_id.clone(); - let mut latest_meta_pass_id = new_db_tail.meta_pass_id.clone(); - let mut latest_audit_tail = new_audit_tail.clone(); - - let new_server_events_res = self - .server_dt - .dt - .send_to_service_and_get(DataSyncMessage::SyncRequest(sync_request)) - .in_current_span() - .await; + let data_sync_response = self + .server_dt + .dt + .send_to_service_and_get(DataSyncRequest::SyncRequest(sync_request)) + .await?; - match new_server_events_res { - Ok(new_events) => { - debug!("id: {:?}. Sync gateway. New events: {:?}", self.id, new_events); - - for new_event in new_events { - let obj_id = self.repo.save_event(new_event.clone()).in_current_span().await; - let key = obj_id.unwrap(); - - match new_event { - GenericKvLogEvent::GlobalIndex(_) => latest_gi = Some(key), - GenericKvLogEvent::Vault(_) => { - latest_vault_id = DbTailObject::Id { tail_id: key.clone() } - } - GenericKvLogEvent::MetaPass(_) => { - latest_meta_pass_id = DbTailObject::Id { tail_id: key.clone() } - } - GenericKvLogEvent::SharedSecret(SharedSecretObject::Audit { event }) => { - latest_audit_tail = Some(event.value) - } - _ => { - //ignore any non global event - } - } - } - - let latest_db_tail = DbTail { - vault_id: latest_vault_id, - meta_pass_id: latest_meta_pass_id, - - maybe_global_index_id: latest_gi, - maybe_mem_pool_id: new_mem_pool_tail_id, - s_s_audit: latest_audit_tail, - }; - - self.save_updated_db_tail(new_db_tail.clone(), latest_db_tail).await - } - Err(_err) => { - error!("DataSync error. Error loading events"); - panic!("Error"); - } - } - } - Err(_) => { - error!("Error! Db tail not exists"); - panic!("Error"); - } - } - } + for new_event in data_sync_response.events { + debug!("id: {:?}. Sync gateway. New event: {:?}", self.id, new_event); + self.persistent_object.repo.save(new_event).await?; } - } - - pub async fn sync_shared_secrets( - &self, - vault_name: &str, - creds: &UserCredentials, - db_tail: &DbTail, - ) -> Option { - let vault_store = self - .meta_db_service_proxy - .get_vault_store(vault_name.to_string()) - .in_current_span() - .await - .unwrap(); - - if let VaultStore::Store { vault, .. } = vault_store { - let s_s_audit_tail = db_tail - .s_s_audit - .clone() - .map(|tail_id| tail_id.next()) - .unwrap_or(ObjectId::unit(&ObjectDescriptor::SharedSecretAudit { - vault_name: vault_name.to_string(), - })); - - let audit_events = self - .persistent_object - .find_object_events(&s_s_audit_tail) - .in_current_span() - .await; - - let user_pk = creds.user_sig.public_key.base64_text.clone(); - - for user_sig in &vault.signatures { - if user_pk == user_sig.public_key.base64_text.clone() { - continue; - } - let transfer = &self.server_dt.dt; + self.sync_shared_secrets(&user_creds).await?; - for audit_event in &audit_events { - if let GenericKvLogEvent::SharedSecret(SharedSecretObject::Audit { event }) = audit_event { - let ss_event_res = self.repo.find_one(event.value.clone()).await; + Ok(()) + } - let Ok(Some(ss_event)) = ss_event_res else { - panic!("Invalid event type: not an audit event"); - }; + async fn sync_global_index(&self, sender: DeviceData) -> anyhow::Result<()> { + //TODO optimization: read global index tail id from db_tail - let GenericKvLogEvent::SharedSecret(ss_obj) = &ss_event else { - panic!("Invalid event type: not shared secret"); - }; + let gi_free_id = { + let gi_desc = ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index); + self.persistent_object + .find_free_id_by_obj_desc(gi_desc) + .await? + }; - if let SharedSecretObject::Audit { .. } = ss_obj { - panic!("Audit log events not allowed"); - } + let sync_request = SyncRequest::GlobalIndex(GlobalIndexRequest { + sender, + global_index: gi_free_id, + }); - debug!("Send shared secret event to server: {:?}", event); - transfer - .send_to_service(DataSyncMessage::Event(ss_event.clone())) - .in_current_span() - .await; - } + let new_gi_events = self + .server_dt + .dt + .send_to_service_and_get(DataSyncRequest::SyncRequest(sync_request)) + .await?; + + for gi_event in new_gi_events.events { + if let GenericKvLogEvent::GlobalIndex(gi_obj) = &gi_event { + self.persistent_object.repo.save(gi_event.clone()).await?; + + // Update vault index according to global index + if let GlobalIndexObject::Update(upd_event) = gi_obj { + let vault_id = upd_event.value.clone(); + let vault_idx_evt = GlobalIndexObject::index_from_vault_id(vault_id).to_generic(); + self.persistent_object.repo.save(vault_idx_evt).await?; } + } else { + return Err(anyhow!("Invalid event: {:?}", gi_event.key().obj_desc())); } - - audit_events.last().map(|evt| evt.key().obj_id.clone()) - } else { - panic!("User is not a member of the vault"); } + Ok(()) } - async fn save_updated_db_tail(&self, db_tail: DbTail, new_db_tail: DbTail) { - if new_db_tail == db_tail { - return; - } - - //update db_tail - let new_db_tail_event = GenericKvLogEvent::LocalEvent(KvLogEventLocal::DbTail { - event: Box::new(KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::DbTail), - value: new_db_tail.clone(), - }), - }); + #[instrument(skip_all)] + async fn sync_shared_secrets(&self, creds: &UserCredentials) -> anyhow::Result<()> { + let p_vault = PersistentVault { + p_obj: self.persistent_object.clone(), + }; - let saved_event_res = self.repo.save_event(new_db_tail_event).await; + let vault_status = p_vault.find(creds.user()).await?; - match saved_event_res { - Ok(_) => debug!("New db tail saved"), - Err(_) => { - info!("Error saving db tail"); + match vault_status { + VaultStatus::Outsider(_) => { + return Ok(()); } - }; - } + VaultStatus::Member(vault) => { + for UserDataMember(member) in vault.members() { + + let ss_event_id = { + let device_link = DeviceLinkBuilder::new() + .sender(creds.device_creds.device.id.clone()) + .receiver(member.device.id.clone()) + .build()?; + + SharedSecretEventId { + vault_name: creds.vault_name.clone(), + device_link, + } + }; - async fn get_new_tail_for_an_obj(&self, db_tail_obj: &DbTailObject) -> DbTailObject { - match db_tail_obj { - DbTailObject::Empty { unit_id } => self - .persistent_object - .find_tail_id(unit_id.clone()) - .await - .map(|tail_id| DbTailObject::Id { tail_id }) - .unwrap_or(DbTailObject::Empty { - unit_id: unit_id.clone(), - }), - DbTailObject::Id { tail_id } => { - let tail_id_sync = match tail_id { - ObjectId::Unit { .. } => tail_id.clone(), - _ => tail_id.next(), - }; + let split_events = { + let split_obj_desc = SharedSecretDescriptor::Split(ss_event_id.clone()).to_obj_desc(); + self.persistent_object + .get_object_events_from_beginning(split_obj_desc) + .await? + }; - let obj_events = self.persistent_object.find_object_events(&tail_id_sync).await; - let last_vault_event = obj_events.last().cloned(); - - for client_event in obj_events { - debug!( - "Send event to server. May stuck if server won't response!!! : {:?}", - client_event - ); - self.server_dt - .dt - .send_to_service(DataSyncMessage::Event(client_event)) - .await; - } + for split_event in split_events { + self + .server_dt + .dt + .send_to_service(DataSyncRequest::Event(split_event)) + .await; + } - let new_tail_id = last_vault_event - .map(|event| event.key().obj_id.clone()) - .unwrap_or(tail_id.clone()); + let recover_events = { + let recover_obj_desc = ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Recover(ss_event_id)); + self.persistent_object + .get_object_events_from_beginning(recover_obj_desc) + .await? + }; + for recover_event in recover_events { + self.server_dt.dt + .send_to_service(DataSyncRequest::Event(recover_event)) + .await; + } + } - DbTailObject::Id { tail_id: new_tail_id } - } - } - } + let ss_sync_request = { + let ss_log_obj_desc = SharedSecretDescriptor::SSLog(creds.vault_name.clone()) + .to_obj_desc(); - async fn get_new_tail_for_global_index(&self, db_tail: &DbTail) -> Option { - let global_index = db_tail - .maybe_global_index_id - .clone() - .unwrap_or(ObjectId::global_index_unit()); + let ss_log_id = self.persistent_object + .find_free_id_by_obj_desc(ss_log_obj_desc) + .await?; - self.persistent_object.find_tail_id(global_index).await - } + SyncRequest::SharedSecret(SharedSecretRequest { + sender: creds.user(), + ss_log: ss_log_id, + }) + }; - async fn get_new_tail_for_mem_pool(&self, db_tail: &DbTail) -> Option { - let mem_pool_id = match db_tail.maybe_mem_pool_id.clone() { - None => ObjectId::mempool_unit(), - Some(obj_id) => obj_id.next(), - }; + let new_ss_log_events = self.server_dt.dt + .send_to_service_and_get(DataSyncRequest::SyncRequest(ss_sync_request)) + .await?; - let mem_pool_events = self.persistent_object.find_object_events(&mem_pool_id).await; - let last_pool_event = mem_pool_events.last().cloned(); + for new_ss_log_event in new_ss_log_events.events { + self.persistent_object.repo.save(new_ss_log_event).await?; + } - for client_event in mem_pool_events { - debug!("send mem pool request to server: {:?}", client_event); - self.server_dt - .dt - .send_to_service(DataSyncMessage::Event(client_event)) - .await; + Ok(()) + } } + } - match last_pool_event { - None => db_tail.maybe_mem_pool_id.clone(), - Some(event) => Some(event.key().obj_id.clone()), + #[instrument(skip_all)] + async fn save_updated_db_tail(&self, db_tail: DbTail, new_db_tail: DbTail) -> anyhow::Result<()> { + if new_db_tail == db_tail { + return Ok(()); } + + //update db_tail + let new_db_tail_event = DbTailObject(KvLogEvent { + key: KvKey::unit(ObjectDescriptor::DbTail), + value: new_db_tail.clone(), + }).to_generic(); + + self.persistent_object.repo.save(new_db_tail_event).await?; + Ok(()) } } diff --git a/core/src/node/app/virtual_device.rs b/core/src/node/app/virtual_device.rs index 5d9766d7..c141f202 100644 --- a/core/src/node/app/virtual_device.rs +++ b/core/src/node/app/virtual_device.rs @@ -1,26 +1,26 @@ use std::sync::Arc; -use crate::node::app::client_meta_app::MetaClient; -use crate::node::app::meta_app::messaging::{GenericAppStateRequest, SignUpRequest}; -use crate::node::app::meta_app::meta_app_service::MetaClientAccessProxy; -use crate::node::app::meta_vault_manager::UserCredentialsManager; +use serde::{Deserialize, Serialize}; +use tracing::{info, instrument}; + +use crate::node::app::meta_app::meta_client_service::MetaClientAccessProxy; use crate::node::app::sync_gateway::SyncGateway; -use crate::node::db::actions::join; -use crate::node::db::events::common::VaultInfo; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::vault_event::VaultObject; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::meta_db_service::MetaDbServiceProxy; -use crate::node::db::meta_db::store::vault_store::VaultStore; +use crate::node::common::model::vault::VaultStatus; +use crate::node::db::descriptors::object_descriptor::ToObjectDescriptor; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::vault_event::{VaultAction, VaultLogObject}; +use crate::node::db::objects::device_log::PersistentDeviceLog; use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::objects::shared_secret::PersistentSharedSecret; +use crate::node::db::objects::vault::PersistentVault; +use crate::node::db::repo::generic_db::KvLogEventRepo; use crate::node::server::server_app::ServerDataTransfer; -use serde::{Deserialize, Serialize}; -use tracing::{info, instrument, Instrument}; pub struct VirtualDevice { - pub meta_client: Arc>, + persistent_object: Arc>, pub meta_client_proxy: Arc, pub server_dt: Arc, + gateway: Arc> } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -31,120 +31,84 @@ pub enum VirtualDeviceEvent { } impl VirtualDevice { - pub fn new( - persistent_object: Arc>, - meta_client_access_proxy: Arc, - meta_db_service_proxy: Arc, - dt: Arc, - ) -> VirtualDevice { - Self { - meta_client: Arc::new(MetaClient { - persistent_obj: persistent_object, - meta_db_service_proxy: meta_db_service_proxy.clone(), - }), - meta_client_proxy: meta_client_access_proxy, - server_dt: dt, - } - } - #[instrument(skip_all)] - pub async fn event_handler( + pub async fn init( persistent_object: Arc>, meta_client_access_proxy: Arc, - meta_db_service_proxy: Arc, - dt: Arc, - gateway: Arc>, - ) { + server_dt: Arc, + gateway: Arc> + ) -> anyhow::Result> { info!("Run virtual device event handler"); - let virtual_device = { - let vd = VirtualDevice::new( - persistent_object.clone(), - meta_client_access_proxy.clone(), - meta_db_service_proxy.clone(), - dt.clone(), - ); - Arc::new(vd) + let virtual_device = Self { + persistent_object, + meta_client_proxy: meta_client_access_proxy.clone(), + server_dt, + gateway }; - info!("Generate device creds"); - let creds = persistent_object - .repo - .get_or_generate_user_creds(String::from("q"), String::from("virtual-device")) - .in_current_span() - .await; - - let vault_name = "q"; - let device_name = "virtual-device"; - - let sign_up_request = GenericAppStateRequest::SignUp(SignUpRequest { - vault_name: String::from(vault_name), - device_name: String::from(device_name), - }); - - //prepare for sign_up - virtual_device - .meta_client_proxy - .send_request(sign_up_request.clone()) - .in_current_span() - .await; - - let vault_info = virtual_device - .meta_client - .get_vault(creds.user_sig.vault.name.clone()) - .in_current_span() - .await; - if let VaultInfo::Member { .. } = vault_info { - //vd is already a member of a vault - } else { - //send a register request - virtual_device - .meta_client_proxy - .send_request(sign_up_request.clone()) - .in_current_span() - .await; - } - - let vault_name = creds.user_sig.vault.name.clone(); - loop { - gateway.sync().in_current_span().await; - - let meta_db_service = virtual_device.meta_client.meta_db_service_proxy.clone(); - let vault_store = meta_db_service - .get_vault_store(vault_name.clone()) - .in_current_span() - .await - .unwrap(); + Ok(virtual_device) + } - if let VaultStore::Store { tail_id, vault, .. } = vault_store { - let vd_repo = virtual_device.meta_client.persistent_obj.repo.clone(); + pub async fn run(&self) -> anyhow::Result<()> { - let latest_event = vd_repo.find_one(tail_id).in_current_span().await; + loop { + self.gateway.sync().await?; - if let Ok(Some(GenericKvLogEvent::Vault(VaultObject::JoinRequest { event }))) = latest_event { - let accept_event = GenericKvLogEvent::Vault(VaultObject::JoinUpdate { - event: join::accept_join_request(&event, &vault), - }); + let p_vault = PersistentVault { + p_obj: self.persistent_object.clone(), + }; - let _ = vd_repo.save_event(accept_event).in_current_span().await; + let vault_status = p_vault.find_for_default_user().await?; + match vault_status { + VaultStatus::Outsider(_) => { + //nothing to do } + VaultStatus::Member(vault) => { + //vault actions + let vault_log_desc = VaultDescriptor::VaultLog(vault.vault_name.clone()) + .to_obj_desc(); + let maybe_vault_log_event = self.persistent_object.find_tail_event(vault_log_desc).await?; + match maybe_vault_log_event { + None => { + //nothing to do + } + Some(vault_log_event) => { + let vault_log = VaultLogObject::try_from(vault_log_event)?; + if let VaultLogObject::Action(vault_action) = vault_log { + match vault_action.value { + VaultAction::JoinRequest { candidate } => { + let p_device_log = PersistentDeviceLog { + p_obj: self.persistent_object.clone(), + }; + + p_device_log + .accept_join_cluster_request(candidate) + .await?; + } + VaultAction::UpdateMembership { .. } => { + //changes made by another device, no need for any actions + } + VaultAction::AddMetaPassword { .. } => { + //changes made by another device, no need for any actions + } + } + }; + } + } + + // shared secret actions + let _p_ss_log = PersistentSharedSecret { + p_obj: self.persistent_object.clone(), + }; + + todo!("Implement SS log actions - replication request. This code must read the log and handle the events. Same as above for vault"); + } + } - let db_tail = virtual_device - .meta_client - .persistent_obj - .get_db_tail(vault_name.as_str()) - .in_current_span() - .await - .unwrap(); - - gateway - .sync_shared_secrets(&vault.vault_name, &creds, &db_tail) - .in_current_span() - .await; - }; + self.gateway.sync().await?; async_std::task::sleep(std::time::Duration::from_millis(300)) - .in_current_span() .await; } } diff --git a/core/src/node/common/data_transfer.rs b/core/src/node/common/data_transfer.rs index f7d43fdd..eebf2876 100644 --- a/core/src/node/common/data_transfer.rs +++ b/core/src/node/common/data_transfer.rs @@ -13,7 +13,7 @@ pub struct MpscServiceChannel { impl MpscServiceChannel { fn new() -> MpscServiceChannel { - let (server_sender, server_receiver) = flume::bounded(1); + let (server_sender, server_receiver) = flume::bounded(100); MpscServiceChannel { sender: server_sender, receiver: server_receiver, @@ -28,7 +28,7 @@ pub struct MpscClientChannel { impl MpscClientChannel { fn new() -> MpscClientChannel { - let (client_sender, client_receiver) = flume::bounded(1); + let (client_sender, client_receiver) = flume::bounded(100); MpscClientChannel { sender: client_sender, receiver: client_receiver, diff --git a/core/src/node/common/mod.rs b/core/src/node/common/mod.rs index eeeecdb9..b21f8c5e 100644 --- a/core/src/node/common/mod.rs +++ b/core/src/node/common/mod.rs @@ -1,3 +1,4 @@ pub mod actor; pub mod data_transfer; pub mod meta_tracing; +pub mod model; diff --git a/core/src/node/common/model/device.rs b/core/src/node/common/model/device.rs new file mode 100644 index 00000000..234243c4 --- /dev/null +++ b/core/src/node/common/model/device.rs @@ -0,0 +1,144 @@ +use std::fmt::Display; + +use anyhow::anyhow; + +use crypto::utils::generate_uuid_b64_url_enc; + +use crate::crypto; +use crate::crypto::keys::{KeyManager, OpenBox}; +use crate::crypto::keys::SecretBox; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceId(String); + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceName(String); + +impl From for DeviceName { + fn from(device_name: String) -> Self { + DeviceName(device_name) + } +} + +impl From<&str> for DeviceName { + fn from(device_name: &str) -> Self { + DeviceName(String::from(device_name)) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum DeviceLink { + Loopback(LoopbackDeviceLink), + PeerToPeer(PeerToPeerDeviceLink), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LoopbackDeviceLink { + device: DeviceId, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PeerToPeerDeviceLink { + sender: DeviceId, + receiver: DeviceId, +} + +pub struct DeviceLinkBuilder { + sender: Option, + receiver: Option, +} + +impl DeviceLinkBuilder { + pub fn new() -> Self { + Self { sender: None, receiver: None } + } + + pub fn sender(mut self, sender: DeviceId) -> Self { + self.sender = Some(sender); + self + } + + pub fn receiver(mut self, receiver: DeviceId) -> Self { + self.receiver = Some(receiver); + self + } + + pub fn build(self) -> anyhow::Result { + let sender = self.sender.ok_or(anyhow!("Sender is not set"))?; + + let device_link = match self.receiver { + Some(receiver) => { + if sender == receiver { + DeviceLink::Loopback(LoopbackDeviceLink { device: sender }) + } else { + DeviceLink::PeerToPeer(PeerToPeerDeviceLink { sender, receiver }) + } + } + None => { + DeviceLink::Loopback(LoopbackDeviceLink { device: sender }) + } + }; + + Ok(device_link) + } +} + +impl DeviceLink { + pub fn is_loopback(&self) -> bool { + matches!(self, DeviceLink::Loopback(_)) + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceData { + pub id: DeviceId, + pub name: DeviceName, + pub keys: OpenBox, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DeviceCredentials { + pub secret_box: SecretBox, + pub device: DeviceData, +} + +/// Contains full information about device (private keys and device id) +impl DeviceCredentials { + pub fn generate(device_name: DeviceName) -> DeviceCredentials { + let secret_box = KeyManager::generate_secret_box(); + let device = DeviceData::from(device_name, OpenBox::from(&secret_box)); + DeviceCredentials { secret_box, device } + } +} + +impl Display for DeviceId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +/// Contains only public information about device +impl DeviceData { + pub fn from(device_name: DeviceName, open_box: OpenBox) -> Self { + Self { + name: device_name, + id: DeviceId::from(&open_box), + keys: open_box, + } + } +} + +impl From<&OpenBox> for DeviceId { + fn from(open_box: &OpenBox) -> Self { + let dsa_pk = open_box.dsa_pk.base64_text.clone(); + let id = generate_uuid_b64_url_enc(dsa_pk); + Self(id) + } +} diff --git a/core/src/node/common/model/mod.rs b/core/src/node/common/model/mod.rs new file mode 100644 index 00000000..2f3643ee --- /dev/null +++ b/core/src/node/common/model/mod.rs @@ -0,0 +1,193 @@ +use std::fmt::Display; + +use crate::node::common::model::device::DeviceData; +use crate::node::common::model::secret::MetaPasswordId; +use crate::node::common::model::vault::VaultStatus; + +pub mod device; +pub mod user; +pub mod vault; + +pub mod crypto { + use crate::crypto::encoding::base64::Base64Text; + use crate::node::common::model::device::DeviceLink; + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct AeadAuthData { + pub associated_data: String, + pub channel: CommunicationChannel, + pub nonce: Base64Text, + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct AeadCipherText { + pub msg: Base64Text, + pub auth_data: AeadAuthData, + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct AeadPlainText { + pub msg: Base64Text, + pub auth_data: AeadAuthData, + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct CommunicationChannel { + pub sender: Base64Text, + pub receiver: Base64Text, + } + + impl CommunicationChannel { + pub fn inverse(self) -> Self { + Self { + sender: self.receiver, + receiver: self.sender, + } + } + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub enum EncryptedMessage { + /// There is only one type of encrypted message for now, which is encrypted share of a secret, + /// and that particular type of message has a device link + /// and it used to figure out which vault the message belongs to + CipherShare { + device_link: DeviceLink, + share: AeadCipherText + } + } + + impl EncryptedMessage { + pub fn device_link(&self) -> DeviceLink { + match self { + EncryptedMessage::CipherShare { device_link, .. } => device_link.clone() + } + } + } +} + +pub mod secret { + use rand::distributions::Alphanumeric; + use rand::Rng; + + use crate::crypto::utils; + use crate::node::common::model::crypto::EncryptedMessage; + use crate::node::common::model::device::DeviceLink; + use crate::node::common::model::vault::VaultName; + + #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct MetaPasswordId { + /// SHA256 hash of a salt + pub id: String, + /// Random String up to 30 characters, must be unique + pub salt: String, + /// Human readable name given to the password + pub name: String, + } + + const SALT_LENGTH: usize = 8; + + impl MetaPasswordId { + pub fn generate(name: String) -> Self { + let salt: String = rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(SALT_LENGTH) + .map(char::from) + .collect(); + MetaPasswordId::build(name, salt) + } + + pub fn build(name: String, salt: String) -> Self { + let mut id_str = name.clone(); + id_str.push('-'); + id_str.push_str(salt.as_str()); + + Self { + id: utils::generate_uuid_b64_url_enc(id_str), + salt, + name, + } + } + } + + #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub enum SecretDistributionType { + Split, + Recover, + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct SecretDistributionData { + pub distribution_type: SecretDistributionType, + pub vault_name: VaultName, + pub meta_password_id: MetaPasswordId, + pub secret_message: EncryptedMessage, + } + + #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] + #[serde(rename_all = "camelCase")] + pub struct PasswordRecoveryRequest { + pub id: MetaPasswordId, + pub device_link: DeviceLink + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum RegistrationStatus { + Registered, + AlreadyExists, +} + +impl Display for RegistrationStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let str = match self { + Self::Registered => String::from("Registered"), + Self::AlreadyExists => String::from("AlreadyExists"), + }; + write!(f, "{}", str) + } +} + +impl Default for RegistrationStatus { + fn default() -> RegistrationStatus { + Self::Registered + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ApplicationState { + pub device: Option, + pub vault: Option, + pub join_component: bool, +} + +impl Default for ApplicationState { + fn default() -> Self { + ApplicationState { + device: None, + vault: None, + join_component: false, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn meta_password_id() { + let pass_id = MetaPasswordId::build("test".to_string(), "salt".to_string()); + assert_eq!(pass_id.id, "CHKANX39xaMXfhe3Qkx9-w".to_string()) + } +} diff --git a/core/src/node/common/model/user.rs b/core/src/node/common/model/user.rs new file mode 100644 index 00000000..346ae8b5 --- /dev/null +++ b/core/src/node/common/model/user.rs @@ -0,0 +1,126 @@ +use crate::node::common::model::device::{DeviceCredentials, DeviceData, DeviceId, DeviceName}; +use crate::node::common::model::vault::VaultName; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserId { + pub vault_name: VaultName, + pub device_id: DeviceId, +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserData { + pub vault_name: VaultName, + pub device: DeviceData, +} + +impl UserData { + pub fn vault_name(&self) -> VaultName { + self.vault_name.clone() + } + + pub fn user_id(&self) -> UserId { + UserId { + vault_name: self.vault_name.clone(), + device_id: self.device.id.clone(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserCredentials { + pub vault_name: VaultName, + pub device_creds: DeviceCredentials, +} + +impl UserCredentials { + pub fn from(device_creds: DeviceCredentials, vault_name: VaultName) -> UserCredentials { + UserCredentials { vault_name, device_creds } + } + + pub fn generate(device_name: DeviceName, vault_name: VaultName) -> UserCredentials { + UserCredentials { + vault_name, + device_creds: DeviceCredentials::generate(device_name), + } + } + + pub fn device(&self) -> DeviceData { + self.device_creds.device.clone() + } + + pub fn user(&self) -> UserData { + UserData { + vault_name: self.vault_name.clone(), + device: self.device(), + } + } + + pub fn user_id(&self) -> UserId { + UserId { + vault_name: self.vault_name.clone(), + device_id: self.device().id.clone(), + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum UserMembership { + Outsider(UserDataOutsider), + Member(UserDataMember), +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserDataMember(pub UserData); + +impl UserDataMember { + pub fn user(self) -> UserData { + self.0 + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UserDataOutsider { + pub user_data: UserData, + pub status: UserDataOutsiderStatus, +} + +impl UserDataOutsider { + pub fn unknown(user_data: UserData) -> Self { + Self { + user_data, + status: UserDataOutsiderStatus::Unknown, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum UserDataOutsiderStatus { + /// Unknown status (the user is not a member of the vault) + Unknown, + Pending, + Declined, +} + +impl UserMembership { + pub fn user_data(&self) -> UserData { + match self { + UserMembership::Outsider(UserDataOutsider { user_data, .. }) => { + user_data.clone() + } + UserMembership::Member(UserDataMember(member)) => { + member.clone() + } + } + } + + pub fn device_id(&self) -> DeviceId { + self.user_data().device.id.clone() + } +} diff --git a/core/src/node/common/model/vault.rs b/core/src/node/common/model/vault.rs new file mode 100644 index 00000000..2bedd1a2 --- /dev/null +++ b/core/src/node/common/model/vault.rs @@ -0,0 +1,108 @@ +use std::collections::{HashMap, HashSet}; +use std::fmt::Display; + +use crate::node::common::model::device::DeviceId; +use crate::node::common::model::MetaPasswordId; +use crate::node::common::model::user::{UserData, UserDataMember, UserDataOutsider, UserMembership}; +use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::db::events::vault_event::VaultObject; + +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VaultName(pub String); + +impl From for VaultName { + fn from(vault_name: String) -> Self { + Self(vault_name) + } +} + +impl From<&str> for VaultName { + fn from(vault_name: &str) -> Self { + VaultName::from(String::from(vault_name)) + } +} + +impl Display for VaultName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VaultData { + pub vault_name: VaultName, + pub users: HashMap, + pub secrets: HashSet, +} + +impl From for VaultData { + fn from(vault_name: VaultName) -> Self { + VaultData { + vault_name, + users: HashMap::new(), + secrets: HashSet::new(), + } + } +} + +impl VaultData { + pub fn members(&self) -> Vec { + let mut members: Vec = vec![]; + self.users.values().for_each(|membership| { + if let UserMembership::Member(user_data_member) = membership { + members.push(user_data_member.clone()); + } + }); + + members + } + + pub fn add_secret(&mut self, meta_password_id: MetaPasswordId) { + self.secrets.insert(meta_password_id); + } + + pub fn update_membership(&mut self, membership: UserMembership) { + self.users.insert(membership.device_id(), membership); + } + + pub fn is_member(&self, device_id: &DeviceId) -> bool { + let maybe_user = self.users.get(device_id); + if let Some(UserMembership::Member(UserDataMember(user_data))) = maybe_user { + user_data.device.id == device_id.clone() + } else { + false + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VaultStatus { + Outsider(UserDataOutsider), + Member(VaultData), +} + +impl VaultStatus { + pub fn try_from(vault_event: GenericKvLogEvent, user: UserData) -> anyhow::Result { + let vault_obj = VaultObject::try_from(vault_event)?; + match vault_obj { + VaultObject::Unit { .. } => { + Ok(VaultStatus::Outsider(UserDataOutsider::unknown(user))) + } + VaultObject::Genesis { .. } => { + Ok(VaultStatus::Outsider(UserDataOutsider::unknown(user))) + } + VaultObject::Vault(event) => { + Ok(VaultStatus::Member(event.value)) + } + } + } +} + +impl VaultStatus { + pub fn unknown(user: UserData) -> Self { + VaultStatus::Outsider(UserDataOutsider::unknown(user)) + } +} diff --git a/core/src/node/db/actions/join.rs b/core/src/node/db/actions/join.rs deleted file mode 100644 index ce3fa295..00000000 --- a/core/src/node/db/actions/join.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::models::{UserSignature, VaultDoc}; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, ObjectId}; - -pub fn join_cluster_request(curr_obj_id: &ObjectId, user_sig: &UserSignature) -> KvLogEvent { - let key = KvKey { - obj_id: curr_obj_id.next(), - obj_desc: ObjectDescriptor::Vault { - vault_name: user_sig.vault.name.clone(), - }, - }; - - KvLogEvent { - key, - value: user_sig.clone(), - } -} - -pub fn accept_join_request(request: &KvLogEvent, vault: &VaultDoc) -> KvLogEvent { - let user_sig = request.value.clone(); - - let mut new_vault = vault.clone(); - new_vault.signatures.push(user_sig); - - KvLogEvent { - key: request.key.next(), - value: new_vault, - } -} diff --git a/core/src/node/db/actions/mod.rs b/core/src/node/db/actions/mod.rs index fd49b3fe..6d50d7f9 100644 --- a/core/src/node/db/actions/mod.rs +++ b/core/src/node/db/actions/mod.rs @@ -1,3 +1,3 @@ -pub mod join; -pub mod sign_up; pub mod recover; +pub mod sign_up; +pub mod ss_replication; diff --git a/core/src/node/db/actions/recover.rs b/core/src/node/db/actions/recover.rs index b2d83365..7617669f 100644 --- a/core/src/node/db/actions/recover.rs +++ b/core/src/node/db/actions/recover.rs @@ -1,182 +1,85 @@ -use crate::models::{MetaPasswordId, PasswordRecoveryRequest}; -use crate::node::app::meta_app::app_state::JoinedAppState; -use crate::node::db::events::common::{ObjectCreator, SharedSecretObject, VaultInfo}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use std::sync::Arc; + +use anyhow::anyhow; +use tracing_attributes::instrument; + +use crate::node::common::model::ApplicationState; +use crate::node::common::model::device::DeviceLinkBuilder; +use crate::node::common::model::secret::{MetaPasswordId, PasswordRecoveryRequest}; +use crate::node::common::model::user::UserDataMember; +use crate::node::common::model::vault::VaultStatus; +use crate::node::db::descriptors::object_descriptor::ToObjectDescriptor; +use crate::node::db::descriptors::shared_secret::SharedSecretDescriptor; +use crate::node::db::events::common::SSDeviceLogObject; +use crate::node::db::events::generic_log_event::ToGenericEvent; use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::{ObjectDescriptor, SharedSecretDescriptor, SharedSecretEventId}; -use crate::node::db::events::object_id::{IdGen, ObjectId}; -use crate::node::db::generic_db::KvLogEventRepo; +use crate::node::db::events::object_id::{ObjectId}; use crate::node::db::objects::persistent_object::PersistentObject; -use std::sync::Arc; +use crate::node::db::repo::generic_db::KvLogEventRepo; pub struct RecoveryAction { pub persistent_obj: Arc>, } impl RecoveryAction { - pub async fn recovery_request(&self, meta_pass_id: MetaPasswordId, app_state: &JoinedAppState) { - if let VaultInfo::Member { vault } = &app_state.vault_info { - for curr_sig in &vault.signatures { - if app_state.creds.user_sig.public_key.base64_text == curr_sig.public_key.base64_text { - continue; - } - - let recovery_request = PasswordRecoveryRequest { - id: Box::new(meta_pass_id.clone()), - consumer: Box::new(curr_sig.clone()), - provider: app_state.creds.user_sig.clone(), - }; - - let recovery_request_id = SharedSecretEventId { - vault_name: curr_sig.vault.name.clone(), - meta_pass_id: meta_pass_id.clone(), - receiver: curr_sig.vault.device.as_ref().clone(), - }; - - let ss_obj_desc = { - let ss_desc = SharedSecretDescriptor::RecoveryRequest(recovery_request_id); - ObjectDescriptor::SharedSecret(ss_desc) - }; - - let audit_obj_desc = ObjectDescriptor::SharedSecretAudit { - vault_name: curr_sig.vault.name.clone(), - }; + /// Send recover request to all vault members except current user + #[instrument(skip_all)] + pub async fn recovery_request(&self, meta_pass_id: MetaPasswordId, app_state: &ApplicationState) -> anyhow::Result<()> { + let Some(sender_device) = app_state.device.clone() else { + return Err(anyhow!("Device not found")); + }; - let audit_event = { - let audit_slot_id = self - .persistent_obj - .find_tail_id_by_obj_desc(&audit_obj_desc) - .await - .map(|id| id.next()) - .unwrap_or(ObjectId::unit(&audit_obj_desc)); + let Some(vault_status) = app_state.vault.clone() else { + return Err(anyhow!("Vault not found")); + }; - GenericKvLogEvent::SharedSecret(SharedSecretObject::Audit { - event: KvLogEvent { + match vault_status { + VaultStatus::Outsider(_) => { + return Err(anyhow!("Vault not found")); + } + VaultStatus::Member(vault) => { + for UserDataMember(curr_member) in &vault.members() { + let curr_device = curr_member.device.clone(); + if sender_device.id == curr_device.id { + continue; + } + + let device_link = DeviceLinkBuilder::new() + .sender(sender_device.id.clone()) + .receiver(curr_device.id.clone()) + .build()?; + + let recovery_request = PasswordRecoveryRequest { + id: meta_pass_id.clone(), + device_link, + }; + + let ss_device_log_desc = SharedSecretDescriptor::SSDeviceLog(sender_device.id.clone()) + .to_obj_desc(); + + let log_event = { + let device_log_slot_id = self + .persistent_obj + .find_free_id_by_obj_desc(ss_device_log_desc.clone()) + .await?; + + let ObjectId::Artifact(ss_artifact_id) = device_log_slot_id else { + return Err(anyhow!("SSDeviceLog is not initialized")); + }; + + SSDeviceLogObject::DeviceLog(KvLogEvent { key: KvKey { - obj_id: audit_slot_id, - obj_desc: audit_obj_desc.clone(), + obj_id: ss_artifact_id, + obj_desc: ss_device_log_desc.clone(), }, - value: ObjectId::unit(&ss_obj_desc), - }, - }) - }; - - let _ = self.persistent_obj.repo.save_event(audit_event).await; - - let recovery_request_event = GenericKvLogEvent::SharedSecret(SharedSecretObject::RecoveryRequest { - event: KvLogEvent { - key: KvKey { - obj_id: ObjectId::unit(&ss_obj_desc), - obj_desc: ss_obj_desc, - }, - value: recovery_request, - }, - }); - - let _ = self.persistent_obj.repo.save_event(recovery_request_event).await; + value: recovery_request, + }).to_generic() + }; + self.persistent_obj.repo.save(log_event).await?; + } } - } else { - panic!("You must be a member of the vault"); } - } -} - -#[cfg(test)] -mod test { - use crate::crypto::keys::KeyManager; - use crate::models::{ApplicationState, DeviceInfo, MetaPasswordId, MetaVault, UserCredentials, VaultDoc}; - use crate::node::app::meta_app::app_state::JoinedAppState; - use crate::node::db::actions::recover::RecoveryAction; - use crate::node::db::events::common::{ObjectCreator, SharedSecretObject, VaultInfo}; - use crate::node::db::events::generic_log_event::GenericKvLogEvent; - use crate::node::db::events::object_descriptor::{ObjectDescriptor, SharedSecretDescriptor, SharedSecretEventId}; - use crate::node::db::events::object_id::ObjectId; - use crate::node::db::in_mem_db::InMemKvLogEventRepo; - use crate::node::db::objects::persistent_object::PersistentObject; - use std::ops::Deref; - use std::sync::Arc; - - #[tokio::test] - async fn test_recovery_request() { - let vault_name = String::from("test_vault"); - - let repo = Arc::new(InMemKvLogEventRepo::default()); - let persistent_obj = PersistentObject::new(repo.clone()); - - let action = RecoveryAction { - persistent_obj: Arc::new(persistent_obj), - }; - - let meta_pass_id = MetaPasswordId { - id: "test_pass_id_123".to_string(), - salt: "pass_salt".to_string(), - name: "test_pass".to_string(), - }; - - let s_box_a = KeyManager::generate_security_box(vault_name.to_string()); - let device_a = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - let user_sig_a = s_box_a.get_user_sig(&device_a); - - let s_box_b = KeyManager::generate_security_box(vault_name.to_string()); - let device_b = DeviceInfo { - device_id: "b".to_string(), - device_name: "b".to_string(), - }; - let user_sig_b = s_box_b.get_user_sig(&device_b); - - let _meta_vault = MetaVault { - name: vault_name.clone(), - device: Box::new(device_a.clone()), - }; - - let creds = UserCredentials { - security_box: Box::new(s_box_a), - user_sig: Box::new(user_sig_a.clone()), - }; - - let app_state = JoinedAppState { - app_state: ApplicationState { - meta_vault: None, - vault: None, - meta_passwords: vec![], - join_component: false, - }, - creds, - vault_info: VaultInfo::Member { - vault: VaultDoc { - vault_name: vault_name.clone(), - signatures: vec![user_sig_a, user_sig_b], - pending_joins: vec![], - declined_joins: vec![], - }, - }, - }; - - action.recovery_request(meta_pass_id.clone(), &app_state).await; - - let tmp_db = repo.db.clone(); - let db = tmp_db.as_ref().lock().await; - let events = db.deref(); - - assert_eq!(2, events.len()); - let audit_obj_id = ObjectId::unit(&ObjectDescriptor::SharedSecretAudit { - vault_name: vault_name.clone(), - }); - let audit_event_id = events.get(&audit_obj_id).unwrap(); - - let GenericKvLogEvent::SharedSecret(SharedSecretObject::Audit { event }) = audit_event_id else { - panic!(); - }; - let recovery_request_desc = - ObjectDescriptor::SharedSecret(SharedSecretDescriptor::RecoveryRequest(SharedSecretEventId { - vault_name, - meta_pass_id, - receiver: device_b, - })); - assert_eq!(recovery_request_desc.to_id(), event.value.id_str()); + Ok(()) } } diff --git a/core/src/node/db/actions/sign_up.rs b/core/src/node/db/actions/sign_up.rs index 0145b88d..c8ec95a8 100644 --- a/core/src/node/db/actions/sign_up.rs +++ b/core/src/node/db/actions/sign_up.rs @@ -1,89 +1,110 @@ -use crate::models::{UserSignature, VaultDoc}; -use crate::node::db::events::common::{LogEventKeyBasedRecord, MetaPassObject, ObjectCreator, PublicKeyRecord}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use tracing_attributes::instrument; + +use crate::node::common::model::device::DeviceData; +use crate::node::common::model::user::{UserData, UserDataMember, UserId, UserMembership}; +use crate::node::common::model::vault::VaultData; +use crate::node::db::descriptors::object_descriptor::ToObjectDescriptor; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, ToGenericEvent}; use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, ObjectId}; -use crate::node::db::events::vault_event::VaultObject; +use crate::node::db::events::object_id::{Next, UnitId}; +use crate::node::db::events::vault_event::{VaultLogObject, VaultMembershipObject, VaultObject}; pub struct SignUpAction {} impl SignUpAction { - pub fn accept( - &self, - sign_up_request: &KvLogEvent, - server_pk: &PublicKeyRecord, - ) -> Vec { - match &sign_up_request.key { - KvKey { - obj_id: ObjectId::Unit { .. }, - obj_desc: ObjectDescriptor::Vault { vault_name }, - } => { - let user_sig: UserSignature = sign_up_request.value.clone(); - - let genesis_event = { - let genesis_update = VaultObject::Genesis { - event: KvLogEvent::genesis(&sign_up_request.key.obj_desc, server_pk), - }; - GenericKvLogEvent::Vault(genesis_update) - }; + #[instrument(skip_all)] + pub fn accept(&self, candidate: UserData, server: DeviceData) -> Vec { + let mut commit_log = vec![]; - let sign_up_event = { - let vault = VaultDoc { - vault_name: vault_name.clone(), - signatures: vec![user_sig], - pending_joins: vec![], - declined_joins: vec![], - }; - - let sign_up_event = KvLogEvent { - key: genesis_event.key().next(), - value: vault, - }; - GenericKvLogEvent::Vault(VaultObject::SignUpUpdate { event: sign_up_event }) - }; + let vault_name = candidate.vault_name.clone(); + + let vault_log_events = { + let vault_log_obj_desc = VaultDescriptor::vault_log(vault_name.clone()); + let unit_event = VaultLogObject::Unit(KvLogEvent { + key: KvKey::unit(vault_log_obj_desc.clone()), + value: vault_name.clone(), + }).to_generic(); + + let genesis_event = VaultLogObject::Genesis(KvLogEvent { + key: KvKey::genesis(vault_log_obj_desc), + value: candidate.clone(), + }).to_generic(); + + vec![unit_event, genesis_event] + }; + commit_log.extend(vault_log_events); + + let vault_events = { + let vault_obj_desc = VaultDescriptor::vault(vault_name.clone()); + let unit_event = VaultObject::Unit(KvLogEvent { + key: KvKey::unit(vault_obj_desc.clone()), + value: vault_name.clone(), + }).to_generic(); + + let genesis_event = VaultObject::Genesis(KvLogEvent { + key: KvKey::genesis(vault_obj_desc.clone()), + value: server, + }).to_generic(); - let generic_sign_up_request = GenericKvLogEvent::Vault(VaultObject::Unit { - event: sign_up_request.clone(), - }); - - let meta_pass_unit_event = { - let event = KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::MetaPassword { - vault_name: vault_name.clone(), - }), - value: (), - }; - GenericKvLogEvent::MetaPass(MetaPassObject::Unit { event }) + let vault_event = { + let vault_data = { + let mut vault = VaultData::from(vault_name.clone()); + let membership = UserMembership::Member(UserDataMember(candidate.clone())); + vault.update_membership(membership); + vault }; - let meta_pass_genesis_event = { - let obj_desc = ObjectDescriptor::MetaPassword { - vault_name: vault_name.clone(), - }; - let event = KvLogEvent::genesis(&obj_desc, server_pk); - GenericKvLogEvent::MetaPass(MetaPassObject::Genesis { event }) + let vault_id = UnitId::vault_unit(vault_name.clone()) + .next() + .next(); + + let sign_up_event = KvLogEvent { + key: KvKey::artifact(vault_obj_desc.clone(), vault_id), + value: vault_data, }; + VaultObject::Vault(sign_up_event).to_generic() + }; - vec![ - generic_sign_up_request, - genesis_event, - sign_up_event, - meta_pass_unit_event, - meta_pass_genesis_event, - ] - } - _ => { - panic!("Invalid object id"); - } - } - } -} + vec![unit_event, genesis_event, vault_event] + }; + commit_log.extend(vault_events); + + let vault_status_events = { + let user_id = UserId { + vault_name: vault_name.clone(), + device_id: candidate.device.id.clone(), + }; + let vault_status_desc = VaultDescriptor::VaultStatus(user_id).to_obj_desc(); + + let unit_event = VaultMembershipObject::Unit(KvLogEvent { + key: KvKey::unit(vault_status_desc.clone()), + value: vault_name.clone(), + }).to_generic(); + + let genesis_event = VaultMembershipObject::Genesis(KvLogEvent { + key: KvKey::genesis(vault_status_desc.clone()), + value: candidate.clone(), + }).to_generic(); + + let status_event = { + let status_event_id = UnitId::unit(&vault_status_desc) + .next() + .next(); + + VaultMembershipObject::Membership(KvLogEvent { + key: KvKey { + obj_id: status_event_id, + obj_desc: vault_status_desc, + }, + value: UserMembership::Member(UserDataMember(candidate.clone())), + }).to_generic() + }; -pub struct SignUpRequest {} + vec![unit_event, genesis_event, status_event] + }; + commit_log.extend(vault_status_events); -impl SignUpRequest { - pub fn generic_request(&self, user_sig: &UserSignature) -> GenericKvLogEvent { - GenericKvLogEvent::Vault(VaultObject::unit(user_sig)) + commit_log } } diff --git a/core/src/node/db/actions/ss_replication.rs b/core/src/node/db/actions/ss_replication.rs new file mode 100644 index 00000000..44116716 --- /dev/null +++ b/core/src/node/db/actions/ss_replication.rs @@ -0,0 +1,72 @@ +use std::sync::Arc; + +use tracing_attributes::instrument; + +use crate::node::common::model::device::DeviceLinkBuilder; +use crate::node::common::model::user::UserDataMember; +use crate::node::common::model::vault::VaultData; +use crate::node::db::descriptors::object_descriptor::ToObjectDescriptor; +use crate::node::db::descriptors::shared_secret::{SharedSecretDescriptor, SharedSecretEventId}; +use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::db::events::object_id::ObjectId; +use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::repo::generic_db::KvLogEventRepo; +use crate::node::server::request::SharedSecretRequest; + +pub struct SSReplicationAction { + pub persistent_obj: Arc>, +} + +impl SSReplicationAction { + + #[instrument(skip_all)] + pub async fn replicate(&self, request: SharedSecretRequest, vault: &VaultData) -> anyhow::Result> { + let mut commit_log: Vec = vec![]; + + let ss_log_events = self.persistent_obj + .find_object_events(request.ss_log) + .await?; + + commit_log.extend(ss_log_events); + + for UserDataMember(member) in vault.members() { + if request.sender == member { + continue; + } + + let ss_event_id = { + let device_link = DeviceLinkBuilder::new() + .sender(member.device.id.clone()) + .receiver(request.sender.device.id.clone()) + .build()?; + + SharedSecretEventId { + vault_name: request.sender.vault_name.clone(), + device_link + } + }; + + let ss_split_events = { + let ss_split_obj_desc = SharedSecretDescriptor::Split(ss_event_id.clone()) + .to_obj_desc(); + + self.persistent_obj + .find_object_events(ObjectId::unit(ss_split_obj_desc)) + .await? + }; + commit_log.extend(ss_split_events); + + let ss_recover_events = { + let ss_recover_obj_desc = SharedSecretDescriptor::Recover(ss_event_id) + .to_obj_desc(); + + self.persistent_obj + .find_object_events(ObjectId::unit(ss_recover_obj_desc)) + .await? + }; + commit_log.extend(ss_recover_events); + } + + Ok(commit_log) + } +} diff --git a/core/src/node/db/descriptors/global_index.rs b/core/src/node/db/descriptors/global_index.rs new file mode 100644 index 00000000..a4a76e47 --- /dev/null +++ b/core/src/node/db/descriptors/global_index.rs @@ -0,0 +1,45 @@ +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::object_descriptor::{ObjectName, ObjectType}; +use crate::node::db::events::object_id::UnitId; + +/// Allows to have access to the global index of all vaults exists across the system. +/// Index + VaultIndex = LinkedHashMap, or linkedList + HaspMap, allows to navigate through the values in the index. +/// Index provides list interface and allows to navigate through elements by their index in the array +/// VaultIndex provides HashMap interface allows to get a vault by its ID +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum GlobalIndexDescriptor { + Index, + /// An id of a vault. We have global index to keep track and being able to iterate over all vaults, + /// and to be able to check if a particular vault exists we ned to have vault index + VaultIndex { vault_id: UnitId }, +} + +impl ObjectType for GlobalIndexDescriptor { + fn object_type(&self) -> String { + match self { + GlobalIndexDescriptor::Index => String::from("GlobalIndex"), + GlobalIndexDescriptor::VaultIndex { .. } => String::from("VaultIdx") + } + } +} + +impl ObjectName for GlobalIndexDescriptor { + fn object_name(&self) -> String { + match self { + GlobalIndexDescriptor::Index => String::from("index"), + GlobalIndexDescriptor::VaultIndex { vault_id } => { + let json_str = serde_json::to_string(&vault_id.id).unwrap(); + //utils::generate_uuid_b64_url_enc(json_str) + json_str + } + } + } +} + +impl GlobalIndexDescriptor { + pub fn vault_index(vault_name: VaultName) -> GlobalIndexDescriptor { + let vault_id = UnitId::vault_unit(vault_name); + GlobalIndexDescriptor::VaultIndex { vault_id } + } +} \ No newline at end of file diff --git a/core/src/node/db/descriptors/mod.rs b/core/src/node/db/descriptors/mod.rs new file mode 100644 index 00000000..7e94758c --- /dev/null +++ b/core/src/node/db/descriptors/mod.rs @@ -0,0 +1,4 @@ +pub mod global_index; +pub mod object_descriptor; +pub mod shared_secret; +pub mod vault; diff --git a/core/src/node/db/descriptors/object_descriptor.rs b/core/src/node/db/descriptors/object_descriptor.rs new file mode 100644 index 00000000..38d5ed6d --- /dev/null +++ b/core/src/node/db/descriptors/object_descriptor.rs @@ -0,0 +1,85 @@ +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::shared_secret::SharedSecretDescriptor; +use crate::node::db::descriptors::vault::VaultDescriptor; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +#[serde(tag = "__obj_desc")] +pub enum ObjectDescriptor { + DbTail, + GlobalIndex(GlobalIndexDescriptor), + /// Describes device and user credentials + CredsIndex, + + Vault(VaultDescriptor), + /// Secret distribution (split, recover, recovery request and so on) + SharedSecret(SharedSecretDescriptor) +} + +pub trait ToObjectDescriptor { + fn to_obj_desc(self) -> ObjectDescriptor; +} + +pub trait ObjectType { + fn object_type(&self) -> String; +} + +pub trait ObjectName { + fn object_name(&self) -> String; +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ObjectDescriptorFqdn { + pub obj_type: String, + pub obj_instance: String, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ObjectDescriptorId { + pub fqdn: ObjectDescriptorFqdn, + /// primary key of an object in the database in terms of keys in a table in relational databases. + /// In our case id is just a counter + pub id: usize, +} + +impl ObjectDescriptor { + pub fn to_fqdn(&self) -> ObjectDescriptorFqdn { + self.fqdn() + } +} + +impl ObjectDescriptor { + /// Fully Qualified Domain Name - unique domain name of an object + pub fn fqdn(&self) -> ObjectDescriptorFqdn { + ObjectDescriptorFqdn { + obj_type: self.object_type(), + obj_instance: self.object_name(), + } + } +} + +impl ObjectName for ObjectDescriptor { + fn object_name(&self) -> String { + match self { + ObjectDescriptor::DbTail => String::from("db_tail"), + ObjectDescriptor::SharedSecret(s_s_descriptor) => s_s_descriptor.as_id_str(), + ObjectDescriptor::GlobalIndex(desc) => desc.object_name(), + ObjectDescriptor::CredsIndex => String::from("index"), + ObjectDescriptor::Vault(vault_desc) => vault_desc.object_name(), + } + } +} + +impl ObjectType for ObjectDescriptor { + fn object_type(&self) -> String { + match self { + ObjectDescriptor::GlobalIndex(gi_desc) => gi_desc.object_type(), + ObjectDescriptor::Vault(vault_desc) => vault_desc.object_type(), + ObjectDescriptor::SharedSecret(ss_desc) => ss_desc.object_type(), + ObjectDescriptor::CredsIndex { .. } => String::from("DeviceCreds"), + ObjectDescriptor::DbTail { .. } => String::from("DbTail"), + } + } +} diff --git a/core/src/node/db/descriptors/shared_secret.rs b/core/src/node/db/descriptors/shared_secret.rs new file mode 100644 index 00000000..2e174da1 --- /dev/null +++ b/core/src/node/db/descriptors/shared_secret.rs @@ -0,0 +1,99 @@ +use crate::node::common::model::crypto::EncryptedMessage; +use crate::node::common::model::device::{DeviceId, DeviceLink}; +use crate::node::common::model::secret::{MetaPasswordId, SecretDistributionData, SecretDistributionType}; +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptor, ObjectType, ToObjectDescriptor}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum SharedSecretDescriptor { + /// Local share of a secret + LocalShare { + vault_name: VaultName, + meta_pass_id: MetaPasswordId, + }, + + Split(SharedSecretEventId), + Recover(SharedSecretEventId), + + SSDeviceLog(DeviceId), + + /// This log allows to recreate a lifetime of the secret sharing workflow and allows to have a consistent view + ///across the cluster on what events of the secret sharing happened at what time. + SSLog(VaultName) +} + +impl ObjectType for SharedSecretDescriptor { + fn object_type(&self) -> String { + match self { + SharedSecretDescriptor::Split(_) => String::from("SSSplit"), + SharedSecretDescriptor::Recover(_) => String::from("SSRecover"), + SharedSecretDescriptor::SSLog { .. } => String::from("SSLog"), + SharedSecretDescriptor::LocalShare { .. } => String::from("SSLocalShare"), + SharedSecretDescriptor::SSDeviceLog(_) => String::from("SSDeviceLog") + } + } +} + +impl SharedSecretDescriptor { + pub fn as_id_str(&self) -> String { + match self { + SharedSecretDescriptor::Split(event_id) => event_id.as_id_str(), + SharedSecretDescriptor::Recover(event_id) => event_id.as_id_str(), + SharedSecretDescriptor::SSLog(vault_name) => vault_name.to_string(), + SharedSecretDescriptor::LocalShare { .. } => { + serde_json::to_string(self).unwrap() + } + SharedSecretDescriptor::SSDeviceLog(device_id) => device_id.to_string() + } + } + + pub fn audit(vault_name: VaultName) -> ObjectDescriptor { + ObjectDescriptor::SharedSecret(SharedSecretDescriptor::SSLog(vault_name)) + } +} + +impl ToObjectDescriptor for SharedSecretDescriptor { + fn to_obj_desc(self) -> ObjectDescriptor { + ObjectDescriptor::SharedSecret(self) + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SharedSecretEventId { + pub vault_name: VaultName, + pub device_link: DeviceLink +} + +impl SharedSecretEventId { + pub fn as_id_str(&self) -> String { + serde_json::to_string(self).unwrap() + } +} + +impl From for SharedSecretEventId { + fn from(secret: SecretDistributionData) -> Self { + let device_link = match secret.secret_message { + EncryptedMessage::CipherShare { device_link, .. } => device_link + }; + + Self { vault_name: secret.vault_name, device_link } + } +} + +impl From<&SecretDistributionData> for ObjectDescriptor { + fn from(secret_distribution: &SecretDistributionData) -> Self { + + let ss_event_id = SharedSecretEventId::from(secret_distribution.clone()); + + match secret_distribution.distribution_type { + SecretDistributionType::Split => { + ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Split(ss_event_id)) + } + SecretDistributionType::Recover => { + ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Recover(ss_event_id)) + } + } + } +} diff --git a/core/src/node/db/descriptors/vault.rs b/core/src/node/db/descriptors/vault.rs new file mode 100644 index 00000000..6f8a950d --- /dev/null +++ b/core/src/node/db/descriptors/vault.rs @@ -0,0 +1,129 @@ +use std::ops::Add; + +use crate::node::common::model::user::UserId; +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptor, ObjectName, ObjectType, ToObjectDescriptor}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VaultDescriptor { + DeviceLog(UserId), + + VaultLog(VaultName), + Vault(VaultName), + VaultStatus(UserId), +} + +impl ToObjectDescriptor for VaultDescriptor { + fn to_obj_desc(self) -> ObjectDescriptor { + ObjectDescriptor::Vault(self) + } +} + +impl VaultDescriptor { + + pub fn device_log(user_id: UserId) -> ObjectDescriptor { + ObjectDescriptor::Vault(VaultDescriptor::DeviceLog(user_id)) + } + + pub fn vault_log(vault_name: VaultName) -> ObjectDescriptor { + ObjectDescriptor::Vault(VaultDescriptor::VaultLog(vault_name)) + } + + pub fn vault(vault_name: VaultName) -> ObjectDescriptor { + ObjectDescriptor::Vault(VaultDescriptor::Vault(vault_name)) + } + + pub fn vault_status(user_id: UserId) -> ObjectDescriptor { + ObjectDescriptor::Vault(VaultDescriptor::VaultStatus(user_id)) + } +} + +impl ObjectType for VaultDescriptor { + fn object_type(&self) -> String { + match self { + VaultDescriptor::DeviceLog(user_id) => { + String::from("DeviceLog:").add(user_id.device_id.to_string().as_str()) + } + VaultDescriptor::VaultStatus(user_id) => { + String::from("VaultStatus:").add(user_id.device_id.to_string().as_str()) + } + VaultDescriptor::Vault(_) => String::from("Vault"), + VaultDescriptor::VaultLog(_) => String::from("VaultLog"), + } + } +} + +impl ObjectName for VaultDescriptor { + fn object_name(&self) -> String { + match self { + VaultDescriptor::Vault(vault_name) => vault_name.to_string(), + VaultDescriptor::DeviceLog(user_id) => user_id.vault_name.to_string(), + VaultDescriptor::VaultLog(vault_name) => vault_name.to_string(), + VaultDescriptor::VaultStatus(user_id) => user_id.vault_name.to_string() + } + } +} + +#[cfg(test)] +pub mod test { + use std::ops::Add; + + use serde_json::json; + + use crate::crypto::keys::{KeyManager, OpenBox}; + use crate::node::common::model::device::DeviceId; + use crate::node::common::model::user::UserId; + use crate::node::common::model::vault::VaultName; + use crate::node::db::descriptors::object_descriptor::{ObjectName, ObjectType}; + use crate::node::db::descriptors::vault::VaultDescriptor; + use crate::node::db::events::object_id::UnitId; + + #[test] + fn test_vault_naming() { + let vault_name = VaultName::from("test"); + let descriptor = VaultDescriptor::vault(vault_name.clone()); + assert_eq!(descriptor.object_type(), "Vault"); + assert_eq!(descriptor.object_name(), vault_name.to_string()); + } + + #[test] + fn test_vault_log_naming() { + let vault_name = VaultName::from("test"); + let descriptor = VaultDescriptor::vault_log(vault_name.clone()); + assert_eq!(descriptor.object_type(), "VaultLog"); + assert_eq!(descriptor.object_name(), vault_name.to_string()); + } + + #[test] + fn test_device_log_naming() { + let vault_name = VaultName::from("test_vault"); + let device_id = { + let secret_box = KeyManager::generate_secret_box(); + DeviceId::from(&OpenBox::from(&secret_box)) + }; + + let user_id = UserId { + device_id: device_id.clone(), + vault_name: vault_name.clone() + }; + let descriptor = VaultDescriptor::device_log(user_id); + let device_log_type = String::from("DeviceLog:").add(device_id.to_string().as_str()); + + assert_eq!(descriptor.object_type(), device_log_type); + assert_eq!(descriptor.object_name(), vault_name.to_string()); + + let unit_id = UnitId::unit(&descriptor); + + let id_json = serde_json::to_value(&unit_id.id).unwrap(); + let expected = json!({ + "fqdn": { + "objType": device_log_type, + "objInstance": vault_name.to_string() + }, + "id": 0 + }); + + assert_eq!(expected, id_json); + } +} \ No newline at end of file diff --git a/core/src/node/db/events/common.rs b/core/src/node/db/events/common.rs index 30686669..9b59de5b 100644 --- a/core/src/node/db/events/common.rs +++ b/core/src/node/db/events/common.rs @@ -1,102 +1,84 @@ -use crate::models::password_recovery_request::PasswordRecoveryRequest; -use crate::models::{Base64EncodedText, MetaPasswordDoc, SecretDistributionDocData, UserSignature, VaultDoc}; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::ObjectId; +use crate::node::common::model::secret::{PasswordRecoveryRequest, SecretDistributionData}; +use crate::node::common::model::user::UserData; +use crate::node::common::model::vault::VaultName; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, KeyExtractor, ObjIdExtractor, ToGenericEvent}; +use crate::node::db::events::kv_log_event::{GenericKvKey, KvLogEvent}; +use crate::node::db::events::object_id::{ArtifactId, GenesisId, ObjectId, UnitId}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub enum MemPoolObject { - JoinRequest { event: KvLogEvent }, +pub enum SharedSecretObject { + LocalShare(KvLogEvent), + + Split(KvLogEvent), + Recover(KvLogEvent), + + SSLog(KvLogEvent) } -impl MemPoolObject { - pub fn key(&self) -> &KvKey { +impl KeyExtractor for SharedSecretObject { + fn key(&self) -> GenericKvKey { match self { - MemPoolObject::JoinRequest { event } => &event.key, + SharedSecretObject::LocalShare(event) => GenericKvKey::from(event.key.clone()), + + SharedSecretObject::Split(event) => GenericKvKey::from(event.key.clone()), + SharedSecretObject::Recover(event) => GenericKvKey::from(event.key.clone()), + + SharedSecretObject::SSLog(event) => GenericKvKey::from(event.key.clone()), } } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub enum MetaPassObject { - Unit { event: KvLogEvent<()> }, - Genesis { event: KvLogEvent }, - Update { event: KvLogEvent }, +pub enum SSDeviceLogObject { + Unit(KvLogEvent), + Genesis(KvLogEvent), + DeviceLog(KvLogEvent), } -impl MetaPassObject { - pub fn key(&self) -> &KvKey { +impl ObjIdExtractor for SSDeviceLogObject { + fn obj_id(&self) -> ObjectId { match self { - MetaPassObject::Unit { event } => &event.key, - MetaPassObject::Genesis { event } => &event.key, - MetaPassObject::Update { event } => &event.key, + SSDeviceLogObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + SSDeviceLogObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + SSDeviceLogObject::DeviceLog(event) => ObjectId::from(event.key.obj_id.clone()), } } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum SharedSecretObject { - Split { - event: KvLogEvent, - }, - Recover { - event: KvLogEvent, - }, - RecoveryRequest { - event: KvLogEvent, - }, - Audit { - event: KvLogEvent, - }, +impl ToGenericEvent for SSDeviceLogObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::SSDeviceLog(self) + } } -impl SharedSecretObject { - pub fn key(&self) -> &KvKey { +impl KeyExtractor for SSDeviceLogObject { + fn key(&self) -> GenericKvKey { match self { - SharedSecretObject::Split { event } => &event.key, - SharedSecretObject::Recover { event } => &event.key, - SharedSecretObject::RecoveryRequest { event } => &event.key, - SharedSecretObject::Audit { event } => &event.key, + SSDeviceLogObject::Unit(event) => GenericKvKey::from(event.key.clone()), + SSDeviceLogObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + SSDeviceLogObject::DeviceLog(event) => GenericKvKey::from(event.key.clone()), } } } -pub trait LogEventKeyBasedRecord { - fn key(&self) -> &KvKey; -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct PublicKeyRecord { - pub pk: Base64EncodedText, -} +impl ObjIdExtractor for SharedSecretObject { + fn obj_id(&self) -> ObjectId { + match self { + SharedSecretObject::LocalShare(event) => ObjectId::from(event.key.obj_id.clone()), -impl From for PublicKeyRecord { - fn from(value: Base64EncodedText) -> Self { - Self { pk: value } + SharedSecretObject::Split(event) => ObjectId::from(event.key.obj_id.clone()), + SharedSecretObject::Recover(event) => ObjectId::from(event.key.obj_id.clone()), + + SharedSecretObject::SSLog(event) => ObjectId::from(event.key.obj_id.clone()), + } } } -pub trait ObjectCreator { - fn unit(value: T) -> Self; - fn genesis(obj_desc: &ObjectDescriptor) -> Self; +impl ToGenericEvent for SharedSecretObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::SharedSecret(self) + } } -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "__vault_ingo")] -pub enum VaultInfo { - /// Device is a member of a vault - Member { vault: VaultDoc }, - /// Device is waiting to be added to a vault. - Pending, - /// Vault members declined to add a device into the vault. - Declined, - /// Vault not found - NotFound, - /// Device can't get any information about the vault, because its signature is not in members or pending list - NotMember, -} diff --git a/core/src/node/db/events/db_tail.rs b/core/src/node/db/events/db_tail.rs index ff75d622..fee94fe5 100644 --- a/core/src/node/db/events/db_tail.rs +++ b/core/src/node/db/events/db_tail.rs @@ -2,19 +2,13 @@ use crate::node::db::events::object_id::ObjectId; #[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct DbTail { - pub maybe_global_index_id: Option, - pub maybe_mem_pool_id: Option, - - pub vault_id: DbTailObject, - pub meta_pass_id: DbTailObject, - pub s_s_audit: Option, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, Hash, Eq)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "__db_tail_obj")] -pub enum DbTailObject { - Empty { unit_id: ObjectId }, - Id { tail_id: ObjectId }, +pub enum DbTail { + Basic { + global_index_id: Option + }, + Full { + global_index_id: Option, + vault_audit_id: ObjectId, + s_s_audit: ObjectId, + } } diff --git a/core/src/node/db/events/generic_log_event.rs b/core/src/node/db/events/generic_log_event.rs index 25d47a97..5ce7fa12 100644 --- a/core/src/node/db/events/generic_log_event.rs +++ b/core/src/node/db/events/generic_log_event.rs @@ -1,34 +1,107 @@ -use crate::node::db::events::common::{LogEventKeyBasedRecord, MemPoolObject, MetaPassObject, SharedSecretObject}; +use anyhow::anyhow; + +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::events::common::{SharedSecretObject, SSDeviceLogObject}; +use crate::node::db::events::db_tail::DbTail; use crate::node::db::events::error::ErrorMessage; use crate::node::db::events::global_index::GlobalIndexObject; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::local::KvLogEventLocal; -use crate::node::db::events::vault_event::VaultObject; +use crate::node::db::events::kv_log_event::{GenericKvKey, KvKey, KvLogEvent}; +use crate::node::db::events::local::{CredentialsObject, DbTailObject}; +use crate::node::db::events::object_id::{ArtifactId, ObjectId}; +use crate::node::db::events::vault_event::{DeviceLogObject, VaultLogObject, VaultMembershipObject, VaultObject}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(tag = "__generic_event_type")] pub enum GenericKvLogEvent { GlobalIndex(GlobalIndexObject), + + Credentials(CredentialsObject), + DbTail(DbTailObject), + + DeviceLog(DeviceLogObject), + VaultLog(VaultLogObject), Vault(VaultObject), - MetaPass(MetaPassObject), + VaultMembership(VaultMembershipObject), + SharedSecret(SharedSecretObject), - MemPool(MemPoolObject), - LocalEvent(KvLogEventLocal), + SSDeviceLog(SSDeviceLogObject), + + Error { + event: KvLogEvent, + }, +} + +impl GenericKvLogEvent { + pub fn to_db_tail(self) -> anyhow::Result { + if let GenericKvLogEvent::DbTail(DbTailObject(event)) = self { + Ok(event.value) + } else { + Err(anyhow!("DbTail. Invalid event type: {:?}", self)) + } + } +} + +pub trait ToGenericEvent { + fn to_generic(self) -> GenericKvLogEvent; +} + +pub trait UnitEvent { + fn unit(value: T) -> Self; +} + +pub trait UnitEventWithEmptyValue { + fn unit() -> Self; +} - Error { event: KvLogEvent }, +pub trait ObjIdExtractor { + fn obj_id(&self) -> ObjectId; } -impl LogEventKeyBasedRecord for GenericKvLogEvent { - fn key(&self) -> &KvKey { +pub trait KeyExtractor { + fn key(&self) -> GenericKvKey; +} + +impl ObjIdExtractor for GenericKvLogEvent { + fn obj_id(&self) -> ObjectId { match self { - GenericKvLogEvent::GlobalIndex(gi_obj) => gi_obj.key(), - GenericKvLogEvent::Vault(vault_obj) => vault_obj.key(), - GenericKvLogEvent::MetaPass(pass_obj) => pass_obj.key(), + GenericKvLogEvent::GlobalIndex(obj) => obj.obj_id(), + GenericKvLogEvent::Vault(obj) => obj.obj_id(), + GenericKvLogEvent::SharedSecret(obj) => obj.obj_id(), + GenericKvLogEvent::Credentials(obj) => obj.obj_id(), + GenericKvLogEvent::DbTail(obj) => obj.obj_id(), + GenericKvLogEvent::Error { event } => ObjectId::from(event.key.obj_id.clone()), + GenericKvLogEvent::DeviceLog(obj) => obj.obj_id(), + GenericKvLogEvent::VaultLog(obj) => obj.obj_id(), + GenericKvLogEvent::VaultMembership(obj) => obj.obj_id(), + GenericKvLogEvent::SSDeviceLog(obj) => obj.obj_id(), + } + } +} + +impl KeyExtractor for GenericKvLogEvent { + fn key(&self) -> GenericKvKey { + match self { + GenericKvLogEvent::GlobalIndex(obj) => obj.key(), + GenericKvLogEvent::Vault(obj) => obj.key(), GenericKvLogEvent::SharedSecret(obj) => obj.key(), - GenericKvLogEvent::MemPool(mem_pool_obj) => mem_pool_obj.key(), - GenericKvLogEvent::LocalEvent(op) => op.key(), - GenericKvLogEvent::Error { event } => &event.key, + GenericKvLogEvent::Credentials(obj) => obj.key(), + GenericKvLogEvent::DbTail(obj) => obj.key(), + GenericKvLogEvent::Error { event } => GenericKvKey::from(event.key.clone()), + GenericKvLogEvent::DeviceLog(obj) => obj.key(), + GenericKvLogEvent::VaultLog(obj) => obj.key(), + GenericKvLogEvent::VaultMembership(obj) => obj.key(), + GenericKvLogEvent::SSDeviceLog(obj) => obj.key() } } } + +impl GenericKvLogEvent { + pub fn db_tail(db_tail: DbTail) -> GenericKvLogEvent { + let event = KvLogEvent { + key: KvKey::unit(ObjectDescriptor::DbTail), + value: db_tail, + }; + GenericKvLogEvent::DbTail(DbTailObject(event)) + } +} diff --git a/core/src/node/db/events/global_index.rs b/core/src/node/db/events/global_index.rs index f59de30b..119ac4c5 100644 --- a/core/src/node/db/events/global_index.rs +++ b/core/src/node/db/events/global_index.rs @@ -1,41 +1,78 @@ -use crate::node::db::events::common::PublicKeyRecord; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use crate::node::common::model::device::DeviceData; +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::events::generic_log_event::{ + GenericKvLogEvent, KeyExtractor, ObjIdExtractor, ToGenericEvent, UnitEventWithEmptyValue +}; +use crate::node::db::events::kv_log_event::{GenericKvKey, KvKey, KvLogEvent}; +use crate::node::db::events::object_id::{ArtifactId, GenesisId, ObjectId, UnitId}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum GlobalIndexObject { - Unit { event: KvLogEvent<()> }, - Genesis { event: KvLogEvent }, - Update { event: KvLogEvent }, + Unit(KvLogEvent), + Genesis(KvLogEvent), + Update(KvLogEvent), + + VaultIndex(KvLogEvent), } impl GlobalIndexObject { - pub fn key(&self) -> &KvKey { + pub fn index_from_vault_name(vault_name: VaultName) -> GlobalIndexObject { + let vault_id = UnitId::vault_unit(vault_name); + + GlobalIndexObject::index_from_vault_id(vault_id) + } + + pub fn index_from_vault_id(vault_id: UnitId) -> GlobalIndexObject { + let idx_desc = ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::VaultIndex { + vault_id: vault_id.clone() + }); + + GlobalIndexObject::VaultIndex(KvLogEvent { + key: KvKey::unit(idx_desc), + value: (), + }) + } +} + +impl ToGenericEvent for GlobalIndexObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::GlobalIndex(self) + } +} + +impl ObjIdExtractor for GlobalIndexObject { + fn obj_id(&self) -> ObjectId { match self { - GlobalIndexObject::Unit { event } => &event.key, - GlobalIndexObject::Genesis { event } => &event.key, - GlobalIndexObject::Update { event } => &event.key, + GlobalIndexObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + GlobalIndexObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + GlobalIndexObject::Update(event) => ObjectId::from(event.key.obj_id.clone()), + GlobalIndexObject::VaultIndex(event) => ObjectId::from(event.key.obj_id.clone()) } } } -impl GlobalIndexObject { - pub fn unit() -> Self { - GlobalIndexObject::Unit { - event: KvLogEvent::global_index_unit(), +impl KeyExtractor for GlobalIndexObject { + fn key(&self) -> GenericKvKey { + match self { + GlobalIndexObject::Unit(event) => GenericKvKey::from(event.key.clone()), + GlobalIndexObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + GlobalIndexObject::Update(event) => GenericKvKey::from(event.key.clone()), + GlobalIndexObject::VaultIndex(event) => GenericKvKey::from(event.key.clone()) } } +} - pub fn genesis(server_pk: &PublicKeyRecord) -> Self { - let genesis_log_event = KvLogEvent::global_index_genesis(server_pk); - GlobalIndexObject::Genesis { - event: genesis_log_event, - } +impl UnitEventWithEmptyValue for GlobalIndexObject { + fn unit() -> Self { + GlobalIndexObject::Unit(KvLogEvent::global_index_unit()) } } -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct GlobalIndexRecord { - pub vault_id: String, +impl GlobalIndexObject { + pub fn genesis(server_pk: DeviceData) -> Self { + GlobalIndexObject::Genesis(KvLogEvent::global_index_genesis(server_pk)) + } } diff --git a/core/src/node/db/events/kv_log_event.rs b/core/src/node/db/events/kv_log_event.rs index f7fc0ad3..f5d84cc8 100644 --- a/core/src/node/db/events/kv_log_event.rs +++ b/core/src/node/db/events/kv_log_event.rs @@ -1,85 +1,127 @@ -use crate::models::UserSignature; -use crate::node::db::events::common::{ObjectCreator, PublicKeyRecord}; -use crate::node::db::events::global_index::GlobalIndexRecord; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, IdStr, ObjectId}; +use crate::node::common::model::device::DeviceData; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::events::object_id::{ArtifactId, GenesisId, Next, UnitId}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct KvLogEvent { - pub key: KvKey, +pub struct KvLogEvent { + pub key: KvKey, pub value: T, } -impl KvLogEvent { - pub fn genesis(obj_desc: &ObjectDescriptor, server_pk: &PublicKeyRecord) -> KvLogEvent { +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct KvEvent { + pub obj_desc: ObjectDescriptor, + pub value: T, +} + +impl KvLogEvent { + pub fn genesis(obj_desc: ObjectDescriptor, server_pk: DeviceData) -> KvLogEvent { KvLogEvent { key: KvKey::genesis(obj_desc), - value: server_pk.clone(), + value: server_pk, } } - pub fn vault_unit(user_sig: &UserSignature) -> KvLogEvent { - let obj_desc = &ObjectDescriptor::vault(user_sig.vault.name.clone()); + pub fn global_index_unit() -> KvLogEvent { KvLogEvent { - key: KvKey::unit(obj_desc), - value: user_sig.clone(), + key: KvKey::unit(ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index)), + value: (), } } - pub fn global_index_unit() -> KvLogEvent<()> { - KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::GlobalIndex), - value: (), - } + pub fn global_index_genesis(server_pk: DeviceData) -> KvLogEvent { + Self::genesis(ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index), server_pk) } +} - pub fn global_index_genesis(server_pk: &PublicKeyRecord) -> KvLogEvent { - Self::genesis(&ObjectDescriptor::GlobalIndex, server_pk) +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum GenericKvKey { + UnitKey { key: KvKey }, + GenesisKey { key: KvKey }, + ArtifactKey { key: KvKey }, +} + +impl From> for GenericKvKey { + fn from(unit_key: KvKey) -> Self { + GenericKvKey::UnitKey { key: unit_key } } } -impl KvLogEvent { - pub fn new_global_index_event(tail_id: &ObjectId, vault_id: &IdStr) -> KvLogEvent { - let key = KvKey { - obj_id: tail_id.clone(), - obj_desc: ObjectDescriptor::GlobalIndex, - }; +impl From> for GenericKvKey { + fn from(genesis_key: KvKey) -> Self { + GenericKvKey::GenesisKey { key: genesis_key } + } +} - KvLogEvent { - key, - value: GlobalIndexRecord { - vault_id: vault_id.id.clone(), - }, +impl From> for GenericKvKey { + fn from(artifact_key: KvKey) -> Self { + GenericKvKey::ArtifactKey { key: artifact_key } + } +} + +impl GenericKvKey { + pub fn obj_desc(&self) -> ObjectDescriptor { + match self { + GenericKvKey::UnitKey { key } => key.obj_desc.clone(), + GenericKvKey::GenesisKey { key } => key.obj_desc.clone(), + GenericKvKey::ArtifactKey { key } => key.obj_desc.clone() } } } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct KvKey { - pub obj_id: ObjectId, +pub struct KvKey { + pub obj_id: Id, pub obj_desc: ObjectDescriptor, } -impl ObjectCreator<&ObjectDescriptor> for KvKey { - fn unit(obj_desc: &ObjectDescriptor) -> Self { +impl KvKey { + pub fn unit(obj_desc: ObjectDescriptor) -> Self { Self { - obj_id: ObjectId::unit(obj_desc), - obj_desc: obj_desc.clone(), + obj_id: UnitId::unit(&obj_desc), + obj_desc, } } +} - fn genesis(obj_desc: &ObjectDescriptor) -> Self { - Self::unit(obj_desc).next() +impl KvKey { + pub fn genesis(obj_desc: ObjectDescriptor) -> Self { + let unit_id = KvKey::unit(obj_desc.clone()); + Self { + obj_id: unit_id.next().obj_id, + obj_desc, + } } } -impl IdGen for KvKey { - fn next(&self) -> Self { - Self { +impl Next> for KvKey { + fn next(self) -> KvKey { + KvKey { obj_id: self.obj_id.next(), obj_desc: self.obj_desc.clone(), } } } + +impl Next> for KvKey { + fn next(self) -> KvKey { + KvKey { + obj_id: self.obj_id.next(), + obj_desc: self.obj_desc.clone(), + } + } +} + +impl KvKey { + pub fn artifact(obj_desc: ObjectDescriptor, obj_id: ArtifactId) -> Self { + Self { + obj_id, + obj_desc, + } + } +} \ No newline at end of file diff --git a/core/src/node/db/events/local.rs b/core/src/node/db/events/local.rs index f580250f..cbeeeaf3 100644 --- a/core/src/node/db/events/local.rs +++ b/core/src/node/db/events/local.rs @@ -1,22 +1,118 @@ -use crate::models::{MetaVault, UserCredentials}; +use anyhow::{anyhow, Error}; + +use crate::node::common::model::device::{DeviceCredentials, DeviceData}; +use crate::node::common::model::user::UserCredentials; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; use crate::node::db::events::db_tail::DbTail; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, KeyExtractor, ObjIdExtractor, ToGenericEvent, UnitEvent}; +use crate::node::db::events::kv_log_event::{GenericKvKey, KvKey, KvLogEvent}; +use crate::node::db::events::object_id::{GenesisId, ObjectId, UnitId}; -/// Local events (persistent objects which lives only in the local environment) which must not be synchronized #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub enum KvLogEventLocal { - MetaVault { event: Box> }, - UserCredentials { event: Box> }, - DbTail { event: Box> }, +pub enum CredentialsObject { + Device(KvLogEvent), + /// Default vault + DefaultUser(KvLogEvent) +} + +impl ObjIdExtractor for CredentialsObject { + fn obj_id(&self) -> ObjectId { + CredentialsObject::unit_id() + } +} + +impl ToGenericEvent for CredentialsObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::Credentials(self) + } +} + +impl UnitEvent for CredentialsObject { + fn unit(value: DeviceCredentials) -> Self { + let event = KvLogEvent { + key: KvKey::unit(ObjectDescriptor::CredsIndex), + value, + }; + + CredentialsObject::Device(event) + } +} + +impl CredentialsObject { + pub fn default_user(user: UserCredentials) -> Self { + let event = KvLogEvent { + key: KvKey::genesis(ObjectDescriptor::CredsIndex), + value: user, + }; + + CredentialsObject::DefaultUser(event) + } +} + +impl TryFrom for CredentialsObject { + type Error = Error; + + fn try_from(creds_event: GenericKvLogEvent) -> Result { + if let GenericKvLogEvent::Credentials(creds_obj) = creds_event { + return Ok(creds_obj); + } else { + let error: Error = anyhow!("Invalid credentials event type: {:?}", creds_event.key().obj_desc()); + Err(error) + } + } +} + +impl KeyExtractor for CredentialsObject { + fn key(&self) -> GenericKvKey { + match self { + CredentialsObject::Device(event) => GenericKvKey::from(event.key.clone()), + CredentialsObject::DefaultUser(event) => GenericKvKey::from(event.key.clone()) + } + } } -impl KvLogEventLocal { - pub fn key(&self) -> &KvKey { +impl CredentialsObject { + pub fn unit_id() -> ObjectId { + ObjectId::unit(ObjectDescriptor::CredsIndex) + } + + pub fn device(&self) -> DeviceData { match self { - KvLogEventLocal::DbTail { event } => &event.key, - KvLogEventLocal::MetaVault { event } => &event.key, - KvLogEventLocal::UserCredentials { event } => &event.key, + CredentialsObject::Device(event) => event.value.device.clone(), + CredentialsObject::DefaultUser(event) => event.value.device_creds.device.clone() } } } + + + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DbTailObject(pub KvLogEvent); + +impl ToGenericEvent for DbTailObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::DbTail(self) + } +} + +impl KeyExtractor for DbTailObject { + fn key(&self) -> GenericKvKey { + GenericKvKey::from(self.0.key.clone()) + } +} + +impl ObjIdExtractor for DbTailObject { + fn obj_id(&self) -> ObjectId { + ObjectId::from(self.0.key.obj_id.clone()) + } +} + +impl UnitEvent for DbTailObject { + fn unit(value: DbTail) -> Self { + let key = KvKey::unit(ObjectDescriptor::DbTail); + let event = KvLogEvent { key, value }; + Self(event) + } +} diff --git a/core/src/node/db/events/mod.rs b/core/src/node/db/events/mod.rs index 3a715c00..d351265d 100644 --- a/core/src/node/db/events/mod.rs +++ b/core/src/node/db/events/mod.rs @@ -5,6 +5,5 @@ pub mod generic_log_event; pub mod global_index; pub mod kv_log_event; pub mod local; -pub mod object_descriptor; pub mod object_id; pub mod vault_event; diff --git a/core/src/node/db/events/object_descriptor.rs b/core/src/node/db/events/object_descriptor.rs deleted file mode 100644 index 6da91dff..00000000 --- a/core/src/node/db/events/object_descriptor.rs +++ /dev/null @@ -1,214 +0,0 @@ -use crate::crypto::utils; -use crate::models::{DeviceInfo, MetaPasswordId, SecretDistributionDocData, SecretDistributionType}; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -#[serde(tag = "__obj_desc")] -pub enum ObjectDescriptor { - GlobalIndex, - MemPool, - DbTail, - Vault { - vault_name: String, - }, - - MetaPassword { - vault_name: String, - }, - - /// Secret distribution (split, recover, recovery request and so on) - SharedSecret(SharedSecretDescriptor), - - /// This Audit log allows to recreate a lifetime of the secret sharing workflow and allows to have a consistent view - ///across the cluster on what events of the secret sharing happened at what time. - /// All the nodes of the system can use this log to sync data (split, recover events) exactly once and keep track - /// of secret shares across the cluster and sync/replicate those shares efficiently between nodes and have more deterministic - /// flow of actions and events for the secret sharing mechanism. - /// - /// We will add new events into the audit log which will indicate that the event has been happened. - /// For instance: - /// we want to send a secret share from one device to another device. - /// - the device_a creates a new SharedSecretAuditDescriptor::SplitEvent and puts it into the audit table (which contains the object_id of the split event). - /// - the device_a creates a SharedSecretDescriptor::Split event (which contains an actual secret share (data)) - /// - sync gateway sends the audit event to the server, and sends the split event also to the server - /// - when device_b syncs the data, the server looks into the audit table, analyses tail records, takes all split/recover events to be sent to the device. - /// - /// By looking into the audit log (since the audit contains the information about what secret shares were created and sent) - /// we know what split/recover events needs to be sent synchronized - SharedSecretAudit { - vault_name: String, - }, - - MetaVault, - UserCreds, -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub enum SharedSecretDescriptor { - Split(SharedSecretEventId), - Recover(SharedSecretEventId), - RecoveryRequest(SharedSecretEventId), -} - -impl SharedSecretDescriptor { - pub fn as_id_str(&self) -> String { - match self { - SharedSecretDescriptor::Split(event_id) => event_id.as_id_str(), - SharedSecretDescriptor::Recover(event_id) => event_id.as_id_str(), - SharedSecretDescriptor::RecoveryRequest(event_id) => event_id.as_id_str(), - } - } -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SharedSecretEventId { - pub vault_name: String, - pub meta_pass_id: MetaPasswordId, - pub receiver: DeviceInfo, -} - -impl SharedSecretEventId { - pub fn as_id_str(&self) -> String { - let pattern = [ - self.vault_name.as_str(), - self.meta_pass_id.id.as_str(), - self.receiver.device_id.as_str(), - ]; - pattern.join("-") - } -} - -impl From<&SecretDistributionDocData> for ObjectDescriptor { - fn from(secret_distribution: &SecretDistributionDocData) -> Self { - let vault_name = secret_distribution.meta_password.meta_password.vault.vault_name.clone(); - let device_id = secret_distribution - .secret_message - .receiver - .vault - .device - .as_ref() - .clone(); - - let meta_pass_id = secret_distribution.meta_password.meta_password.id.as_ref().clone(); - let ss_event_id = SharedSecretEventId { - vault_name, - meta_pass_id, - receiver: device_id, - }; - match secret_distribution.distribution_type { - SecretDistributionType::Split => ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Split(ss_event_id)), - SecretDistributionType::Recover => { - ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Recover(ss_event_id)) - } - } - } -} - -impl ObjectDescriptor { - pub fn to_id(&self) -> String { - utils::to_id(self.fqdn().as_str()) - } - - pub fn vault(vault_name: String) -> ObjectDescriptor { - ObjectDescriptor::Vault { vault_name } - } -} - -impl ObjectDescriptor { - /// Fully Qualified Domain Name - unique domain name of an object - pub fn fqdn(&self) -> String { - format!("{}:{}", self.object_type(), self.object_name()) - } - - pub fn object_name(&self) -> String { - match self { - ObjectDescriptor::GlobalIndex => String::from("index"), - ObjectDescriptor::MemPool => String::from("mem_pool"), - - ObjectDescriptor::DbTail => String::from("db_tail"), - ObjectDescriptor::Vault { vault_name } => vault_name.clone(), - - ObjectDescriptor::SharedSecret(s_s_descriptor) => s_s_descriptor.as_id_str(), - ObjectDescriptor::SharedSecretAudit { vault_name } => vault_name.clone(), - - ObjectDescriptor::MetaPassword { vault_name } => vault_name.clone(), - ObjectDescriptor::MetaVault => String::from("index"), - ObjectDescriptor::UserCreds => String::from("index"), - } - } -} - -impl ToString for ObjectDescriptor { - fn to_string(&self) -> String { - self.object_type() - } -} - -impl ObjectDescriptor { - pub fn object_type(&self) -> String { - match self { - ObjectDescriptor::GlobalIndex { .. } => String::from("GlobalIndex"), - ObjectDescriptor::MemPool { .. } => String::from("MemPool"), - - ObjectDescriptor::Vault { .. } => String::from("Vault"), - ObjectDescriptor::SharedSecret(ss_desc) => match ss_desc { - SharedSecretDescriptor::Split(_) => String::from("SSSplit"), - SharedSecretDescriptor::Recover(_) => String::from("SSRecover"), - SharedSecretDescriptor::RecoveryRequest(_) => String::from("SSRecoveryRequest"), - }, - - ObjectDescriptor::SharedSecretAudit { .. } => String::from("SSAudit"), - - ObjectDescriptor::MetaPassword { .. } => String::from("MetaPass"), - ObjectDescriptor::MetaVault { .. } => String::from("MetaVault"), - ObjectDescriptor::UserCreds { .. } => String::from("UserCreds"), - ObjectDescriptor::DbTail { .. } => String::from("DbTail"), - } - } -} - -#[cfg(test)] -mod test { - use crate::models::{DeviceInfo, MetaPasswordId}; - use crate::node::db::events::object_descriptor::{ObjectDescriptor, SharedSecretDescriptor, SharedSecretEventId}; - - #[test] - fn test_global_index() { - let obj_desc = ObjectDescriptor::GlobalIndex; - assert_eq!(String::from("GlobalIndex:index::0"), obj_desc.to_id()) - } - - #[test] - fn test_vault() { - let obj_desc = ObjectDescriptor::Vault { - vault_name: String::from("test"), - }; - assert_eq!(String::from("Vault:test::0"), obj_desc.to_id()) - } - - #[test] - fn test_meta_pass() { - let obj_desc = ObjectDescriptor::MetaPassword { - vault_name: String::from("test"), - }; - assert_eq!(String::from("MetaPass:test::0"), obj_desc.to_id()) - } - - #[test] - fn test_shared_secret_split() { - let event_id = SharedSecretEventId { - vault_name: String::from("test_vault"), - meta_pass_id: MetaPasswordId::build(String::from("test_meta_pass"), String::from("salt")), - receiver: DeviceInfo { - device_id: "test_device".to_string(), - device_name: "321".to_string(), - }, - }; - - let obj_desc = ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Split(event_id)); - let expected = String::from("SSSplit:test_vault-cqH6kknDPPWHmlYXEaKJWA-test_device::0"); - assert_eq!(expected, obj_desc.to_id()) - } -} diff --git a/core/src/node/db/events/object_id.rs b/core/src/node/db/events/object_id.rs index 859fe5b8..257e908c 100644 --- a/core/src/node/db/events/object_id.rs +++ b/core/src/node/db/events/object_id.rs @@ -1,157 +1,176 @@ use serde_derive::{Deserialize, Serialize}; -use crate::crypto::utils; -use crate::node::db::events::common::ObjectCreator; -use crate::node::db::events::object_descriptor::ObjectDescriptor; +use crate::crypto::utils::NextId; +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptor, ObjectDescriptorId}; +use crate::node::db::descriptors::vault::VaultDescriptor; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[serde(tag = "__obj_id")] pub enum ObjectId { - /// In category theory, a unit type is a fundamental concept that arises in the study of types and functions. - /// It is often denoted as the unit object, represented by the symbol "1" or "Unit." - /// The unit type serves as a foundational element within category theory, - /// providing a way to represent the absence of information or the presence of a single unique value. - /// - /// Same here, Unit is a inittial request to create/initialize an object, it's step zero. - Unit { id: String }, - /// Next step after Unit is Genesis, it's a first step in object initialization, - /// it contains digital signature and public key of the actor (for instance it could be meta secret server) that - /// is responsible to create a persistent object - Genesis { id: String, unit_id: String }, - /// Any regular request or update event in the objects' lifetime - Regular { - id: String, - prev_id: String, - unit_id: String, - }, -} - -#[derive(Debug)] -pub struct IdStr { - pub id: String, -} - -pub trait IdGen { - fn next(&self) -> Self; -} - -impl IdGen for ObjectId { - fn next(&self) -> ObjectId { - let next_id_str = utils::to_id(self.id_str().as_str()); + Unit(UnitId), + Genesis(GenesisId), + Artifact(ArtifactId), +} - match self { - ObjectId::Unit { id } => ObjectId::Genesis { - id: next_id_str, - unit_id: id.clone(), - }, - ObjectId::Genesis { id, unit_id } => ObjectId::Regular { - id: next_id_str, - prev_id: id.clone(), - unit_id: unit_id.clone(), - }, - ObjectId::Regular { id, unit_id, .. } => ObjectId::Regular { - id: next_id_str, - prev_id: id.clone(), - unit_id: unit_id.clone(), - }, +impl ObjectId { + pub fn id_str(&self) -> String { + let id = match self { + ObjectId::Unit(unit_id) => unit_id.id.clone(), + ObjectId::Genesis(genesis_id) => genesis_id.id.clone(), + ObjectId::Artifact(artifact_id) => artifact_id.id.clone(), + }; + + serde_json::to_string(&id).unwrap() + } +} + +pub trait Next { + fn next(self) -> To; +} + +/// In category theory, a unit type is a fundamental concept that arises in the study of types and functions. +/// It is often denoted as the unit object, represented by the symbol "1" or "Unit." +/// The unit type serves as a foundational element within category theory, +/// providing a way to represent the absence of information or the presence of a single unique value. +/// +/// Same here, Unit is a initial request to create/initialize an object, it's step zero. +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct UnitId { + pub id: ObjectDescriptorId, +} + +impl Next for UnitId { + fn next(self) -> GenesisId { + GenesisId { + id: self.id.clone().next_id(), + unit_id: self, } } } -impl From<&ObjectId> for IdStr { - fn from(obj_id: &ObjectId) -> IdStr { - IdStr { id: obj_id.id_str() } +impl From for UnitId { + fn from(id: ObjectDescriptorId) -> Self { + Self { id } } } -impl ObjectId { - pub fn unit_id(&self) -> ObjectId { - match self { - ObjectId::Unit { .. } => self.clone(), - ObjectId::Genesis { unit_id, .. } => ObjectId::Unit { id: unit_id.clone() }, - ObjectId::Regular { unit_id, .. } => Self::Unit { id: unit_id.clone() }, - } +impl From for ObjectId { + fn from(value: UnitId) -> Self { + ObjectId::Unit(value) } +} - pub fn id_str(&self) -> String { - match self { - ObjectId::Genesis { id, .. } => id.clone(), - ObjectId::Regular { id, .. } => id.clone(), - ObjectId::Unit { id } => id.clone(), - } +impl From for ObjectId { + fn from(value: GenesisId) -> Self { + ObjectId::Genesis(value) + } +} + +impl From for ObjectId { + fn from(value: ArtifactId) -> Self { + ObjectId::Artifact(value) } +} - pub fn is_unit(&self) -> bool { - match self { - ObjectId::Unit { .. } => true, - ObjectId::Genesis { .. } => false, - ObjectId::Regular { .. } => false, - } +impl ObjectId { + pub fn unit(obj_desc: ObjectDescriptor) -> Self { + ObjectId::Unit(UnitId::unit(&obj_desc)) + } + + pub fn genesis(obj_desc: ObjectDescriptor) -> Self { + ObjectId::Genesis(GenesisId::genesis(obj_desc)) } - pub fn is_genesis(&self) -> bool { + pub fn get_unit_id(&self) -> UnitId { match self { - ObjectId::Unit { .. } => false, - ObjectId::Genesis { .. } => true, - ObjectId::Regular { .. } => false, + ObjectId::Unit(unit_id) => unit_id.clone(), + ObjectId::Genesis(genesis_id) => genesis_id.unit_id.clone(), + ObjectId::Artifact(artifact_id) => artifact_id.unit_id.clone() } } +} - pub fn db_tail() -> ObjectId { - ObjectId::unit(&ObjectDescriptor::DbTail) +impl Next for ObjectId { + fn next(self) -> ObjectId { + match self { + ObjectId::Unit(unit_id) => ObjectId::from(unit_id.next()), + ObjectId::Genesis(genesis_id) => ObjectId::from(genesis_id.next()), + ObjectId::Artifact(artifact_id) => ObjectId::from(artifact_id.next()) + } } +} - pub fn global_index_unit() -> ObjectId { - ObjectId::unit(&ObjectDescriptor::GlobalIndex) +impl UnitId { + pub fn unit(obj_descriptor: &ObjectDescriptor) -> UnitId { + let fqdn = obj_descriptor.to_fqdn(); + UnitId { id: fqdn.next_id() } } - pub fn global_index_genesis() -> ObjectId { - ObjectId::genesis(&ObjectDescriptor::GlobalIndex) + pub fn db_tail() -> UnitId { + UnitId::unit(&ObjectDescriptor::DbTail) } - pub fn meta_vault_index() -> ObjectId { - ObjectId::unit(&ObjectDescriptor::MetaVault) + pub fn global_index() -> UnitId { + UnitId::unit(&ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index)) } - pub fn vault_unit(vault_name: &str) -> Self { - let vault_desc = ObjectDescriptor::Vault { - vault_name: vault_name.to_string(), - }; - ObjectId::unit(&vault_desc) + pub fn vault_unit(vault_name: VaultName) -> UnitId { + let vault_desc = ObjectDescriptor::Vault(VaultDescriptor::Vault(vault_name)); + UnitId::unit(&vault_desc) } +} - pub fn meta_pass_unit(vault_name: &str) -> Self { - let vault_desc = ObjectDescriptor::MetaPassword { - vault_name: vault_name.to_string(), - }; - ObjectId::unit(&vault_desc) - } +/// Next step after Unit is Genesis, it's a first step in object initialization, +/// it contains digital signature and public key of the actor (for instance it could be meta secret server) that +/// is responsible to create a persistent object +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GenesisId { + id: ObjectDescriptorId, + unit_id: UnitId, +} - pub fn mempool_unit() -> Self { - ObjectId::unit(&ObjectDescriptor::MemPool) +impl Next for GenesisId { + fn next(self) -> ArtifactId { + ArtifactId { + id: self.id.clone().next_id(), + prev_id: self.id, + unit_id: self.unit_id, + } } } -impl ObjectCreator<&ObjectDescriptor> for ObjectId { - fn unit(obj_descriptor: &ObjectDescriptor) -> Self { - let unit_id = obj_descriptor.to_id(); - Self::Unit { id: unit_id } +impl GenesisId { + pub fn genesis(obj_desc: ObjectDescriptor) -> GenesisId { + let unit_id = UnitId::unit(&obj_desc); + unit_id.next() } - fn genesis(obj_desc: &ObjectDescriptor) -> Self { - Self::unit(obj_desc).next() + pub fn global_index_genesis() -> GenesisId { + GenesisId::genesis(ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index)) } } -#[cfg(test)] -mod test { - use crate::node::db::events::object_id::ObjectId; +/// Any regular request or update event in the objects' lifetime +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ArtifactId { + id: ObjectDescriptorId, + prev_id: ObjectDescriptorId, + unit_id: UnitId, +} - #[test] - fn json_parsing_test() { - let obj_id = ObjectId::Unit { id: "test".to_string() }; - let obj_id_json = serde_json::to_string(&obj_id).unwrap(); - println!("{}", obj_id_json); +/// Generate next artifact from the previous one +impl Next for ArtifactId { + fn next(self) -> ArtifactId { + ArtifactId { + id: self.id.clone().next_id(), + prev_id: self.id, + unit_id: self.unit_id, + } } } diff --git a/core/src/node/db/events/vault_event.rs b/core/src/node/db/events/vault_event.rs index 64ed4802..f441b20b 100644 --- a/core/src/node/db/events/vault_event.rs +++ b/core/src/node/db/events/vault_event.rs @@ -1,47 +1,243 @@ -use crate::models::{UserSignature, VaultDoc}; -use crate::node::db::events::common::PublicKeyRecord; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use anyhow::anyhow; + +use crate::node::common::model::device::DeviceData; +use crate::node::common::model::secret::MetaPasswordId; +use crate::node::common::model::user::{UserData, UserDataMember, UserMembership}; +use crate::node::common::model::vault::{VaultData, VaultName}; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, KeyExtractor, ObjIdExtractor, ToGenericEvent}; +use crate::node::db::events::kv_log_event::{GenericKvKey, KvLogEvent}; +use crate::node::db::events::object_id::{ArtifactId, GenesisId, ObjectId, UnitId}; + +/// Each device has its own unique device_log table, to prevent conflicts in updates vault state +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum DeviceLogObject { + Unit(KvLogEvent), + /// Device sends its data to ensure that the only this device can send events to this log + Genesis(KvLogEvent), + Action(KvLogEvent), +} + +impl TryFrom for DeviceLogObject { + type Error = anyhow::Error; + + fn try_from(event: GenericKvLogEvent) -> Result { + if let GenericKvLogEvent::DeviceLog(device_log) = event { + Ok(device_log) + } else { + Err(anyhow!("Not a device log event")) + } + } +} + +impl ToGenericEvent for DeviceLogObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::DeviceLog(self) + } +} + +impl ObjIdExtractor for DeviceLogObject { + fn obj_id(&self) -> ObjectId { + match self { + DeviceLogObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + DeviceLogObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + DeviceLogObject::Action(event) => ObjectId::from(event.key.obj_id.clone()), + } + } +} + +impl KeyExtractor for DeviceLogObject { + fn key(&self) -> GenericKvKey { + match self { + DeviceLogObject::Unit(event) => GenericKvKey::from(event.key.clone()), + DeviceLogObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + DeviceLogObject::Action(event) => GenericKvKey::from(event.key.clone()), + } + } +} + +/// VaultLog keeps incoming events in order, the log is a queue for incoming messages and used to +/// recreate the vault state from events (event sourcing) +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VaultLogObject { + Unit(KvLogEvent), + Genesis(KvLogEvent), + Action(KvLogEvent) +} + +impl TryFrom for VaultLogObject { + type Error = anyhow::Error; + + fn try_from(event: GenericKvLogEvent) -> Result { + if let GenericKvLogEvent::VaultLog(vault_log) = event { + Ok(vault_log) + } else { + Err(anyhow!("Not a vault log event")) + } + } +} + +impl ToGenericEvent for VaultLogObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::VaultLog(self) + } +} + +impl KeyExtractor for VaultLogObject { + fn key(&self) -> GenericKvKey { + match self { + VaultLogObject::Unit(event) => GenericKvKey::from(event.key.clone()), + VaultLogObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + VaultLogObject::Action(event) => GenericKvKey::from(event.key.clone()), + } + } +} + +impl ObjIdExtractor for VaultLogObject { + fn obj_id(&self) -> ObjectId { + match self { + VaultLogObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + VaultLogObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + VaultLogObject::Action(event) => ObjectId::from(event.key.obj_id.clone()), + } + } +} #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum VaultObject { - /// SingUp request - Unit { - event: KvLogEvent, - }, - Genesis { - event: KvLogEvent, - }, + Unit(KvLogEvent), + /// Meta Server public keys + Genesis(KvLogEvent), + Vault(KvLogEvent) +} - SignUpUpdate { - event: KvLogEvent, - }, +impl TryFrom for VaultObject { + type Error = anyhow::Error; - JoinUpdate { - event: KvLogEvent, - }, + fn try_from(event: GenericKvLogEvent) -> Result { + if let GenericKvLogEvent::Vault(vault) = event { + Ok(vault) + } else { + Err(anyhow!("Not a vault event")) + } + } +} - JoinRequest { - event: KvLogEvent, - }, +impl ToGenericEvent for VaultObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::Vault(self) + } +} + +impl ObjIdExtractor for VaultObject { + fn obj_id(&self) -> ObjectId { + match self { + VaultObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + VaultObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + VaultObject::Vault(event) => ObjectId::from(event.key.obj_id.clone()), + } + } +} + +impl KeyExtractor for VaultObject { + fn key(&self) -> GenericKvKey { + match self { + VaultObject::Unit(event) => GenericKvKey::from(event.key.clone()), + VaultObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + VaultObject::Vault(event) => GenericKvKey::from(event.key.clone()), + } + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VaultMembershipObject { + Unit(KvLogEvent), + /// Device public keys + Genesis(KvLogEvent), + Membership(KvLogEvent) +} + +impl VaultMembershipObject { + pub fn is_member(&self) -> bool { + let VaultMembershipObject::Membership(membership_event) = self else { + return false; + }; + + if let UserMembership::Member(UserDataMember { .. }) = membership_event.value { + true + } else { + false + } + } + + pub fn is_not_member(&self) -> bool { + !self.is_member() + } +} + +impl TryFrom for VaultMembershipObject { + type Error = anyhow::Error; + + fn try_from(event: GenericKvLogEvent) -> Result { + if let GenericKvLogEvent::VaultMembership(vault_status) = event { + Ok(vault_status) + } else { + Err(anyhow!("Not a vault status event")) + } + } +} + +impl KeyExtractor for VaultMembershipObject { + fn key(&self) -> GenericKvKey { + match self { + VaultMembershipObject::Unit(event) => GenericKvKey::from(event.key.clone()), + VaultMembershipObject::Genesis(event) => GenericKvKey::from(event.key.clone()), + VaultMembershipObject::Membership(event) => GenericKvKey::from(event.key.clone()), + } + } +} + +impl ToGenericEvent for VaultMembershipObject { + fn to_generic(self) -> GenericKvLogEvent { + GenericKvLogEvent::VaultMembership(self) + } } -impl VaultObject { - pub fn key(&self) -> &KvKey { +impl ObjIdExtractor for VaultMembershipObject { + fn obj_id(&self) -> ObjectId { match self { - VaultObject::Unit { event } => &event.key, - VaultObject::Genesis { event } => &event.key, - VaultObject::SignUpUpdate { event } => &event.key, - VaultObject::JoinUpdate { event } => &event.key, - VaultObject::JoinRequest { event } => &event.key, + VaultMembershipObject::Unit(event) => ObjectId::from(event.key.obj_id.clone()), + VaultMembershipObject::Genesis(event) => ObjectId::from(event.key.obj_id.clone()), + VaultMembershipObject::Membership(event) => ObjectId::from(event.key.obj_id.clone()), } } } -impl VaultObject { - pub fn unit(user_sig: &UserSignature) -> Self { - VaultObject::Unit { - event: KvLogEvent::vault_unit(user_sig), +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VaultAction { + JoinRequest { candidate: UserData }, + /// When the device becomes a member of the vault, it can change membership of other members + UpdateMembership { + sender: UserDataMember, + update: UserMembership + }, + /// A member can add a new meta password into the vault + AddMetaPassword { + sender: UserDataMember, + meta_pass_id: MetaPasswordId + }, +} + +impl VaultAction { + pub fn vault_name(&self) -> VaultName { + match self { + VaultAction::JoinRequest { candidate } => candidate.vault_name.clone(), + VaultAction::UpdateMembership { update, .. } => update.user_data().vault_name, + VaultAction::AddMetaPassword { sender: UserDataMember(user), .. } => user.vault_name.clone() } } } diff --git a/core/src/node/db/in_mem_db.rs b/core/src/node/db/in_mem_db.rs index f66a1ea5..30906797 100644 --- a/core/src/node/db/in_mem_db.rs +++ b/core/src/node/db/in_mem_db.rs @@ -1,13 +1,13 @@ -use async_mutex::Mutex; use std::collections::HashMap; use std::sync::Arc; +use async_mutex::Mutex; use async_trait::async_trait; -use tracing::Instrument; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, ObjIdExtractor}; use crate::node::db::events::object_id::ObjectId; -use crate::node::db::generic_db::{DeleteCommand, FindOneQuery, KvLogEventRepo, SaveCommand}; +use crate::node::db::repo::generic_db::{DeleteCommand, FindOneQuery, KvLogEventRepo, SaveCommand}; +use tracing::instrument; pub struct InMemKvLogEventRepo { pub db: Arc>>, @@ -26,25 +26,38 @@ pub enum InMemDbError {} #[async_trait(? Send)] impl FindOneQuery for InMemKvLogEventRepo { + + #[instrument(skip_all)] async fn find_one(&self, key: ObjectId) -> anyhow::Result> { - let maybe_value = self.db.lock().in_current_span().await.get(&key).cloned(); + let maybe_value = self.db.lock().await.get(&key).cloned(); Ok(maybe_value) } + + async fn get_key(&self, key: ObjectId) -> anyhow::Result> { + let maybe_value = self.db.lock().await.get(&key).cloned(); + Ok(maybe_value.map(|value| value.obj_id())) + } } #[async_trait(? Send)] impl SaveCommand for InMemKvLogEventRepo { - async fn save(&self, key: ObjectId, value: GenericKvLogEvent) -> anyhow::Result { - let mut db = self.db.lock().in_current_span().await; + + #[instrument(skip_all)] + async fn save(&self, value: GenericKvLogEvent) -> anyhow::Result { + let mut db = self.db.lock().await; + + let key = value.obj_id(); db.insert(key.clone(), value.clone()); - Ok(key.clone()) + Ok(key) } } #[async_trait(? Send)] impl DeleteCommand for InMemKvLogEventRepo { + + #[instrument(skip_all)] async fn delete(&self, key: ObjectId) { - let mut db = self.db.lock().in_current_span().await; + let mut db = self.db.lock().await; let _ = db.remove(&key); } } diff --git a/core/src/node/db/meta_db/meta_db_service.rs b/core/src/node/db/meta_db/meta_db_service.rs deleted file mode 100644 index 555195c2..00000000 --- a/core/src/node/db/meta_db/meta_db_service.rs +++ /dev/null @@ -1,183 +0,0 @@ -use std::sync::Arc; - -use crate::node::common::data_transfer::MpscDataTransfer; -use anyhow::anyhow; -use tracing::{debug, info, instrument, Instrument}; - -use crate::node::db::events::common::VaultInfo; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::meta_db_view::{MetaDb, TailId}; -use crate::node::db::meta_db::store::meta_pass_store::MetaPassStore; -use crate::node::db::meta_db::store::vault_store::VaultStore; -use crate::node::db::objects::persistent_object::PersistentObject; - -pub struct MetaDbService { - pub persistent_obj: Arc>, - pub repo: Arc, - pub meta_db_id: String, - pub data_transfer: Arc, -} - -pub struct MetaDbDataTransfer { - pub dt: MpscDataTransfer, -} - -pub enum MetaDbRequestMessage { - GetVaultInfo { vault_name: String }, - GetVaultStore { vault_name: String }, - GetMetaPassStore { vault_name: String }, -} - -pub enum MetaDbResponseMessage { - VaultInfo { vault: VaultInfo }, - VaultStore { vault_store: VaultStore }, - MetaPassStore { meta_pass_store: MetaPassStore }, -} - -impl MetaDbService { - #[instrument(skip_all)] - pub async fn run(&self) { - info!("Run meta_db service"); - - while let Ok(msg) = self.data_transfer.dt.service_receive().in_current_span().await { - let mut meta_db = MetaDb::new(self.meta_db_id.clone()); - //Global index - FULL synchronization - self.sync_meta_db(&mut meta_db).in_current_span().await; - - match msg { - MetaDbRequestMessage::GetVaultInfo { vault_name } => { - meta_db.update_vault_info(vault_name.as_str()); - self.sync_meta_db(&mut meta_db).in_current_span().await; - - let vault_unit_id = ObjectId::vault_unit(vault_name.as_str()); - let vault_info = if meta_db.global_index_store.contains(vault_unit_id.id_str()) { - //if the vault is already present: - match &meta_db.vault_store { - VaultStore::Store { vault, .. } => VaultInfo::Member { vault: vault.clone() }, - _ => VaultInfo::NotMember, - } - } else { - VaultInfo::NotFound - }; - - let response = MetaDbResponseMessage::VaultInfo { vault: vault_info }; - let _ = self.data_transfer.dt.send_to_client(response).in_current_span().await; - } - MetaDbRequestMessage::GetVaultStore { vault_name } => { - meta_db.update_vault_info(vault_name.as_str()); - self.sync_meta_db(&mut meta_db).in_current_span().await; - - let response = MetaDbResponseMessage::VaultStore { - vault_store: meta_db.vault_store.clone(), - }; - let _ = self.data_transfer.dt.send_to_client(response).in_current_span().await; - } - MetaDbRequestMessage::GetMetaPassStore { vault_name } => { - meta_db.update_vault_info(vault_name.as_str()); - self.sync_meta_db(&mut meta_db).in_current_span().await; - - let response = MetaDbResponseMessage::MetaPassStore { - meta_pass_store: meta_db.meta_pass_store.clone(), - }; - let _ = self.data_transfer.dt.send_to_client(response).in_current_span().await; - } - } - } - } - - async fn sync_meta_db(&self, meta_db: &mut MetaDb) { - debug!("Sync meta db"); - - let vault_events = match meta_db.vault_store.tail_id() { - None => { - vec![] - } - Some(tail_id) => self.persistent_obj.find_object_events(&tail_id).in_current_span().await, - }; - - //sync global index - let gi_events = { - let maybe_gi_tail_id = meta_db.global_index_store.tail_id(); - - match maybe_gi_tail_id { - None => { - self.persistent_obj - .find_object_events(&ObjectId::global_index_unit()) - .in_current_span() - .await - } - Some(tail_id) => self.persistent_obj.find_object_events(&tail_id).in_current_span().await, - } - }; - - let meta_pass_events = { - match meta_db.meta_pass_store.tail_id() { - None => { - vec![] - } - Some(tail_id) => self.persistent_obj.find_object_events(&tail_id).in_current_span().await, - } - }; - - let mut commit_log = vec![]; - commit_log.extend(vault_events); - commit_log.extend(gi_events); - commit_log.extend(meta_pass_events); - - meta_db.apply(commit_log); - } -} - -pub struct MetaDbServiceProxy { - pub dt: Arc, -} - -impl MetaDbServiceProxy { - pub async fn get_vault_info(&self, vault_name: String) -> anyhow::Result { - let msg = self - .dt - .dt - .send_to_service_and_get(MetaDbRequestMessage::GetVaultInfo { vault_name }) - .in_current_span() - .await?; - - match msg { - MetaDbResponseMessage::VaultInfo { vault } => Ok(vault), - _ => Err(anyhow!("Invalid message")), - } - } - - pub async fn get_vault_store(&self, vault_name: String) -> anyhow::Result { - let msg = self - .dt - .dt - .send_to_service_and_get(MetaDbRequestMessage::GetVaultStore { vault_name }) - .in_current_span() - .await?; - - match msg { - MetaDbResponseMessage::VaultStore { vault_store } => Ok(vault_store), - MetaDbResponseMessage::VaultInfo { .. } => { - Err(anyhow!("Invalid message. Expected VaultStore, got VaultInfo")) - } - MetaDbResponseMessage::MetaPassStore { .. } => { - Err(anyhow!("Invalid message. Expected VaultStore, got MetaPassStore")) - } - } - } - - pub async fn get_meta_pass_store(&self, vault_name: String) -> anyhow::Result { - let msg = self - .dt - .dt - .send_to_service_and_get(MetaDbRequestMessage::GetMetaPassStore { vault_name }) - .in_current_span() - .await?; - - match msg { - MetaDbResponseMessage::MetaPassStore { meta_pass_store } => Ok(meta_pass_store), - _ => Err(anyhow!("Invalid message")), - } - } -} diff --git a/core/src/node/db/meta_db/meta_db_view.rs b/core/src/node/db/meta_db/meta_db_view.rs deleted file mode 100644 index 76de194f..00000000 --- a/core/src/node/db/meta_db/meta_db_view.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::fmt::{Display, Formatter}; - -use tracing::info; - -use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::meta_db::store::meta_pass_store::MetaPassStore; -use crate::node::db::meta_db::store::{global_index_store::GlobalIndexStore, vault_store::VaultStore}; - -pub trait TailId { - fn tail_id(&self) -> Option; -} - -pub struct MetaDb { - pub id: String, - pub vault_store: VaultStore, - pub global_index_store: GlobalIndexStore, - pub meta_pass_store: MetaPassStore, -} - -impl MetaDb { - pub fn new(id: String) -> Self { - Self { - id, - vault_store: VaultStore::Empty, - global_index_store: GlobalIndexStore::Empty, - meta_pass_store: MetaPassStore::Empty, - } - } - - /// Apply new events to the database - pub fn apply(&mut self, commit_log: Vec) { - for (_index, generic_event) in commit_log.iter().enumerate() { - self.apply_event(generic_event); - } - } - - fn apply_event(&mut self, generic_event: &GenericKvLogEvent) { - match generic_event { - GenericKvLogEvent::GlobalIndex(gi_event) => { - self.global_index_store.apply(gi_event); - } - GenericKvLogEvent::Vault(vault_obj_info) => { - self.apply_vault_event(vault_obj_info); - } - GenericKvLogEvent::MetaPass(meta_pass_obj) => { - self.apply_meta_pass_event(meta_pass_obj); - } - GenericKvLogEvent::MemPool(_) => { - info!("Error. Mem pool events not for meta db"); - panic!("Internal mem pool event"); - } - GenericKvLogEvent::LocalEvent(_) => { - info!("Error. LocalEvents not for sync"); - panic!("Internal event"); - } - GenericKvLogEvent::SharedSecret(_) => { - //not yet implemented - } - GenericKvLogEvent::Error { .. } => { - info!("Skip. errors"); - println!("Skip errors"); - } - } - } - - pub fn update_vault_info(&mut self, vault_name: &str) { - let vault_unit_id = ObjectId::vault_unit(vault_name); - - if self.vault_store == VaultStore::Empty { - self.vault_store = VaultStore::Unit { - tail_id: vault_unit_id.clone(), - } - } - - if self.meta_pass_store == MetaPassStore::Empty { - self.meta_pass_store = MetaPassStore::Unit { - tail_id: ObjectId::meta_pass_unit(vault_name), - } - } - } -} - -impl Display for MetaDb { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "(id: {}, vault: {:?}, gi: {:?}, meta pass: {:?})", - self.id, self.vault_store, self.global_index_store, self.meta_pass_store - ) - } -} - -#[cfg(test)] -mod test { - use crate::crypto::keys::KeyManager; - use crate::models::DeviceInfo; - use crate::node::db::events::common::PublicKeyRecord; - use crate::node::db::events::global_index::GlobalIndexObject; - use crate::node::db::events::kv_log_event::KvLogEvent; - use crate::node::db::events::object_id::{IdGen, IdStr, ObjectId}; - use crate::node::db::meta_db::meta_db_view::MetaDb; - use crate::node::db::meta_db::store::global_index_store::GlobalIndexStore; - - #[test] - fn test_apply_global_index_event() { - let mut meta_db = MetaDb::new(String::from("test")); - - let s_box = KeyManager::generate_security_box("test_vault".to_string()); - let device = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - let user_sig = s_box.get_user_sig(&device); - let server_pk = PublicKeyRecord::from(user_sig.public_key.as_ref().clone()); - - meta_db.global_index_store.apply(&GlobalIndexObject::unit()); - - let genesis_event = &GlobalIndexObject::genesis(&server_pk); - meta_db.global_index_store.apply(genesis_event); - - let obj_id = &ObjectId::vault_unit("test_vault"); - let vault_id = IdStr::from(obj_id); - - meta_db.global_index_store.apply(&GlobalIndexObject::Update { - event: KvLogEvent::new_global_index_event(&obj_id.next(), &vault_id), - }); - - match meta_db.global_index_store { - GlobalIndexStore::Store { global_index, .. } => { - assert_eq!(1, global_index.len()) - } - _ => panic!("Invalid state"), - } - } -} diff --git a/core/src/node/db/meta_db/mod.rs b/core/src/node/db/meta_db/mod.rs deleted file mode 100644 index 5eceae32..00000000 --- a/core/src/node/db/meta_db/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod meta_db_service; -pub mod meta_db_view; -pub mod processor; -pub mod store; diff --git a/core/src/node/db/meta_db/processor/meta_pass_processor.rs b/core/src/node/db/meta_db/processor/meta_pass_processor.rs deleted file mode 100644 index 4a843d04..00000000 --- a/core/src/node/db/meta_db/processor/meta_pass_processor.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::node::db::events::common::MetaPassObject; -use crate::node::db::meta_db::meta_db_view::MetaDb; -use crate::node::db::meta_db::store::meta_pass_store::MetaPassStore; - -use tracing::{debug, info}; - -impl MetaDb { - pub fn apply_meta_pass_event(&mut self, meta_pass_obj: &MetaPassObject) { - debug!("Apply meta pass event"); - - let obj_id = meta_pass_obj.key().obj_id.clone(); - - match meta_pass_obj { - MetaPassObject::Unit { .. } => { - self.meta_pass_store = match &self.meta_pass_store { - MetaPassStore::Empty => MetaPassStore::Unit { tail_id: obj_id }, - MetaPassStore::Unit { .. } => MetaPassStore::Unit { tail_id: obj_id }, - _ => { - let err_str = format!( - "Invalid state. Meta pass. Got a unit event, expected db state is Empty or Unit, actual: {:?}", - &self.meta_pass_store - ); - info!(err_str); - panic!("Invalid state") - } - } - } - MetaPassObject::Genesis { event } => { - self.meta_pass_store = match &self.meta_pass_store { - MetaPassStore::Unit { .. } => MetaPassStore::Genesis { - tail_id: obj_id, - server_pk: event.value.clone(), - }, - - MetaPassStore::Genesis { .. } => MetaPassStore::Genesis { - tail_id: obj_id, - server_pk: event.value.clone(), - }, - _ => { - let err_msg = format!( - "Invalid state. Meta Pass, genesis event. Actual: {:?}, expected: unit", - self.meta_pass_store - ); - info!(err_msg); - panic!("Invalid state") - } - } - } - MetaPassObject::Update { event } => match self.meta_pass_store.clone() { - MetaPassStore::Genesis { server_pk, .. } => { - let passwords = vec![event.value.clone()]; - - self.meta_pass_store = MetaPassStore::Store { - tail_id: obj_id, - server_pk: server_pk.clone(), - passwords, - }; - } - MetaPassStore::Store { mut passwords, .. } => { - passwords.push(event.value.clone()); - } - _ => { - let err_msg = format!( - "Invalid state. Meta Pass, update event. Actual state: {:?}, expected: genesis or store", - self.meta_pass_store - ); - info!(err_msg); - panic!("Invalid state") - } - }, - } - } -} diff --git a/core/src/node/db/meta_db/processor/mod.rs b/core/src/node/db/meta_db/processor/mod.rs deleted file mode 100644 index eba3964a..00000000 --- a/core/src/node/db/meta_db/processor/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod meta_pass_processor; -pub mod vault_event_processor; diff --git a/core/src/node/db/meta_db/processor/vault_event_processor.rs b/core/src/node/db/meta_db/processor/vault_event_processor.rs deleted file mode 100644 index 10e18745..00000000 --- a/core/src/node/db/meta_db/processor/vault_event_processor.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::node::db::events::kv_log_event::KvKey; -use crate::node::db::events::vault_event::VaultObject; -use crate::node::db::meta_db::meta_db_view::MetaDb; -use crate::node::db::meta_db::store::vault_store::VaultStore; - -use tracing::{debug, error, info}; - -impl MetaDb { - pub fn apply_vault_event(&mut self, vault_obj: &VaultObject) { - debug!("Apply vault event: {:?}", vault_obj); - - let KvKey { obj_id, .. } = vault_obj.key().clone(); - - match vault_obj { - VaultObject::Unit { .. } => match self.vault_store { - VaultStore::Empty => self.vault_store = VaultStore::Unit { tail_id: obj_id }, - VaultStore::Unit { .. } => self.vault_store = VaultStore::Unit { tail_id: obj_id }, - _ => { - let msg_str = format!("Unit event. Invalid vault store state: {:?}", self.vault_store); - error!(msg_str); - } - }, - VaultObject::Genesis { event } => { - match &self.vault_store { - VaultStore::Unit { .. } => { - self.vault_store = VaultStore::Genesis { - tail_id: obj_id, - server_pk: event.value.clone(), - } - } - _ => { - let msg_error = format!("Genesis event. Invalid vault store state: {:?}", self.vault_store); - error!(msg_error); - } - }; - } - VaultObject::SignUpUpdate { event } => { - match &self.vault_store { - VaultStore::Genesis { server_pk, .. } => { - self.vault_store = VaultStore::Store { - tail_id: obj_id, - server_pk: server_pk.clone(), - vault: event.value.clone(), - } - } - _ => { - //let err_msg = format!("SignUp event. Invalid vault store state: {:?}", self.vault_store); - //panic!("{}", err_msg); - } - }; - } - VaultObject::JoinUpdate { event } => { - match &self.vault_store { - VaultStore::Store { server_pk, .. } => { - self.vault_store = VaultStore::Store { - tail_id: obj_id, - server_pk: server_pk.clone(), - vault: event.value.clone(), - } - } - _ => { - let err_msg = format!("JoinUpdate event. Invalid vault store state: {:?}", self.vault_store); - info!(err_msg); - } - }; - } - VaultObject::JoinRequest { .. } => { - match &self.vault_store { - VaultStore::Store { server_pk, vault, .. } => { - self.vault_store = VaultStore::Store { - tail_id: obj_id, - server_pk: server_pk.clone(), - vault: vault.clone(), - } - } - _ => { - let err_msg = format!("JoinRequest event. Invalid vault store state: {:?}", self.vault_store); - error!(err_msg); - } - }; - } - } - } -} - -#[cfg(test)] -mod test { - use crate::crypto::keys::KeyManager; - use crate::models::DeviceInfo; - use crate::node::db::events::object_id::ObjectId; - use crate::node::db::events::vault_event::VaultObject; - use crate::node::db::meta_db::meta_db_view::MetaDb; - use crate::node::db::meta_db::store::vault_store::VaultStore; - - #[test] - fn test() { - let mut meta_db = MetaDb::new(String::from("test")); - - let vault_name = String::from("test_vault"); - let s_box = KeyManager::generate_security_box(vault_name.clone()); - let device = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - let user_sig = s_box.get_user_sig(&device); - - let vault_obj = VaultObject::unit(&user_sig); - meta_db.apply_vault_event(&vault_obj); - match meta_db.vault_store { - VaultStore::Unit { tail_id } => { - assert_eq!(ObjectId::vault_unit(vault_name.as_str()), tail_id); - } - _ => { - panic!("Invalid state"); - } - } - } -} diff --git a/core/src/node/db/meta_db/store/global_index_store.rs b/core/src/node/db/meta_db/store/global_index_store.rs deleted file mode 100644 index 6f4e1c94..00000000 --- a/core/src/node/db/meta_db/store/global_index_store.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::collections::HashSet; - -use crate::node::db::events::common::PublicKeyRecord; -use crate::node::db::events::global_index::GlobalIndexObject; -use crate::node::db::events::kv_log_event::KvKey; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::meta_db::meta_db_view::TailId; - -impl GlobalIndexStore { - pub fn contains(&self, vault_id: String) -> bool { - match self { - GlobalIndexStore::Empty => false, - GlobalIndexStore::Genesis { .. } => false, - GlobalIndexStore::Store { global_index, .. } => global_index.contains(vault_id.as_str()), - } - } -} - -#[derive(Debug, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum GlobalIndexStore { - Empty, - Genesis { - tail_id: ObjectId, - server_pk: PublicKeyRecord, - }, - Store { - server_pk: PublicKeyRecord, - tail_id: ObjectId, - global_index: HashSet, - }, -} - -impl GlobalIndexStore { - pub fn apply(&mut self, gi_event: &GlobalIndexObject) { - let KvKey { obj_id, .. } = gi_event.key(); - - match self { - GlobalIndexStore::Empty => { - match gi_event { - GlobalIndexObject::Unit { .. } => { - // ignore - } - GlobalIndexObject::Genesis { event } => { - *self = GlobalIndexStore::Genesis { - tail_id: obj_id.clone(), - server_pk: event.value.clone(), - }; - } - GlobalIndexObject::Update { .. } => { - panic!("Error: applying gi event: update. Invalid state: Empty. Must be Genesis or Store"); - } - } - } - GlobalIndexStore::Genesis { server_pk, .. } => match gi_event { - GlobalIndexObject::Unit { .. } => { - panic!("Invalid event. Must be at least Genesis"); - } - GlobalIndexObject::Genesis { .. } => { - //Skip. Meta db already has Genesis - } - GlobalIndexObject::Update { event } => { - let mut global_index_set = HashSet::new(); - global_index_set.insert(event.value.vault_id.clone()); - - *self = GlobalIndexStore::Store { - tail_id: obj_id.clone(), - server_pk: server_pk.clone(), - global_index: global_index_set, - }; - } - }, - GlobalIndexStore::Store { - global_index, tail_id, .. - } => match gi_event { - GlobalIndexObject::Unit { .. } => { - panic!("Invalid event: unit. MetaDb state is: store"); - } - GlobalIndexObject::Genesis { .. } => { - panic!("Invalid event: genesis. MetaDb state is: store"); - } - GlobalIndexObject::Update { event } => { - global_index.insert(event.value.vault_id.clone()); - *tail_id = obj_id.clone(); - } - }, - } - } -} - -impl TailId for GlobalIndexStore { - fn tail_id(&self) -> Option { - match self { - GlobalIndexStore::Empty => None, - GlobalIndexStore::Genesis { tail_id, .. } => Some(tail_id.clone()), - GlobalIndexStore::Store { tail_id, .. } => Some(tail_id.clone()), - } - } -} - -#[cfg(test)] -mod test { - use crate::models::Base64EncodedText; - use crate::node::db::events::common::PublicKeyRecord; - use crate::node::db::events::global_index::GlobalIndexObject; - use crate::node::db::events::kv_log_event::KvLogEvent; - use crate::node::db::events::object_id::{IdGen, IdStr, ObjectId}; - use crate::node::db::meta_db::meta_db_view::MetaDb; - - #[test] - fn test_happy_case() { - let mut meta_db = MetaDb::new(String::from("test")); - - let unit_event = GlobalIndexObject::unit(); - meta_db.global_index_store.apply(&unit_event); - - let genesis = GlobalIndexObject::genesis(&PublicKeyRecord::from(Base64EncodedText::from("test"))); - meta_db.global_index_store.apply(&genesis); - - let update = { - let obj_id = &ObjectId::vault_unit("test_vault").next().next(); - let vault_id = IdStr::from(obj_id); - - GlobalIndexObject::Update { - event: KvLogEvent::new_global_index_event(obj_id, &vault_id), - } - }; - meta_db.global_index_store.apply(&update); - assert!(meta_db.global_index_store.contains(String::from("Vault:test_vault::2"))); - } -} diff --git a/core/src/node/db/meta_db/store/meta_pass_store.rs b/core/src/node/db/meta_db/store/meta_pass_store.rs deleted file mode 100644 index bc2db722..00000000 --- a/core/src/node/db/meta_db/store/meta_pass_store.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::models::MetaPasswordDoc; -use crate::node::db::events::common::PublicKeyRecord; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::meta_db::meta_db_view::TailId; - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum MetaPassStore { - Empty, - Unit { - tail_id: ObjectId, - }, - Genesis { - tail_id: ObjectId, - server_pk: PublicKeyRecord, - }, - Store { - tail_id: ObjectId, - server_pk: PublicKeyRecord, - passwords: Vec, - }, -} - -impl MetaPassStore { - pub fn passwords(&self) -> Vec { - match self { - MetaPassStore::Empty => { - vec![] - } - MetaPassStore::Unit { .. } => { - vec![] - } - MetaPassStore::Genesis { .. } => { - vec![] - } - MetaPassStore::Store { passwords, .. } => passwords.clone(), - } - } -} - -impl TailId for MetaPassStore { - fn tail_id(&self) -> Option { - match self { - MetaPassStore::Empty => None, - MetaPassStore::Unit { tail_id } => Some(tail_id.clone()), - MetaPassStore::Genesis { tail_id, .. } => Some(tail_id.clone()), - MetaPassStore::Store { tail_id, .. } => Some(tail_id.clone()), - } - } -} diff --git a/core/src/node/db/meta_db/store/mod.rs b/core/src/node/db/meta_db/store/mod.rs deleted file mode 100644 index 1ab3c750..00000000 --- a/core/src/node/db/meta_db/store/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod global_index_store; -pub mod meta_pass_store; -pub mod vault_store; diff --git a/core/src/node/db/meta_db/store/vault_store.rs b/core/src/node/db/meta_db/store/vault_store.rs deleted file mode 100644 index f0a29944..00000000 --- a/core/src/node/db/meta_db/store/vault_store.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::models::VaultDoc; -use crate::node::db::events::common::PublicKeyRecord; -use crate::node::db::events::object_id::ObjectId; -use crate::node::db::meta_db::meta_db_view::TailId; - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "camelCase")] -pub enum VaultStore { - Empty, - Unit { - tail_id: ObjectId, - }, - Genesis { - tail_id: ObjectId, - server_pk: PublicKeyRecord, - }, - Store { - tail_id: ObjectId, - server_pk: PublicKeyRecord, - vault: VaultDoc, - }, -} - -impl TailId for VaultStore { - fn tail_id(&self) -> Option { - match self { - VaultStore::Empty => None, - VaultStore::Unit { tail_id } => Some(tail_id.clone()), - VaultStore::Genesis { tail_id, .. } => Some(tail_id.clone()), - VaultStore::Store { tail_id, .. } => Some(tail_id.clone()), - } - } -} diff --git a/core/src/node/db/mod.rs b/core/src/node/db/mod.rs index 3f216e7d..4df3c77e 100644 --- a/core/src/node/db/mod.rs +++ b/core/src/node/db/mod.rs @@ -1,6 +1,6 @@ pub mod actions; pub mod events; -pub mod generic_db; pub mod in_mem_db; -pub mod meta_db; pub mod objects; +pub mod descriptors; +pub mod repo; diff --git a/core/src/node/db/objects/device_log.rs b/core/src/node/db/objects/device_log.rs new file mode 100644 index 00000000..3dff866e --- /dev/null +++ b/core/src/node/db/objects/device_log.rs @@ -0,0 +1,86 @@ +use std::sync::Arc; + +use tracing::debug; +use tracing_attributes::instrument; + +use crate::node::common::model::user::{UserData, UserDataMember, UserMembership}; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::generic_log_event::ToGenericEvent; +use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use crate::node::db::events::object_id::{Next, ObjectId, UnitId}; +use crate::node::db::events::vault_event::{DeviceLogObject, VaultAction}; +use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::repo::generic_db::KvLogEventRepo; + +pub struct PersistentDeviceLog { + pub p_obj: Arc>, +} + +impl PersistentDeviceLog { + + #[instrument(skip_all)] + pub async fn accept_join_cluster_request(&self, user: UserData) -> anyhow::Result<()> { + self.init(&user).await?; + + let obj_desc = { + let user_id = user.user_id(); + VaultDescriptor::device_log(user_id) + }; + + let free_id = self.p_obj + .find_free_id_by_obj_desc(obj_desc.clone()) + .await?; + + let ObjectId::Artifact(free_artifact_id) = free_id else { + return Ok(()); + }; + + //join request!!!! + let artifact_key = KvKey::artifact(obj_desc.clone(), free_artifact_id); + let join_request = DeviceLogObject::Action(KvLogEvent { + key: artifact_key, + value: VaultAction::UpdateMembership { + sender: UserDataMember(user.clone()), + update: UserMembership::Member(UserDataMember(user)), + }, + }); + self.p_obj.repo + .save(join_request.to_generic()) + .await?; + + Ok(()) + } + + async fn init(&self, user: &UserData) -> anyhow::Result<()> { + let user_id = user.user_id(); + let obj_desc = VaultDescriptor::device_log(user_id.clone()); + let unit_id = UnitId::unit(&obj_desc); + + let maybe_unit_event = self.p_obj.repo + .find_one(ObjectId::Unit(unit_id)) + .await?; + + if let Some(unit_event) = maybe_unit_event { + debug!("Device log already initialized: {:?}", unit_event); + return Ok(()); + } + + //create new unit and genesis events + let unit_key = KvKey::unit(obj_desc.clone()); + let unit_event = DeviceLogObject::Unit(KvLogEvent { + key: unit_key.clone(), + value: user_id.vault_name.clone(), + }); + + self.p_obj.repo.save(unit_event.to_generic()).await?; + + let genesis_key = unit_key.next(); + let genesis_event = DeviceLogObject::Genesis(KvLogEvent { + key: genesis_key, + value: user.clone(), + }); + self.p_obj.repo.save(genesis_event.to_generic()).await?; + + Ok(()) + } +} diff --git a/core/src/node/db/objects/mod.rs b/core/src/node/db/objects/mod.rs index 41134b2e..d3bf2658 100644 --- a/core/src/node/db/objects/mod.rs +++ b/core/src/node/db/objects/mod.rs @@ -1 +1,5 @@ pub mod persistent_object; +pub mod persistent_object_navigator; +pub mod device_log; +pub mod vault; +pub mod shared_secret; diff --git a/core/src/node/db/objects/persistent_object.rs b/core/src/node/db/objects/persistent_object.rs index 573f0583..526d1631 100644 --- a/core/src/node/db/objects/persistent_object.rs +++ b/core/src/node/db/objects/persistent_object.rs @@ -1,19 +1,17 @@ use std::sync::Arc; use async_trait::async_trait; -use tracing::{debug, info, Instrument}; +use tracing::{debug, info, instrument, Instrument}; -use crate::models::user_signature::UserSignature; -use crate::node::db::events::common::{ObjectCreator, PublicKeyRecord}; -use crate::node::db::events::db_tail::{DbTail, DbTailObject}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::common::model::device::DeviceData; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::events::db_tail::DbTail; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, ObjIdExtractor, ToGenericEvent}; use crate::node::db::events::global_index::GlobalIndexObject; -use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::local::KvLogEventLocal; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, ObjectId}; -use crate::node::db::events::vault_event::VaultObject; -use crate::node::db::generic_db::KvLogEventRepo; +use crate::node::db::events::kv_log_event::KvLogEvent; +use crate::node::db::events::object_id::{Next, ObjectId}; +use crate::node::db::objects::persistent_object_navigator::PersistentObjectNavigator; +use crate::node::db::repo::generic_db::KvLogEventRepo; pub struct PersistentObject { pub repo: Arc, @@ -21,152 +19,151 @@ pub struct PersistentObject { } impl PersistentObject { + + #[instrument(skip_all)] pub async fn get_object_events_from_beginning( &self, - obj_desc: &ObjectDescriptor, + obj_desc: ObjectDescriptor, ) -> anyhow::Result> { debug!("get_object_events_from_beginning"); let unit_id = ObjectId::unit(obj_desc); - let commit_log = self.find_object_events(&unit_id).in_current_span().await; + let commit_log = self.find_object_events(unit_id).await?; Ok(commit_log) } - pub async fn find_object_events(&self, tail_id: &ObjectId) -> Vec { - //logger.log("find_object_events"); - + #[instrument(skip_all)] + pub async fn find_object_events(&self, tail_id: ObjectId) -> anyhow::Result> { let mut commit_log: Vec = vec![]; let mut curr_tail_id = tail_id.clone(); loop { - let curr_db_event_result = self.repo.find_one(curr_tail_id.clone()).in_current_span().await; - - match curr_db_event_result { - Ok(maybe_curr_db_event) => match maybe_curr_db_event { - Some(curr_db_event) => { - if let GenericKvLogEvent::SharedSecret(_) = &curr_db_event { - self.repo.delete(curr_tail_id.clone()).in_current_span().await; - } - - curr_tail_id = curr_tail_id.next(); - commit_log.push(curr_db_event); - } - None => { - break; - } - }, - Err(_) => { - break; + let maybe_curr_db_event = self.repo.find_one(curr_tail_id.clone()).await?; + + if let Some(curr_db_event) = maybe_curr_db_event { + if let GenericKvLogEvent::SharedSecret(_) = &curr_db_event { + self.repo.delete(curr_tail_id.clone()).in_current_span().await; } + + curr_tail_id = curr_tail_id.next(); + commit_log.push(curr_db_event); + } else { + break; } } - commit_log + Ok(commit_log) } - pub async fn find_tail_id_by_obj_desc(&self, obj_desc: &ObjectDescriptor) -> Option { - let unit_id = ObjectId::unit(obj_desc); - self.find_tail_id(unit_id).in_current_span().await + #[instrument(skip_all)] + pub async fn find_tail_event(&self, obj_desc: ObjectDescriptor) -> anyhow::Result> { + let maybe_tail_id = self + .find_tail_id_by_obj_desc(obj_desc) + .await?; + + self.find_event_by_id(maybe_tail_id).await } - pub async fn find_tail_id(&self, curr_id: ObjectId) -> Option { - let curr_result = self.repo.find_one(curr_id.clone()).in_current_span().await; - - match curr_result { - Ok(maybe_event) => match maybe_event { - None => None, - Some(_curr_event) => { - let mut existing_id = curr_id.clone(); - let mut curr_tail_id = curr_id.clone(); - - loop { - let found_event_result = self.repo.find_one(curr_tail_id.clone()).in_current_span().await; - - match found_event_result { - Ok(Some(_curr_tail)) => { - existing_id = curr_tail_id.clone(); - curr_tail_id = curr_tail_id.next(); - } - _ => break, - } - } - - Some(existing_id) - } - }, - Err(_) => None, - } + pub async fn find_tail_event_by_obj_id(&self, obj_id: ObjectId) -> anyhow::Result> { + let maybe_tail_id = self.find_tail_id(obj_id).await?; + self.find_event_by_id(maybe_tail_id).await } - pub async fn get_db_tail(&self, vault_name: &str) -> anyhow::Result { - let obj_id = ObjectId::unit(&ObjectDescriptor::DbTail); - let maybe_db_tail = self.repo.find_one(obj_id).in_current_span().await?; - - match maybe_db_tail { - None => { - let db_tail = DbTail { - vault_id: DbTailObject::Empty { - unit_id: ObjectId::vault_unit(vault_name), - }, - maybe_global_index_id: None, - maybe_mem_pool_id: None, - meta_pass_id: DbTailObject::Empty { - unit_id: ObjectId::meta_pass_unit(vault_name), - }, - s_s_audit: None, - }; - - let tail_event = { - let event = KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::DbTail), - value: db_tail.clone(), - }; - GenericKvLogEvent::LocalEvent(KvLogEventLocal::DbTail { event: Box::new(event) }) - }; - - self.repo.save_event(tail_event).in_current_span().await?; - Ok(db_tail) - } - Some(db_tail) => match db_tail { - GenericKvLogEvent::LocalEvent(local_evt) => match local_evt { - KvLogEventLocal::DbTail { event } => Ok(event.value), - _ => { - panic!("DbTail. Invalid data"); - } - }, - _ => { - panic!("DbTail. Invalid event type"); - } - }, + async fn find_event_by_id(&self, maybe_tail_id: Option) -> anyhow::Result> { + if let Some(tail_id) = maybe_tail_id { + let maybe_tail_event = self.repo.find_one(tail_id).await?; + Ok(maybe_tail_event) + } else { + Ok(None) } } - pub async fn get_user_sig(&self, tail_id: ObjectId) -> Vec { - let sig_result = self.get_vault_unit_signature(tail_id).in_current_span().await; - match sig_result { - Ok(Some(vault_sig)) => { - vec![vault_sig] - } - _ => { - vec![] + #[instrument(skip_all)] + pub async fn find_free_id_by_obj_desc(&self, obj_desc: ObjectDescriptor) -> anyhow::Result { + let maybe_tail_id = self + .find_tail_id_by_obj_desc(obj_desc.clone()) + .await?; + + let free_id = maybe_tail_id + .map(|tail_id| tail_id.next()) + .unwrap_or(ObjectId::unit(obj_desc)); + + Ok(free_id) + } + + #[instrument(skip_all)] + pub async fn find_free_id(&self, obj_id: ObjectId) -> anyhow::Result { + let maybe_tail_id = self + .find_tail_id(obj_id.clone()) + .await?; + + let free_id = maybe_tail_id + .map(|tail_id| tail_id.next()) + .unwrap_or(ObjectId::from(obj_id.get_unit_id())); + + Ok(free_id) + } + + #[instrument(skip_all)] + pub async fn find_tail_id_by_obj_desc(&self, obj_desc: ObjectDescriptor) -> anyhow::Result> { + let unit_id = ObjectId::unit(obj_desc); + self.find_tail_id(unit_id).await + } + + #[instrument(skip_all)] + pub async fn navigator(&self, obj_id: ObjectId) -> PersistentObjectNavigator { + PersistentObjectNavigator::build(self.repo.clone(), obj_id).await + } + + #[instrument(skip_all)] + pub async fn find_tail_id(&self, curr_id: ObjectId) -> anyhow::Result> { + let maybe_event = self.repo.find_one(curr_id.clone()).await?; + + if let Some(curr_event) = maybe_event { + let mut existing_id = curr_event.obj_id(); + let mut curr_tail_id = curr_event.obj_id(); + + loop { + let found_event = self.repo.find_one(curr_tail_id.clone()).await?; + + if let Some(curr_tail) = found_event { + let curr_obj_id = curr_tail.obj_id(); + existing_id = curr_obj_id.clone(); + curr_tail_id = curr_obj_id.next(); + } else { + break; + } } + + Ok(Some(existing_id)) + } else { + Ok(None) } } - async fn get_vault_unit_signature(&self, tail_id: ObjectId) -> anyhow::Result> { - let maybe_unit_event = self.repo.find_one(tail_id).in_current_span().await?; + #[instrument(skip_all)] + pub async fn get_db_tail(&self) -> anyhow::Result { + let maybe_db_tail = { + let db_tail_unit_id = ObjectId::unit(ObjectDescriptor::DbTail); + self.repo.find_one(db_tail_unit_id).in_current_span().await? + }; + + if let Some(db_tail_event) = maybe_db_tail { + db_tail_event.to_db_tail() + } else { + let db_tail = DbTail::Basic { global_index_id: None }; + let tail_event = GenericKvLogEvent::db_tail(db_tail.clone()); - match maybe_unit_event { - Some(GenericKvLogEvent::Vault(VaultObject::Unit { event })) => Ok(Some(event.value)), - _ => Ok(None), + self.repo.save(tail_event).await?; + Ok(db_tail) } } } #[async_trait(? Send)] pub trait PersistentGlobalIndexApi { - async fn gi_init(&self, public_key: &PublicKeyRecord) -> anyhow::Result>; + async fn gi_init(&self, public_key: DeviceData) -> anyhow::Result>; } pub struct PersistentGlobalIndex { @@ -175,21 +172,20 @@ pub struct PersistentGlobalIndex { #[async_trait(? Send)] impl PersistentGlobalIndexApi for PersistentGlobalIndex { + ///create a genesis event and save into the database - async fn gi_init(&self, public_key: &PublicKeyRecord) -> anyhow::Result> { + #[instrument(skip(self))] + async fn gi_init(&self, public_key: DeviceData) -> anyhow::Result> { info!("Init global index"); - let unit_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Unit { - event: KvLogEvent::global_index_unit(), - }); + let unit_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Unit(KvLogEvent::global_index_unit())); - self.repo.save_event(unit_event.clone()).in_current_span().await?; + self.repo.save(unit_event.clone()).await?; - let genesis_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Genesis { - event: KvLogEvent::global_index_genesis(public_key), - }); + let genesis_event = GlobalIndexObject::Genesis(KvLogEvent::global_index_genesis(public_key)) + .to_generic(); - self.repo.save_event(genesis_event.clone()).in_current_span().await?; + self.repo.save(genesis_event.clone()).await?; Ok(vec![unit_event, genesis_event]) } @@ -203,115 +199,3 @@ impl PersistentObject { } } } - -#[cfg(test)] -mod test { - use std::sync::Arc; - use tracing::Instrument; - - use crate::crypto::keys::KeyManager; - use crate::models::DeviceInfo; - use crate::node::db::events::common::{LogEventKeyBasedRecord, ObjectCreator, PublicKeyRecord}; - use crate::node::db::events::generic_log_event::GenericKvLogEvent; - use crate::node::db::events::global_index::{GlobalIndexObject, GlobalIndexRecord}; - use crate::node::db::events::kv_log_event::KvKey; - use crate::node::db::events::kv_log_event::KvLogEvent; - use crate::node::db::events::object_descriptor::ObjectDescriptor; - use crate::node::db::events::object_id::{IdGen, ObjectId}; - use crate::node::db::generic_db::SaveCommand; - use crate::node::db::in_mem_db::InMemKvLogEventRepo; - use crate::node::db::objects::persistent_object::PersistentObject; - - #[tokio::test] - async fn test_find_events() { - let persistent_object = { - let repo = Arc::new(InMemKvLogEventRepo::default()); - PersistentObject::new(repo.clone()) - }; - - let user_sig = { - let s_box = KeyManager::generate_security_box("test_vault".to_string()); - let device = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - s_box.get_user_sig(&device) - }; - - let unit_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::unit()); - persistent_object - .repo - .save_event(unit_event) - .in_current_span() - .await - .unwrap(); - - let genesis_event = { - let server_pk = PublicKeyRecord::from(user_sig.public_key.as_ref().clone()); - GenericKvLogEvent::GlobalIndex(GlobalIndexObject::genesis(&server_pk)) - }; - - let vault_1_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Update { - event: KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::GlobalIndex), - value: GlobalIndexRecord { - vault_id: String::from("vault_1"), - }, - }, - }); - - persistent_object - .repo - .save_event(genesis_event) - .in_current_span() - .await - .unwrap(); - - persistent_object - .repo - .save(ObjectId::global_index_genesis().next(), vault_1_event) - .await - .unwrap(); - - let tail_id = persistent_object - .find_tail_id_by_obj_desc(&ObjectDescriptor::GlobalIndex) - .await - .unwrap(); - - assert_eq!(String::from("GlobalIndex:index::2"), tail_id.id_str()); - } - - #[tokio::test] - async fn test_global_index() { - let persistent_object = { - let repo = Arc::new(InMemKvLogEventRepo::default()); - PersistentObject::new(repo.clone()) - }; - - let user_sig = { - let s_box = KeyManager::generate_security_box("test_vault".to_string()); - let device = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - s_box.get_user_sig(&device) - }; - - let unit_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::unit()); - persistent_object.repo.save_event(unit_event).await.unwrap(); - - let genesis_event = { - let server_pk = PublicKeyRecord::from(user_sig.public_key.as_ref().clone()); - GenericKvLogEvent::GlobalIndex(GlobalIndexObject::genesis(&server_pk)) - }; - - persistent_object.repo.save_event(genesis_event.clone()).await.unwrap(); - - let tail_id = persistent_object - .find_tail_id_by_obj_desc(&ObjectDescriptor::GlobalIndex) - .await - .unwrap(); - - assert_eq!(genesis_event.key().obj_id.id_str(), tail_id.id_str()); - } -} diff --git a/core/src/node/db/objects/persistent_object_navigator.rs b/core/src/node/db/objects/persistent_object_navigator.rs new file mode 100644 index 00000000..0eab970d --- /dev/null +++ b/core/src/node/db/objects/persistent_object_navigator.rs @@ -0,0 +1,65 @@ +use std::sync::Arc; + +use crate::node::db::events::object_id::{Next, ObjectId}; +use crate::node::db::repo::generic_db::KvLogEventRepo; + +pub struct PersistentObjectNavigator { + repo: Arc, + obj_id: ObjectId, +} + +impl PersistentObjectNavigator { + pub async fn build(repo: Arc, obj_id: ObjectId) -> PersistentObjectNavigator { + PersistentObjectNavigator { + repo: repo.clone(), + obj_id, + } + } + + pub async fn next(&mut self) -> anyhow::Result> { + let maybe_key = self.repo.get_key(self.obj_id.clone()).await?; + + if let Some(obj_id) = maybe_key { + self.obj_id = obj_id.clone().next(); + Ok(Some(obj_id.clone())) + } else { + Ok(None) + } + } +} + +#[cfg(test)] +mod test { + use std::sync::Arc; + + use crate::crypto::keys::{KeyManager, OpenBox}; + use crate::node::common::model::device::{DeviceData, DeviceName}; + use crate::node::db::events::generic_log_event::{ObjIdExtractor, ToGenericEvent, UnitEventWithEmptyValue}; + use crate::node::db::events::global_index::GlobalIndexObject; + use crate::node::db::in_mem_db::InMemKvLogEventRepo; + use crate::node::db::objects::persistent_object_navigator::PersistentObjectNavigator; + use crate::node::db::repo::generic_db::SaveCommand; + + #[tokio::test] + async fn test_iterator() -> anyhow::Result<()> { + let repo = Arc::new(InMemKvLogEventRepo::default()); + + let server_device = { + let secret_box = KeyManager::generate_secret_box(); + let open_box = OpenBox::from(&secret_box); + DeviceData::from(DeviceName::from("qwe"), open_box) + }; + + let unit_event = GlobalIndexObject::unit().to_generic(); + let genesis_event = GlobalIndexObject::genesis(server_device).to_generic(); + + repo.save(unit_event.clone()).await?; + repo.save(genesis_event.clone()).await?; + + let mut navigator = PersistentObjectNavigator::build(repo, unit_event.obj_id()).await; + assert_eq!(Some(unit_event.obj_id()), navigator.next().await?); + assert_eq!(Some(genesis_event.obj_id()), navigator.next().await?); + + Ok(()) + } +} diff --git a/core/src/node/db/objects/shared_secret.rs b/core/src/node/db/objects/shared_secret.rs new file mode 100644 index 00000000..16989c3e --- /dev/null +++ b/core/src/node/db/objects/shared_secret.rs @@ -0,0 +1,53 @@ +use std::sync::Arc; + +use tracing::debug; + +use crate::node::common::model::user::UserData; +use crate::node::db::descriptors::object_descriptor::ToObjectDescriptor; +use crate::node::db::descriptors::shared_secret::SharedSecretDescriptor; +use crate::node::db::events::common::SSDeviceLogObject; +use crate::node::db::events::generic_log_event::ToGenericEvent; +use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use crate::node::db::events::object_id::{Next, ObjectId, UnitId}; +use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::repo::generic_db::KvLogEventRepo; + +pub struct PersistentSharedSecret { + pub p_obj: Arc>, +} + +impl PersistentSharedSecret { + + pub async fn init(&self, user: UserData) -> anyhow::Result<()> { + let user_id = user.user_id(); + let obj_desc = SharedSecretDescriptor::SSDeviceLog(user_id.device_id).to_obj_desc(); + let unit_id = UnitId::unit(&obj_desc); + + let maybe_unit_event = self.p_obj.repo + .find_one(ObjectId::Unit(unit_id)) + .await?; + + if let Some(unit_event) = maybe_unit_event { + debug!("SSDeviceLog already initialized: {:?}", unit_event); + return Ok(()); + } + + //create new unit and genesis events + let unit_key = KvKey::unit(obj_desc.clone()); + let unit_event = SSDeviceLogObject::Unit(KvLogEvent { + key: unit_key.clone(), + value: user_id.vault_name.clone(), + }); + + self.p_obj.repo.save(unit_event.to_generic()).await?; + + let genesis_key = unit_key.next(); + let genesis_event = SSDeviceLogObject::Genesis(KvLogEvent { + key: genesis_key, + value: user, + }); + self.p_obj.repo.save(genesis_event.to_generic()).await?; + + Ok(()) + } +} \ No newline at end of file diff --git a/core/src/node/db/objects/vault.rs b/core/src/node/db/objects/vault.rs new file mode 100644 index 00000000..19808aaf --- /dev/null +++ b/core/src/node/db/objects/vault.rs @@ -0,0 +1,90 @@ +use std::sync::Arc; + +use anyhow::anyhow; +use tracing_attributes::instrument; + +use crate::node::common::model::user::{UserData, UserDataMember, UserDataOutsider, UserMembership}; +use crate::node::common::model::vault::{VaultData, VaultStatus}; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::vault_event::VaultMembershipObject; +use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::repo::credentials_repo::CredentialsRepo; +use crate::node::db::repo::generic_db::KvLogEventRepo; + +pub struct PersistentVault { + pub p_obj: Arc>, +} + +impl PersistentVault { + + pub async fn get_vault(&self) -> anyhow::Result { + let vault_status = self.find_for_default_user().await?; + match vault_status { + VaultStatus::Outsider(_) => { + Err(anyhow!("Vault not found")) + } + VaultStatus::Member(member) => { + Ok(member) + } + } + } + + pub async fn find_for_default_user(&self) -> anyhow::Result { + let creds_repo = CredentialsRepo { + p_obj: self.p_obj.clone() + }; + + let creds = creds_repo.get_user_creds().await?; + self.find(creds.user()).await + } + + #[instrument(skip_all)] + pub async fn find(&self, user: UserData) -> anyhow::Result { + let membership = self.vault_status(user).await?; + + match membership { + UserMembership::Outsider(outsider) => { + Ok(VaultStatus::Outsider(outsider)) + } + UserMembership::Member(UserDataMember(member)) => { + let maybe_vault = { + let vault_desc = VaultDescriptor::vault(member.vault_name.clone()); + self.p_obj.find_tail_event(vault_desc).await? + }; + + if let Some(vault_event) = maybe_vault { + let vault_status = VaultStatus::try_from(vault_event, member)?; + Ok(vault_status) + } else { + Ok(VaultStatus::Outsider(UserDataOutsider::unknown(member))) + } + } + } + } + + pub async fn vault_status(&self, user_data: UserData) -> anyhow::Result { + let desc = VaultDescriptor::vault_status(user_data.user_id()); + let maybe_tail_event = self.p_obj.find_tail_event(desc).await?; + + match maybe_tail_event { + None => { + Ok(UserMembership::Outsider(UserDataOutsider::unknown(user_data))) + } + Some(tail_event) => { + let vault_status_obj = VaultMembershipObject::try_from(tail_event)?; + + match vault_status_obj { + VaultMembershipObject::Unit { .. } => { + Ok(UserMembership::Outsider(UserDataOutsider::unknown(user_data))) + } + VaultMembershipObject::Genesis { .. } => { + Ok(UserMembership::Outsider(UserDataOutsider::unknown(user_data))) + } + VaultMembershipObject::Membership(event) => { + Ok(event.value) + } + } + } + } + } +} \ No newline at end of file diff --git a/core/src/node/db/repo/credentials_repo.rs b/core/src/node/db/repo/credentials_repo.rs new file mode 100644 index 00000000..bf5fc585 --- /dev/null +++ b/core/src/node/db/repo/credentials_repo.rs @@ -0,0 +1,134 @@ +use std::sync::Arc; + +use anyhow::{anyhow, Error}; +use tracing::{info, instrument}; + +use crate::node::common::model::device::{DeviceCredentials, DeviceName}; +use crate::node::common::model::user::UserCredentials; +use crate::node::common::model::vault::VaultName; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, ToGenericEvent, UnitEvent}; +use crate::node::db::events::local::CredentialsObject; +use crate::node::db::events::object_id::ObjectId; +use crate::node::db::objects::persistent_object::PersistentObject; +use crate::node::db::repo::generic_db::KvLogEventRepo; + +pub struct CredentialsRepo { + pub p_obj: Arc>, +} + +impl CredentialsRepo { + + #[instrument(skip(self))] + pub async fn generate_user(&self, device_name: DeviceName, vault_name: VaultName) -> anyhow::Result { + info!("Create a new user locally"); + + let device_creds = self.get_or_generate_device_creds(device_name).await?; + + let user_creds = CredentialsObject::default_user(UserCredentials::from(device_creds, vault_name)); + + self.save(user_creds.clone()).await?; + + Ok(user_creds) + } + + pub async fn get_or_generate_device_creds(&self, device_name: DeviceName) -> Result { + let maybe_creds = self.find().await?; + + let device_creds = match maybe_creds { + None => { + self.generate_device_creds(device_name).await? + } + Some(creds) => { + match creds { + CredentialsObject::Device(event) => { + event.value + } + CredentialsObject::DefaultUser(_) => { + Err(anyhow!("User credentials found, Device credentials expected"))? + } + } + } + }; + Ok(device_creds) + } + + pub async fn save(&self, creds: CredentialsObject) -> anyhow::Result { + let generic_event = creds.to_generic(); + self.p_obj.repo.save(generic_event).await + } + + #[instrument(skip_all)] + pub async fn get_user_creds(&self) -> anyhow::Result { + let creds_obj = self.find().await? + .ok_or_else(|| anyhow!("No credentials found"))?; + + match creds_obj { + CredentialsObject::Device { .. } => { + Err(anyhow!("Device credentials found, User credentials expected")) + } + CredentialsObject::DefaultUser(event) => { + Ok(event.value) + } + } + } + + #[instrument(skip_all)] + pub async fn get(&self) -> anyhow::Result { + self.find().await? + .ok_or_else(|| anyhow!("No credentials found")) + } + + #[instrument(skip_all)] + pub async fn find(&self) -> anyhow::Result> { + let maybe_creds = self.p_obj + .find_tail_event(ObjectDescriptor::CredsIndex) + .await?; + + let Some(creds) = maybe_creds else { + return Ok(None); + }; + + let creds_obj = CredentialsObject::try_from(creds)?; + Ok(Some(creds_obj)) + } + + pub async fn generate_device_creds(&self, device_name: DeviceName) -> anyhow::Result { + let device_creds = DeviceCredentials::generate(device_name); + let creds_obj = CredentialsObject::unit(device_creds.clone()); + self.p_obj.repo + .save(GenericKvLogEvent::Credentials(creds_obj.clone())) + .await?; + Ok(device_creds) + } + + #[instrument(skip_all)] + pub async fn generate_user_creds(&self, device_name: DeviceName, vault_name: VaultName) -> anyhow::Result { + let user_creds = UserCredentials::generate(device_name, vault_name); + let creds_obj = CredentialsObject::default_user(user_creds.clone()); + + self.save(creds_obj).await?; + + Ok(user_creds) + } + + #[instrument(skip_all)] + pub async fn get_or_generate_user_creds(&self, device_name: DeviceName, vault_name: VaultName) -> anyhow::Result { + let maybe_creds = self.find().await?; + + let Some(creds) = maybe_creds else { + return self.generate_user_creds(device_name, vault_name).await; + }; + + match creds { + CredentialsObject::Device(event) => { + let user_creds = UserCredentials::from(event.value, vault_name); + self.save(CredentialsObject::default_user(user_creds.clone())).await?; + Ok(user_creds) + } + CredentialsObject::DefaultUser(event) => { + Ok(event.value) + } + } + } +} diff --git a/core/src/node/db/generic_db.rs b/core/src/node/db/repo/generic_db.rs similarity index 56% rename from core/src/node/db/generic_db.rs rename to core/src/node/db/repo/generic_db.rs index 05f22b91..e8675a0c 100644 --- a/core/src/node/db/generic_db.rs +++ b/core/src/node/db/repo/generic_db.rs @@ -1,28 +1,17 @@ use async_trait::async_trait; -use tracing::Instrument; -use crate::node::db::events::common::LogEventKeyBasedRecord; use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::kv_log_event::KvKey; use crate::node::db::events::object_id::ObjectId; #[async_trait(? Send)] pub trait SaveCommand { - async fn save(&self, key: ObjectId, value: GenericKvLogEvent) -> anyhow::Result; - - async fn save_event(&self, value: GenericKvLogEvent) -> anyhow::Result { - match &value.key() { - KvKey { obj_id, .. } => { - let _ = self.save(obj_id.clone(), value.clone()).in_current_span().await; - Ok(obj_id.clone()) - } - } - } + async fn save(&self, value: GenericKvLogEvent) -> anyhow::Result; } #[async_trait(? Send)] -pub trait FindOneQuery: Send { +pub trait FindOneQuery { async fn find_one(&self, key: ObjectId) -> anyhow::Result>; + async fn get_key(&self, key: ObjectId) -> anyhow::Result>; } #[async_trait(? Send)] diff --git a/core/src/node/db/repo/mod.rs b/core/src/node/db/repo/mod.rs new file mode 100644 index 00000000..42f06ce1 --- /dev/null +++ b/core/src/node/db/repo/mod.rs @@ -0,0 +1,2 @@ +pub mod credentials_repo; +pub mod generic_db; diff --git a/core/src/node/mod.rs b/core/src/node/mod.rs index 830b61e6..e99a652d 100644 --- a/core/src/node/mod.rs +++ b/core/src/node/mod.rs @@ -1,5 +1,4 @@ pub mod app; pub mod common; pub mod db; -pub mod model_utils; pub mod server; diff --git a/core/src/node/model_utils.rs b/core/src/node/model_utils.rs deleted file mode 100644 index db3ae866..00000000 --- a/core/src/node/model_utils.rs +++ /dev/null @@ -1,11 +0,0 @@ -use crate::crypto; -use crate::models::DeviceInfo; - -impl From for DeviceInfo { - fn from(device_name: String) -> Self { - Self { - device_id: crypto::utils::rand_64bit_b64_url_enc().base64_text, - device_name, - } - } -} diff --git a/core/src/node/server/data_sync.rs b/core/src/node/server/data_sync.rs index 2e1f5854..b7c1e5e4 100644 --- a/core/src/node/server/data_sync.rs +++ b/core/src/node/server/data_sync.rs @@ -1,556 +1,436 @@ use std::sync::Arc; +use anyhow::anyhow; use async_trait::async_trait; -use tracing::{debug, info, instrument, Instrument}; +use tracing::{debug, info, instrument}; -use crate::crypto::key_pair::KeyPair; -use crate::crypto::keys::KeyManager; -use crate::models::{UserCredentials, UserSignature}; -use crate::node::app::meta_vault_manager::UserCredentialsManager; -use crate::node::db::actions::join; +use crate::node::common::model::device::{DeviceCredentials, DeviceData}; +use crate::node::common::model::user::{UserData, UserDataMember, UserId}; +use crate::node::common::model::vault::{VaultData, VaultName}; use crate::node::db::actions::sign_up::SignUpAction; -use crate::node::db::events::common::{MemPoolObject, MetaPassObject, PublicKeyRecord}; -use crate::node::db::events::common::{ObjectCreator, SharedSecretObject}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::db::actions::ss_replication::SSReplicationAction; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::{ObjectDescriptor, ToObjectDescriptor}; +use crate::node::db::descriptors::vault::VaultDescriptor; +use crate::node::db::events::generic_log_event::{GenericKvLogEvent, ToGenericEvent}; use crate::node::db::events::global_index::GlobalIndexObject; -use crate::node::db::events::kv_log_event::KvLogEvent; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, IdStr, ObjectId}; -use crate::node::db::events::vault_event::VaultObject; -use crate::node::db::generic_db::KvLogEventRepo; -use crate::node::db::meta_db::meta_db_service::MetaDbServiceProxy; -use crate::node::db::meta_db::store::vault_store::VaultStore; +use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; +use crate::node::db::events::object_id::{ArtifactId, ObjectId, UnitId}; +use crate::node::db::events::vault_event::{DeviceLogObject, VaultAction, VaultLogObject, VaultMembershipObject, VaultObject}; use crate::node::db::objects::persistent_object::PersistentObject; - -use crate::node::server::request::SyncRequest; +use crate::node::db::repo::generic_db::KvLogEventRepo; +use crate::node::server::request::{SyncRequest, VaultRequest}; #[async_trait(? Send)] pub trait DataSyncApi { async fn replication(&self, request: SyncRequest) -> anyhow::Result>; - async fn send(&self, event: GenericKvLogEvent); + async fn send(&self, event: GenericKvLogEvent) -> anyhow::Result<()>; } pub struct ServerDataSync { pub persistent_obj: Arc>, - pub context: Arc, - meta_db_service_proxy: Arc, + pub device_creds: DeviceCredentials, } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -#[serde(tag = "__sync_msg_type")] -pub enum DataSyncMessage { +pub enum DataSyncRequest { SyncRequest(SyncRequest), Event(GenericKvLogEvent), } +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DataSyncResponse { + pub events: Vec, +} + #[async_trait(? Send)] impl DataSyncApi for ServerDataSync { + #[instrument(skip(self))] async fn replication(&self, request: SyncRequest) -> anyhow::Result> { let mut commit_log: Vec = vec![]; - self.global_index_replication(&request, &mut commit_log) - .in_current_span() - .await?; + match request { + SyncRequest::GlobalIndex(gi_request) => { + let gi_events = self + .global_index_replication(gi_request.global_index.clone()) + .await?; + commit_log.extend(gi_events); + } - self.vault_replication(&request, &mut commit_log) - .in_current_span() - .await; + SyncRequest::Vault(vault_request) => { + let maybe_vault = self.find_vault(vault_request.vault.clone()).await?; + let Some(vault) = maybe_vault else { + return Ok(commit_log); + }; + + if !vault.is_member(&vault_request.sender.device.id) { + return Ok(commit_log); + } - self.meta_pass_replication(&request, &mut commit_log) - .in_current_span() - .await; + let vault_events = self + .vault_replication(vault_request) + .await?; + + commit_log.extend(vault_events); + } + + SyncRequest::SharedSecret(ss_request) => { + let maybe_vault = self.find_vault(ss_request.ss_log.clone()).await?; + let Some(vault) = maybe_vault else { + return Ok(commit_log); + }; + + if !vault.is_member(&ss_request.sender.device.id) { + return Ok(commit_log); + } + + let s_s_replication_action = SSReplicationAction { + persistent_obj: self.persistent_obj.clone(), + }; + let s_s_replication_events = s_s_replication_action + .replicate(ss_request, &vault) + .await?; - self.shared_secret_replication(&request, &mut commit_log) - .in_current_span() - .await; + commit_log.extend(s_s_replication_events); + } + } Ok(commit_log) } /// Handle request: all types of requests will be handled and the actions will be executed accordingly - async fn send(&self, generic_event: GenericKvLogEvent) { - self.server_processing(generic_event).in_current_span().await; - } -} - -impl ServerDataSync { - pub async fn new( - persistent_obj: Arc>, - meta_db_service_proxy: Arc, - ) -> Self { - let server_creds = persistent_obj - .repo - .get_or_generate_user_creds(String::from("q"), String::from("server")) - .in_current_span() - .await; - - ServerDataSync { - persistent_obj: persistent_obj.clone(), - context: Arc::new(MetaServerContextState::from(&server_creds)), - meta_db_service_proxy, - } + async fn send(&self, generic_event: GenericKvLogEvent) -> anyhow::Result<()> { + self.server_processing(generic_event).await?; + Ok(()) } } impl ServerDataSync { #[instrument(skip_all)] - async fn server_processing(&self, generic_event: GenericKvLogEvent) { + async fn server_processing(&self, generic_event: GenericKvLogEvent) -> anyhow::Result<()> { debug!("DataSync::event_processing: {:?}", &generic_event); match &generic_event { GenericKvLogEvent::GlobalIndex(_) => { info!("Global index not allowed to be sent"); } + GenericKvLogEvent::DbTail(_) => { + info!("DbTail not allowed to be sent"); + } + GenericKvLogEvent::Credentials(_) => { + info!("Credentials not allowed to be sent"); + } + GenericKvLogEvent::DeviceLog(device_log_obj) => { + self.persistent_obj.repo + .save(generic_event.clone()) + .await?; - GenericKvLogEvent::Vault(vault_obj_info) => { - match vault_obj_info { - VaultObject::Unit { event } => { - info!("Handle 'vault_object:unit' event"); - // Handled by the server. Add a vault to the system - let vault_id = event.key.obj_id.clone(); - - info!("Looking for a vault: {}", vault_id.id_str()); - - let vault_formation_event_result = self - .persistent_obj - .repo - .find_one(vault_id.clone()) - .in_current_span() - .await; - - let vault_id_str = IdStr::from(&vault_id); - - match vault_formation_event_result { - Err(_) => { - self.accept_sign_up_request(event, &vault_id_str) - .in_current_span() - .await; - } - Ok(maybe_sign_up) => match maybe_sign_up { - None => { - self.accept_sign_up_request(event, &vault_id_str).await; - } - Some(_sign_up) => { - info!("Error. Vault already exists. Skip"); - } - }, - } + let vault_action_event = match device_log_obj { + DeviceLogObject::Unit { .. } => { + return Ok(()); } - VaultObject::Genesis { .. } => { - info!("Genesis event not allowed to send. Skip"); + DeviceLogObject::Genesis(_) => { + return Ok(()); } - VaultObject::SignUpUpdate { .. } => { - info!("SignUp update not allowed to send. Skip"); + DeviceLogObject::Action(event) => { + event } - VaultObject::JoinUpdate { .. } => { - let _ = self.persistent_obj.repo.save_event(generic_event).await; - } - VaultObject::JoinRequest { .. } => { - //self.logger.log("Handle join request"); - //self.accept_join_cluster_request(event).await; - info!("Ignore Join request on server side"); + }; + + let vault_action = vault_action_event.value.clone(); + + let vault_log_desc = VaultDescriptor::VaultLog(vault_action.vault_name()) + .to_obj_desc(); + + let vault_log_free_id = self.persistent_obj + .find_free_id_by_obj_desc(vault_log_desc.clone()) + .await?; + + let ObjectId::Artifact(vault_log_artifact_id) = vault_log_free_id else { + return Err(anyhow!("Vault log invalid state: {:?}", vault_log_free_id)); + }; + + let vault_log_action_event = GenericKvLogEvent::VaultLog(VaultLogObject::Action(KvLogEvent { + key: KvKey::artifact(vault_log_desc, vault_log_artifact_id), + value: vault_action.clone(), + })); + + self.persistent_obj + .repo + .save(vault_log_action_event) + .await?; + + match vault_action { + VaultAction::JoinRequest { candidate } => { + // create vault if not exists + let vault_name = candidate.vault_name.clone(); + let vault_desc = VaultDescriptor::vault(vault_name.clone()); + let maybe_vault = self + .find_vault(ObjectId::unit(vault_desc.clone())) + .await?; + + if let Some(_vault) = maybe_vault { + return Ok(()); + }; + + //create vault_log, vault and vault status + self.accept_sign_up_request(candidate).await? } - } - } - GenericKvLogEvent::MetaPass(meta_pass_obj) => match meta_pass_obj { - MetaPassObject::Unit { .. } => { - info!("Ignore unit event for meta pass"); - } - MetaPassObject::Genesis { .. } => { - info!("Ignore genesis event for meta pass"); - } - MetaPassObject::Update { event } => { - let meta_pass_event = GenericKvLogEvent::MetaPass(MetaPassObject::Update { event: event.clone() }); - let save_command = self.persistent_obj.repo.save_event(meta_pass_event).await; - - if save_command.is_err() { - let err_msg = String::from("Error saving meta pass request"); - info!(err_msg); - panic!("Error"); + + VaultAction::UpdateMembership { + sender: UserDataMember(sender_user), + update + } => { + //check if a sender is a member of the vault and update the vault then + + let vault_name = sender_user.vault_name.clone(); + let (vault_artifact_id, vault) = self + .get_vault(vault_name.clone(), &sender_user.device) + .await?; + + let vault_event = { + let mut new_vault = vault.clone(); + new_vault.update_membership(update.clone()); + + VaultObject::Vault(KvLogEvent { + key: KvKey { + obj_id: vault_artifact_id, + obj_desc: VaultDescriptor::vault(vault_name.clone()), + }, + value: new_vault, + }).to_generic() + }; + + self.persistent_obj + .repo + .save(vault_event) + .await?; + + // Don't forget to update the vault status + + let vault_status_desc = { + let user_id = UserId { + device_id: update.device_id(), + vault_name, + }; + VaultDescriptor::VaultStatus(user_id).to_obj_desc() + }; + + let vault_status_free_id = self.persistent_obj + .find_free_id_by_obj_desc(vault_status_desc.clone()) + .await?; + + let ObjectId::Artifact(vault_status_artifact_id) = vault_status_free_id else { + return Ok(()); + }; + + let vault_status_event = { + let event = KvLogEvent { + key: KvKey::artifact(vault_status_desc, vault_status_artifact_id), + value: update.clone(), + }; + VaultMembershipObject::Membership(event).to_generic() + }; + + self.persistent_obj + .repo + .save(vault_status_event) + .await?; } - } - }, - GenericKvLogEvent::MemPool(evt_type) => { - // save mempool event in the database - info!("Data Sync. Handle mem pool request"); - match evt_type { - MemPoolObject::JoinRequest { event } => { - let vault_name = event.value.vault.name.clone(); - let vault_obj_id = ObjectId::vault_unit(vault_name.as_str()); - - let maybe_vault_tail_id = self.persistent_obj.find_tail_id(vault_obj_id).await; - - match maybe_vault_tail_id { - None => { - //ignore, vault not exists yet, no way to join vault - } - Some(vault_tail_id) => { - let join_request = GenericKvLogEvent::Vault(VaultObject::JoinRequest { - event: join::join_cluster_request(&vault_tail_id, &event.value), - }); - - let _ = self.persistent_obj.repo.save_event(join_request).await; - } - } + VaultAction::AddMetaPassword { sender, meta_pass_id } => { + let user = sender.user(); + let vault_name = user.vault_name.clone(); + let (vault_artifact_id, vault) = self + .get_vault(vault_name.clone(), &user.device) + .await?; + + let vault_event = { + let mut new_vault = vault.clone(); + new_vault.add_secret(meta_pass_id.clone()); + + let event = KvLogEvent { + key: KvKey { + obj_id: vault_artifact_id, + obj_desc: VaultDescriptor::vault(vault_name.clone()), + }, + value: new_vault, + }; + + VaultObject::Vault(event).to_generic() + }; + + self.persistent_obj + .repo + .save(vault_event) + .await?; } } } - GenericKvLogEvent::SharedSecret(_) => { - let _ = self.persistent_obj.repo.save_event(generic_event.clone()).await; + todo!("Implement shared secret distribution"); } - - GenericKvLogEvent::LocalEvent(evt_type) => { - info!("Local events can't be sent: {:?}", evt_type); + GenericKvLogEvent::VaultLog(_) => { + info!("VaultLog can be updated only by the server"); + } + GenericKvLogEvent::Vault(_) => { + info!("Vault can be updated only by the server"); + } + GenericKvLogEvent::VaultMembership(_) => { + info!("VaultStatus can be updated only by the server"); } GenericKvLogEvent::Error { .. } => { info!("Errors not yet implemented"); } - } - } - - async fn global_index_replication( - &self, - request: &SyncRequest, - commit_log: &mut Vec, - ) -> anyhow::Result<()> { - match &request.global_index { - None => { - let meta_g = self - .persistent_obj - .get_object_events_from_beginning(&ObjectDescriptor::GlobalIndex) - .await?; - commit_log.extend(meta_g); - } - Some(index_id) => { - let meta_g = self.persistent_obj.find_object_events(index_id).await; - commit_log.extend(meta_g); + GenericKvLogEvent::SSDeviceLog(_) => { + info!("SSLog can be updated only by the server itself"); } } + Ok(()) } - async fn shared_secret_replication(&self, request: &SyncRequest, commit_log: &mut Vec) { - match &request.vault_tail_id { - None => { - // Ignore empty vault requests - } - Some(_) => { - let audit_desc = ObjectDescriptor::SharedSecretAudit { - vault_name: request.sender.vault.name.clone(), - }; + async fn get_vault(&self, vault_name: VaultName, sender_device: &DeviceData) -> anyhow::Result<(ArtifactId, VaultData)> { + let vault_desc = VaultDescriptor::vault(vault_name.clone()); + let maybe_vault = self.find_vault(ObjectId::unit(vault_desc.clone())).await?; + let Some(vault) = maybe_vault else { + return Err(anyhow!("Vault not found")); + }; - let audit_tail_id = request.s_s_audit.clone().unwrap_or(ObjectId::unit(&audit_desc)); + if !vault.is_member(&sender_device.id) { + return Err(anyhow!("Sender is not a member of the vault")); + } - let events = self.persistent_obj.find_object_events(&audit_tail_id).await; + //save new vault state + let vault_free_id = self.persistent_obj + .find_free_id_by_obj_desc(vault_desc.clone()) + .await?; - for audit_event in events { - commit_log.push(audit_event.clone()); + let ObjectId::Artifact(vault_artifact_id) = vault_free_id else { + return Err(anyhow!("Invalid vault id, must be ArtifactId, but it's: {:?}", vault_free_id)); + }; - if let GenericKvLogEvent::SharedSecret(SharedSecretObject::Audit { event }) = audit_event { - let ss_event_res = self.persistent_obj.repo.find_one(event.value.clone()).await; + Ok((vault_artifact_id, vault)) + } - let Ok(Some(ss_event)) = ss_event_res else { - panic!("Invalid event type: not an audit event"); - }; + #[instrument(skip_all)] + async fn global_index_replication(&self, gi_id: ObjectId) -> anyhow::Result> { + let events = self.persistent_obj + .find_object_events(gi_id) + .await?; + Ok(events) + } - let GenericKvLogEvent::SharedSecret(ss_obj) = &ss_event else { - panic!("Invalid event type: not shared secret"); - }; + pub async fn vault_replication(&self, request: VaultRequest) -> anyhow::Result> { + let mut commit_log = vec![]; - if let SharedSecretObject::Audit { .. } = ss_obj { - panic!("Audit log events not allowed"); - } + //sync VaultLog + { + let vault_log_events = self.persistent_obj + .find_object_events(request.vault_log.clone()) + .await?; + commit_log.extend(vault_log_events); + } - commit_log.push(ss_event); - } - } - } + //sync Vault + { + let vault_events = self.persistent_obj + .find_object_events(request.vault.clone()) + .await?; + + commit_log.extend(vault_events); } - } - pub async fn vault_replication(&self, request: &SyncRequest, commit_log: &mut Vec) { - match &request.vault_tail_id { - None => { - // Ignore empty requests - } - Some(vault_tail_id) => { - //sync meta db!!! how? See MetaDbService::sync_db() - let vault_store = self - .meta_db_service_proxy - .get_vault_store(request.sender.vault.name.clone()) - .await - .unwrap(); - - let vault_signatures = match &vault_store { - VaultStore::Empty => { - info!("Empty vault store"); - vec![] - } - VaultStore::Unit { tail_id } => self.persistent_obj.get_user_sig(tail_id.clone()).await, - VaultStore::Genesis { tail_id, .. } => self.persistent_obj.get_user_sig(tail_id.clone()).await, - VaultStore::Store { vault, .. } => vault.signatures.clone(), - }; + //sync vault status + { + let vault_status_events = self.persistent_obj + .find_object_events(request.vault_status.clone()) + .await?; - let vault_signatures: Vec = vault_signatures - .iter() - .map(|sig| sig.public_key.base64_text.clone()) - .collect(); - - if vault_signatures.contains(&request.sender.public_key.base64_text) { - let vault_events = self.persistent_obj.find_object_events(vault_tail_id).await; - commit_log.extend(vault_events); - } else { - debug!( - "The client is not a member of the vault.\nRequest: {:?},\nvault store: {:?}", - &request, &vault_store - ); - } - } + commit_log.extend(vault_status_events); } + + Ok(commit_log) } - async fn meta_pass_replication(&self, request: &SyncRequest, commit_log: &mut Vec) { - match &request.meta_pass_tail_id { - None => { - // Ignore empty requests - } - Some(meta_pass_tail_id) => { - let meta_pass_events = self.persistent_obj.find_object_events(meta_pass_tail_id).await; - commit_log.extend(meta_pass_events); - } - } + async fn find_vault(&self, vault_id: ObjectId) -> anyhow::Result> { + let maybe_vault_event = self.persistent_obj + .find_tail_event_by_obj_id(vault_id) + .await?; + + let Some(vault_event) = maybe_vault_event else { + return Ok(None); + }; + + let GenericKvLogEvent::Vault(VaultObject::Vault(event)) = vault_event else { + return Ok(None); + }; + + let vault = event.value; + Ok(Some(vault)) } } impl ServerDataSync { - async fn accept_sign_up_request(&self, event: &KvLogEvent, vault_id: &IdStr) { + async fn accept_sign_up_request(&self, candidate: UserData) -> anyhow::Result<()> { //vault not found, we can create our new vault - info!("Accept SignUp request, for the vault: {:?}", vault_id); + info!("Accept SignUp request, for the vault: {:?}", candidate.vault_name()); + + let server = self.device_creds.device.clone(); - let server_pk = self.context.server_pk(); let sign_up_action = SignUpAction {}; - let sign_up_events = sign_up_action.accept(event, &server_pk); + let sign_up_events = sign_up_action.accept(candidate.clone(), server.clone()); for sign_up_event in sign_up_events { self.persistent_obj .repo - .save_event(sign_up_event) - .await - .expect("Error saving sign_up events"); + .save(sign_up_event) + .await?; } - //update global index + self.update_global_index(candidate.vault_name()).await?; + + Ok(()) + } + + async fn update_global_index(&self, vault_name: VaultName) -> anyhow::Result<()> { //find the latest global_index_id??? - let gi_obj_id = ObjectId::unit(&ObjectDescriptor::GlobalIndex); - let global_index_tail_id = self + let gi_free_id = self .persistent_obj - .find_tail_id(gi_obj_id.clone()) - .await - .unwrap_or(gi_obj_id); - - let mut gi_events = vec![]; - if let ObjectId::Unit { id: _ } = global_index_tail_id.clone() { - let unit_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Unit { - event: KvLogEvent::global_index_unit(), - }); + .find_free_id_by_obj_desc(ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index)) + .await?; - let genesis_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Genesis { - event: KvLogEvent::global_index_genesis(&server_pk), - }); + let ObjectId::Artifact(gi_artifact_id) = gi_free_id else { + return Err(anyhow!("Invalid global index state")); + }; - gi_events.push(unit_event); - gi_events.push(genesis_event); - } + let vault_id = UnitId::vault_unit(vault_name.clone()); - let gi_obj_id = match global_index_tail_id { - ObjectId::Unit { .. } => ObjectId::global_index_unit().next().next(), - ObjectId::Genesis { .. } => ObjectId::global_index_genesis().next(), - ObjectId::Regular { .. } => global_index_tail_id.next(), + let gi_update_event = { + GlobalIndexObject::Update(KvLogEvent { + key: KvKey { + obj_id: gi_artifact_id, + obj_desc: ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index), + }, + value: vault_id.clone(), + }).to_generic() }; - let gi_update_event = GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Update { - event: KvLogEvent::new_global_index_event(&gi_obj_id, vault_id), - }); - + let mut gi_events = vec![]; gi_events.push(gi_update_event); for gi_event in gi_events { self.persistent_obj .repo - .save_event(gi_event) - .await - .expect("Error saving vaults genesis event"); + .save(gi_event) + .await?; } - } -} -pub trait MetaServerContext { - fn server_pk(&self) -> PublicKeyRecord; -} - -pub struct MetaServerContextState { - pub km: KeyManager, -} + let vault_idx_evt = GlobalIndexObject::index_from_vault_id(vault_id).to_generic(); -impl MetaServerContext for MetaServerContextState { - fn server_pk(&self) -> PublicKeyRecord { - PublicKeyRecord::from(self.km.dsa.public_key()) - } -} - -impl Default for MetaServerContextState { - /// conn_url="file:///tmp/test.db" - fn default() -> Self { - let km = KeyManager::generate(); - Self { km } - } -} + self.persistent_obj.repo.save(vault_idx_evt).await?; -impl From<&UserCredentials> for MetaServerContextState { - fn from(creds: &UserCredentials) -> Self { - Self { - km: KeyManager::try_from(creds.security_box.key_manager.as_ref()).unwrap(), - } - } -} - -#[cfg(test)] -pub mod test { - use crate::models::DeviceInfo; - use crate::node::common::data_transfer::MpscDataTransfer; - use crate::node::db::in_mem_db::InMemKvLogEventRepo; - use crate::node::db::meta_db::meta_db_service::{MetaDbDataTransfer, MetaDbService}; - - use super::*; - - /// Disabled. Reason: DataSyncTestContext has to start MetaDbService as a separate task, otherwise test get stuck - /// because the service has been stopped - #[ignore] - #[tokio::test] - async fn test_accept_sign_up() { - let ctx = DataSyncTestContext::default(); - let data_sync = ctx.data_sync; - - let vault_unit = GenericKvLogEvent::Vault(VaultObject::unit(&ctx.user_sig)); - data_sync.send(vault_unit).await; - - let request = SyncRequest { - sender: ctx.user_sig.as_ref().clone(), - vault_tail_id: Some(ObjectId::vault_unit("test_vault")), - meta_pass_tail_id: None, - global_index: None, - s_s_audit: None, - }; - let events = data_sync.replication(request).await.unwrap(); - - match &events[0] { - GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Unit { - event: KvLogEvent { key, .. }, - }) => { - assert!(key.obj_id.is_unit()); - } - _ => panic!("Invalid event"), - } - - match &events[1] { - GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Genesis { - event: KvLogEvent { key, .. }, - }) => { - assert!(key.obj_id.is_genesis()); - } - _ => panic!("Invalid event"), - } - - match &events[2] { - GenericKvLogEvent::GlobalIndex(GlobalIndexObject::Update { - event: KvLogEvent { key, .. }, - }) => { - assert_eq!(key.obj_id.unit_id().next().next(), key.obj_id); - } - _ => panic!("Invalid event"), - } - - match &events[3] { - GenericKvLogEvent::Vault(VaultObject::Unit { - event: KvLogEvent { key, .. }, - }) => { - assert!(key.obj_id.is_unit()); - } - _ => panic!("Invalid event"), - } - - match &events[4] { - GenericKvLogEvent::Vault(VaultObject::Genesis { - event: KvLogEvent { key, .. }, - }) => { - assert!(key.obj_id.is_genesis()); - } - _ => panic!("Invalid event"), - } - - match &events[5] { - GenericKvLogEvent::Vault(VaultObject::SignUpUpdate { - event: KvLogEvent { key, .. }, - }) => { - assert_eq!(key.obj_id.unit_id().next().next(), key.obj_id); - } - _ => panic!("Invalid event"), - } - } - - pub struct DataSyncTestContext { - pub repo: Arc, - pub persistent_obj: Arc>, - pub meta_db_service: Arc>, - pub data_sync: ServerDataSync, - pub user_sig: Arc, - pub user_creds: Arc, - } - - impl Default for DataSyncTestContext { - fn default() -> Self { - let repo = Arc::new(InMemKvLogEventRepo::default()); - - let persistent_object = Arc::new(PersistentObject::new(repo.clone())); - - let meta_db_dt = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - - let client_meta_db_service = Arc::new(MetaDbService { - persistent_obj: persistent_object.clone(), - repo: persistent_object.repo.clone(), - meta_db_id: String::from("test"), - data_transfer: meta_db_dt.clone(), - }); - - let s_box = KeyManager::generate_security_box("test_vault".to_string()); - let device = DeviceInfo { - device_id: "a".to_string(), - device_name: "a".to_string(), - }; - let user_sig = s_box.get_user_sig(&device); - let user_creds = Arc::new(UserCredentials { - security_box: Box::new(s_box), - user_sig: Box::new(user_sig.clone()), - }); - - let data_sync = ServerDataSync { - persistent_obj: persistent_object.clone(), - context: Arc::new(MetaServerContextState::from(user_creds.as_ref())), - meta_db_service_proxy: Arc::new(MetaDbServiceProxy { dt: meta_db_dt }), - }; - - Self { - repo, - persistent_obj: persistent_object, - meta_db_service: client_meta_db_service, - data_sync, - user_sig: Arc::new(user_sig), - user_creds: user_creds.clone(), - } - } + Ok(()) } } diff --git a/core/src/node/server/request.rs b/core/src/node/server/request.rs index 2155b10d..bf9a0d68 100644 --- a/core/src/node/server/request.rs +++ b/core/src/node/server/request.rs @@ -1,16 +1,36 @@ use serde::{Deserialize, Serialize}; -use crate::models::UserSignature; +use crate::node::common::model::device::DeviceData; +use crate::node::common::model::user::UserData; use crate::node::db::events::object_id::ObjectId; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct SyncRequest { - pub sender: UserSignature, +#[serde(rename_all = "camelCase")] +pub enum SyncRequest { + GlobalIndex(GlobalIndexRequest), + Vault(VaultRequest), + SharedSecret(SharedSecretRequest), +} - pub vault_tail_id: Option, - pub meta_pass_tail_id: Option, +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VaultRequest { + pub sender: UserData, + pub vault_log: ObjectId, + pub vault: ObjectId, + pub vault_status: ObjectId, +} - pub global_index: Option, - - pub s_s_audit: Option +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SharedSecretRequest { + pub sender: UserData, + pub ss_log: ObjectId, } + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct GlobalIndexRequest { + pub sender: DeviceData, + pub global_index: ObjectId, +} \ No newline at end of file diff --git a/core/src/node/server/server_app.rs b/core/src/node/server/server_app.rs index ed9e5c0d..7bc266d6 100644 --- a/core/src/node/server/server_app.rs +++ b/core/src/node/server/server_app.rs @@ -1,39 +1,41 @@ use std::sync::Arc; -use tracing::{error, info, instrument, Instrument}; + +use tracing::{error, info, instrument}; use crate::node::common::data_transfer::MpscDataTransfer; -use crate::node::db::events::common::ObjectCreator; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; -use crate::node::db::events::object_descriptor::ObjectDescriptor; +use crate::node::common::model::device::DeviceCredentials; +use crate::node::db::descriptors::global_index::GlobalIndexDescriptor; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; use crate::node::db::events::object_id::ObjectId; -use crate::node::db::generic_db::KvLogEventRepo; use crate::node::db::objects::persistent_object::PersistentGlobalIndexApi; - -use crate::node::server::data_sync::{DataSyncApi, DataSyncMessage, MetaServerContext, ServerDataSync}; +use crate::node::db::repo::generic_db::KvLogEventRepo; +use crate::node::server::data_sync::{DataSyncApi, DataSyncRequest, DataSyncResponse, ServerDataSync}; pub struct ServerApp { - pub data_sync: Arc>, + pub data_sync: ServerDataSync, pub data_transfer: Arc, + pub device_creds: DeviceCredentials } pub struct ServerDataTransfer { - pub dt: MpscDataTransfer>, + pub dt: MpscDataTransfer, } -impl ServerApp -where - Repo: KvLogEventRepo, -{ +impl ServerApp { + #[instrument(skip(self))] - pub async fn run(&self) { + pub async fn run(&self) -> anyhow::Result<()> { info!("Run server app"); - self.gi_initialization().in_current_span().await; + self.gi_initialization().await; - while let Ok(sync_message) = self.data_transfer.dt.service_receive().in_current_span().await { + while let Ok(sync_message) = self.data_transfer.dt.service_receive().await { match sync_message { - DataSyncMessage::SyncRequest(request) => { - let new_events_result = self.data_sync.replication(request).in_current_span().await; + DataSyncRequest::SyncRequest(request) => { + let new_events_result = self.data_sync + .replication(request) + .await; + let new_events = match new_events_result { Ok(data) => { //debug!(format!("New events for a client: {:?}", data).as_str()); @@ -45,31 +47,31 @@ where } }; - self.data_transfer.dt.send_to_client(new_events).in_current_span().await; + self.data_transfer.dt + .send_to_client(DataSyncResponse { events: new_events}) + .await; } - DataSyncMessage::Event(event) => { - self.data_sync.send(event).in_current_span().await; + DataSyncRequest::Event(event) => { + self.data_sync.send(event).await?; } } } + + Ok(()) } + #[instrument(skip(self))] async fn gi_initialization(&self) { //Check if all required persistent objects has been created - let maybe_gi_unit_id = self - .data_sync - .persistent_obj - .repo - .find_one(ObjectId::unit(&ObjectDescriptor::GlobalIndex)) - .in_current_span() - .await; + let gi_obj_desc = ObjectDescriptor::GlobalIndex(GlobalIndexDescriptor::Index); - let maybe_gi_genesis = self - .data_sync - .persistent_obj - .repo - .find_one(ObjectId::genesis(&ObjectDescriptor::GlobalIndex)) - .in_current_span() + let maybe_gi_unit_id = { + let gi_unit = ObjectId::unit(gi_obj_desc.clone()); + self.repo().find_one(gi_unit).await + }; + + let maybe_gi_genesis = self.repo() + .find_one(ObjectId::genesis(gi_obj_desc)) .await; let gi_genesis_exists = matches!(maybe_gi_genesis, Ok(Some(_))); @@ -77,14 +79,16 @@ where //If either of unit or genesis not exists then create initial records for the global index if !gi_unit_exists || !gi_genesis_exists { - let server_pk = self.data_sync.context.server_pk(); + let server_pk = self.device_creds.device.clone(); let _meta_g = self .data_sync .persistent_obj .global_index - .gi_init(&server_pk) - .in_current_span() + .gi_init(server_pk) .await; } } + fn repo(&self) -> Arc { + self.data_sync.persistent_obj.repo.clone() + } } diff --git a/core/src/sdk/mod.rs b/core/src/sdk/mod.rs deleted file mode 100644 index a1495285..00000000 --- a/core/src/sdk/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod password; -pub mod vault; diff --git a/core/src/sdk/password.rs b/core/src/sdk/password.rs deleted file mode 100644 index cda69664..00000000 --- a/core/src/sdk/password.rs +++ /dev/null @@ -1,40 +0,0 @@ -use rand::{distributions::Alphanumeric, Rng}; - -use crate::crypto::utils; -use crate::models::MetaPasswordId; - -const SALT_LENGTH: usize = 8; - -impl MetaPasswordId { - pub fn generate(name: String) -> Self { - let salt: String = rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(SALT_LENGTH) - .map(char::from) - .collect(); - MetaPasswordId::build(name, salt) - } - - pub fn build(name: String, salt: String) -> Self { - let mut id_str = name.clone(); - id_str.push('-'); - id_str.push_str(salt.as_str()); - - Self { - id: utils::generate_uuid_b64_url_enc(id_str), - salt, - name, - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn meta_password_id() { - let pass_id = MetaPasswordId::build("test".to_string(), "salt".to_string()); - assert_eq!(pass_id.id, "CHKANX39xaMXfhe3Qkx9-w".to_string()) - } -} diff --git a/core/src/sdk/vault.rs b/core/src/sdk/vault.rs deleted file mode 100644 index ba0ae3de..00000000 --- a/core/src/sdk/vault.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::crypto; -use crate::crypto::key_pair::KeyPair; -use crate::crypto::keys::KeyManager; -use crate::models::{DeviceInfo, MetaVault, UserSignature, VaultDoc}; - -impl UserSignature { - pub fn to_initial_vault_doc(self) -> VaultDoc { - VaultDoc { - vault_name: self.vault.name.clone(), - signatures: vec![self], - pending_joins: vec![], - declined_joins: vec![], - } - } - - pub fn generate_default_for_tests(key_manager: &KeyManager) -> Self { - let vault_name = "test_vault".to_string(); - - UserSignature { - vault: Box::new(MetaVault { - name: vault_name, - device: Box::from(DeviceInfo { - device_name: "test_device".to_string(), - device_id: crypto::utils::rand_uuid_b64_url_enc().base64_text, - }), - }), - public_key: Box::from(key_manager.dsa.public_key()), - transport_public_key: Box::from(key_manager.transport_key_pair.public_key()), - } - } -} diff --git a/core/src/secret/data_block/encrypted_data_block.rs b/core/src/secret/data_block/encrypted_data_block.rs index 9b1f9318..8e6d0733 100644 --- a/core/src/secret/data_block/encrypted_data_block.rs +++ b/core/src/secret/data_block/encrypted_data_block.rs @@ -34,8 +34,8 @@ impl EncryptedDataBlock { #[cfg(test)] mod test { + use crate::crypto::encoding::base64::Base64Text; use crate::errors::CoreError; - use crate::models::Base64EncodedText; use crate::secret::data_block::common::BlockMetaData; use crate::secret::data_block::common::SharedSecretConfig; use crate::secret::data_block::encrypted_data_block::{EncryptedDataBlock, SECRET_DATA_BLOCK_SIZE}; @@ -45,7 +45,7 @@ mod test { fn test_encrypted_data_block() -> Result<(), CoreError> { let meta_data = BlockMetaData { size: 11 }; let raw_data = vec![1; SECRET_DATA_BLOCK_SIZE]; - let text = Base64EncodedText::from(raw_data.clone()); + let text = Base64Text::from(raw_data.clone()); let secret_share_dto = SecretShareWithOrderingDto { block: 0, diff --git a/core/src/secret/mod.rs b/core/src/secret/mod.rs index 45bf4469..5fd92e0f 100644 --- a/core/src/secret/mod.rs +++ b/core/src/secret/mod.rs @@ -1,22 +1,20 @@ use std::sync::Arc; -use tracing::Instrument; +use crate::{PlainText, SharedSecretConfig, SharedSecretEncryption, UserShareDto}; +use crate::CoreResult; use crate::crypto::keys::KeyManager; -use crate::models::{ - AeadCipherText, EncryptedMessage, MetaPasswordDoc, MetaPasswordId, MetaPasswordRequest, SecretDistributionDocData, - SecretDistributionType, UserCredentials, UserSecurityBox, UserSignature, VaultDoc, -}; -use crate::node::db::events::common::ObjectCreator; -use crate::node::db::events::common::{MetaPassObject, SharedSecretObject}; -use crate::node::db::events::generic_log_event::GenericKvLogEvent; +use crate::node::common::model::crypto::EncryptedMessage; +use crate::node::common::model::device::{DeviceLink, DeviceLinkBuilder}; +use crate::node::common::model::secret::{MetaPasswordId, SecretDistributionData, SecretDistributionType}; +use crate::node::common::model::user::UserCredentials; +use crate::node::common::model::vault::VaultData; +use crate::node::db::descriptors::object_descriptor::ObjectDescriptor; +use crate::node::db::descriptors::shared_secret::SharedSecretDescriptor; +use crate::node::db::events::common::SharedSecretObject; +use crate::node::db::events::generic_log_event::ToGenericEvent; use crate::node::db::events::kv_log_event::{KvKey, KvLogEvent}; -use crate::node::db::events::object_descriptor::ObjectDescriptor; -use crate::node::db::events::object_id::{IdGen, ObjectId}; -use crate::node::db::generic_db::KvLogEventRepo; use crate::node::db::objects::persistent_object::PersistentObject; - -use crate::CoreResult; -use crate::{PlainText, SharedSecretConfig, SharedSecretEncryption, UserShareDto}; +use crate::node::db::repo::generic_db::KvLogEventRepo; pub mod data_block; pub mod shared_secret; @@ -35,8 +33,8 @@ pub fn split(secret: String, config: SharedSecretConfig) -> CoreResult, + vault: VaultData, } impl MetaEncryptor { @@ -44,238 +42,99 @@ impl MetaEncryptor { /// - generate meta password id /// - split /// - encrypt each share with ECIES Encryption Scheme - fn encrypt(self, password: String) -> Vec { + fn encrypt(self, password: String) -> anyhow::Result> { let cfg = SharedSecretConfig::default(); - let key_manager = KeyManager::try_from(self.security_box.key_manager.as_ref()).unwrap(); + let key_manager = KeyManager::try_from(&self.user.device_creds.secret_box)?; let shares = split(password, cfg).unwrap(); let mut encrypted_shares = vec![]; - for index in 0..self.vault.signatures.len() { - let receiver_sig = &self.vault.signatures[index]; + for (index, receiver) in self.vault.members().iter().enumerate() { let share: &UserShareDto = &shares[index]; let share_str = serde_json::to_string(&share).unwrap(); - let receiver_pk = receiver_sig.public_key.as_ref().clone(); - let encrypted_share: AeadCipherText = key_manager + let receiver_pk = receiver.clone().user().device.keys.transport_pk.clone(); + + let encrypted_share = key_manager .transport_key_pair - .encrypt_string(share_str, receiver_pk) - .unwrap(); + .encrypt_string(share_str, receiver_pk)?; - encrypted_shares.push(MetaCipherShare { - receiver: receiver_sig.clone(), - cipher_share: encrypted_share, - }); + let device_link = DeviceLinkBuilder::new() + .sender(self.user.device_creds.device.id.clone()) + .receiver(receiver.clone().user().device.id.clone()) + .build()?; + + let cipher_share = EncryptedMessage::CipherShare { device_link, share: encrypted_share }; + encrypted_shares.push(cipher_share); } - encrypted_shares + Ok(encrypted_shares) } } -struct MetaCipherShare { - receiver: UserSignature, - cipher_share: AeadCipherText, -} - pub struct MetaDistributor { pub persistent_obj: Arc>, pub user_creds: Arc, - pub vault: VaultDoc, + pub vault: VaultData, } impl MetaDistributor { - /// Encrypt and distribute password across the cluster - pub async fn distribute(self, password_id: String, password: String) { + pub async fn distribute(self, password_id: String, password: String) -> anyhow::Result<()> { let encryptor = MetaEncryptor { - security_box: self.user_creds.security_box.as_ref().clone(), + user: self.user_creds.clone(), vault: self.vault.clone(), }; - let pass = { - let pass_id = Box::new(MetaPasswordId::generate(password_id)); - - MetaPasswordDoc { - id: pass_id, - vault: Box::new(self.vault.clone()), - } - }; + let pass_id = MetaPasswordId::generate(password_id); //save meta password!!! - let vault_name = self.user_creds.user_sig.vault.name.clone(); - let meta_pass_obj_desc = ObjectDescriptor::MetaPassword { vault_name }; + let vault_name = self.user_creds.vault_name.clone(); - let pass_tail_id = self - .persistent_obj - .find_tail_id_by_obj_desc(&meta_pass_obj_desc) - .in_current_span() - .await - .map(|id| id.next()) - .unwrap(); + let encrypted_shares = encryptor.encrypt(password)?; - let meta_pass_event = GenericKvLogEvent::MetaPass(MetaPassObject::Update { - event: KvLogEvent { - key: KvKey { - obj_id: pass_tail_id, - obj_desc: meta_pass_obj_desc, - }, - value: pass.clone(), - }, - }); - - self.persistent_obj - .repo - .save_event(meta_pass_event) - .in_current_span() - .await - .unwrap(); - - let encrypted_shares = encryptor.encrypt(password); - - for cipher_share in encrypted_shares.iter() { - let cipher_msg = EncryptedMessage { - receiver: Box::from(cipher_share.receiver.clone()), - encrypted_text: Box::new(cipher_share.cipher_share.clone()), - }; - - let distribution_share = SecretDistributionDocData { + for secret_share in encrypted_shares { + let distribution_share = SecretDistributionData { distribution_type: SecretDistributionType::Split, - meta_password: Box::new(MetaPasswordRequest { - user_sig: Box::new(self.user_creds.user_sig.as_ref().clone()), - meta_password: Box::new(pass.clone()), - }), - secret_message: Box::new(cipher_msg), + vault_name: vault_name.clone(), + secret_message: secret_share.clone(), + meta_password_id: pass_id.clone(), }; - if cipher_share.receiver.vault.device.device_id == self.user_creds.user_sig.vault.device.device_id { - let secret_share_event = GenericKvLogEvent::SharedSecret(SharedSecretObject::Split { - event: KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::from(&distribution_share)), - value: distribution_share, - }, - }); + let ss_obj = match secret_share.device_link() { + DeviceLink::Loopback(_) => { + let ss_local_desc = SharedSecretDescriptor::LocalShare { + vault_name: vault_name.clone(), + meta_pass_id: pass_id.clone(), + }; - let _ = self - .persistent_obj - .repo - .save_event(secret_share_event) - .in_current_span() - .await; - } else { - let obj_desc = ObjectDescriptor::from(&distribution_share); - let secret_share_event = GenericKvLogEvent::SharedSecret(SharedSecretObject::Split { - event: KvLogEvent { - key: KvKey::unit(&ObjectDescriptor::from(&distribution_share)), + SharedSecretObject::LocalShare(KvLogEvent { + key: KvKey::unit(ObjectDescriptor::SharedSecret(ss_local_desc)), value: distribution_share, - }, - }); - - let tail_id = self - .persistent_obj - .find_tail_id_by_obj_desc(&obj_desc) - .await - .map(|id| id.next()) - .unwrap_or(ObjectId::unit(&obj_desc)); - - let _ = self.persistent_obj.repo.save(tail_id, secret_share_event).await; - }; - } - } -} - -#[cfg(test)] -mod test { - use crate::models::DeviceInfo; - use crate::node::db::actions::join; - use crate::node::db::events::common::{LogEventKeyBasedRecord, PublicKeyRecord}; - use crate::node::db::events::vault_event::VaultObject; - use crate::node::db::generic_db::{FindOneQuery, SaveCommand}; - use crate::node::server::data_sync::test::DataSyncTestContext; - use crate::node::server::data_sync::DataSyncApi; - - use super::*; - - #[tokio::test] - async fn test() { - let ctx = DataSyncTestContext::default(); - let data_sync = ctx.data_sync; - - let vault_unit = GenericKvLogEvent::Vault(VaultObject::unit(&ctx.user_sig)); - data_sync.send(vault_unit).await; - - let _user_pk = PublicKeyRecord::from(ctx.user_sig.public_key.as_ref().clone()); - - let vault_unit_id = ObjectId::vault_unit("test_vault"); - let vault_tail_id = ctx.persistent_obj.find_tail_id(vault_unit_id.clone()).await.unwrap(); - let vault_event = ctx.repo.find_one(vault_tail_id).await.unwrap().unwrap(); - - let s_box_b = KeyManager::generate_security_box("test_vault".to_string()); - let device_b = DeviceInfo { - device_id: "b".to_string(), - device_name: "b".to_string(), - }; - let user_sig_b = s_box_b.get_user_sig(&device_b); - - let s_box_c = KeyManager::generate_security_box("test_vault".to_string()); - let device_c = DeviceInfo { - device_id: "c".to_string(), - device_name: "c".to_string(), - }; - let user_sig_c = s_box_c.get_user_sig(&device_c); - - if let GenericKvLogEvent::Vault(VaultObject::SignUpUpdate { event }) = vault_event { - let vault = event.value; - - let join_request = join::join_cluster_request(&vault_unit_id.next().next(), &user_sig_b); - let kv_join_event = join::accept_join_request(&join_request, &vault); - let accept_event = GenericKvLogEvent::Vault(VaultObject::JoinUpdate { - event: kv_join_event.clone(), - }); - let _ = ctx.repo.save_event(accept_event).await; - - let join_request_c = join::join_cluster_request(&vault_unit_id.next().next().next(), &user_sig_c); - let kv_join_event_c = join::accept_join_request(&join_request_c, &kv_join_event.value); - let accept_event_c = GenericKvLogEvent::Vault(VaultObject::JoinUpdate { - event: kv_join_event_c.clone(), - }); - let _ = ctx.repo.save_event(accept_event_c).await; - - let distributor = MetaDistributor { - persistent_obj: ctx.persistent_obj, - user_creds: ctx.user_creds, - vault: kv_join_event_c.value, + }) + } + DeviceLink::PeerToPeer { .. } => { + let split_key = { + let split_obj_desc = ObjectDescriptor::from(&distribution_share); + KvKey::unit(split_obj_desc) + }; + + SharedSecretObject::Split(KvLogEvent { + key: split_key.clone(), + value: distribution_share, + }) + } }; - distributor - .distribute(String::from("test"), String::from("t0p$ecret")) - .await; - - let mut db = ctx + let _ = self + .persistent_obj .repo - .db - .lock() - .await - .values() - .cloned() - .collect::>(); - db.sort_by(|a, b| { - let a_id = a.key().obj_id.id_str(); - let b_id = b.key().obj_id.id_str(); - - a_id.as_str().partial_cmp(b_id.as_str()).unwrap() - }); - - println!("total events: {}", db.len()); - for event in db { - println!("event:"); - let id = event.key().obj_id.id_str(); - println!(" key: {}", serde_json::to_string(&id).unwrap()); - println!(" event: {}", serde_json::to_string(&event).unwrap()); - } - } else { - panic!("Invalid event") + .save(ss_obj.to_generic()) + .await; } + + Ok(()) } } diff --git a/core/src/secret/shared_secret.rs b/core/src/secret/shared_secret.rs index 00fd6404..5bad8ace 100644 --- a/core/src/secret/shared_secret.rs +++ b/core/src/secret/shared_secret.rs @@ -3,14 +3,14 @@ use std::str; use serde::{Deserialize, Serialize}; -use crate::errors::RecoveryError::InvalidShare; +use crate::CoreResult; +use crate::crypto::encoding::base64::Base64Text; use crate::errors::{CoreError, RecoveryError}; -use crate::models::Base64EncodedText; +use crate::errors::RecoveryError::InvalidShare; use crate::secret::data_block::common::{BlockMetaData, SharedSecretConfig}; use crate::secret::data_block::encrypted_data_block::EncryptedDataBlock; -use crate::secret::data_block::plain_data_block::{PlainDataBlock, PLAIN_DATA_BLOCK_SIZE}; +use crate::secret::data_block::plain_data_block::{PLAIN_DATA_BLOCK_SIZE, PlainDataBlock}; use crate::secret::data_block::shared_secret_data_block::SharedSecretBlock; -use crate::CoreResult; #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct PlainText { @@ -67,10 +67,10 @@ impl UserShareDto { } } -impl TryFrom<&Base64EncodedText> for UserShareDto { +impl TryFrom<&Base64Text> for UserShareDto { type Error = CoreError; - fn try_from(base64_content: &Base64EncodedText) -> Result { + fn try_from(base64_content: &Base64Text) -> Result { let data = Vec::try_from(base64_content)?; let json = serde_json::from_slice(data.as_slice())?; Ok(json) @@ -82,7 +82,7 @@ pub struct SecretShareWithOrderingDto { pub block: usize, pub config: SharedSecretConfig, pub meta_data: BlockMetaData, - pub data: Base64EncodedText, + pub data: Base64Text, } impl TryFrom<&SecretShareWithOrderingDto> for EncryptedDataBlock { @@ -149,7 +149,7 @@ impl SharedSecret { block: index, config: curr_secret_block.config, meta_data: curr_secret_block.meta_data, - data: Base64EncodedText::from(curr_block_of_a_share.data.as_slice()), + data: Base64Text::from(curr_block_of_a_share.data.as_slice()), }; share_blocks.push(share_data); } diff --git a/core/tests/common/mod.rs b/core/tests/common/mod.rs index 594d0ede..e69de29b 100644 --- a/core/tests/common/mod.rs +++ b/core/tests/common/mod.rs @@ -1 +0,0 @@ -pub mod native_app_state_manager; diff --git a/core/tests/common/native_app_state_manager.rs b/core/tests/common/native_app_state_manager.rs deleted file mode 100644 index a4ba43f2..00000000 --- a/core/tests/common/native_app_state_manager.rs +++ /dev/null @@ -1,293 +0,0 @@ -use std::sync::Arc; -use std::thread; -use tokio::runtime::Builder; -use tracing::{info, instrument, Instrument}; - -use meta_secret_core::node::app::app_state_update_manager::NoOpJsAppStateManager; -use meta_secret_core::node::app::client_meta_app::MetaClient; -use meta_secret_core::node::app::meta_app::meta_app_service::{ - MetaClientAccessProxy, MetaClientDataTransfer, MetaClientService, -}; -use meta_secret_core::node::app::sync_gateway::SyncGateway; -use meta_secret_core::node::app::virtual_device::VirtualDevice; -use meta_secret_core::node::common::data_transfer::MpscDataTransfer; -use meta_secret_core::node::common::meta_tracing::{client_span, server_span, vd_span}; -use meta_secret_core::node::db::in_mem_db::InMemKvLogEventRepo; -use meta_secret_core::node::db::meta_db::meta_db_service::{MetaDbDataTransfer, MetaDbService, MetaDbServiceProxy}; -use meta_secret_core::node::db::objects::persistent_object::PersistentObject; -use meta_secret_core::node::server::data_sync::ServerDataSync; -use meta_secret_core::node::server::server_app::{ServerApp, ServerDataTransfer}; - -pub struct NativeApplicationStateManager { - pub state_manager: Arc, - pub meta_client_proxy: Arc, - pub server_data_transfer: Arc, -} - -impl NativeApplicationStateManager { - pub async fn init( - client_repo: Arc, - server_repo: Arc, - vd_repo: Arc, - ) -> NativeApplicationStateManager { - let server_data_transfer = Arc::new(ServerDataTransfer { - dt: MpscDataTransfer::new(), - }); - - NativeApplicationStateManager::server_setup(server_repo, server_data_transfer.clone()).await; - - let device_state_manager = Arc::new(NoOpJsAppStateManager {}); - - NativeApplicationStateManager::virtual_device_setup( - vd_repo, - server_data_transfer.clone(), - device_state_manager, - ) - .await; - - let client_state_manager = Arc::new(NoOpJsAppStateManager {}); - - NativeApplicationStateManager::client_setup(client_repo, server_data_transfer, client_state_manager).await - } - - #[instrument(name = "Client", skip_all)] - pub async fn client_setup( - client_repo: Arc, - server_dt: Arc, - js_app_state: Arc, - ) -> NativeApplicationStateManager { - info!("Client setup"); - - let dt_meta_client = Arc::new(MetaClientDataTransfer { - dt: MpscDataTransfer::new(), - }); - let meta_client_proxy = Arc::new(MetaClientAccessProxy { - dt: dt_meta_client.clone(), - }); - - let meta_db_data_transfer = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - let meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: meta_db_data_transfer.clone(), - }); - - //run meta db service - let client_repo_for_meta_db = client_repo.clone(); - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let persistent_obj = { - let obj = PersistentObject::new(client_repo_for_meta_db); - Arc::new(obj) - }; - - let meta_db_service = Arc::new(MetaDbService { - persistent_obj: persistent_obj.clone(), - repo: persistent_obj.repo.clone(), - meta_db_id: String::from("Client"), - data_transfer: meta_db_data_transfer, - }); - meta_db_service.run().instrument(client_span()).await - }); - }); - - //run meta client sync gateway - let dt_for_gateway = server_dt.clone(); - let proxy_for_sync_gw = meta_db_service_proxy.clone(); - - let sync_gateway = Arc::new(SyncGateway { - id: String::from("client-gateway"), - repo: client_repo.clone(), - persistent_object: Arc::new(PersistentObject::new(client_repo.clone())), - server_dt: dt_for_gateway, - meta_db_service_proxy: proxy_for_sync_gw, - }); - let mc_sync_gateway = sync_gateway.clone(); - - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { sync_gateway.run().instrument(client_span()).await }); - }); - - //run meta client service - let js_app_state_for_client = js_app_state.clone(); - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let persistent_obj = { - let obj = PersistentObject::new(client_repo.clone()); - Arc::new(obj) - }; - - let meta_client = Arc::new(MetaClient { - persistent_obj, - meta_db_service_proxy, - }); - - let mcs = MetaClientService { - data_transfer: dt_meta_client.clone(), - meta_client: meta_client.clone(), - state_manager: js_app_state_for_client, - sync_gateway: mc_sync_gateway, - }; - - mcs.run().instrument(client_span()).await; - }); - }); - - Self { - state_manager: js_app_state, - meta_client_proxy, - server_data_transfer: server_dt, - } - } - - #[instrument(name = "Vd", skip_all)] - pub async fn virtual_device_setup( - vd_repo: Arc, - dt: Arc, - js_app_state: Arc, - ) { - let vd_meta_db_data_transfer = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - let vd_meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: vd_meta_db_data_transfer.clone(), - }); - - let vd_meta_client_data_transfer = Arc::new(MetaClientDataTransfer { - dt: MpscDataTransfer::new(), - }); - let vd_meta_client_proxy = Arc::new(MetaClientAccessProxy { - dt: vd_meta_client_data_transfer.clone(), - }); - - //run vd meta db service - let vd_repo_meta_db = vd_repo.clone(); - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let persistent_obj = Arc::new(PersistentObject::new(vd_repo_meta_db.clone())); - - let meta_db_service = MetaDbService { - persistent_obj: persistent_obj.clone(), - repo: vd_repo_meta_db, - meta_db_id: String::from("virtual_device"), - data_transfer: vd_meta_db_data_transfer, - }; - - meta_db_service.run().instrument(vd_span()).await; - }); - }); - - let persistent_object = Arc::new(PersistentObject::new(vd_repo.clone())); - let gateway = Arc::new(SyncGateway { - id: String::from("vd-gateway"), - repo: persistent_object.repo.clone(), - persistent_object: persistent_object.clone(), - server_dt: dt.clone(), - meta_db_service_proxy: vd_meta_db_service_proxy.clone(), - }); - - //run meta client service - let vd_db_meta_client = vd_repo.clone(); - let service_proxy_for_client = vd_meta_db_service_proxy.clone(); - let mc_gw = gateway.clone(); - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let persistent_object = Arc::new(PersistentObject::new(vd_db_meta_client)); - - let meta_client_service = { - let meta_client = Arc::new(MetaClient { - persistent_obj: persistent_object.clone(), - meta_db_service_proxy: service_proxy_for_client, - }); - - Arc::new(MetaClientService { - data_transfer: vd_meta_client_data_transfer, - meta_client: meta_client.clone(), - state_manager: js_app_state.clone(), - sync_gateway: mc_gw, - }) - }; - - meta_client_service.run().instrument(vd_span()).await - }); - }); - - //run virtual device - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - VirtualDevice::event_handler( - persistent_object, - vd_meta_client_proxy, - vd_meta_db_service_proxy, - dt, - gateway, - ) - .instrument(vd_span()) - .await - }); - }); - } - - #[instrument(name = "MetaServer", skip_all)] - pub async fn server_setup(server_repo: Arc, server_dt: Arc) { - info!("Server initialization"); - - let meta_db_data_transfer = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - - //run meta_db service - let dt_for_meta = meta_db_data_transfer.clone(); - let server_repo_for_meta = server_repo.clone(); - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let server_persistent_obj = { - let obj = PersistentObject::new(server_repo_for_meta.clone()); - Arc::new(obj) - }; - - let meta_db_service = MetaDbService { - persistent_obj: server_persistent_obj, - repo: server_repo_for_meta, - meta_db_id: String::from("Server"), - data_transfer: dt_for_meta, - }; - - meta_db_service.run().instrument(server_span()).await; - }); - }); - - //run server - thread::spawn(move || { - let rt = Builder::new_current_thread().enable_all().build().unwrap(); - rt.block_on(async { - let server_persistent_obj = { - let obj = PersistentObject::new(server_repo.clone()); - Arc::new(obj) - }; - - let meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: meta_db_data_transfer, - }); - - let server_data_sync = ServerDataSync::new(server_persistent_obj, meta_db_service_proxy) - .instrument(server_span()) - .await; - let data_sync = Arc::new(server_data_sync); - - let server = Arc::new(ServerApp { - data_sync, - data_transfer: server_dt, - }); - server.run().instrument(server_span()).await; - }); - }); - } -} diff --git a/core/tests/meta_app_service_test.rs b/core/tests/meta_app_service_test.rs deleted file mode 100644 index eaeaf639..00000000 --- a/core/tests/meta_app_service_test.rs +++ /dev/null @@ -1,298 +0,0 @@ -use std::collections::HashMap; -use std::ops::Deref; -use std::sync::Arc; -use std::time::Duration; - -use async_mutex::Mutex; -use tracing::{info, Level}; - -use meta_secret_core::node::app::meta_app::messaging::{ - ClusterDistributionRequest, GenericAppStateRequest, SignUpRequest, -}; -use meta_secret_core::node::db::events::common::{MemPoolObject, MetaPassObject, ObjectCreator}; -use meta_secret_core::node::db::events::db_tail::DbTailObject; -use meta_secret_core::node::db::events::generic_log_event::GenericKvLogEvent; -use meta_secret_core::node::db::events::local::KvLogEventLocal; -use meta_secret_core::node::db::events::object_descriptor::{ObjectDescriptor, SharedSecretDescriptor}; -use meta_secret_core::node::db::events::object_id::{IdGen, ObjectId}; -use meta_secret_core::node::db::events::vault_event::VaultObject; -use meta_secret_core::node::db::in_mem_db::InMemKvLogEventRepo; - -use crate::common::native_app_state_manager::NativeApplicationStateManager; - -mod common; - -fn setup_logging() { - tracing_subscriber::fmt().with_max_level(Level::INFO).pretty().init(); -} - -#[tokio::test] -async fn server_test() { - setup_logging(); - - let client_repo = Arc::new(InMemKvLogEventRepo { - db: Arc::new(Mutex::new(HashMap::default())), - }); - - let server_repo = Arc::new(InMemKvLogEventRepo { - db: Arc::new(Mutex::new(HashMap::default())), - }); - - let device_repo = Arc::new(InMemKvLogEventRepo { - db: Arc::new(Mutex::new(HashMap::default())), - }); - - let app_manager = - NativeApplicationStateManager::init(client_repo.clone(), server_repo.clone(), device_repo.clone()).await; - - async_std::task::sleep(Duration::from_secs(3)).await; - - let sign_up_request = GenericAppStateRequest::SignUp(SignUpRequest { - vault_name: String::from("q"), - device_name: String::from("client"), - }); - - app_manager - .meta_client_proxy - .send_request(sign_up_request.clone()) - .await; - - async_std::task::sleep(Duration::from_secs(1)).await; - - app_manager - .meta_client_proxy - .send_request(sign_up_request.clone()) - .await; - - async_std::task::sleep(Duration::from_secs(1)).await; - - app_manager - .meta_client_proxy - .send_request(sign_up_request.clone()) - .await; - - async_std::task::sleep(Duration::from_secs(1)).await; - - app_manager - .meta_client_proxy - .send_request(GenericAppStateRequest::ClusterDistribution( - ClusterDistributionRequest { - pass_id: String::from("pass_id:123"), - pass: String::from("t0p$ecret"), - }, - )) - .await; - - async_std::task::sleep(Duration::from_secs(3)).await; - - info!("Verification"); - - { - let events = server_repo.as_ref().db.as_ref().clone().lock().await.deref().clone(); - - let verifier = MetaAppTestVerifier { - vault_name: String::from("q"), - events, - }; - - verifier.server_verification(); - }; - - { - let events = client_repo.as_ref().db.as_ref().clone().lock().await.deref().clone(); - - let verifier = MetaAppTestVerifier { - vault_name: String::from("q"), - events, - }; - - verifier.client_verification(); - }; - - { - let events = device_repo.as_ref().db.as_ref().clone().lock().await.deref().clone(); - - let verifier = MetaAppTestVerifier { - vault_name: String::from("q"), - events, - }; - - verifier.device_verification(); - }; -} - -struct MetaAppTestVerifier { - vault_name: String, - events: HashMap, -} - -impl MetaAppTestVerifier { - fn device_verification(&self) { - info!("Virtual Device verification"); - - for evt in self.events.values() { - println!("{:?}", evt); - println!(); - } - - assert_eq!(13, self.events.len()); - self.common_verification(); - } - - fn server_verification(&self) { - info!("Server verification"); - - assert_eq!(13, self.events.len()); - self.common_verification(); - } - - fn client_verification(&self) { - info!("Client verification"); - - assert_eq!(16, self.events.len()); - - self.common_verification(); - - self.verify_db_tail(); - self.verify_mem_pool(); - - todo!("check shared secret record") - //self.verify_local_secret_share(); - } - - fn common_verification(&self) { - self.verify_meta_vault(); - self.verify_user_creds(); - - self.verify_global_index(); - self.verify_meta_pass(); - self.verify_vault(); - - self.verify_distributed_meta_pass(); - } - - fn verify_vault(&self) { - let vault_unit = ObjectId::unit(&ObjectDescriptor::Vault { - vault_name: self.vault_name.clone(), - }); - let vault_genesis = vault_unit.next(); - let vault_sign_up_update = vault_genesis.next(); - let vault_join_request = vault_sign_up_update.next(); - let vault_join_update = vault_join_request.next(); - - assert!(self.events.contains_key(&vault_unit)); - assert!(self.events.contains_key(&vault_genesis)); - assert!(self.events.contains_key(&vault_sign_up_update)); - assert!(self.events.contains_key(&vault_join_request)); - assert!(self.events.contains_key(&vault_join_update)); - - let join_event = self.events.get(&vault_join_update).unwrap(); - if let GenericKvLogEvent::Vault(VaultObject::JoinUpdate { event }) = join_event { - assert_eq!(2, event.value.signatures.len()); - assert_eq!( - String::from("virtual-device"), - event.value.signatures[0].vault.device.device_name - ); - assert_eq!( - String::from("client"), - event.value.signatures[1].vault.device.device_name - ); - } else { - panic!("Invalid vault object. Not enough signatures"); - } - } - - fn verify_user_creds(&self) { - let creds_unit_id = ObjectId::unit(&ObjectDescriptor::UserCreds); - assert!(self.events.contains_key(&creds_unit_id)); - } - - fn verify_meta_pass(&self) { - let meta_pass_unit = ObjectId::unit(&ObjectDescriptor::MetaPassword { - vault_name: self.vault_name.clone(), - }); - assert!(self.events.contains_key(&meta_pass_unit)); - assert!(self.events.contains_key(&meta_pass_unit.next())); - } - - fn verify_distributed_meta_pass(&self) { - let meta_pass_genesis = ObjectId::genesis(&ObjectDescriptor::MetaPassword { - vault_name: self.vault_name.clone(), - }); - - assert!(self.events.contains_key(&meta_pass_genesis.next())); - } - - fn verify_global_index(&self) { - let gi_unit = ObjectId::unit(&ObjectDescriptor::GlobalIndex); - let gi_genesis = gi_unit.next(); - let gi_vault_record = gi_genesis.next(); - - assert!(self.events.contains_key(&gi_unit)); - assert!(self.events.contains_key(&gi_genesis)); - assert!(self.events.contains_key(&gi_vault_record)); - } - - fn verify_meta_vault(&self) { - let meta_vault_unit_id = ObjectId::unit(&ObjectDescriptor::MetaVault); - assert!(self.events.contains_key(&meta_vault_unit_id)); - } - - fn verify_db_tail(&self) { - let db_tail_unit = ObjectId::unit(&ObjectDescriptor::DbTail); - assert!(self.events.contains_key(&db_tail_unit)); - - let db_tail_event = self.events.get(&db_tail_unit).unwrap(); - if let GenericKvLogEvent::LocalEvent(KvLogEventLocal::DbTail { event }) = db_tail_event { - if let Some(ObjectId::Regular { unit_id, id, prev_id }) = &event.value.maybe_global_index_id { - assert_eq!(String::from("GlobalIndex:index::0"), unit_id.clone()); - assert_eq!(String::from("GlobalIndex:index::1"), prev_id.clone()); - assert_eq!(String::from("GlobalIndex:index::2"), id.clone()); - } else { - panic!("Invalid Global Index Event"); - } - - if let DbTailObject::Id { tail_id } = &event.value.meta_pass_id { - let meta_pass_genesis_id = ObjectId::genesis(&ObjectDescriptor::MetaPassword { - vault_name: String::from("q"), - }); - assert_eq!(meta_pass_genesis_id.next(), tail_id.clone()); - } else { - panic!("Invalid Meta Pass Id"); - } - - //TODO add verification for vault_id, maybe_mem_pool_id - } else { - panic!("Invalid DbTail event"); - } - } - fn verify_mem_pool(&self) { - let mem_pool_unit_id = ObjectId::mempool_unit(); - let mem_pool_event = &self.events[&mem_pool_unit_id]; - if let GenericKvLogEvent::MemPool(MemPoolObject::JoinRequest { event }) = mem_pool_event { - assert_eq!(String::from("client"), event.value.vault.device.device_name); - } else { - panic!("Invalid mem pool event"); - } - } - fn verify_local_secret_share(&self) { - let meta_pass_genesis = ObjectId::genesis(&ObjectDescriptor::MetaPassword { - vault_name: self.vault_name.clone(), - }); - let meta_pass_record_id = meta_pass_genesis.next(); - - let meta_pass_generic_evt = self.events.get(&meta_pass_record_id).unwrap(); - - let GenericKvLogEvent::MetaPass(MetaPassObject::Update { event }) = meta_pass_generic_evt else { - panic!("Invalid event"); - }; - - /*let local_secret_share_id = ObjectId::unit(&ObjectDescriptor::SharedSecret(SharedSecretDescriptor::Split { - vault_name: "".to_string(), - meta_pass_id: MetaPasswordId {}, - receiver: event.value.clone(), - }); - - assert!(self.events.contains_key(&local_secret_share_id));*/ - } -} diff --git a/core/tests/mod.rs b/core/tests/mod.rs new file mode 100644 index 00000000..34994bf5 --- /dev/null +++ b/core/tests/mod.rs @@ -0,0 +1 @@ +pub mod common; diff --git a/docs/join_cluster.md b/docs/join_cluster.md index 15bffb3a..5baa0ce0 100644 --- a/docs/join_cluster.md +++ b/docs/join_cluster.md @@ -12,7 +12,7 @@ sequenceDiagram box DeviceA participant app_a - participant meta_db_a + participant read_db_a participant db_sync_a end @@ -48,9 +48,9 @@ db_a -->> Vault_a: get vault db_a -->> GlobalIndex_a: get global index db_a -->>- app_a: provide vault and global index -app_a ->> meta_db_a: apply db events to meta_db +app_a ->> read_db_a: apply db events to read_db -app_a ->> meta_db_a: find vault in global index +app_a ->> read_db_a: find vault in global index Note right of app_a: We can join cluster
if vault exists app_a ->> db_a: mempool(join_event) @@ -81,8 +81,8 @@ app_server -->>- db_sync_a: provide new events db_sync_a ->> db_a: save new events app_a ->> db_a: get new events -app_a ->> meta_db_a: apply new events to meta_db +app_a ->> read_db_a: apply new events to read_db -app_a ->> meta_db_a: get vault +app_a ->> read_db_a: get vault app_a ->> app_a: show vault to the user ``` diff --git a/meta-server-emulator/Cargo.toml b/meta-server-emulator/Cargo.toml index 16415e6b..f1fab3a4 100644 --- a/meta-server-emulator/Cargo.toml +++ b/meta-server-emulator/Cargo.toml @@ -6,14 +6,14 @@ edition = "2021" [dependencies] meta-secret-core = { path = "../core" } -thiserror = "1.0.40" +thiserror.workspace = true +anyhow.workspace = true -diesel = { version = "2.0.0", features = ["sqlite"] } -diesel_migrations = "2.0.0" +async-trait.workspace = true -async-trait = "0.1" +serde.workspace = true +serde_json.workspace = true +serde_derive.workspace = true -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" - -anyhow = "1.0.66" +diesel = { workspace = true, features = ["sqlite"] } +diesel_migrations = { workspace = true, features = ["sqlite"] } \ No newline at end of file diff --git a/meta-server-emulator/src/models.rs b/meta-server-emulator/src/models.rs index cae17505..2da1ff58 100644 --- a/meta-server-emulator/src/models.rs +++ b/meta-server-emulator/src/models.rs @@ -1,8 +1,6 @@ use crate::schema::db_commit_log; use diesel::prelude::*; -use meta_secret_core::node::db::events::common::LogEventKeyBasedRecord; -use meta_secret_core::node::db::events::generic_log_event::GenericKvLogEvent; -use meta_secret_core::node::db::events::kv_log_event::KvKey; +use meta_secret_core::node::db::events::generic_log_event::{GenericKvLogEvent, ObjIdExtractor}; #[derive(Debug, Queryable)] pub struct DbLogEvent { @@ -20,14 +18,9 @@ pub struct NewDbLogEvent { impl From<&GenericKvLogEvent> for NewDbLogEvent { fn from(log_event: &GenericKvLogEvent) -> Self { - match log_event.key() { - KvKey::Empty { .. } => { - panic!("Empty key can't be saved to the database") - } - KvKey::Key { obj_id, .. } => Self { - key_id: obj_id.id_str(), - event: serde_json::to_string(log_event).unwrap(), - }, + Self { + key_id: log_event.obj_id().id_str(), + event: serde_json::to_string(log_event).unwrap(), } } } diff --git a/meta-server-emulator/src/server/sqlite_store.rs b/meta-server-emulator/src/server/sqlite_store.rs index 4a005704..92cb4f2f 100644 --- a/meta-server-emulator/src/server/sqlite_store.rs +++ b/meta-server-emulator/src/server/sqlite_store.rs @@ -1,14 +1,11 @@ -use std::sync::Arc; - use async_trait::async_trait; use diesel::{Connection, ExpressionMethods, QueryDsl, RunQueryDsl, SqliteConnection}; -use meta_secret_core::node::db::events::generic_log_event::GenericKvLogEvent; +use meta_secret_core::node::db::events::generic_log_event::{GenericKvLogEvent, ObjIdExtractor}; use meta_secret_core::node::db::events::object_id::ObjectId; -use meta_secret_core::node::db::generic_db::{ +use meta_secret_core::node::db::repo::generic_db::{ DeleteCommand, FindOneQuery, KvLogEventRepo, SaveCommand, }; -use meta_secret_core::node::server::data_sync::MetaServerContextState; use crate::models::DbLogEvent; use crate::models::NewDbLogEvent; @@ -18,7 +15,6 @@ use crate::schema::db_commit_log::dsl; pub struct SqlIteRepo { /// conn_url="file:///tmp/test.db" pub conn_url: String, - pub context: Arc, } #[derive(thiserror::Error, Debug)] @@ -32,20 +28,20 @@ pub enum SqliteDbError { #[async_trait(? Send)] impl SaveCommand for SqlIteRepo { - async fn save(&self, _key: ObjectId, value: GenericKvLogEvent) -> anyhow::Result { + async fn save(&self, value: GenericKvLogEvent) -> anyhow::Result { let mut conn = SqliteConnection::establish(self.conn_url.as_str()).unwrap(); diesel::insert_into(schema_log::table) .values(&NewDbLogEvent::from(&value)) .execute(&mut conn)?; - Ok(_key.clone()) + Ok(value.obj_id()) } } #[async_trait(? Send)] impl FindOneQuery for SqlIteRepo { async fn find_one(&self, key: ObjectId) -> anyhow::Result> { - let mut conn = SqliteConnection::establish(self.conn_url.as_str()).unwrap(); + let mut conn = SqliteConnection::establish(self.conn_url.as_str())?; let db_event: DbLogEvent = dsl::db_commit_log .filter(dsl::key_id.eq(key.id_str())) @@ -53,6 +49,18 @@ impl FindOneQuery for SqlIteRepo { Ok(Some(GenericKvLogEvent::from(&db_event))) } + + async fn get_key(&self, key: ObjectId) -> anyhow::Result> { + let maybe_event = self.find_one(key).await?; + match maybe_event { + None => { + Ok(None) + } + Some(event) => { + Ok(Some(event.obj_id())) + } + } + } } #[async_trait(? Send)] diff --git a/meta-test/Cargo.toml b/meta-test/Cargo.toml deleted file mode 100644 index 04d37457..00000000 --- a/meta-test/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "meta-test" -version = "0.1.0" -edition = "2021" - -[dependencies] -meta-secret-core = { path = "../core" } -meta-server-emulator = { path = "../meta-server-emulator" } - -diesel = { version = "2.0.0", features = ["sqlite"] } -diesel_migrations = "2.0.0" - -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" - -async-trait = "0.1" -anyhow = "1.0" -thiserror = "1.0" - -[dev-dependencies] -tokio = { version = "1.20.1", features = ["macros"] } diff --git a/meta-test/src/lib.rs b/meta-test/src/lib.rs deleted file mode 100644 index 8b137891..00000000 --- a/meta-test/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/meta-test/tests/app_test.rs b/meta-test/tests/app_test.rs deleted file mode 100644 index 49b06d03..00000000 --- a/meta-test/tests/app_test.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod test {} diff --git a/meta-test/tests/server_test.rs b/meta-test/tests/server_test.rs deleted file mode 100644 index 49b06d03..00000000 --- a/meta-test/tests/server_test.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod test {} diff --git a/schema/schema.yaml b/schema/schema.yaml index 67dda46b..835c99c4 100644 --- a/schema/schema.yaml +++ b/schema/schema.yaml @@ -4,383 +4,19 @@ info: version: 1.0.0 x-cargo-authors: - - MetaBynull + - bynull components: schemas: - Base64EncodedText: + Fundamental: type: object required: - - base64Text + - statement properties: - base64Text: + statement: type: string - DeviceInfo: - type: object - required: - - deviceId - - deviceName - properties: - deviceId: - type: string - minLength: 1 - maxLength: 100 - deviceName: - type: string - minimum: 0 - maximum: 250 - - MetaVault: - type: object - description: | - It keeps the information about a vault. - It's the origin of the objects generated to create a user vault and generate - all necessary credentials and user signatures. - MetaVault -> KeyManager -> UserSignature - required: - - name - - device - properties: - name: - description: vault name - type: string - device: - $ref: '#/components/schemas/DeviceInfo' - - UserSignature: - type: object - required: - - vault - - publicKey - - transportPublicKey - properties: - vault: - description: distributed vault, unique across the entire system - $ref: '#/components/schemas/MetaVault' - publicKey: - $ref: '#/components/schemas/Base64EncodedText' - transportPublicKey: - $ref: '#/components/schemas/Base64EncodedText' - - SerializedDsaKeyPair: - type: object - required: - - keyPair - - publicKey - properties: - keyPair: - $ref: '#/components/schemas/Base64EncodedText' - publicKey: - $ref: '#/components/schemas/Base64EncodedText' - - - SerializedTransportKeyPair: - type: object - required: - - secretKey - - publicKey - properties: - secretKey: - $ref: '#/components/schemas/Base64EncodedText' - publicKey: - $ref: '#/components/schemas/Base64EncodedText' - - SerializedKeyManager: - type: object - required: - - dsa - - transport - properties: - dsa: - $ref: '#/components/schemas/SerializedDsaKeyPair' - transport: - $ref: '#/components/schemas/SerializedTransportKeyPair' - - UserSecurityBox: - type: object - required: - - vaultName - - signature - - keyManager - properties: - vaultName: - type: string - minLength: 1 - signature: - $ref: '#/components/schemas/Base64EncodedText' - keyManager: - $ref: '#/components/schemas/SerializedKeyManager' - # Encryption - CommunicationChannel: - type: object - description: Represents virtual encrypted communication channel between two points. - required: - - sender - - receiver - properties: - sender: - $ref: '#/components/schemas/Base64EncodedText' - receiver: - $ref: '#/components/schemas/Base64EncodedText' - - AeadAuthData: - type: object - required: - - associatedData - - channel - - nonce - properties: - associatedData: - type: string - channel: - $ref: '#/components/schemas/CommunicationChannel' - nonce: - $ref: '#/components/schemas/Base64EncodedText' - - AeadCipherText: - type: object - required: - - msg - - authData - properties: - msg: - $ref: '#/components/schemas/Base64EncodedText' - authData: - $ref: '#/components/schemas/AeadAuthData' - AeadPlainText: - type: object - required: - - msg - - authData - properties: - msg: - $ref: '#/components/schemas/Base64EncodedText' - authData: - $ref: '#/components/schemas/AeadAuthData' - - VaultDoc: - type: object - required: - - vaultName - - signatures - - pendingJoins - - declinedJoins - properties: - vaultName: - type: string - minLength: 1 - signatures: - type: array - items: - $ref: '#/components/schemas/UserSignature' - pendingJoins: - type: array - items: - $ref: '#/components/schemas/UserSignature' - declinedJoins: - type: array - items: - $ref: '#/components/schemas/UserSignature' - MetaPasswordId: - type: object - required: - - id - - salt - - name - properties: - id: - description: SHA256 hash of a salt - type: string - minLength: 1 - salt: - description: Random String up to 30 characters, must be unique - type: string - minLength: 1 - name: - description: Human readable name given to the password - type: string - minLength: 1 - - MetaPasswordDoc: - type: object - required: - - id - - vault - properties: - id: - $ref: '#/components/schemas/MetaPasswordId' - vault: - $ref: '#/components/schemas/VaultDoc' - description: 'We need to keep the entire vault here, because the vault can be changed (new members can appear some members can be deleted), then we will not be able to restore the password if we would have different members than in original vault' - - SecretDistributionType: - type: string - enum: - - Split - - Recover - - MetaPasswordRequest: - type: object - required: - - userSig - - metaPassword - properties: - userSig: - description: Creator of the meta password record - $ref: '#/components/schemas/UserSignature' - metaPassword: - description: meta information about password - $ref: '#/components/schemas/MetaPasswordDoc' - - EncryptedMessage: - type: object - required: - - receiver - - encryptedText - properties: - receiver: - description: "Message receiver who can decrypt message. We can't use a receiver from inside AeadCipherText because it's static and we can't know if a receiver send message back or it's the sender sending message." - $ref: '#/components/schemas/UserSignature' - encryptedText: - description: Message text encrypted with receivers public key - $ref: '#/components/schemas/AeadCipherText' - - SecretDistributionDocData: - type: object - required: - - distributionType - - metaPassword - - secretMessage - properties: - distributionType: - $ref: '#/components/schemas/SecretDistributionType' - metaPassword: - $ref: '#/components/schemas/MetaPasswordRequest' - secretMessage: - $ref: '#/components/schemas/EncryptedMessage' - - RegistrationStatus: - type: string - enum: - - Registered - - AlreadyExists - - JoinRequest: - type: object - required: - - member - - candidate - properties: - member: - $ref: '#/components/schemas/UserSignature' - candidate: - $ref: '#/components/schemas/UserSignature' - - MetaPasswordsStatus: - type: string - enum: - - Ok - - VaultNotFound - - MetaPasswordsData: - type: object - required: - - passwordStatus - - passwords - properties: - passwordStatus: - $ref: '#/components/schemas/MetaPasswordsStatus' - passwords: - type: array - items: - $ref: '#/components/schemas/MetaPasswordDoc' - - PasswordRecoveryRequest: - type: object - required: - - id - - consumer - - provider - properties: - id: - $ref: '#/components/schemas/MetaPasswordId' - consumer: - description: The device that needs data ("consumer" - the device that asks provider to provide data) - $ref: '#/components/schemas/UserSignature' - provider: - description: The device that has data and must provide data to consumer device - $ref: '#/components/schemas/UserSignature' - - MembershipStatus: - type: string - description: | - `AlreadyMember`: Device is a member of a vault already. - `Finished`: Operation finished successfully. - enum: - - VaultNotFound - - AlreadyMember - - Finished - - MembershipRequestType: - type: string - enum: - - Accept - - Decline - - FindSharesResult: - type: object - required: - - userRequestType - - shares - properties: - userRequestType: - $ref: '#/components/schemas/SecretDistributionType' - description: In case of empty shares in response we need to know what kind of request user just sent. - shares: - type: array - items: - $ref: '#/components/schemas/SecretDistributionDocData' - - FindSharesRequest: - type: object - required: - - userRequestType - - userSignature - properties: - userRequestType: - $ref: '#/components/schemas/SecretDistributionType' - userSignature: - $ref: '#/components/schemas/UserSignature' - - UserCredentials: - type: object - required: - - securityBox - - userSig - properties: - securityBox: - $ref: '#/components/schemas/UserSecurityBox' - userSig: - $ref: '#/components/schemas/UserSignature' - - ApplicationState: - type: object - required: - - joinComponent - - metaPasswords - properties: - metaVault: - $ref: '#/components/schemas/MetaVault' - vault: - $ref: '#/components/schemas/VaultDoc' - metaPasswords: - type: array - items: - $ref: '#/components/schemas/MetaPasswordDoc' - joinComponent: - type: boolean paths: diff --git a/wasm/Cargo.toml b/wasm/Cargo.toml index 0cd472be..88cbe3eb 100644 --- a/wasm/Cargo.toml +++ b/wasm/Cargo.toml @@ -1,7 +1,7 @@ [package] -name = "meta-secret-web-cli" +name = "meta-secret-wasm" version = "0.1.0" -authors = ["metabynull "] +authors = ["cypherkitty "] edition = "2018" [lib] @@ -11,29 +11,31 @@ crate-type = ["cdylib", "rlib"] default = ["console_error_panic_hook"] [dependencies] -tracing = "0.1.37" -tracing-subscriber = { version = "0.3.17", default-features = false, features = ["fmt", "time"] } -tracing-web = "0.1.2" +meta-secret-core = { path = "../core" } -wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] } +anyhow.workspace = true +thiserror.workspace = true -indexed_db_futures = "0.3.0" +async-trait.workspace = true +flume.workspace = true +async-mutex.workspace = true -gloo-timers = "0.2.6" +serde.workspace = true +serde_json.workspace = true +serde_derive.workspace = true -async-std = { version = "1.12.0", features = ["wasm-bindgen-futures", "futures-channel"] } -flume = "0.10.14" +tracing.workspace = true +tracing-subscriber = { workspace = true, default-features = false, features = ["fmt", "time"] } -async-trait = "0.1" -anyhow = "1.0" -thiserror = "1.0" +getrandom.workspace = true -meta-secret-core = { path = "../core" } +# Wasm dependencies +tracing-web = "0.1.2" -serde = { version = "1.0.163", features = ["derive"] } -serde_json = "1.0.96" +wasm-bindgen = { version = "0.2.87", features = ["serde-serialize"] } +indexed_db_futures = "0.3.0" -serde-wasm-bindgen = "0.5.0" +serde-wasm-bindgen = "0.6.0" wasm-bindgen-futures = "0.4.37" js-sys = { version = "0.3.63" } @@ -45,10 +47,6 @@ web-sys = { version = "0.3.60", features = [ "Window" ] } -async-mutex = "1.4.0" - -getrandom = { version = "0.2.8", features = ["js"] } - # The `console_error_panic_hook` crate provides better debugging of panics by # logging them with `console.error`. This is great for development, but requires # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for @@ -65,6 +63,5 @@ wee_alloc = { version = "0.4.5", optional = true } [dev-dependencies] wasm-bindgen-test = "0.3.37" -[profile.release] -# Tell `rustc` to optimize for small code size. -opt-level = "s" +[target.'cfg(target_arch = "wasm32")'.dependencies] +meta-secret-core = { path = "../core" } \ No newline at end of file diff --git a/wasm/src/app_state_manager.rs b/wasm/src/app_state_manager.rs index 046e7f68..1d134447 100644 --- a/wasm/src/app_state_manager.rs +++ b/wasm/src/app_state_manager.rs @@ -1,57 +1,53 @@ use std::sync::Arc; -use tracing::{info, instrument, Instrument}; +use tracing::{info, instrument, Instrument}; use wasm_bindgen_futures::spawn_local; use meta_secret_core::node::app::app_state_update_manager::{ ApplicationStateManagerConfigurator, JsAppStateManager, }; -use meta_secret_core::node::app::client_meta_app::MetaClient; -use meta_secret_core::node::app::meta_app::meta_app_service::{ + +use meta_secret_core::node::app::meta_app::meta_client_service::{ MetaClientAccessProxy, MetaClientDataTransfer, MetaClientService, }; + use meta_secret_core::node::app::sync_gateway::SyncGateway; use meta_secret_core::node::app::virtual_device::VirtualDevice; use meta_secret_core::node::common::data_transfer::MpscDataTransfer; use meta_secret_core::node::common::meta_tracing::{client_span, server_span, vd_span}; -use meta_secret_core::node::db::generic_db::KvLogEventRepo; -use meta_secret_core::node::db::meta_db::meta_db_service::{ - MetaDbDataTransfer, MetaDbService, MetaDbServiceProxy, -}; +use meta_secret_core::node::common::model::device::DeviceName; +use meta_secret_core::node::common::model::vault::VaultName; +use meta_secret_core::node::db::repo::generic_db::KvLogEventRepo; use meta_secret_core::node::db::objects::persistent_object::PersistentObject; +use meta_secret_core::node::db::repo::credentials_repo::CredentialsRepo; use meta_secret_core::node::server::data_sync::ServerDataSync; use meta_secret_core::node::server::server_app::{ServerApp, ServerDataTransfer}; pub struct ApplicationStateManager -where - Repo: KvLogEventRepo, - - StateManager: JsAppStateManager, + where + Repo: KvLogEventRepo, + StateManager: JsAppStateManager, { pub state_manager: Arc, pub meta_client_service: Arc>, pub server_dt: Arc, - pub meta_db_service: Arc>, pub sync_gateway: Arc>, } impl ApplicationStateManager -where - Repo: KvLogEventRepo, - - State: JsAppStateManager + 'static, + where + Repo: KvLogEventRepo, + State: JsAppStateManager + 'static, { pub fn new( - meta_db_service: Arc>, server_dt: Arc, state: Arc, sync_gateway: Arc>, meta_client_service: Arc>, - ) -> ApplicationStateManager { + ) -> ApplicationStateManager { info!("New. Application State Manager"); ApplicationStateManager { - meta_db_service, server_dt, state_manager: state, sync_gateway, @@ -59,83 +55,51 @@ where } } - pub async fn init( - cfg: ApplicationStateManagerConfigurator, - ) -> ApplicationStateManager { + pub async fn init(cfg: ApplicationStateManagerConfigurator) -> anyhow::Result> { info!("Initialize application state manager"); let server_dt = Arc::new(ServerDataTransfer { dt: MpscDataTransfer::new(), }); - ApplicationStateManager::::server_setup(cfg.server_repo, server_dt.clone()) - .await; - - ApplicationStateManager::::virtual_device_setup( - cfg.device_repo, - server_dt.clone(), - cfg.vd_js_app_state, - ) - .await; - - ApplicationStateManager::::client_setup( - cfg.client_repo, - server_dt.clone(), - cfg.js_app_state, - ) - .await + Self::server_setup(cfg.server_repo, server_dt.clone()) + .await?; + + Self::virtual_device_setup(cfg.device_repo, server_dt.clone(), cfg.vd_js_app_state) + .await?; + + let app_manager = Self::client_setup(cfg.client_repo, server_dt.clone(), cfg.js_app_state) + .await?; + + Ok(app_manager) } #[instrument(name = "MetaClient", skip(client_repo, dt, js_app_state))] pub async fn client_setup( - client_repo: Arc, - dt: Arc, - js_app_state: Arc, - ) -> ApplicationStateManager { + client_repo: Arc, dt: Arc, js_app_state: Arc, + ) -> anyhow::Result> { let persistent_obj = { let obj = PersistentObject::new(client_repo.clone()); Arc::new(obj) }; - - let dt_meta_db = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - - let meta_db_service = Arc::new(MetaDbService { - persistent_obj: persistent_obj.clone(), - repo: client_repo.clone(), - meta_db_id: String::from("Client"), - data_transfer: dt_meta_db.clone(), - }); - - let meta_db_service_proxy = Arc::new(MetaDbServiceProxy { dt: dt_meta_db }); - + let sync_gateway = Arc::new(SyncGateway { id: String::from("client-gateway"), - repo: client_repo, persistent_object: persistent_obj.clone(), - server_dt: dt.clone(), - meta_db_service_proxy: meta_db_service_proxy.clone(), + server_dt: dt.clone() }); - let meta_client_service: Arc> = { - let meta_client = Arc::new(MetaClient { - persistent_obj, - meta_db_service_proxy: meta_db_service_proxy.clone(), - }); - + let meta_client_service = { Arc::new(MetaClientService { data_transfer: Arc::new(MetaClientDataTransfer { dt: MpscDataTransfer::new(), }), - meta_client: meta_client.clone(), state_manager: js_app_state.clone(), sync_gateway: sync_gateway.clone(), }) }; let app_manager = ApplicationStateManager::new( - meta_db_service, dt, js_app_state.clone(), sync_gateway, @@ -147,13 +111,14 @@ where meta_client_service_runner .run() .instrument(client_span()) - .await + .await. + unwrap(); }); let sync_gateway_rc = app_manager.sync_gateway.clone(); spawn_local(async move { sync_gateway_rc.run().instrument(client_span()).await }); - app_manager + Ok(app_manager) } #[instrument(name = "Vd", skip(device_repo, dt, js_app_state))] @@ -161,32 +126,18 @@ where device_repo: Arc, dt: Arc, js_app_state: Arc, - ) { + ) -> anyhow::Result<()> { info!("Device initialization"); let persistent_object = Arc::new(PersistentObject::new(device_repo.clone())); - let vd_meta_db_data_transfer = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - let vd_meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: vd_meta_db_data_transfer.clone(), - }); - - let meta_db_service = MetaDbService { - persistent_obj: persistent_object.clone(), - repo: device_repo, - meta_db_id: String::from("virtual_device"), - data_transfer: vd_meta_db_data_transfer.clone(), + let creds_repo = CredentialsRepo { + p_obj: persistent_object.clone(), }; - let meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: vd_meta_db_data_transfer, - }); - - let meta_db_service = Arc::new(meta_db_service); - - let vd_meta_db_service = meta_db_service.clone(); + let user_creds = creds_repo + .get_or_generate_user_creds(DeviceName::from("virtual-device"), VaultName::from("q")) + .await?; let dt_meta_client = Arc::new(MetaClientDataTransfer { dt: MpscDataTransfer::new(), @@ -194,50 +145,37 @@ where let gateway = Arc::new(SyncGateway { id: String::from("vd-gateway"), - repo: persistent_object.repo.clone(), persistent_object: persistent_object.clone(), - server_dt: dt.clone(), - meta_db_service_proxy: vd_meta_db_service_proxy.clone(), + server_dt: dt.clone() }); let meta_client_service = { - let meta_client = Arc::new(MetaClient { - persistent_obj: persistent_object.clone(), - meta_db_service_proxy: meta_db_service_proxy.clone(), - }); - - Arc::new(MetaClientService { + MetaClientService { data_transfer: dt_meta_client.clone(), - meta_client: meta_client.clone(), state_manager: js_app_state.clone(), - sync_gateway: gateway.clone(), - }) + sync_gateway: gateway.clone() + } }; spawn_local(async move { - vd_meta_db_service.run().instrument(vd_span()).await; + meta_client_service + .run() + .instrument(vd_span()) + .await + .unwrap(); }); - let meta_client_service_runner = meta_client_service.clone(); - spawn_local(async move { meta_client_service_runner.run().instrument(vd_span()).await }); + let meta_client_access_proxy = Arc::new(MetaClientAccessProxy { dt: dt_meta_client }); + let vd = VirtualDevice::init(persistent_object, meta_client_access_proxy, dt, gateway) + .await?; + let vd = Arc::new(vd); + spawn_local(async move { vd.run().instrument(vd_span()).await.unwrap() }); - spawn_local(async move { - let meta_client_access_proxy = Arc::new(MetaClientAccessProxy { dt: dt_meta_client }); - - let vd_async = VirtualDevice::event_handler( - persistent_object, - meta_client_access_proxy, - meta_db_service_proxy, - dt, - gateway, - ); - - vd_async.instrument(vd_span()).await - }) + Ok(()) } #[instrument(name = "MetaServer", skip_all)] - pub async fn server_setup(server_repo: Arc, server_dt: Arc) { + pub async fn server_setup(server_repo: Arc, server_dt: Arc) -> anyhow::Result<()> { info!("Server initialization"); let server_persistent_obj = { @@ -245,37 +183,27 @@ where Arc::new(obj) }; - let meta_db_dt = Arc::new(MetaDbDataTransfer { - dt: MpscDataTransfer::new(), - }); - - let meta_db_service_proxy = Arc::new(MetaDbServiceProxy { - dt: meta_db_dt.clone(), - }); + let creds_repo = CredentialsRepo { + p_obj: server_persistent_obj.clone(), + }; - let meta_db_service = Arc::new(MetaDbService { + let device_creds = creds_repo + .get_or_generate_device_creds(DeviceName::from("server")) + .await?; + + let data_sync = ServerDataSync { persistent_obj: server_persistent_obj.clone(), - repo: server_repo.clone(), - meta_db_id: String::from("Server"), - data_transfer: meta_db_dt.clone(), - }); - - spawn_local(async move { - meta_db_service.run().instrument(server_span()).await; - }); - - let data_sync = Arc::new( - ServerDataSync::new(server_persistent_obj.clone(), meta_db_service_proxy.clone()) - .in_current_span() - .await, - ); + device_creds: device_creds.clone(), + }; - let server = Arc::new(ServerApp { + let server = ServerApp { data_sync, data_transfer: server_dt.clone(), - }); + device_creds + }; + + spawn_local(async move { server.run().instrument(server_span()).await.unwrap() }); - let server_async = server.clone(); - spawn_local(async move { server_async.run().instrument(server_span()).await }); + Ok(()) } } diff --git a/wasm/src/wasm_app_state_manager.rs b/wasm/src/wasm_app_state_manager.rs index 489dfa1a..18ab9254 100644 --- a/wasm/src/wasm_app_state_manager.rs +++ b/wasm/src/wasm_app_state_manager.rs @@ -5,18 +5,16 @@ use tracing::info; use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; -use meta_secret_core::models::application_state::ApplicationState; -use meta_secret_core::models::MetaPasswordId; use meta_secret_core::node::app::app_state_update_manager::{ ApplicationStateManagerConfigurator, JsAppStateManager, NoOpJsAppStateManager, }; use meta_secret_core::node::app::meta_app::messaging::{ - ClusterDistributionRequest, GenericAppStateRequest, RecoveryRequest, SignUpRequest, + ClusterDistributionRequest, GenericAppStateRequest }; - +use meta_secret_core::node::common::model::ApplicationState; use crate::app_state_manager::ApplicationStateManager; -use crate::wasm_repo::WasmRepo; use crate::{configure, updateJsState}; +use crate::wasm_repo::WasmRepo; pub struct JsJsAppStateManager {} @@ -58,7 +56,10 @@ impl WasmApplicationStateManager { vd_js_app_state: Arc::new(NoOpJsAppStateManager {}), }; - let app_state_manager = ApplicationStateManager::init(cfg).await; + let app_state_manager = ApplicationStateManager::init(cfg) + .await + .expect("Application state manager must be initialized"); + WasmApplicationStateManager { app_manager: GenericApplicationStateManager::InMem { app_state_manager }, } @@ -77,32 +78,34 @@ impl WasmApplicationStateManager { vd_js_app_state: Arc::new(JsJsAppStateManager {}), }; - let app_state_manager = ApplicationStateManager::init(cfg).await; + let app_state_manager = ApplicationStateManager::init(cfg) + .await + .expect("Application state manager must be initialized"); + WasmApplicationStateManager { app_manager: GenericApplicationStateManager::Wasm { app_state_manager }, } } - pub async fn sign_up(&self, vault_name: &str, device_name: &str) { - let request = GenericAppStateRequest::SignUp(SignUpRequest { - vault_name: vault_name.to_string(), - device_name: device_name.to_string(), - }); + pub async fn sign_up(&self) { + info!("Sign Up"); + + let sign_up = GenericAppStateRequest::SignUp; match &self.app_manager { GenericApplicationStateManager::Wasm { app_state_manager } => { app_state_manager .meta_client_service - .send_request(request) - .await + .send_request(sign_up) + .await; } GenericApplicationStateManager::InMem { app_state_manager } => { app_state_manager .meta_client_service - .send_request(request) - .await + .send_request(sign_up) + .await; } - } + }; } pub async fn cluster_distribution(&self, pass_id: &str, pass: &str) { @@ -124,13 +127,13 @@ impl WasmApplicationStateManager { .send_request(request) .await; } - } + }; } pub async fn recover_js(&self, meta_pass_id_js: JsValue) { - let meta_pass_id: MetaPasswordId = serde_wasm_bindgen::from_value(meta_pass_id_js).unwrap(); + let meta_pass_id = serde_wasm_bindgen::from_value(meta_pass_id_js).unwrap(); - let request = GenericAppStateRequest::Recover(RecoveryRequest { meta_pass_id }); + let request = GenericAppStateRequest::Recover(meta_pass_id); match &self.app_manager { GenericApplicationStateManager::Wasm { app_state_manager } => { diff --git a/wasm/src/wasm_repo.rs b/wasm/src/wasm_repo.rs index 7810aa60..87b76dd3 100644 --- a/wasm/src/wasm_repo.rs +++ b/wasm/src/wasm_repo.rs @@ -1,16 +1,17 @@ -use anyhow::anyhow; +use anyhow::{anyhow, Context}; use async_trait::async_trait; -use indexed_db_futures::prelude::*; use indexed_db_futures::IdbDatabase; +use indexed_db_futures::prelude::*; use js_sys::Object; -use meta_secret_core::node::db::events::generic_log_event::GenericKvLogEvent; +use tracing::{Instrument, instrument}; +use wasm_bindgen::JsValue; +use web_sys::IdbTransactionMode; + +use meta_secret_core::node::db::events::generic_log_event::{GenericKvLogEvent, ObjIdExtractor}; use meta_secret_core::node::db::events::object_id::ObjectId; -use meta_secret_core::node::db::generic_db::{ +use meta_secret_core::node::db::repo::generic_db::{ CommitLogDbConfig, DeleteCommand, FindOneQuery, KvLogEventRepo, SaveCommand, }; -use tracing::Instrument; -use wasm_bindgen::JsValue; -use web_sys::IdbTransactionMode; pub struct WasmRepo { pub db_name: String, @@ -50,68 +51,86 @@ impl WasmRepo { } impl WasmRepo { + #[instrument(skip_all)] pub async fn delete_db(&self) { - let db = open_db(self.db_name.as_str()).in_current_span().await; + let db = open_db(self.db_name.as_str()).await; db.delete().unwrap(); } } #[async_trait(? Send)] impl SaveCommand for WasmRepo { - async fn save(&self, key: ObjectId, event: GenericKvLogEvent) -> anyhow::Result { - let event_js: JsValue = serde_wasm_bindgen::to_value(&event) - .map_err(|err| anyhow!("Error parsing data to save: {:?}", err))?; + #[instrument(skip_all)] + async fn save(&self, event: GenericKvLogEvent) -> anyhow::Result { + let event_js: JsValue = serde_wasm_bindgen::to_value(&event).unwrap(); let db = open_db(self.db_name.as_str()).in_current_span().await; let tx = db .transaction_on_one_with_mode(self.store_name.as_str(), IdbTransactionMode::Readwrite) .unwrap(); + let store = tx.object_store(self.store_name.as_str()).unwrap(); - store - .put_key_val_owned(key.id_str().as_str(), &event_js) - .unwrap(); + + let obj_id_js = serde_wasm_bindgen::to_value(&event.obj_id()).unwrap(); + store.put_key_val_owned(obj_id_js, &event_js).unwrap(); tx.in_current_span().await.into_result().unwrap(); // All of the requests in the transaction have already finished so we can just drop it to // avoid the unused future warning, or assign it to _. //let _ = tx; - Ok(key.clone()) + Ok(event.obj_id().clone()) } } #[async_trait(? Send)] impl FindOneQuery for WasmRepo { + + #[instrument(skip_all)] async fn find_one(&self, key: ObjectId) -> anyhow::Result> { - let db = open_db(self.db_name.as_str()).in_current_span().await; + let db = open_db(self.db_name.as_str()).await; let tx = db.transaction_on_one(self.store_name.as_str()).unwrap(); let store = tx.object_store(self.store_name.as_str()).unwrap(); - let future: OptionalJsValueFuture = store.get_owned(key.id_str().as_str()).unwrap(); - let maybe_obj_js: Option = future.in_current_span().await.unwrap(); - if let Some(obj_js) = maybe_obj_js { - if obj_js.is_undefined() { - return Ok(None); + let maybe_event_js: Option = { + let maybe_value: OptionalJsValueFuture = store.get_owned(key.id_str().as_str()).unwrap(); + maybe_value.await.unwrap() + }; + + match maybe_event_js { + None => { + Ok(None) } + Some(event_js) => { + if event_js.is_undefined() { + return Ok(None); + } - match Object::from_entries(&obj_js) { - Ok(obj_js) => { - let obj_js: JsValue = JsValue::from(obj_js); + let js_object = Object::from_entries(&event_js).unwrap(); + let obj_js: JsValue = JsValue::from(js_object); - let obj = serde_wasm_bindgen::from_value(obj_js) - .map_err(|err| anyhow!("Js object error parsing: {}", err))?; - Ok(Some(obj)) - } - Err(_) => Err(anyhow!("IndexedDb object error parsing")), + let obj = serde_wasm_bindgen::from_value(obj_js).unwrap(); + Ok(Some(obj)) + } + } + } + + async fn get_key(&self, key: ObjectId) -> anyhow::Result> { + let maybe_event = self.find_one(key).await?; + match maybe_event { + None => { + Ok(None) + } + Some(event) => { + Ok(Some(event.obj_id())) } - } else { - Ok(None) } } } #[async_trait(? Send)] impl DeleteCommand for WasmRepo { + #[instrument(skip_all)] async fn delete(&self, key: ObjectId) { let db = open_db(self.db_name.as_str()).in_current_span().await; let tx: IdbTransaction = db @@ -123,8 +142,9 @@ impl DeleteCommand for WasmRepo { } } +#[instrument(skip_all)] pub async fn open_db(db_name: &str) -> IdbDatabase { - let mut db_req: OpenDbRequest = IdbDatabase::open_u32(db_name, 1).unwrap(); + let mut db_req = IdbDatabase::open_u32(db_name, 1).unwrap(); let on_upgrade_task = move |evt: &IdbVersionChangeEvent| -> Result<(), JsValue> { // Check if the object store exists; create it if it doesn't @@ -136,7 +156,8 @@ pub async fn open_db(db_name: &str) -> IdbDatabase { db_req.set_on_upgrade_needed(Some(on_upgrade_task)); - db_req.into_future().in_current_span().await.unwrap() + let idb = db_req.into_future().in_current_span().await.unwrap(); + idb } impl KvLogEventRepo for WasmRepo {} diff --git a/wasm/tests/web.rs b/wasm/tests/web.rs index 8b15b32f..cae4b1cc 100644 --- a/wasm/tests/web.rs +++ b/wasm/tests/web.rs @@ -1,10 +1,10 @@ #![cfg(target_arch = "wasm32")] use meta_secret_core::node::db::events::object_id::ObjectId; -use meta_secret_core::node::db::generic_db::{FindOneQuery, SaveCommand}; +use meta_secret_core::node::db::repo::generic_db::{FindOneQuery, SaveCommand}; use meta_secret_core::node::db::in_mem_db::InMemKvLogEventRepo; use meta_secret_web_cli::wasm_app_state_manager::WasmApplicationStateManager; use meta_secret_web_cli::wasm_repo::WasmRepo; -use meta_secret_web_cli::{alert, configure}; +use meta_secret_web_cli::{alert, configure, info}; use std::rc::Rc; use wasm_bindgen::JsValue; /// @@ -18,6 +18,7 @@ use meta_secret_core::node::db::events::global_index::{GlobalIndexObject, Global use meta_secret_core::node::db::events::kv_log_event::KvLogEvent; use meta_secret_core::node::db::events::vault_event::VaultObject; use std::time::Duration; +use tracing::info; wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); @@ -42,8 +43,20 @@ async fn pass_async() { async fn run_app() { let app_manager = WasmApplicationStateManager::init_in_mem().await; async_std::task::sleep(Duration::from_secs(5)).await; - app_manager.sign_up("q", "web").await; + + info!("Initial sign up"); + let _ = app_manager.sign_up("q", "web").await; async_std::task::sleep(Duration::from_secs(3)).await; //join - app_manager.sign_up("q", "web").await; + info!("Initiate Join!"); + let _ = app_manager.sign_up("q", "web").await; + + async_std::task::sleep(Duration::from_secs(3)).await; + + info!("Cluster Distribution"); + app_manager + .cluster_distribution("pass_id:123", "t0p$ecret") + .await; + + async_std::task::sleep(Duration::from_secs(3)).await; }