1#![doc = include_str!(env!("STRIPPED_README_PATH"))]
7#![cfg_attr(not(test), deny(missing_docs))]
8#![allow(clippy::single_component_path_imports)]
9
10#[cfg(test)]
11#[macro_use]
12pub mod test_utils;
13mod build_metadata;
16mod ephemeral;
17mod error;
18mod group_store;
19mod identity;
20
21pub mod mls;
23mod mls_provider;
24#[cfg(feature = "proteus")]
26pub mod proteus;
27pub mod transaction_context;
28
29use std::sync::Arc;
30
31#[cfg(feature = "proteus")]
32use async_lock::Mutex;
33use async_lock::RwLock;
34pub use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
35#[cfg(test)]
36pub use core_crypto_macros::{dispotent, durable, idempotent};
37pub use openmls::{
38 group::{MlsGroup, MlsGroupConfig},
39 prelude::{
40 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, Node, SignatureScheme,
41 group_info::VerifiableGroupInfo,
42 },
43};
44use wire_e2e_identity::{
45 legacy::{E2eiEnrollment, device_status::DeviceStatus},
46 pki_env::PkiEnvironment,
47};
48
49pub use crate::{
50 build_metadata::{BUILD_METADATA, BuildMetadata},
51 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
52 error::{
53 Error, InnermostErrorMessage, KeystoreError, LeafError, MlsError, MlsErrorKind, ProteusError, ProteusErrorKind,
54 RecursiveError, Result, ToRecursiveError,
55 },
56 identity::{WireIdentity, X509Identity},
57 mls::{
58 ciphersuite::Ciphersuite,
59 conversation::{
60 ConversationId, MlsConversation,
61 commit::MlsCommitBundle,
62 config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
63 conversation_guard::decrypt::{MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
64 group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
65 proposal::MlsProposalBundle,
66 welcome::WelcomeBundle,
67 },
68 credential::{
69 Credential, CredentialRef, CredentialType, FindFilters as CredentialFindFilters, x509::CertificateBundle,
70 },
71 key_package::{Keypackage, KeypackageRef},
72 proposal::{MlsProposal, MlsProposalRef},
73 session::{
74 EpochObserver, HistoryObserver, Session,
75 id::{ClientId, ClientIdRef},
76 identifier::ClientIdentifier,
77 user_id::UserId,
78 },
79 },
80 mls_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed, RustCrypto},
81 transaction_context::{
82 e2e_identity::conversation_state::E2eiConversationState, key_package::KEYPACKAGE_DEFAULT_LIFETIME,
83 },
84};
85
86pub enum MlsTransportResponse {
88 Success,
90 Retry,
92 Abort {
94 reason: String,
96 },
97}
98
99#[derive(Debug, derive_more::From, derive_more::Deref, serde::Serialize, serde::Deserialize)]
102pub struct MlsTransportData(pub Vec<u8>);
103
104#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
107#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
108pub trait MlsTransport: std::fmt::Debug + Send + Sync {
109 async fn send_commit_bundle(&self, commit_bundle: MlsCommitBundle) -> Result<MlsTransportResponse>;
111 async fn send_message(&self, mls_message: Vec<u8>) -> Result<MlsTransportResponse>;
113
114 async fn prepare_for_transport(&self, secret: &HistorySecret) -> Result<MlsTransportData>;
121}
122
123#[derive(Debug, Default)]
126pub struct CoreCryptoTransportNotImplementedProvider();
127
128#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
129#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
130impl MlsTransport for CoreCryptoTransportNotImplementedProvider {
131 async fn send_commit_bundle(&self, _commit_bundle: MlsCommitBundle) -> crate::Result<MlsTransportResponse> {
132 Err(Error::MlsTransportNotProvided)
133 }
134
135 async fn send_message(&self, _mls_message: Vec<u8>) -> crate::Result<MlsTransportResponse> {
136 Err(Error::MlsTransportNotProvided)
137 }
138
139 async fn prepare_for_transport(&self, _secret: &HistorySecret) -> crate::Result<MlsTransportData> {
140 Err(Error::MlsTransportNotProvided)
141 }
142}
143
144#[derive(Debug, Clone)]
151pub struct CoreCrypto {
152 database: Database,
153 pki_environment: Arc<RwLock<Option<PkiEnvironment>>>,
154 mls: Arc<RwLock<Option<mls::session::Session<Database>>>>,
155 #[cfg(feature = "proteus")]
156 proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
157 #[cfg(not(feature = "proteus"))]
158 #[allow(dead_code)]
159 proteus: (),
160}
161
162impl CoreCrypto {
163 pub fn new(database: Database) -> Self {
165 Self {
166 database,
167 pki_environment: Default::default(),
168 mls: Default::default(),
169 proteus: Default::default(),
170 }
171 }
172
173 pub async fn set_pki_environment(&self, pki_environment: Option<PkiEnvironment>) -> Result<()> {
175 if let Some(mls_session) = self.mls.write().await.as_mut() {
176 mls_session
177 .crypto_provider
178 .set_pki_environment_provider(pki_environment.as_ref().map(|p| p.mls_pki_env_provider()))
179 .await
180 }
181
182 let mut guard = self.pki_environment.write().await;
183 *guard = pki_environment;
184
185 Ok(())
186 }
187
188 pub async fn get_pki_environment(&self) -> Option<PkiEnvironment> {
190 self.pki_environment.read().await.clone()
191 }
192
193 pub async fn mls_session(&self) -> Result<Session<Database>> {
195 if let Some(session) = self.mls.read().await.as_ref() {
196 return Ok(session.clone());
197 }
198 let err = Err(mls::session::Error::MlsNotInitialized);
199 err.map_err(RecursiveError::mls_client("Getting mls session"))?
200 }
201
202 pub fn database(&self) -> Database {
204 self.database.clone()
205 }
206}