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;
19
20pub mod e2e_identity;
22pub mod mls;
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 mls_crypto_provider::{EntropySeed, MlsCryptoProvider, RawEntropySeed};
38pub use openmls::{
39 group::{MlsGroup, MlsGroupConfig},
40 prelude::{
41 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, Node, SignatureScheme,
42 group_info::VerifiableGroupInfo,
43 },
44};
45
46pub use crate::{
47 build_metadata::{BUILD_METADATA, BuildMetadata},
48 e2e_identity::{
49 E2eiEnrollment,
50 device_status::DeviceStatus,
51 identity::{WireIdentity, X509Identity},
52 types::{E2eiAcmeChallenge, E2eiAcmeDirectory, E2eiNewAcmeAuthz, E2eiNewAcmeOrder},
53 },
54 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
55 error::{
56 Error, InnermostErrorMessage, KeystoreError, LeafError, MlsError, MlsErrorKind, ProteusError, ProteusErrorKind,
57 RecursiveError, Result, ToRecursiveError,
58 },
59 mls::{
60 ciphersuite::Ciphersuite,
61 conversation::{
62 ConversationId, MlsConversation,
63 commit::MlsCommitBundle,
64 config::{MlsConversationConfiguration, MlsCustomConfiguration, MlsWirePolicy},
65 conversation_guard::decrypt::{MlsBufferedConversationDecryptMessage, MlsConversationDecryptMessage},
66 group_info::{GroupInfoPayload, MlsGroupInfoBundle, MlsGroupInfoEncryptionType, MlsRatchetTreeType},
67 proposal::MlsProposalBundle,
68 welcome::WelcomeBundle,
69 },
70 credential::{
71 Credential, CredentialRef, CredentialType, FindFilters as CredentialFindFilters, x509::CertificateBundle,
72 },
73 key_package::{Keypackage, KeypackageRef},
74 proposal::{MlsProposal, MlsProposalRef},
75 session::{
76 EpochObserver, HistoryObserver, Session,
77 id::{ClientId, ClientIdRef},
78 identifier::ClientIdentifier,
79 key_package::{INITIAL_KEYING_MATERIAL_COUNT, KEYPACKAGE_DEFAULT_LIFETIME},
80 user_id::UserId,
81 },
82 },
83 transaction_context::e2e_identity::conversation_state::E2eiConversationState,
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 mls: Arc<RwLock<Option<mls::session::Session>>>,
154 #[cfg(feature = "proteus")]
155 proteus: Arc<Mutex<Option<proteus::ProteusCentral>>>,
156 #[cfg(not(feature = "proteus"))]
157 #[allow(dead_code)]
158 proteus: (),
159}
160
161impl CoreCrypto {
162 pub fn new(database: Database) -> Self {
164 Self {
165 database,
166 mls: Default::default(),
167 proteus: Default::default(),
168 }
169 }
170
171 pub async fn mls_session(&self) -> Result<Session> {
173 if let Some(session) = self.mls.read().await.as_ref() {
174 return Ok(session.clone());
175 }
176 let err = Err(mls::session::Error::MlsNotInitialized);
177 err.map_err(RecursiveError::mls_client("Getting mls session"))?
178 }
179
180 pub fn database(&self) -> Database {
182 self.database.clone()
183 }
184
185 pub async fn close(&self) -> Result<()> {
188 self.database
189 .close()
190 .await
191 .map_err(crate::KeystoreError::wrap("Closing database"))?;
192 Ok(())
193 }
194}