diff --git a/Cargo.lock b/Cargo.lock index edbb5ac..d5c8689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1424,6 +1424,7 @@ dependencies = [ "double-ratchets", "hex", "openmls", + "openmls_libcrux_crypto 0.3.1", "openmls_traits 0.5.0", "prost", "rand_core 0.6.4", diff --git a/core/conversations/Cargo.toml b/core/conversations/Cargo.toml index 5ee70d1..512cfa6 100644 --- a/core/conversations/Cargo.toml +++ b/core/conversations/Cargo.toml @@ -21,6 +21,7 @@ thiserror = "2.0.17" x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] } storage = { path = "../storage" } openmls = { version = "0.8.1", features = ["libcrux-provider"] } +openmls_libcrux_crypto = "0.3.1" openmls_traits = "0.5.0" [dev-dependencies] diff --git a/core/conversations/src/account.rs b/core/conversations/src/account.rs index 3ca7dfc..161710f 100644 --- a/core/conversations/src/account.rs +++ b/core/conversations/src/account.rs @@ -18,11 +18,11 @@ impl LogosAccount { /// TODO: (P1) Remove once implementation is ready. pub fn new_test(explicit_id: impl Into) -> Self { let signing_key = Ed25519SigningKey::generate(); - let verifying_key = signing_key.verifying_key() + let verifying_key = signing_key.verifying_key(); Self { id: AccountId::new(explicit_id.into()), signing_key, - verifying_key + verifying_key, } } diff --git a/core/conversations/src/context.rs b/core/conversations/src/context.rs index e3d6906..fef0bf4 100644 --- a/core/conversations/src/context.rs +++ b/core/conversations/src/context.rs @@ -1,12 +1,10 @@ -use std::cell::Ref; +use std::cell::{Ref, RefMut}; use std::sync::Arc; use std::{cell::RefCell, rc::Rc}; use crate::account::LogosAccount; -use crate::conversation::{Convo, GroupConvo, IdentityProvider}; -use crate::ctx::ClientCtx; +use crate::conversation::{Convo, GroupConvo}; -use crate::account::LogosAccount; use crate::{DeliveryService, RegistrationService}; use crate::{ conversation::{Conversation, Id, PrivateV1Convo}, @@ -26,13 +24,18 @@ pub use crate::inbox::Introduction; // Ctx manages lifetimes of objects to process and generate payloads. pub struct Context { identity: Rc, - client_ctx: ClientCtx, - inbox: Inbox, - pq_inbox: InboxV2, + ds: Rc>, store: Rc>, + inbox: Inbox, + pq_inbox: InboxV2, } -impl Context { +impl Context +where + DS: DeliveryService + 'static, + RS: RegistrationService + 'static, + CS: ChatStore + 'static, +{ /// Opens or creates a Context with the given storage configuration. /// /// If an identity exists in storage, it will be restored. @@ -40,13 +43,15 @@ impl Cont pub fn new_from_store( name: impl Into, delivery: DS, - contact_reg: RS, + registration: RS, store: CS, ) -> Result { let name = name.into(); + // Services for sharing with Converastions/Inboxes + let ds = Rc::new(RefCell::new(delivery)); + let contact_registry = Rc::new(RefCell::new(registration)); let store = Rc::new(RefCell::new(store)); - let mut ctx = ClientCtx::new(delivery, contact_reg, store.clone()); // Load or create identity let identity = if let Some(identity) = store.borrow().load_identity()? { @@ -60,20 +65,24 @@ impl Cont let identity = Rc::new(identity); let inbox = Inbox::new(Rc::clone(&store), Rc::clone(&identity)); - let pq_inbox = InboxV2::new_with_account(LogosAccount::new_test(name)); + let pq_inbox = InboxV2::new( + LogosAccount::new_test(name), + ds.clone(), + contact_registry.clone(), + store.clone(), + ); // Subscribe - ctx.ds() + ds.borrow_mut() .subscribe(&pq_inbox.delivery_address()) .map_err(ChatError::generic)?; Ok(Self { identity: identity, - client_ctx: ctx, + ds, + store, inbox, pq_inbox, - store, - account: LogosAccount::new_test(name.as_str()), }) } @@ -83,47 +92,55 @@ impl Cont pub fn new_with_name( name: impl Into, delivery: DS, - contact_reg: RS, + registration: RS, chat_store: CS, ) -> Result { let name = name.into(); let identity = Identity::new(&name); - let chat_store = Rc::new(RefCell::new(chat_store)); - let mut ctx = ClientCtx::new(delivery, contact_reg, chat_store.clone()); - chat_store + // Services for sharing with Converastions/Inboxes + let ds = Rc::new(RefCell::new(delivery)); + let contact_registry = Rc::new(RefCell::new(registration)); + let store = Rc::new(RefCell::new(chat_store)); + + store .borrow_mut() .save_identity(&identity) .expect("in-memory storage should not fail"); let identity = Rc::new(identity); - let inbox = Inbox::new(Rc::clone(&chat_store), Rc::clone(&identity)); - let mut pq_inbox = InboxV2::new_with_account(LogosAccount::new_test(name)); - pq_inbox.register(&mut ctx)?; + let inbox = Inbox::new(store.clone(), Rc::clone(&identity)); + let mut pq_inbox = InboxV2::new( + LogosAccount::new_test(name), + ds.clone(), + contact_registry.clone(), + store.clone(), + ); - ctx.ds() + // TODO: (!) This seems weird here + pq_inbox.register()?; + + ds.borrow_mut() .subscribe(&pq_inbox.delivery_address()) .map_err(ChatError::generic)?; Ok(Self { identity, - client_ctx: ctx, + ds, + store, pq_inbox, inbox, - - store: chat_store, - account: LogosAccount::new_test(name.as_str()), }) } + pub fn ds(&self) -> RefMut<'_, DS> { + self.ds.borrow_mut() + } + pub fn store(&self) -> Ref<'_, CS> { self.store.borrow() } - pub fn client_ctx(&mut self) -> &mut ClientCtx { - &mut self.client_ctx - } - pub fn identity(&self) -> &Identity { &self.identity } @@ -164,16 +181,17 @@ impl Cont pub fn create_group_convo( &mut self, participants: &[&AccountId], - ) -> Result>, ChatError> { - let mut convo = self.pq_inbox.create_group_v1(&mut self.client_ctx)?; - self.client_ctx - .store() + ) -> Result>, ChatError> { + // TODO: (!) Perform this in InboxV2? + let mut convo = self.pq_inbox.create_group_v1()?; + self.store + .borrow_mut() .save_conversation(&storage::ConversationMeta { local_convo_id: convo.id().to_string(), remote_convo_id: "0".into(), kind: ConversationKind::GroupV1, })?; - convo.add_member(&mut self.client_ctx, participants)?; + convo.add_member(participants)?; Ok(Box::new(convo)) } @@ -246,7 +264,7 @@ impl Cont // Dispatch encrypted payload to Inbox, and register the created Conversation fn dispatch_to_inbox2(&mut self, payload: &[u8]) -> Result, ChatError> { - self.pq_inbox.handle_frame(&mut self.client_ctx, payload)?; + self.pq_inbox.handle_frame(payload)?; Ok(None) } @@ -270,7 +288,7 @@ impl Cont pub fn get_convo( &mut self, convo_id: ConversationId, - ) -> Result>, ChatError> { + ) -> Result>, ChatError> { self.load_group_convo(convo_id) } @@ -292,8 +310,7 @@ impl Cont Ok(Box::new(private_convo)) } ConversationKind::GroupV1 => Ok(Box::new( - self.pq_inbox - .load_mls_convo(&mut self.client_ctx, record.local_convo_id)?, + self.pq_inbox.load_mls_convo(record.local_convo_id)?, )), ConversationKind::Unknown(_) => Err(ChatError::BadBundleValue(format!( "unsupported conversation type: {}", @@ -306,7 +323,7 @@ impl Cont fn load_group_convo( &mut self, convo_id: ConversationId, - ) -> Result>, ChatError> { + ) -> Result>, ChatError> { let record = self .store .borrow() @@ -318,8 +335,7 @@ impl Cont Err(ChatError::NoConvo("This is not a group convo".into())) } ConversationKind::GroupV1 => Ok(Box::new( - self.pq_inbox - .load_mls_convo(&mut self.client_ctx, record.local_convo_id)?, + self.pq_inbox.load_mls_convo(record.local_convo_id)?, )), ConversationKind::Unknown(_) => Err(ChatError::BadBundleValue(format!( "unsupported conversation type: {}", diff --git a/core/conversations/src/conversation.rs b/core/conversations/src/conversation.rs index 4a36bc3..702ca93 100644 --- a/core/conversations/src/conversation.rs +++ b/core/conversations/src/conversation.rs @@ -2,14 +2,14 @@ pub mod group_v1; mod privatev1; use crate::{ - DeliveryService, service_traits::KeyPackageProvider, - ctx::ClientCtx, + DeliveryService, + service_traits::KeyPackageProvider, types::{AccountId, AddressedEncryptedPayload, ContentData}, }; use chat_proto::logoschat::encryption::EncryptedPayload; use std::fmt::Debug; use std::sync::Arc; -use storage::{ChatStore, ConversationKind, ConversationStore, RatchetStore}; +use storage::{ConversationKind, ConversationStore, RatchetStore}; pub use crate::errors::ChatError; pub use group_v1::{GroupV1Convo, IdentityProvider}; @@ -42,27 +42,12 @@ pub trait Convo: Id + Debug { fn convo_type(&self) -> ConversationKind; } -pub trait GroupConvo: Convo { - fn add_member( - &mut self, - ctx: &mut ClientCtx, - members: &[&AccountId], - ) -> Result<(), ChatError>; +pub trait GroupConvo: Convo { + fn add_member(&mut self, members: &[&AccountId]) -> Result<(), ChatError>; - // Default implementation which dispatches envelopes to the DeliveryService - fn send_content( - &mut self, - ctx: &mut ClientCtx, - content: &[u8], - ) -> Result<(), ChatError> { - let payloads = self.send_message(content)?; - for payload in payloads { - ctx.ds() - .publish(payload.into_envelope(self.id().into())) - .map_err(|e| ChatError::Delivery(e.to_string()))?; - } - Ok(()) - } + // This is intended to replace `send_message`. The trait change is that it automatically + // sends the payload directly. + fn send_content(&mut self, content: &[u8]) -> Result<(), ChatError>; } pub enum Conversation { diff --git a/core/conversations/src/conversation/group_v1.rs b/core/conversations/src/conversation/group_v1.rs index 12a71da..f54c56d 100644 --- a/core/conversations/src/conversation/group_v1.rs +++ b/core/conversations/src/conversation/group_v1.rs @@ -8,13 +8,13 @@ use openmls::prelude::tls_codec::Deserialize; use openmls::prelude::*; use openmls_libcrux_crypto::Provider as LibcruxProvider; use openmls_traits::signatures::Signer as OpenMlsSigner; -use storage::{ChatStore, ConversationKind}; +use storage::ConversationKind; use crate::types::AccountId; use crate::{ - DeliveryService, service_traits::KeyPackageProvider, + DeliveryService, conversation::{ChatError, ConversationId, Convo, GroupConvo, Id}, - ctx::ClientCtx, + service_traits::KeyPackageProvider, types::{AddressedEncryptedPayload, ContentData}, }; @@ -37,21 +37,28 @@ pub trait MlsContext { } } - fn invite_user( + fn invite_user( &self, - ctx: &mut ClientCtx, + ds: &mut DS, account_id: &AccountId, welcome: &MlsMessageOut, ) -> Result<(), ChatError>; } -pub struct GroupV1Convo { - ctx: Rc>, +pub struct GroupV1Convo { + ctx: Rc>, + ds: Rc>, + keypkg_provider: Rc>, pub(crate) mls_group: MlsGroup, // TODO: (!) Fix Visibility convo_id: String, } -impl std::fmt::Debug for GroupV1Convo { +impl std::fmt::Debug for GroupV1Convo +where + MlsCtx: MlsContext, + DS: DeliveryService, + KP: KeyPackageProvider, +{ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("GroupV1Convo") .field("name", &self.ctx.borrow().ident().friendly_name()) @@ -61,8 +68,17 @@ impl std::fmt::Debug for GroupV1Convo { } } -impl GroupV1Convo { - pub fn new(ctx: Rc>, ds: &mut DS) -> Self { +impl GroupV1Convo +where + MlsCtx: MlsContext, + DS: DeliveryService, + KP: KeyPackageProvider, +{ + pub fn new( + ctx: Rc>, + ds: Rc>, + keypkg_provider: Rc>, + ) -> Self { let config = Self::mls_create_config(); let mls_group = { let ctx_ref = ctx.borrow(); @@ -75,7 +91,7 @@ impl GroupV1Convo { .unwrap() }; let convo_id = hex::encode(mls_group.group_id().as_slice()); - Self::subscribe(ds, &convo_id); + Self::subscribe(&mut ds.borrow_mut(), &convo_id); println!( "@ Create Convo: {}. {}. d:{} dc:{}", @@ -86,14 +102,17 @@ impl GroupV1Convo { ); Self { ctx, + ds, + keypkg_provider, mls_group, convo_id, } } - pub fn new_from_welcome( - ctx: Rc>, - ds: &mut DS, + pub fn new_from_welcome( + ctx: Rc>, + ds: Rc>, + keypkg_provider: Rc>, welcome: Welcome, ) -> Self { let mls_group = { @@ -109,7 +128,7 @@ impl GroupV1Convo { }; let convo_id = hex::encode(mls_group.group_id().as_slice()); - Self::subscribe(ds, &convo_id); + Self::subscribe(&mut *ds.borrow_mut(), &convo_id); println!( "@ Welcome Convo: I:{}. {}. d:{} dc:{}", @@ -121,14 +140,17 @@ impl GroupV1Convo { GroupV1Convo { ctx, + ds, + keypkg_provider, mls_group, convo_id, } } - pub fn load( - ctx: Rc>, - ds: &mut DS, + pub fn load( + ctx: Rc>, + ds: Rc>, + keypkg_provider: Rc>, convo_id: String, group_id: GroupId, ) -> Result { @@ -138,16 +160,18 @@ impl GroupV1Convo { return Err(ChatError::NoConvo("mls group not found".into())); }; - Self::subscribe(ds, &convo_id)?; + Self::subscribe(&mut *ds.borrow_mut(), &convo_id)?; Ok(GroupV1Convo { ctx, + ds, + keypkg_provider, mls_group, convo_id, }) } - fn subscribe(ds: &mut DS, convo_id: &str) -> Result<(), ChatError> { + fn subscribe(ds: &mut DS, convo_id: &str) -> Result<(), ChatError> { ds.subscribe(&Self::delivery_address_from_id(&convo_id)) .map_err(ChatError::generic)?; ds.subscribe(&Self::ctrl_delivery_address_from_id(&convo_id)) @@ -191,15 +215,12 @@ impl GroupV1Convo { Self::ctrl_delivery_address_from_id(&self.convo_id) } - fn key_package_for_account( - &self, - ctx: &mut ClientCtx, - ident: &AccountId, - ) -> Result { - let retrieved_bytes = ctx - .contact_registry() + fn key_package_for_account(&self, ident: &AccountId) -> Result { + let retrieved_bytes = self + .keypkg_provider + .borrow() .retrieve(ident) - .map_err(|e| ChatError::Generic(e.to_string()))?; + .map_err(|e: KP::Error| ChatError::Generic(e.to_string()))?; // dbg!(ctx.contact_registry()); let Some(keypkg_bytes) = retrieved_bytes else { @@ -215,13 +236,23 @@ impl GroupV1Convo { } } -impl Id for GroupV1Convo { +impl Id for GroupV1Convo +where + MlsCtx: MlsContext, + DS: DeliveryService, + KP: KeyPackageProvider, +{ fn id(&self) -> ConversationId<'_> { &self.convo_id } } -impl Convo for GroupV1Convo { +impl Convo for GroupV1Convo +where + MlsCtx: MlsContext, + DS: DeliveryService, + KP: KeyPackageProvider, +{ fn send_message( &mut self, content: &[u8], @@ -314,14 +345,13 @@ impl Convo for GroupV1Convo { } } -impl - GroupConvo for GroupV1Convo +impl GroupConvo for GroupV1Convo +where + MlsCtx: MlsContext, + DS: DeliveryService, + KP: KeyPackageProvider, { - fn add_member( - &mut self, - ctx: &mut ClientCtx, - members: &[&AccountId], - ) -> Result<(), ChatError> { + fn add_member(&mut self, members: &[&AccountId]) -> Result<(), ChatError> { // add_members returns: // commit — the Commit message Alice broadcasts to all members // welcome — the Welcome message sent privately to each new joiner @@ -341,7 +371,7 @@ impl, ChatError>>()?; let (commit, welcome, _group_info) = self @@ -353,7 +383,7 @@ impl Result<(), ChatError> { + let payloads = self.send_message(content)?; + for payload in payloads { + self.ds + .borrow_mut() + .publish(payload.into_envelope(self.id().into())) + .map_err(|e| ChatError::Delivery(e.to_string()))?; + } + Ok(()) + } } diff --git a/core/conversations/src/ctx.rs b/core/conversations/src/ctx.rs deleted file mode 100644 index d540a9f..0000000 --- a/core/conversations/src/ctx.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::{ - cell::{RefCell, RefMut}, - rc::Rc, -}; - -use storage::ChatStore; - -use crate::{DeliveryService, RegistrationService}; -use crate::service_traits::KeyPackageProvider; - -pub struct ClientCtx { - ds: DS, - contact_registry: RS, - convo_store: Rc>, // TODO: (P2) Remove Rc/Refcell -} - -impl<'a, DS: DeliveryService, RS: KeyPackageProvider, CS: ChatStore> ClientCtx { - pub fn new(ds: DS, contact_registry: RS, convo_store: Rc>) -> Self { - Self { - ds, - contact_registry, - convo_store, - } - } - - pub fn ds(&'a mut self) -> &'a mut DS { - &mut self.ds - } - - pub fn contact_registry(&'a self) -> &'a RS { - &self.contact_registry - } - - pub fn store(&'a self) -> RefMut<'a, CS> { - self.convo_store.borrow_mut() - } -} - -impl<'a, DS: DeliveryService, RS: RegistrationService, CS: ChatStore> ClientCtx { - pub fn contact_registry_mut(&'a mut self) -> &'a mut RS { - &mut self.contact_registry - } -} diff --git a/core/conversations/src/inbox_v2.rs b/core/conversations/src/inbox_v2.rs index f072726..4aea37a 100644 --- a/core/conversations/src/inbox_v2.rs +++ b/core/conversations/src/inbox_v2.rs @@ -12,15 +12,13 @@ use storage::ConversationMeta; use crate::AddressedEnvelope; use crate::ChatError; use crate::DeliveryService; +use crate::RegistrationService; use crate::account::LogosAccount; use crate::conversation::GroupConvo; use crate::conversation::group_v1::MlsContext; use crate::conversation::{GroupV1Convo, IdentityProvider}; -use crate::ctx::ClientCtx; use crate::types::AccountId; use crate::utils::{blake2b_hex, hash_size}; -use crate::RegistrationService; -use crate::service_traits::KeyPackageProvider; pub struct PqMlsContext { ident_provider: LogosAccount, provider: LibcruxProvider, @@ -37,9 +35,9 @@ impl MlsContext for PqMlsContext { &self.provider } - fn invite_user( + fn invite_user( &self, - ctx: &mut ClientCtx, + ds: &mut DS, account_id: &AccountId, welcome: &MlsMessageOut, ) -> Result<(), ChatError> { @@ -62,7 +60,7 @@ impl MlsContext for PqMlsContext { data: envelope.encode_to_vec(), }; - ctx.ds().publish(outbound_msg).map_err(ChatError::generic)?; + ds.publish(outbound_msg).map_err(ChatError::generic)?; Ok(()) } } @@ -81,17 +79,33 @@ impl InboxProtocolParams { type ProtocolParams = InboxProtocolParams; -pub struct InboxV2 { +pub struct InboxV2 { account_id: AccountId, + ds: Rc>, + reg_service: Rc>, + store: Rc>, ctx: Rc>, } -impl<'a> InboxV2 { - pub fn new_with_account(account: LogosAccount) -> Self { +impl<'a, DS, CS, RS> InboxV2 +where + DS: DeliveryService, + RS: RegistrationService, + CS: ChatStore, +{ + pub fn new( + account: LogosAccount, + ds: Rc>, + reg_service: Rc>, + store: Rc>, + ) -> Self { let account_id = account.account_id().clone(); let provider = LibcruxProvider::new().unwrap(); Self { account_id, + ds, + reg_service, + store, ctx: Rc::new(RefCell::new(PqMlsContext { ident_provider: account, provider, @@ -103,18 +117,19 @@ impl<'a> InboxV2 { &self.account_id } - pub fn register( - &mut self, - ctx: &mut ClientCtx, - ) -> Result<(), ChatError> { - let keypackage = self.create_keypackage()?; + /// Submit MlsKeypackage to registration service + pub fn register(&mut self) -> Result<(), ChatError> { + let keypackage_bytes = self.create_keypackage()?.tls_serialize_detached()?; - let bytes = keypackage.tls_serialize_detached()?; - - ctx.contact_registry_mut() - .register(&self.ctx.borrow().ident_provider.friendly_name(), bytes) - .map_err(ChatError::generic)?; //TODO: (P1) create an address scheme instead of using names - Ok(()) + // TODO: (P3) Each keypackage can only be used once either enable... + // "LastResort" package or publish multiple + self.reg_service + .borrow_mut() + .register( + &self.ctx.borrow().ident_provider.friendly_name(), + keypackage_bytes, + ) + .map_err(ChatError::generic) } pub fn delivery_address(&self) -> String { @@ -125,19 +140,12 @@ impl<'a> InboxV2 { ProtocolParams::conversation_id_for_account_id(&self.account_id) } - pub fn create_group_v1( - &self, - ctx: &mut ClientCtx, - ) -> Result, ChatError> { - let convo = GroupV1Convo::new(self.assemble_ctx(), ctx.ds()); + pub fn create_group_v1(&self) -> Result, ChatError> { + let convo = GroupV1Convo::new(self.ctx.clone(), self.ds.clone(), self.reg_service.clone()); Ok(convo) } - pub fn handle_frame( - &self, - ctx: &mut ClientCtx, - payload_bytes: &[u8], - ) -> Result<(), ChatError> { + pub fn handle_frame(&self, payload_bytes: &[u8]) -> Result<(), ChatError> { let inbox_frame = InboxV2Frame::decode(payload_bytes)?; let Some(payload) = inbox_frame.payload else { @@ -146,20 +154,12 @@ impl<'a> InboxV2 { match payload { InviteType::GroupV1(group_v1_heavy_invite) => { - self.handle_heavy_invite(ctx, group_v1_heavy_invite) + self.handle_heavy_invite(group_v1_heavy_invite) } } } - fn assemble_ctx(&self) -> Rc> { - self.ctx.clone() - } - - fn persist_convo( - &self, - ctx: &'a ClientCtx, - convo: impl GroupConvo, - ) -> Result<(), ChatError> { + fn persist_convo(&self, convo: impl GroupConvo) -> Result<(), ChatError> { // TODO: (P2) Remove remote_convo_id this is an implementation detail specific to PrivateV1 // TODO: (P3) Implement From for ConversationMeta let meta = ConversationMeta { @@ -167,16 +167,12 @@ impl<'a> InboxV2 { remote_convo_id: "0".into(), kind: storage::ConversationKind::GroupV1, }; - ctx.store().save_conversation(&meta)?; + self.store.borrow_mut().save_conversation(&meta)?; // TODO: (P1) Persist state Ok(()) } - fn handle_heavy_invite( - &self, - ctx: &mut ClientCtx, - invite: GroupV1HeavyInvite, - ) -> Result<(), ChatError> { + fn handle_heavy_invite(&self, invite: GroupV1HeavyInvite) -> Result<(), ChatError> { let (msg_in, _rest) = MlsMessageIn::tls_deserialize_bytes(invite.welcome_bytes.as_slice())?; let MlsMessageBodyIn::Welcome(welcome) = msg_in.extract() else { @@ -186,8 +182,13 @@ impl<'a> InboxV2 { )); }; - let convo = GroupV1Convo::new_from_welcome(self.assemble_ctx(), ctx.ds(), welcome); - self.persist_convo(ctx, convo) + let convo = GroupV1Convo::new_from_welcome( + self.ctx.clone(), + self.ds.clone(), + self.reg_service.clone(), + welcome, + ); + self.persist_convo(convo) } fn create_keypackage(&self) -> Result { @@ -211,14 +212,19 @@ impl<'a> InboxV2 { Ok(a.key_package().clone()) } - pub fn load_mls_convo( + pub fn load_mls_convo( &self, - ctx: &mut ClientCtx, convo_id: String, - ) -> Result, ChatError> { + ) -> Result, ChatError> { let group_id_bytes = hex::decode(&convo_id).map_err(ChatError::generic)?; let group_id = GroupId::from_slice(&group_id_bytes); - let convo = GroupV1Convo::load(self.assemble_ctx(), ctx.ds(), convo_id, group_id)?; + let convo = GroupV1Convo::load( + self.ctx.clone(), + self.ds.clone(), + self.reg_service.clone(), + convo_id, + group_id, + )?; Ok(convo) } diff --git a/core/conversations/src/lib.rs b/core/conversations/src/lib.rs index 516edeb..9e53aa5 100644 --- a/core/conversations/src/lib.rs +++ b/core/conversations/src/lib.rs @@ -2,12 +2,11 @@ mod account; mod context; mod conversation; mod crypto; -mod ctx; mod errors; -mod service_traits; mod inbox; mod inbox_v2; mod proto; +mod service_traits; mod types; mod utils; diff --git a/core/conversations/src/test_utils.rs b/core/conversations/src/test_utils.rs index cceb668..9999735 100644 --- a/core/conversations/src/test_utils.rs +++ b/core/conversations/src/test_utils.rs @@ -10,7 +10,7 @@ use storage::{ConversationMeta, ConversationStore, IdentityStore}; use storage::{EphemeralKeyStore, RatchetStore}; use crate::{ - AccountId, AddressedEnvelope, DeliveryService, RegistrationService, KeyPackageProvider, + AccountId, AddressedEnvelope, DeliveryService, RegistrationService, utils::{blake2b_hex, hash_size::Testing}, }; @@ -159,18 +159,23 @@ impl Debug for EphemeralRegistry { } } -impl KeyPackageProvider for EphemeralRegistry { +impl RegistrationService for EphemeralRegistry { type Error = String; + fn register(&mut self, identity: &str, key_bundle: Vec) -> Result<(), Self::Error> { + self.registry + .lock() + .unwrap() + .insert(identity.to_string(), key_bundle); + Ok(()) + } fn retrieve(&self, identity: &AccountId) -> Result>, Self::Error> { - Ok(self.registry.lock().unwrap().get(identity.as_str()).cloned()) - } -} - -impl RegistrationService for EphemeralRegistry { - fn register(&mut self, identity: &str, key_bundle: Vec) -> Result<(), Self::Error> { - self.registry.lock().unwrap().insert(identity.to_string(), key_bundle); - Ok(()) + Ok(self + .registry + .lock() + .unwrap() + .get(identity.as_str()) + .cloned()) } } @@ -292,13 +297,3 @@ impl RatchetStore for MemStore { todo!() } } - -// impl GroupMlsStorageV1 for MemStore { -// fn save_state(&self, convo_id: &str, state: &[u8]) { -// self.state.insert(convo_id, state) -// } - -// fn load_state(&self, convo_id: &str) -> Vec { -// self.state.get(convo_id).unwrap().clone() -// } -// } diff --git a/core/conversations/src/utils.rs b/core/conversations/src/utils.rs index 3b51997..3c81443 100644 --- a/core/conversations/src/utils.rs +++ b/core/conversations/src/utils.rs @@ -33,13 +33,12 @@ pub mod hash_size { }; } - use blake2::digest::consts::{U4, U8, U18}; + use blake2::digest::consts::{U4, U8}; hash_sizes! { /// Generic hash size for tests and debug Testing => U4, /// Account ID hash length AccountId => U8, - ConversationId => U18, } } diff --git a/core/integration_tests_core/tests/mls_integration.rs b/core/integration_tests_core/tests/mls_integration.rs index 1769725..f0bc16a 100644 --- a/core/integration_tests_core/tests/mls_integration.rs +++ b/core/integration_tests_core/tests/mls_integration.rs @@ -1,25 +1,7 @@ use std::ops::{Deref, DerefMut}; use components::{EphemeralRegistry, LocalBroadcaster, MemStore}; -use libchat::{ChatStorage, ContentData, Context, ConversationId, GroupConvo, hex_trunc}; - -type TestContext = Context; - -fn send_and_verify( - sender: &mut TestContext, - receiver: &mut TestContext, - convo_id: ConversationId, - content: &[u8], -) { - let payloads = sender.send_content(convo_id, content).unwrap(); - let payload = payloads.first().unwrap(); - let received = receiver - .handle_payload(&payload.data) - .unwrap() - .expect("expected content"); - assert_eq!(content, received.data.as_slice()); - assert!(!received.is_new_convo); // Check that `is_new_convo` is FALSE -} +use libchat::{ContentData, Context, GroupConvo, hex_trunc}; // Simple client Functionality for testing struct Client { @@ -39,12 +21,16 @@ impl Client { } fn process_messages(&mut self) { - while let Some(data) = self.client_ctx().ds().poll() { + let messages: Vec<_> = { + let mut ds = self.ds(); + std::iter::from_fn(|| ds.poll()).collect() + }; + + for data in messages { let res = self.handle_payload(&data).unwrap(); if let Some(cb) = &self.on_content { - match res { - Some(content_data) => cb(content_data), - None => continue, + if let Some(content_data) = res { + cb(content_data); } } } @@ -53,7 +39,7 @@ impl Client { fn convo( &mut self, convo_id: &str, - ) -> Box> { + ) -> Box> { // TODO: (P1) Convos are being copied somewhere, which means hanging on to a reference causes state desync self.get_convo(convo_id).unwrap() } @@ -117,24 +103,16 @@ fn create_group() { clients[SARO] .convo(convo_id) - .send_content( - &mut clients[SARO].client_ctx(), - b"ok who broke the group chat again", - ) + .send_content(b"ok who broke the group chat again") .unwrap(); - // clients[SARO].process_messages(); process(&mut clients); clients[RAYA] .convo(convo_id) - .send_content( - &mut clients[RAYA].client_ctx(), - b"it was literally working five minutes ago", - ) + .send_content(b"it was literally working five minutes ago") .unwrap(); - // clients[SARO].process_messages(); process(&mut clients); let pax_ctx = Context::new_with_name("pax", ds, rs, MemStore::new()).unwrap(); @@ -144,32 +122,22 @@ fn create_group() { let pax_id = clients[PAX].account_id().clone(); clients[SARO] .convo(convo_id) - .add_member(&mut clients[SARO].client_ctx(), &[&pax_id]) + .add_member(&[&pax_id]) .unwrap(); - // clients[SARO].process_messages(); process(&mut clients); clients[PAX] .convo(convo_id) - .send_content( - &mut clients[PAX].client_ctx(), - b"ngl the key rotation is cooked", - ) + .send_content(b"ngl the key rotation is cooked") .unwrap(); - // clients[SARO].process_messages(); - process(&mut clients); clients[SARO] .convo(convo_id) - .send_content( - &mut clients[SARO].client_ctx(), - b"bro we literally just added you to the group ", - ) + .send_content(b"bro we literally just added you to the group ") .unwrap(); process(&mut clients); - // process(&mut clients); } diff --git a/core/integration_tests_core/tests/private_integration.rs b/core/integration_tests_core/tests/private_integration.rs index b9eec0b..90d2a9b 100644 --- a/core/integration_tests_core/tests/private_integration.rs +++ b/core/integration_tests_core/tests/private_integration.rs @@ -1,11 +1,9 @@ -use std::ops::{Deref, DerefMut}; - -use libchat::{AddressedEnvelope, Context, Introduction}; +use libchat::{Context, Introduction}; use sqlite::{ChatStorage, StorageConfig}; use storage::{ConversationStore, IdentityStore}; use tempfile::tempdir; -use components::{EphemeralRegistry, LocalBroadcaster, MemStore}; +use components::{EphemeralRegistry, LocalBroadcaster}; fn send_and_verify( sender: &mut Context,