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