1use crate::{ClientId, MlsConversation, Session, mls_provider::MlsCryptoProvider};
2
3pub(crate) mod ciphersuite;
4pub mod conversation;
5pub mod credential;
6mod error;
7pub mod key_package;
8pub(crate) mod proposal;
9pub(crate) mod session;
10
11use core_crypto_keystore::Database;
12pub use error::{Error, Result};
13pub use session::{EpochObserver, HistoryObserver};
14
15#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
16#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
17pub(crate) trait HasSessionAndCrypto: Send {
18 async fn session(&self) -> Result<Session<Database>>;
19 async fn crypto_provider(&self) -> Result<MlsCryptoProvider>;
20}
21
22#[cfg(test)]
23mod tests {
24
25 use crate::{
26 CertificateBundle, ClientIdentifier, CoreCrypto, CredentialType,
27 test_utils::{x509::X509TestChain, *},
28 transaction_context::Error as TransactionError,
29 };
30
31 mod conversation_epoch {
32 use super::*;
33 use crate::mls::conversation::Conversation as _;
34
35 #[apply(all_cred_cipher)]
36 async fn can_get_newly_created_conversation_epoch(case: TestContext) {
37 let [session] = case.sessions().await;
38 let conversation = case.create_conversation([&session]).await;
39 let epoch = conversation.guard().await.epoch().await;
40 assert_eq!(epoch, 0);
41 }
42
43 #[apply(all_cred_cipher)]
44 async fn can_get_conversation_epoch(case: TestContext) {
45 let [alice, bob] = case.sessions().await;
46 Box::pin(async move {
47 let conversation = case.create_conversation([&alice, &bob]).await;
48 let epoch = conversation.guard().await.epoch().await;
49 assert_eq!(epoch, 1);
50 })
51 .await;
52 }
53
54 #[apply(all_cred_cipher)]
55 async fn conversation_not_found(case: TestContext) {
56 use crate::LeafError;
57 let [session] = case.sessions().await;
58 let id = conversation_id();
59 let err = session.transaction.conversation(&id).await.unwrap_err();
60 assert!(matches!(
61 err,
62 TransactionError::Leaf(LeafError::ConversationNotFound(i)) if i == id
63 ));
64 }
65 }
66
67 #[apply(all_cred_cipher)]
68 async fn create_conversation_should_fail_when_already_exists(case: TestContext) {
69 use crate::LeafError;
70
71 let [alice] = case.sessions().await;
72 Box::pin(async move {
73 let conversation = case.create_conversation([&alice]).await;
74 let id = conversation.id().clone();
75 let credentials =alice.session().await.find_credentials(Default::default()).await.expect("finding credentials");
76 let credential = credentials.first().expect("first credential");
77
78 let repeat_create = alice
80 .transaction
81 .new_conversation(&id, credential, case.cfg.clone())
82 .await;
83 assert!(matches!(repeat_create.unwrap_err(), TransactionError::Leaf(LeafError::ConversationAlreadyExists(i)) if i == id));
84 })
85 .await;
86 }
87
88 #[apply(all_cred_cipher)]
89 async fn can_2_phase_init_central(mut case: TestContext) {
90 let db = case.create_persistent_db().await;
91 Box::pin(async move {
92 use std::sync::Arc;
93
94 use wire_e2e_identity::pki_env::PkiEnvironment;
95
96 use crate::{ClientId, Credential, test_utils::DummyPkiEnvironmentHooks};
97
98 let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
99
100 let cc = CoreCrypto::new(db.clone());
102 let context = cc.new_transaction().await.unwrap();
103
104 let hooks = Arc::new(DummyPkiEnvironmentHooks);
105 let pki_env = PkiEnvironment::new(hooks, db).await.expect("creating pki environment");
106 cc.set_pki_environment(Some(pki_env))
107 .await
108 .expect("setting pki environment");
109
110 x509_test_chain.register_with_central(&context).await;
111
112 let session_id = ClientId::from("alice");
114 let identifier = match case.credential_type {
115 CredentialType::Basic => ClientIdentifier::Basic(session_id),
116 CredentialType::X509 => {
117 CertificateBundle::rand_identifier(&session_id, &[x509_test_chain.find_local_intermediate_ca()])
118 }
119 };
120 let session_id = identifier
121 .get_id()
122 .expect("get session_id from identifier")
123 .into_owned();
124 context
125 .mls_init(
126 session_id.clone(),
127 Arc::new(CoreCryptoTransportSuccessProvider::default()),
128 )
129 .await
130 .unwrap();
131
132 let credential = Credential::from_identifier(&identifier, case.ciphersuite()).unwrap();
133 let credential_ref = context.add_credential(credential).await.unwrap();
134
135 assert!(context.generate_keypackage(&credential_ref, None).await.is_ok());
137 })
138 .await
139 }
140}