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 #[ignore]
80 #[apply(all_cred_cipher)]
81 async fn can_2_phase_init_central(mut case: TestContext) {
82 let db = case.create_persistent_db().await;
83 Box::pin(async move {
84 use std::sync::Arc;
85
86 use wire_e2e_identity::pki_env::PkiEnvironment;
87
88 use crate::{ClientId, Credential, test_utils::DummyPkiEnvironmentHooks};
89
90 let x509_test_chain = X509TestChain::init_empty(case.signature_scheme());
91
92 let cc = CoreCrypto::new(db.clone());
94 let context = cc.new_transaction().await.unwrap();
95
96 let hooks = Arc::new(DummyPkiEnvironmentHooks);
97 let pki_env = PkiEnvironment::new(hooks, db).await.expect("creating pki environment");
98 cc.set_pki_environment(Some(Arc::new(pki_env))).await;
99
100 x509_test_chain.register_with_central(&context).await;
101
102 let session_id = ClientId::from("alice");
104 let identifier = match case.credential_type {
105 CredentialType::Basic => ClientIdentifier::Basic(session_id),
106 CredentialType::X509 => {
107 CertificateBundle::rand_identifier(&session_id, &[x509_test_chain.find_local_intermediate_ca()])
108 }
109 };
110 let pki_env = cc.get_pki_environment().await;
111 let session_id = identifier
112 .get_id(pki_env.as_deref())
113 .await
114 .expect("get session_id from identifier")
115 .into_owned();
116 context
117 .mls_init(
118 session_id.clone(),
119 Arc::new(CoreCryptoTransportSuccessProvider::default()),
120 )
121 .await
122 .unwrap();
123
124 let credential = Credential::from_identifier(&identifier, case.cipher_suite()).unwrap();
125 let credential_ref = context.add_credential(credential).await.unwrap();
126
127 assert!(context.generate_key_package(&credential_ref, None).await.is_ok());
129 })
130 .await
131 }
132}