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 bytes_wrapper;
17mod ephemeral;
18mod error;
19mod identity;
20mod immutable_database;
21
22pub mod mls;
24mod mls_provider;
25#[cfg(feature = "proteus")]
27pub mod proteus;
28pub mod transaction_context;
29
30use std::sync::Arc;
31
32#[cfg(feature = "proteus")]
33use async_lock::Mutex;
34use async_lock::RwLock;
35pub(crate) use bytes_wrapper::bytes_wrapper;
36pub use core_crypto_keystore::{ConnectionType, Database, DatabaseKey};
37#[cfg(test)]
38pub use core_crypto_macros::{dispotent, durable, idempotent};
39pub(crate) use immutable_database::ImmutableDatabase;
40pub use openmls::{
41 group::{MlsGroup, MlsGroupConfig},
42 prelude::{
43 Ciphersuite as MlsCiphersuite, GroupEpoch, KeyPackageIn, MlsMessageIn, MlsMessageInBody, Node, SignatureScheme,
44 group_info::VerifiableGroupInfo,
45 },
46};
47use wire_e2e_identity::{legacy::device_status::DeviceStatus, pki_env::PkiEnvironment};
48
49pub use crate::{
50 build_metadata::{BUILD_METADATA, BuildMetadata},
51 ephemeral::{HISTORY_CLIENT_ID_PREFIX, HistorySecret},
52 error::{
53 Error, InnermostErrorMessage, KeystoreError, LeafError, OpenMlsError, OpenMlsErrorKind, ProteusError,
54 ProteusErrorKind, RecursiveError, Result, ToRecursiveError,
55 },
56 identity::{WireIdentity, X509Identity},
57 mls::{
58 ExternalSender,
59 cipher_suite::CipherSuite,
60 conversation::{
61 BufferedDecryptedMessage, CommitBundle, ConversationConfiguration, ConversationId, CustomConfiguration,
62 DecryptedMessage, GroupInfoBundle, GroupInfoEncryptionType, GroupInfoPayload, RatchetTreeType, WirePolicy,
63 },
64 credential::{
65 Credential, CredentialRef, CredentialType, FindFilters as CredentialFindFilters, x509::CertificateBundle,
66 },
67 key_package::{Keypackage, KeypackageRef},
68 session::{
69 EpochObserver, HistoryObserver, Session,
70 id::{ClientId, ClientIdRef},
71 user_id::UserId,
72 },
73 },
74 mls_provider::{CryptoProvider, EntropySeed, RawEntropySeed, RustCrypto},
75 transaction_context::{
76 e2e_identity::conversation_state::E2eiConversationState, key_package::KEYPACKAGE_DEFAULT_LIFETIME,
77 },
78};
79
80#[derive(Debug, derive_more::From, derive_more::Deref, serde::Serialize, serde::Deserialize)]
83pub struct TransportData(pub Vec<u8>);
84
85#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
88#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
89pub trait MlsTransport: std::fmt::Debug + Send + Sync {
90 async fn send_commit_bundle(&self, commit_bundle: CommitBundle) -> Result<()>;
92
93 async fn prepare_for_transport(&self, secret: &HistorySecret) -> Result<TransportData>;
100}
101
102#[derive(Debug, Default)]
105pub struct CoreCryptoTransportNotImplementedProvider();
106
107#[cfg_attr(target_os = "unknown", async_trait::async_trait(?Send))]
108#[cfg_attr(not(target_os = "unknown"), async_trait::async_trait)]
109impl MlsTransport for CoreCryptoTransportNotImplementedProvider {
110 async fn send_commit_bundle(&self, _commit_bundle: CommitBundle) -> crate::Result<()> {
111 Err(Error::MlsTransportNotProvided)
112 }
113
114 async fn prepare_for_transport(&self, _secret: &HistorySecret) -> crate::Result<TransportData> {
115 Err(Error::MlsTransportNotProvided)
116 }
117}
118
119#[derive(Debug)]
124pub struct CoreCrypto {
125 database: Arc<Database>,
126 pki_environment: RwLock<Option<Arc<PkiEnvironment>>>,
127 mls: RwLock<Option<mls::session::Session>>,
128 #[cfg(feature = "proteus")]
129 proteus: Mutex<Option<proteus::ProteusCentral>>,
130 #[cfg(not(feature = "proteus"))]
131 #[allow(dead_code)]
132 proteus: (),
133}
134
135impl CoreCrypto {
136 pub fn new(database: Arc<Database>) -> Arc<Self> {
138 Self {
139 database,
140 pki_environment: Default::default(),
141 mls: Default::default(),
142 proteus: Default::default(),
143 }
144 .into()
145 }
146
147 pub async fn set_pki_environment(&self, pki_environment: Option<Arc<PkiEnvironment>>) {
149 *self.pki_environment.write().await = pki_environment.clone();
150 if let Some(mls_session) = self.mls.write().await.as_mut() {
151 mls_session.crypto_provider.set_pki_environment(pki_environment).await;
152 }
153 }
154
155 pub async fn get_pki_environment(&self) -> Option<Arc<PkiEnvironment>> {
157 self.pki_environment.read().await.clone()
158 }
159
160 pub async fn mls_session(&self) -> Result<Session> {
162 if let Some(session) = self.mls.read().await.as_ref() {
163 return Ok(session.clone());
164 }
165 let err = Err(mls::session::Error::MlsNotInitialized);
166 err.map_err(RecursiveError::mls_client("Getting mls session"))?
167 }
168
169 pub fn database(&self) -> ImmutableDatabase {
171 self.database.clone().into()
172 }
173}