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