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