1#![allow(deprecated)]
2use log::kv::{Key, Value, Visitor};
19use log::{kv, Level, LevelFilter, Metadata, Record};
20use log_reload::ReloadLog;
21use std::collections::{BTreeMap, HashMap};
22use std::ops::{Deref, DerefMut};
23use std::sync::{Arc, LazyLock, Once};
24use tls_codec::{Deserialize, Serialize};
25
26use crate::UniffiCustomTypeConverter;
27pub use core_crypto::prelude::ConversationId;
28use core_crypto::{
29 prelude::{
30 ClientIdentifier, CryptoError, E2eIdentityError, EntropySeed, KeyPackageIn, KeyPackageRef,
31 MlsBufferedConversationDecryptMessage, MlsCentral, MlsCentralConfiguration, MlsCiphersuite, MlsCommitBundle,
32 MlsConversationConfiguration, MlsConversationCreationMessage, MlsConversationDecryptMessage,
33 MlsConversationInitBundle, MlsCustomConfiguration, MlsGroupInfoBundle, MlsProposalBundle, MlsRotateBundle,
34 VerifiableGroupInfo,
35 },
36 CryptoResult,
37};
38
39use self::context::CoreCryptoContext;
40
41use crate::proteus_impl;
42
43pub mod context;
44
45#[allow(dead_code)]
46pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
47
48#[uniffi::export]
49pub fn version() -> String {
50 VERSION.to_string()
51}
52
53#[derive(uniffi::Record)]
54pub struct BuildMetadata {
56 pub timestamp: String,
58 pub cargo_debug: String,
60 pub cargo_features: String,
62 pub opt_level: String,
64 pub target_triple: String,
66 pub git_branch: String,
68 pub git_describe: String,
70 pub git_sha: String,
72 pub git_dirty: String,
74}
75
76#[uniffi::export]
77pub fn build_metadata() -> BuildMetadata {
78 BuildMetadata {
79 timestamp: core_crypto::BUILD_METADATA.timestamp.to_string(),
80 cargo_debug: core_crypto::BUILD_METADATA.cargo_debug.to_string(),
81 cargo_features: core_crypto::BUILD_METADATA.cargo_features.to_string(),
82 opt_level: core_crypto::BUILD_METADATA.opt_level.to_string(),
83 target_triple: core_crypto::BUILD_METADATA.target_triple.to_string(),
84 git_branch: core_crypto::BUILD_METADATA.git_branch.to_string(),
85 git_describe: core_crypto::BUILD_METADATA.git_describe.to_string(),
86 git_sha: core_crypto::BUILD_METADATA.git_sha.to_string(),
87 git_dirty: core_crypto::BUILD_METADATA.git_dirty.to_string(),
88 }
89}
90
91#[derive(Debug, thiserror::Error, uniffi::Error)]
92pub enum MlsError {
93 #[error("Conversation already exists")]
94 ConversationAlreadyExists(core_crypto::prelude::ConversationId),
95 #[error("We already decrypted this message once")]
96 DuplicateMessage,
97 #[error("Incoming message is for a future epoch. We will buffer it until the commit for that epoch arrives")]
98 BufferedFutureMessage,
99 #[error("Incoming message is from an epoch too far in the future to buffer.")]
100 WrongEpoch,
101 #[error("The epoch in which message was encrypted is older than allowed")]
102 MessageEpochTooOld,
103 #[error("Tried to decrypt a commit created by self which is likely to have been replayed by the DS")]
104 SelfCommitIgnored,
105 #[error(
106 "You tried to join with an external commit but did not merge it yet. We will reapply this message for you when you merge your external commit"
107 )]
108 UnmergedPendingGroup,
109 #[error("The received proposal is deemed stale and is from an older epoch.")]
110 StaleProposal,
111 #[error("The received commit is deemed stale and is from an older epoch.")]
112 StaleCommit,
113 #[error("Although this Welcome seems valid, the local KeyPackage it references has already been deleted locally. Join this group with an external commit")]
118 OrphanWelcome,
119 #[error("{0}")]
120 Other(String),
121}
122
123impl From<core_crypto::MlsError> for MlsError {
124 #[inline]
125 fn from(e: core_crypto::MlsError) -> Self {
126 Self::Other(e.to_string())
127 }
128}
129
130#[cfg(feature = "proteus")]
131#[derive(Debug, thiserror::Error, uniffi::Error)]
132pub enum ProteusError {
133 #[error("The requested session was not found")]
134 SessionNotFound,
135 #[error("We already decrypted this message once")]
136 DuplicateMessage,
137 #[error("The remote identity has changed")]
138 RemoteIdentityChanged,
139 #[error("Another Proteus error occurred but the details are probably irrelevant to clients")]
140 Other(u16),
141}
142
143#[cfg(feature = "proteus")]
144impl ProteusError {
145 pub fn from_error_code(code: u16) -> Self {
146 match code {
147 102 => Self::SessionNotFound,
148 204 => Self::RemoteIdentityChanged,
149 209 => Self::DuplicateMessage,
150 _ => Self::Other(code),
151 }
152 }
153
154 pub fn error_code(&self) -> u16 {
155 match self {
156 Self::SessionNotFound => 102,
157 Self::RemoteIdentityChanged => 204,
158 Self::DuplicateMessage => 209,
159 Self::Other(code) => *code,
160 }
161 }
162}
163
164#[cfg(feature = "proteus")]
165impl From<core_crypto::ProteusError> for ProteusError {
166 fn from(value: core_crypto::ProteusError) -> Self {
167 type SessionError = proteus_wasm::session::Error<core_crypto_keystore::CryptoKeystoreError>;
168 match value {
169 core_crypto::ProteusError::ProteusSessionError(SessionError::InternalError(
170 proteus_wasm::internal::types::InternalError::NoSessionForTag,
171 )) => Self::SessionNotFound,
172 core_crypto::ProteusError::ProteusSessionError(SessionError::DuplicateMessage) => Self::DuplicateMessage,
173 core_crypto::ProteusError::ProteusSessionError(SessionError::RemoteIdentityChanged) => {
174 Self::RemoteIdentityChanged
175 }
176 _ => Self::Other(value.error_code().unwrap_or_default()),
177 }
178 }
179}
180
181#[derive(Debug, thiserror::Error, uniffi::Error)]
182pub enum CoreCryptoError {
183 #[error(transparent)]
184 Mls(#[from] MlsError),
185 #[cfg(feature = "proteus")]
186 #[error(transparent)]
187 Proteus(#[from] ProteusError),
188 #[error("End to end identity error: {0}")]
189 E2eiError(String),
190 #[error("error from client: {0}")]
191 ClientError(String),
192}
193
194impl From<CryptoError> for CoreCryptoError {
200 fn from(value: CryptoError) -> Self {
201 #[cfg(feature = "proteus")]
202 if let Some(error_code) = value.proteus_error_code() {
203 if error_code != 0 {
204 return ProteusError::from_error_code(error_code).into();
206 }
207 }
208
209 match value {
210 CryptoError::ConversationAlreadyExists(id) => MlsError::ConversationAlreadyExists(id).into(),
211 CryptoError::DuplicateMessage => MlsError::DuplicateMessage.into(),
212 CryptoError::BufferedFutureMessage { .. } => MlsError::BufferedFutureMessage.into(),
213 CryptoError::WrongEpoch => MlsError::WrongEpoch.into(),
214 CryptoError::MessageEpochTooOld => MlsError::MessageEpochTooOld.into(),
215 CryptoError::SelfCommitIgnored => MlsError::SelfCommitIgnored.into(),
216 CryptoError::UnmergedPendingGroup => MlsError::UnmergedPendingGroup.into(),
217 CryptoError::StaleProposal => MlsError::StaleProposal.into(),
218 CryptoError::StaleCommit => MlsError::StaleCommit.into(),
219 CryptoError::OrphanWelcome => MlsError::OrphanWelcome.into(),
220 CryptoError::E2eiError(e) => Self::E2eiError(e.to_string()),
221 _ => MlsError::Other(value.to_string()).into(),
222 }
223 }
224}
225
226impl From<E2eIdentityError> for CoreCryptoError {
227 fn from(e: E2eIdentityError) -> Self {
228 Self::E2eiError(e.to_string())
229 }
230}
231
232impl From<uniffi::UnexpectedUniFFICallbackError> for CoreCryptoError {
233 fn from(value: uniffi::UnexpectedUniFFICallbackError) -> Self {
234 Self::ClientError(value.reason)
235 }
236}
237
238type CoreCryptoResult<T> = Result<T, CoreCryptoError>;
239
240#[derive(Debug, Clone, Eq, Hash, PartialEq)]
241pub struct ClientId(core_crypto::prelude::ClientId);
242
243uniffi::custom_type!(ClientId, Vec<u8>);
244
245impl UniffiCustomTypeConverter for ClientId {
246 type Builtin = Vec<u8>;
247
248 fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
249 Ok(Self(core_crypto::prelude::ClientId::from(val)))
250 }
251
252 fn from_custom(obj: Self) -> Self::Builtin {
253 obj.0.to_vec()
254 }
255}
256
257#[allow(non_camel_case_types)]
258#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Enum)]
259#[repr(u16)]
260pub enum CiphersuiteName {
261 MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 = 0x0001,
263 MLS_128_DHKEMP256_AES128GCM_SHA256_P256 = 0x0002,
265 MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 = 0x0003,
267 MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 = 0x0004,
269 MLS_256_DHKEMP521_AES256GCM_SHA512_P521 = 0x0005,
271 MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 = 0x0006,
273 MLS_256_DHKEMP384_AES256GCM_SHA384_P384 = 0x0007,
275}
276
277#[derive(Debug, Clone)]
278pub struct Ciphersuite(core_crypto::prelude::CiphersuiteName);
279
280uniffi::custom_type!(Ciphersuite, u16);
281
282impl From<core_crypto::prelude::CiphersuiteName> for Ciphersuite {
283 fn from(cs: core_crypto::prelude::CiphersuiteName) -> Self {
284 Self(cs)
285 }
286}
287
288impl From<Ciphersuite> for core_crypto::prelude::CiphersuiteName {
289 fn from(cs: Ciphersuite) -> Self {
290 cs.0
291 }
292}
293
294impl From<Ciphersuite> for MlsCiphersuite {
295 fn from(cs: Ciphersuite) -> Self {
296 cs.0.into()
297 }
298}
299
300impl UniffiCustomTypeConverter for Ciphersuite {
301 type Builtin = u16;
302
303 fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
304 core_crypto::prelude::CiphersuiteName::try_from(val)
305 .map(Into::into)
306 .map_err(|_| CryptoError::ImplementationError.into())
307 }
308
309 fn from_custom(obj: Self) -> Self::Builtin {
310 (&obj.0).into()
311 }
312}
313
314#[derive(Debug, Default, Clone)]
315pub struct Ciphersuites(Vec<core_crypto::prelude::CiphersuiteName>);
316
317impl From<Vec<core_crypto::prelude::CiphersuiteName>> for Ciphersuites {
318 fn from(cs: Vec<core_crypto::prelude::CiphersuiteName>) -> Self {
319 Self(cs)
320 }
321}
322
323impl From<Ciphersuites> for Vec<core_crypto::prelude::CiphersuiteName> {
324 fn from(cs: Ciphersuites) -> Self {
325 cs.0
326 }
327}
328
329impl<'a> From<&'a Ciphersuites> for Vec<MlsCiphersuite> {
330 fn from(cs: &'a Ciphersuites) -> Self {
331 cs.0.iter().fold(Vec::with_capacity(cs.0.len()), |mut acc, c| {
332 acc.push((*c).into());
333 acc
334 })
335 }
336}
337
338uniffi::custom_type!(Ciphersuites, Vec<u16>);
339
340impl UniffiCustomTypeConverter for Ciphersuites {
341 type Builtin = Vec<u16>;
342
343 fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
344 val.iter().try_fold(Self(vec![]), |mut acc, c| -> uniffi::Result<Self> {
345 let cs =
346 core_crypto::prelude::CiphersuiteName::try_from(*c).map_err(|_| CryptoError::ImplementationError)?;
347 acc.0.push(cs);
348 Ok(acc)
349 })
350 }
351
352 fn from_custom(obj: Self) -> Self::Builtin {
353 obj.0.into_iter().map(|c| (&c).into()).collect()
354 }
355}
356
357#[derive(Debug, Clone, Copy, PartialEq, Eq, uniffi::Record)]
358pub struct CrlRegistration {
360 pub dirty: bool,
362 pub expiration: Option<u64>,
364}
365
366impl From<core_crypto::e2e_identity::CrlRegistration> for CrlRegistration {
367 fn from(value: core_crypto::e2e_identity::CrlRegistration) -> Self {
368 Self {
369 dirty: value.dirty,
370 expiration: value.expiration,
371 }
372 }
373}
374
375#[derive(Debug, Clone, uniffi::Record)]
376pub struct ProteusAutoPrekeyBundle {
377 pub id: u16,
378 pub pkb: Vec<u8>,
379}
380
381#[derive(Debug, uniffi::Record)]
382pub struct MemberAddedMessages {
384 pub welcome: Vec<u8>,
385 pub commit: Vec<u8>,
386 pub group_info: GroupInfoBundle,
387 pub crl_new_distribution_points: Option<Vec<String>>,
388}
389
390impl TryFrom<MlsConversationCreationMessage> for MemberAddedMessages {
391 type Error = CoreCryptoError;
392
393 fn try_from(msg: MlsConversationCreationMessage) -> Result<Self, Self::Error> {
394 let (welcome, commit, group_info, crl_new_distribution_points) = msg.to_bytes()?;
395 Ok(Self {
396 welcome,
397 commit,
398 group_info: group_info.into(),
399 crl_new_distribution_points: crl_new_distribution_points.into(),
400 })
401 }
402}
403
404#[derive(Debug, uniffi::Record)]
405pub struct WelcomeBundle {
407 pub id: ConversationId,
408 pub crl_new_distribution_points: Option<Vec<String>>,
409}
410
411impl From<core_crypto::prelude::WelcomeBundle> for WelcomeBundle {
412 fn from(w: core_crypto::prelude::WelcomeBundle) -> Self {
413 Self {
414 id: w.id,
415 crl_new_distribution_points: w.crl_new_distribution_points.into(),
416 }
417 }
418}
419
420#[derive(Debug, uniffi::Record)]
421pub struct CommitBundle {
422 pub welcome: Option<Vec<u8>>,
423 pub commit: Vec<u8>,
424 pub group_info: GroupInfoBundle,
425}
426
427impl TryFrom<MlsCommitBundle> for CommitBundle {
428 type Error = CoreCryptoError;
429
430 fn try_from(msg: MlsCommitBundle) -> Result<Self, Self::Error> {
431 let (welcome, commit, group_info) = msg.to_bytes_triple()?;
432 Ok(Self {
433 welcome,
434 commit,
435 group_info: group_info.into(),
436 })
437 }
438}
439
440#[derive(Debug, Clone, Copy, uniffi::Enum)]
441#[repr(u8)]
442pub enum MlsGroupInfoEncryptionType {
443 Plaintext = 1,
445 JweEncrypted = 2,
447}
448
449impl From<core_crypto::prelude::MlsGroupInfoEncryptionType> for MlsGroupInfoEncryptionType {
450 fn from(value: core_crypto::prelude::MlsGroupInfoEncryptionType) -> Self {
451 match value {
452 core_crypto::prelude::MlsGroupInfoEncryptionType::Plaintext => Self::Plaintext,
453 core_crypto::prelude::MlsGroupInfoEncryptionType::JweEncrypted => Self::JweEncrypted,
454 }
455 }
456}
457
458impl From<MlsGroupInfoEncryptionType> for core_crypto::prelude::MlsGroupInfoEncryptionType {
459 fn from(value: MlsGroupInfoEncryptionType) -> Self {
460 match value {
461 MlsGroupInfoEncryptionType::Plaintext => Self::Plaintext,
462 MlsGroupInfoEncryptionType::JweEncrypted => Self::JweEncrypted,
463 }
464 }
465}
466
467#[derive(Debug, Clone, Copy, uniffi::Enum)]
468#[repr(u8)]
469pub enum MlsRatchetTreeType {
470 Full = 1,
472 Delta = 2,
475 ByRef = 3,
476}
477
478impl From<core_crypto::prelude::MlsRatchetTreeType> for MlsRatchetTreeType {
479 fn from(value: core_crypto::prelude::MlsRatchetTreeType) -> Self {
480 match value {
481 core_crypto::prelude::MlsRatchetTreeType::Full => Self::Full,
482 core_crypto::prelude::MlsRatchetTreeType::Delta => Self::Delta,
483 core_crypto::prelude::MlsRatchetTreeType::ByRef => Self::ByRef,
484 }
485 }
486}
487
488impl From<MlsRatchetTreeType> for core_crypto::prelude::MlsRatchetTreeType {
489 fn from(value: MlsRatchetTreeType) -> Self {
490 match value {
491 MlsRatchetTreeType::Full => Self::Full,
492 MlsRatchetTreeType::Delta => Self::Delta,
493 MlsRatchetTreeType::ByRef => Self::ByRef,
494 }
495 }
496}
497
498#[derive(Debug, Clone, uniffi::Record)]
499pub struct GroupInfoBundle {
500 pub encryption_type: MlsGroupInfoEncryptionType,
501 pub ratchet_tree_type: MlsRatchetTreeType,
502 pub payload: Vec<u8>,
503}
504
505impl From<MlsGroupInfoBundle> for GroupInfoBundle {
506 fn from(gi: MlsGroupInfoBundle) -> Self {
507 Self {
508 encryption_type: gi.encryption_type.into(),
509 ratchet_tree_type: gi.ratchet_tree_type.into(),
510 payload: gi.payload.bytes(),
511 }
512 }
513}
514
515#[derive(Debug, uniffi::Record)]
516pub struct RotateBundle {
517 pub commits: HashMap<String, CommitBundle>,
518 pub new_key_packages: Vec<Vec<u8>>,
519 pub key_package_refs_to_remove: Vec<Vec<u8>>,
520 pub crl_new_distribution_points: Option<Vec<String>>,
521}
522
523impl TryFrom<MlsRotateBundle> for RotateBundle {
524 type Error = CoreCryptoError;
525
526 fn try_from(bundle: MlsRotateBundle) -> Result<Self, Self::Error> {
527 let (commits, new_key_packages, key_package_refs_to_remove, crl_new_distribution_points) = bundle.to_bytes()?;
528 let commits_size = commits.len();
529 let commits = commits
530 .into_iter()
531 .try_fold(HashMap::with_capacity(commits_size), |mut acc, (id, c)| {
532 let _ = acc.insert(id, c.try_into()?);
533 CoreCryptoResult::Ok(acc)
534 })?;
535 Ok(Self {
536 commits,
537 new_key_packages,
538 key_package_refs_to_remove,
539 crl_new_distribution_points: crl_new_distribution_points.into(),
540 })
541 }
542}
543
544#[derive(Debug, uniffi::Record)]
545pub struct ProposalBundle {
546 pub proposal: Vec<u8>,
547 pub proposal_ref: Vec<u8>,
548 pub crl_new_distribution_points: Option<Vec<String>>,
549}
550
551impl TryFrom<MlsProposalBundle> for ProposalBundle {
552 type Error = CoreCryptoError;
553
554 fn try_from(msg: MlsProposalBundle) -> Result<Self, Self::Error> {
555 let (proposal, proposal_ref, crl_new_distribution_points) = msg.to_bytes()?;
556 Ok(Self {
557 proposal,
558 proposal_ref,
559 crl_new_distribution_points: crl_new_distribution_points.into(),
560 })
561 }
562}
563
564#[derive(Debug, uniffi::Record)]
565pub struct ConversationInitBundle {
566 pub conversation_id: Vec<u8>,
567 pub commit: Vec<u8>,
568 pub group_info: GroupInfoBundle,
569 pub crl_new_distribution_points: Option<Vec<String>>,
570}
571
572impl TryFrom<MlsConversationInitBundle> for ConversationInitBundle {
573 type Error = CoreCryptoError;
574
575 fn try_from(mut from: MlsConversationInitBundle) -> Result<Self, Self::Error> {
576 let conversation_id = std::mem::take(&mut from.conversation_id);
577 let (commit, gi, crl_new_distribution_points) = from.to_bytes()?;
578 Ok(Self {
579 conversation_id,
580 commit,
581 group_info: gi.into(),
582 crl_new_distribution_points: crl_new_distribution_points.into(),
583 })
584 }
585}
586
587#[derive(Debug, uniffi::Record)]
588pub struct DecryptedMessage {
590 pub message: Option<Vec<u8>>,
591 pub proposals: Vec<ProposalBundle>,
592 pub is_active: bool,
593 pub commit_delay: Option<u64>,
594 pub sender_client_id: Option<ClientId>,
595 pub has_epoch_changed: bool,
596 pub identity: WireIdentity,
597 pub buffered_messages: Option<Vec<BufferedDecryptedMessage>>,
598 pub crl_new_distribution_points: Option<Vec<String>>,
599}
600
601#[derive(Debug, uniffi::Record)]
602pub struct BufferedDecryptedMessage {
604 pub message: Option<Vec<u8>>,
605 pub proposals: Vec<ProposalBundle>,
606 pub is_active: bool,
607 pub commit_delay: Option<u64>,
608 pub sender_client_id: Option<ClientId>,
609 pub has_epoch_changed: bool,
610 pub identity: WireIdentity,
611 pub crl_new_distribution_points: Option<Vec<String>>,
612}
613
614impl TryFrom<MlsConversationDecryptMessage> for DecryptedMessage {
615 type Error = CoreCryptoError;
616
617 fn try_from(from: MlsConversationDecryptMessage) -> Result<Self, Self::Error> {
618 let proposals = from
619 .proposals
620 .into_iter()
621 .map(ProposalBundle::try_from)
622 .collect::<CoreCryptoResult<Vec<_>>>()?;
623
624 let buffered_messages = if let Some(bm) = from.buffered_messages {
625 let bm = bm
626 .into_iter()
627 .map(TryInto::try_into)
628 .collect::<CoreCryptoResult<Vec<_>>>()?;
629 Some(bm)
630 } else {
631 None
632 };
633
634 Ok(Self {
635 message: from.app_msg,
636 proposals,
637 is_active: from.is_active,
638 commit_delay: from.delay,
639 sender_client_id: from.sender_client_id.map(ClientId),
640 has_epoch_changed: from.has_epoch_changed,
641 identity: from.identity.into(),
642 buffered_messages,
643 crl_new_distribution_points: from.crl_new_distribution_points.into(),
644 })
645 }
646}
647
648impl TryFrom<MlsBufferedConversationDecryptMessage> for BufferedDecryptedMessage {
649 type Error = CoreCryptoError;
650
651 fn try_from(from: MlsBufferedConversationDecryptMessage) -> Result<Self, Self::Error> {
652 let proposals = from
653 .proposals
654 .into_iter()
655 .map(ProposalBundle::try_from)
656 .collect::<CoreCryptoResult<Vec<_>>>()?;
657
658 Ok(Self {
659 message: from.app_msg,
660 proposals,
661 is_active: from.is_active,
662 commit_delay: from.delay,
663 sender_client_id: from.sender_client_id.map(ClientId),
664 has_epoch_changed: from.has_epoch_changed,
665 identity: from.identity.into(),
666 crl_new_distribution_points: from.crl_new_distribution_points.into(),
667 })
668 }
669}
670
671#[derive(Debug, uniffi::Record)]
672pub struct WireIdentity {
674 pub client_id: String,
675 pub status: DeviceStatus,
676 pub thumbprint: String,
677 pub credential_type: MlsCredentialType,
678 pub x509_identity: Option<X509Identity>,
679}
680
681impl From<core_crypto::prelude::WireIdentity> for WireIdentity {
682 fn from(i: core_crypto::prelude::WireIdentity) -> Self {
683 Self {
684 client_id: i.client_id,
685 status: i.status.into(),
686 thumbprint: i.thumbprint,
687 credential_type: i.credential_type.into(),
688 x509_identity: i.x509_identity.map(Into::into),
689 }
690 }
691}
692
693#[derive(Debug, Copy, Clone, Eq, PartialEq, uniffi::Enum)]
694#[repr(u8)]
695pub enum DeviceStatus {
696 Valid = 1,
698 Expired = 2,
700 Revoked = 3,
702}
703
704impl From<core_crypto::prelude::DeviceStatus> for DeviceStatus {
705 fn from(value: core_crypto::prelude::DeviceStatus) -> Self {
706 match value {
707 core_crypto::prelude::DeviceStatus::Valid => Self::Valid,
708 core_crypto::prelude::DeviceStatus::Expired => Self::Expired,
709 core_crypto::prelude::DeviceStatus::Revoked => Self::Revoked,
710 }
711 }
712}
713
714#[derive(Debug, uniffi::Record)]
715pub struct X509Identity {
717 pub handle: String,
718 pub display_name: String,
719 pub domain: String,
720 pub certificate: String,
721 pub serial_number: String,
722 pub not_before: u64,
723 pub not_after: u64,
724}
725
726impl From<core_crypto::prelude::X509Identity> for X509Identity {
727 fn from(i: core_crypto::prelude::X509Identity) -> Self {
728 Self {
729 handle: i.handle,
730 display_name: i.display_name,
731 domain: i.domain,
732 certificate: i.certificate,
733 serial_number: i.serial_number,
734 not_before: i.not_before,
735 not_after: i.not_after,
736 }
737 }
738}
739
740#[derive(Debug, Clone, uniffi::Record)]
741pub struct ConversationConfiguration {
743 pub ciphersuite: Ciphersuite,
744 pub external_senders: Vec<Vec<u8>>,
745 pub custom: CustomConfiguration,
746}
747
748#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, uniffi::Enum)]
749#[repr(u8)]
750pub enum MlsWirePolicy {
751 #[default]
753 Plaintext = 1,
754 Ciphertext = 2,
756}
757
758impl From<core_crypto::prelude::MlsWirePolicy> for MlsWirePolicy {
759 fn from(value: core_crypto::prelude::MlsWirePolicy) -> Self {
760 match value {
761 core_crypto::prelude::MlsWirePolicy::Plaintext => Self::Plaintext,
762 core_crypto::prelude::MlsWirePolicy::Ciphertext => Self::Ciphertext,
763 }
764 }
765}
766
767impl From<MlsWirePolicy> for core_crypto::prelude::MlsWirePolicy {
768 fn from(value: MlsWirePolicy) -> core_crypto::prelude::MlsWirePolicy {
769 match value {
770 MlsWirePolicy::Plaintext => core_crypto::prelude::MlsWirePolicy::Plaintext,
771 MlsWirePolicy::Ciphertext => core_crypto::prelude::MlsWirePolicy::Ciphertext,
772 }
773 }
774}
775
776#[derive(Debug, Clone, uniffi::Record)]
777pub struct CustomConfiguration {
779 pub key_rotation_span: Option<std::time::Duration>,
780 pub wire_policy: Option<MlsWirePolicy>,
781}
782
783impl From<CustomConfiguration> for MlsCustomConfiguration {
784 fn from(cfg: CustomConfiguration) -> Self {
785 Self {
786 key_rotation_span: cfg.key_rotation_span,
787 wire_policy: cfg.wire_policy.unwrap_or_default().into(),
788 ..Default::default()
789 }
790 }
791}
792
793#[derive(Debug, Clone, uniffi::Record)]
794pub struct E2eiDumpedPkiEnv {
796 pub root_ca: String,
797 pub intermediates: Vec<String>,
798 pub crls: Vec<String>,
799}
800
801impl From<core_crypto::e2e_identity::E2eiDumpedPkiEnv> for E2eiDumpedPkiEnv {
802 fn from(value: core_crypto::e2e_identity::E2eiDumpedPkiEnv) -> Self {
803 Self {
804 root_ca: value.root_ca,
805 intermediates: value.intermediates,
806 crls: value.crls,
807 }
808 }
809}
810
811#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, uniffi::Enum)]
812#[repr(u8)]
813pub enum MlsCredentialType {
814 #[default]
816 Basic = 0x01,
817 X509 = 0x02,
819}
820
821impl From<core_crypto::prelude::MlsCredentialType> for MlsCredentialType {
822 fn from(value: core_crypto::prelude::MlsCredentialType) -> Self {
823 match value {
824 core_crypto::prelude::MlsCredentialType::Basic => Self::Basic,
825 core_crypto::prelude::MlsCredentialType::X509 => Self::X509,
826 }
827 }
828}
829
830impl From<MlsCredentialType> for core_crypto::prelude::MlsCredentialType {
831 fn from(value: MlsCredentialType) -> core_crypto::prelude::MlsCredentialType {
832 match value {
833 MlsCredentialType::Basic => core_crypto::prelude::MlsCredentialType::Basic,
834 MlsCredentialType::X509 => core_crypto::prelude::MlsCredentialType::X509,
835 }
836 }
837}
838
839#[derive(Debug)]
840struct CoreCryptoCallbacksWrapper(std::sync::Arc<dyn CoreCryptoCallbacks>);
841
842#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
843#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
844impl core_crypto::prelude::CoreCryptoCallbacks for CoreCryptoCallbacksWrapper {
845 async fn authorize(&self, conversation_id: Vec<u8>, client_id: core_crypto::prelude::ClientId) -> bool {
846 self.0.authorize(conversation_id, ClientId(client_id)).await
847 }
848 async fn user_authorize(
849 &self,
850 conversation_id: Vec<u8>,
851 external_client_id: core_crypto::prelude::ClientId,
852 existing_clients: Vec<core_crypto::prelude::ClientId>,
853 ) -> bool {
854 self.0
855 .user_authorize(
856 conversation_id,
857 ClientId(external_client_id),
858 existing_clients.into_iter().map(ClientId).collect(),
859 )
860 .await
861 }
862 async fn client_is_existing_group_user(
863 &self,
864 conversation_id: Vec<u8>,
865 client_id: core_crypto::prelude::ClientId,
866 existing_clients: Vec<core_crypto::prelude::ClientId>,
867 parent_conversation_clients: Option<Vec<core_crypto::prelude::ClientId>>,
868 ) -> bool {
869 self.0
870 .client_is_existing_group_user(
871 conversation_id,
872 ClientId(client_id),
873 existing_clients.into_iter().map(ClientId).collect(),
874 parent_conversation_clients.map(|pccs| pccs.into_iter().map(ClientId).collect()),
875 )
876 .await
877 }
878}
879
880#[uniffi::export(with_foreign)]
883#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
884#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
885pub trait CoreCryptoCallbacks: std::fmt::Debug + Send + Sync {
886 async fn authorize(&self, conversation_id: Vec<u8>, client_id: ClientId) -> bool;
887 async fn user_authorize(
888 &self,
889 conversation_id: Vec<u8>,
890 external_client_id: ClientId,
891 existing_clients: Vec<ClientId>,
892 ) -> bool;
893 async fn client_is_existing_group_user(
894 &self,
895 conversation_id: Vec<u8>,
896 client_id: ClientId,
897 existing_clients: Vec<ClientId>,
898 parent_conversation_clients: Option<Vec<ClientId>>,
899 ) -> bool;
900}
901
902static INIT_LOGGER: Once = Once::new();
903static LOGGER: LazyLock<ReloadLog<CoreCryptoLoggerWrapper>> = LazyLock::new(|| {
904 ReloadLog::new(CoreCryptoLoggerWrapper {
905 logger: Arc::new(DummyLogger {}),
906 })
907});
908
909#[uniffi::export]
913pub fn set_logger(logger: Arc<dyn CoreCryptoLogger>, level: CoreCryptoLogLevel) {
914 set_logger_only(logger);
915 set_max_log_level(level);
916}
917
918#[uniffi::export]
920pub fn set_logger_only(logger: Arc<dyn CoreCryptoLogger>) {
921 LOGGER.handle().replace(CoreCryptoLoggerWrapper { logger }).unwrap();
923
924 INIT_LOGGER.call_once(|| {
925 log::set_logger(LOGGER.deref()).unwrap();
926 log::set_max_level(LevelFilter::Warn);
927 });
928}
929
930#[uniffi::export]
932pub fn set_max_log_level(level: CoreCryptoLogLevel) {
933 log::set_max_level(level.into());
934}
935
936#[uniffi::export(with_foreign)]
938pub trait CoreCryptoLogger: std::fmt::Debug + Send + Sync {
939 fn log(&self, level: CoreCryptoLogLevel, message: String, context: Option<String>);
942}
943
944struct KeyValueVisitor<'kvs>(BTreeMap<Key<'kvs>, Value<'kvs>>);
945
946impl<'kvs> Visitor<'kvs> for KeyValueVisitor<'kvs> {
947 #[inline]
948 fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
949 self.0.insert(key, value);
950 Ok(())
951 }
952}
953#[derive(Debug)]
954struct DummyLogger {}
955
956impl CoreCryptoLogger for DummyLogger {
957 #[allow(unused_variables)]
958 fn log(&self, level: CoreCryptoLogLevel, json_msg: String, context: Option<String>) {}
959}
960
961#[derive(Clone)]
962struct CoreCryptoLoggerWrapper {
963 logger: std::sync::Arc<dyn CoreCryptoLogger>,
964}
965
966impl CoreCryptoLoggerWrapper {
967 fn adjusted_log_level(&self, metadata: &Metadata) -> Level {
968 match (metadata.level(), metadata.target()) {
969 (level, "refinery_core::traits") if level >= Level::Info => Level::Debug,
971 (level, "refinery_core::traits::sync") if level >= Level::Info => Level::Debug,
972 (level, _) => level,
973 }
974 }
975}
976
977impl log::Log for CoreCryptoLoggerWrapper {
978 fn enabled(&self, metadata: &Metadata) -> bool {
979 log::max_level() >= self.adjusted_log_level(metadata)
980 }
981
982 fn log(&self, record: &Record) {
983 let kvs = record.key_values();
984 let mut visitor = KeyValueVisitor(BTreeMap::new());
985 let _ = kvs.visit(&mut visitor);
986
987 if !self.enabled(record.metadata()) {
988 return;
989 }
990
991 let message = format!("{}", record.args());
992 let context = serde_json::to_string(&visitor.0).ok();
993 self.logger.log(
994 CoreCryptoLogLevel::from(&self.adjusted_log_level(record.metadata())),
995 message,
996 context,
997 );
998 }
999
1000 fn flush(&self) {}
1001}
1002
1003#[derive(Debug, Clone, Copy, uniffi::Enum)]
1005pub enum CoreCryptoLogLevel {
1006 Off,
1007 Trace,
1008 Debug,
1009 Info,
1010 Warn,
1011 Error,
1012}
1013
1014impl From<CoreCryptoLogLevel> for LevelFilter {
1015 fn from(value: CoreCryptoLogLevel) -> LevelFilter {
1016 match value {
1017 CoreCryptoLogLevel::Off => LevelFilter::Off,
1018 CoreCryptoLogLevel::Trace => LevelFilter::Trace,
1019 CoreCryptoLogLevel::Debug => LevelFilter::Debug,
1020 CoreCryptoLogLevel::Info => LevelFilter::Info,
1021 CoreCryptoLogLevel::Warn => LevelFilter::Warn,
1022 CoreCryptoLogLevel::Error => LevelFilter::Error,
1023 }
1024 }
1025}
1026
1027impl From<&Level> for CoreCryptoLogLevel {
1028 fn from(value: &Level) -> Self {
1029 match *value {
1030 Level::Warn => CoreCryptoLogLevel::Warn,
1031 Level::Error => CoreCryptoLogLevel::Error,
1032 Level::Info => CoreCryptoLogLevel::Info,
1033 Level::Debug => CoreCryptoLogLevel::Debug,
1034 Level::Trace => CoreCryptoLogLevel::Trace,
1035 }
1036 }
1037}
1038
1039#[derive(Debug, uniffi::Object)]
1040pub struct CoreCrypto {
1041 central: core_crypto::CoreCrypto,
1042 proteus_last_error_code: std::sync::atomic::AtomicU16,
1043}
1044
1045#[uniffi::export]
1046pub async fn core_crypto_new(
1048 path: String,
1049 key: String,
1050 client_id: ClientId,
1051 ciphersuites: Ciphersuites,
1052 nb_key_package: Option<u32>,
1053) -> CoreCryptoResult<CoreCrypto> {
1054 CoreCrypto::new(path, key, Some(client_id), Some(ciphersuites), nb_key_package).await
1055}
1056
1057#[uniffi::export]
1058pub async fn core_crypto_deferred_init(path: String, key: String) -> CoreCryptoResult<CoreCrypto> {
1061 CoreCrypto::new(path, key, None, None, None).await
1062}
1063
1064#[allow(dead_code, unused_variables)]
1065#[uniffi::export]
1066impl CoreCrypto {
1067 #[uniffi::constructor]
1068 pub async fn new(
1069 path: String,
1070 key: String,
1071 client_id: Option<ClientId>,
1072 ciphersuites: Option<Ciphersuites>,
1073 nb_key_package: Option<u32>,
1074 ) -> CoreCryptoResult<Self> {
1075 let nb_key_package = nb_key_package
1076 .map(usize::try_from)
1077 .transpose()
1078 .map_err(CryptoError::from)?;
1079 let configuration = MlsCentralConfiguration::try_new(
1080 path,
1081 key,
1082 client_id.map(|cid| cid.0.clone()),
1083 (&ciphersuites.unwrap_or_default()).into(),
1084 None,
1085 nb_key_package,
1086 )?;
1087
1088 let central = MlsCentral::try_new(configuration).await?;
1089 let central = core_crypto::CoreCrypto::from(central);
1090
1091 Ok(CoreCrypto {
1092 central,
1093 proteus_last_error_code: std::sync::atomic::AtomicU16::new(0),
1094 })
1095 }
1096
1097 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1099 pub async fn mls_init(
1100 &self,
1101 client_id: ClientId,
1102 ciphersuites: Ciphersuites,
1103 nb_key_package: Option<u32>,
1104 ) -> CoreCryptoResult<()> {
1105 self.deprecated_transaction(|context| async move {
1106 let nb_key_package = nb_key_package
1107 .map(usize::try_from)
1108 .transpose()
1109 .map_err(CryptoError::from)?;
1110 context
1111 .mls_init(
1112 ClientIdentifier::Basic(client_id.0),
1113 (&ciphersuites).into(),
1114 nb_key_package,
1115 )
1116 .await
1117 })
1118 .await
1119 }
1120
1121 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1123 pub async fn mls_generate_keypairs(&self, ciphersuites: Ciphersuites) -> CoreCryptoResult<Vec<ClientId>> {
1124 self.deprecated_transaction(|context| async move {
1125 context
1126 .mls_generate_keypairs((&ciphersuites).into())
1127 .await
1128 .map(|cids| cids.into_iter().map(ClientId).collect())
1129 })
1130 .await
1131 }
1132
1133 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1135 pub async fn mls_init_with_client_id(
1136 &self,
1137 client_id: ClientId,
1138 tmp_client_ids: Vec<ClientId>,
1139 ciphersuites: Ciphersuites,
1140 ) -> CoreCryptoResult<()> {
1141 self.deprecated_transaction(|context| async move {
1142 context
1143 .mls_init_with_client_id(
1144 client_id.0,
1145 tmp_client_ids.into_iter().map(|cid| cid.0).collect(),
1146 (&ciphersuites).into(),
1147 )
1148 .await
1149 })
1150 .await
1151 }
1152
1153 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1155 pub async fn restore_from_disk(&self) -> CoreCryptoResult<()> {
1156 cfg_if::cfg_if! {
1157 if #[cfg(feature = "proteus")] {
1158 self.deprecated_transaction(|context| async move {
1159 context.proteus_reload_sessions().await.inspect_err(|e|{
1160 let errcode = e.proteus_error_code();
1161 if errcode.is_some() {
1162 self.proteus_last_error_code.store(errcode.unwrap_or_default(), std::sync::atomic::Ordering::SeqCst);
1163 }
1164 })?;
1165 Ok(())
1166 }).await?
1167 }
1168 }
1169 Ok(())
1170 }
1171
1172 pub async fn unload(self: std::sync::Arc<Self>) -> CoreCryptoResult<()> {
1174 if let Some(cc) = std::sync::Arc::into_inner(self) {
1175 cc.central.take().close().await?;
1176 Ok(())
1177 } else {
1178 Err(CryptoError::LockPoisonError.into())
1179 }
1180 }
1181
1182 pub async fn wipe(self: std::sync::Arc<Self>) -> CoreCryptoResult<()> {
1184 if let Some(cc) = std::sync::Arc::into_inner(self) {
1185 cc.central.take().wipe().await?;
1186 Ok(())
1187 } else {
1188 Err(CryptoError::LockPoisonError.into())
1189 }
1190 }
1191
1192 pub async fn set_callbacks(&self, callbacks: std::sync::Arc<dyn CoreCryptoCallbacks>) -> CoreCryptoResult<()> {
1194 self.central
1195 .callbacks(std::sync::Arc::new(CoreCryptoCallbacksWrapper(callbacks)))
1196 .await;
1197 Ok(())
1198 }
1199
1200 pub async fn client_public_key(
1202 &self,
1203 ciphersuite: Ciphersuite,
1204 credential_type: MlsCredentialType,
1205 ) -> CoreCryptoResult<Vec<u8>> {
1206 Ok(self
1207 .central
1208 .client_public_key(ciphersuite.into(), credential_type.into())
1209 .await?)
1210 }
1211
1212 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1214 pub async fn client_keypackages(
1215 &self,
1216 ciphersuite: Ciphersuite,
1217 credential_type: MlsCredentialType,
1218 amount_requested: u32,
1219 ) -> CoreCryptoResult<Vec<Vec<u8>>> {
1220 self.deprecated_transaction(|context| async move {
1221 let kps = context
1222 .get_or_create_client_keypackages(ciphersuite.into(), credential_type.into(), amount_requested as usize)
1223 .await?;
1224 kps.into_iter()
1225 .map(|kp| {
1226 kp.tls_serialize_detached()
1227 .map_err(core_crypto::MlsError::from)
1228 .map_err(CryptoError::from)
1229 })
1230 .collect::<CryptoResult<Vec<Vec<u8>>>>()
1231 })
1232 .await
1233 }
1234
1235 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1237 pub async fn client_valid_keypackages_count(
1238 &self,
1239 ciphersuite: Ciphersuite,
1240 credential_type: MlsCredentialType,
1241 ) -> CoreCryptoResult<u64> {
1242 self.deprecated_transaction(|context| async move {
1243 let count = context
1244 .client_valid_key_packages_count(ciphersuite.into(), credential_type.into())
1245 .await?;
1246 Ok(count.try_into().unwrap_or(0))
1247 })
1248 .await
1249 }
1250
1251 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1253 pub async fn delete_keypackages(&self, refs: Vec<Vec<u8>>) -> CoreCryptoResult<()> {
1254 let refs = refs
1255 .into_iter()
1256 .map(|r| KeyPackageRef::from_slice(&r))
1257 .collect::<Vec<_>>();
1258
1259 self.deprecated_transaction(|context| async move { context.delete_keypackages(&refs[..]).await })
1260 .await
1261 }
1262
1263 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1265 pub async fn create_conversation(
1266 &self,
1267 conversation_id: Vec<u8>,
1268 creator_credential_type: MlsCredentialType,
1269 config: ConversationConfiguration,
1270 ) -> CoreCryptoResult<()> {
1271 let mut lower_cfg = MlsConversationConfiguration {
1272 custom: config.custom.into(),
1273 ciphersuite: config.ciphersuite.into(),
1274 ..Default::default()
1275 };
1276
1277 self.deprecated_transaction(|context| async move {
1278 context
1279 .set_raw_external_senders(&mut lower_cfg, config.external_senders)
1280 .await?;
1281 context
1282 .new_conversation(&conversation_id, creator_credential_type.into(), lower_cfg)
1283 .await
1284 })
1285 .await
1286 }
1287
1288 pub async fn conversation_epoch(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<u64> {
1290 Ok(self.central.conversation_epoch(&conversation_id).await?)
1291 }
1292
1293 pub async fn conversation_ciphersuite(&self, conversation_id: &ConversationId) -> CoreCryptoResult<Ciphersuite> {
1295 let cs = self.central.conversation_ciphersuite(conversation_id).await?;
1296 Ok(Ciphersuite::from(core_crypto::prelude::CiphersuiteName::from(cs)))
1297 }
1298
1299 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1301 pub async fn process_welcome_message(
1302 &self,
1303 welcome_message: Vec<u8>,
1304 custom_configuration: CustomConfiguration,
1305 ) -> CoreCryptoResult<WelcomeBundle> {
1306 self.deprecated_transaction(|context| async move {
1307 Ok(context
1308 .process_raw_welcome_message(welcome_message, custom_configuration.into())
1309 .await?
1310 .into())
1311 })
1312 .await
1313 }
1314
1315 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1317 pub async fn add_clients_to_conversation(
1318 &self,
1319 conversation_id: Vec<u8>,
1320 key_packages: Vec<Vec<u8>>,
1321 ) -> CoreCryptoResult<MemberAddedMessages> {
1322 let key_packages = key_packages
1323 .into_iter()
1324 .map(|kp| {
1325 KeyPackageIn::tls_deserialize(&mut kp.as_slice())
1326 .map_err(|e| CoreCryptoError::from(CryptoError::MlsError(e.into())))
1327 })
1328 .collect::<CoreCryptoResult<Vec<_>>>()?;
1329
1330 self.deprecated_transaction(|context| async move {
1331 context
1332 .add_members_to_conversation(&conversation_id, key_packages)
1333 .await
1334 })
1335 .await?
1336 .try_into()
1337 }
1338
1339 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1341 pub async fn remove_clients_from_conversation(
1342 &self,
1343 conversation_id: Vec<u8>,
1344 clients: Vec<ClientId>,
1345 ) -> CoreCryptoResult<CommitBundle> {
1346 let clients: Vec<core_crypto::prelude::ClientId> = clients.into_iter().map(|c| c.0).collect();
1347 self.deprecated_transaction(|context| async move {
1348 context
1349 .remove_members_from_conversation(&conversation_id, &clients)
1350 .await
1351 })
1352 .await?
1353 .try_into()
1354 }
1355
1356 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1358 pub async fn mark_conversation_as_child_of(&self, child_id: Vec<u8>, parent_id: Vec<u8>) -> CoreCryptoResult<()> {
1359 self.deprecated_transaction(|context| async move {
1360 context.mark_conversation_as_child_of(&child_id, &parent_id).await
1361 })
1362 .await
1363 }
1364
1365 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1367 pub async fn update_keying_material(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<CommitBundle> {
1368 self.deprecated_transaction(|context| async move { context.update_keying_material(&conversation_id).await })
1369 .await?
1370 .try_into()
1371 }
1372
1373 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1375 pub async fn commit_pending_proposals(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<Option<CommitBundle>> {
1376 self.deprecated_transaction(|context| async move { context.commit_pending_proposals(&conversation_id).await })
1377 .await
1378 .transpose()
1379 .map(|r| r?.try_into())
1380 .transpose()
1381 }
1382
1383 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1385 pub async fn wipe_conversation(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<()> {
1386 self.deprecated_transaction(|context| async move { context.wipe_conversation(&conversation_id).await })
1387 .await
1388 }
1389
1390 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1392 pub async fn decrypt_message(
1393 &self,
1394 conversation_id: Vec<u8>,
1395 payload: Vec<u8>,
1396 ) -> CoreCryptoResult<DecryptedMessage> {
1397 self.deprecated_transaction(|context| async move { context.decrypt_message(&conversation_id, payload).await })
1398 .await?
1399 .try_into()
1400 }
1401
1402 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1404 pub async fn encrypt_message(&self, conversation_id: Vec<u8>, message: Vec<u8>) -> CoreCryptoResult<Vec<u8>> {
1405 self.deprecated_transaction(|context| async move { context.encrypt_message(&conversation_id, message).await })
1406 .await
1407 }
1408
1409 pub async fn conversation_exists(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<bool> {
1411 Ok(self.central.conversation_exists(&conversation_id).await?)
1412 }
1413
1414 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1416 pub async fn new_add_proposal(
1417 &self,
1418 conversation_id: Vec<u8>,
1419 keypackage: Vec<u8>,
1420 ) -> CoreCryptoResult<ProposalBundle> {
1421 let kp = KeyPackageIn::tls_deserialize(&mut keypackage.as_slice())
1422 .map_err(core_crypto::MlsError::from)
1423 .map_err(CryptoError::from)?;
1424 self.deprecated_transaction(
1425 |context| async move { context.new_add_proposal(&conversation_id, kp.into()).await },
1426 )
1427 .await?
1428 .try_into()
1429 }
1430
1431 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1433 pub async fn new_update_proposal(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<ProposalBundle> {
1434 self.deprecated_transaction(|context| async move { context.new_update_proposal(&conversation_id).await })
1435 .await?
1436 .try_into()
1437 }
1438
1439 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1441 pub async fn new_remove_proposal(
1442 &self,
1443 conversation_id: Vec<u8>,
1444 client_id: ClientId,
1445 ) -> CoreCryptoResult<ProposalBundle> {
1446 self.deprecated_transaction(|context| async move {
1447 context.new_remove_proposal(&conversation_id, client_id.0).await
1448 })
1449 .await?
1450 .try_into()
1451 }
1452
1453 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1455 pub async fn new_external_add_proposal(
1456 &self,
1457 conversation_id: Vec<u8>,
1458 epoch: u64,
1459 ciphersuite: Ciphersuite,
1460 credential_type: MlsCredentialType,
1461 ) -> CoreCryptoResult<Vec<u8>> {
1462 self.deprecated_transaction(|context| async move {
1463 context
1464 .new_external_add_proposal(
1465 conversation_id,
1466 epoch.into(),
1467 ciphersuite.into(),
1468 credential_type.into(),
1469 )
1470 .await?
1471 .to_bytes()
1472 .map_err(core_crypto::MlsError::from)
1473 .map_err(CryptoError::from)
1474 })
1475 .await
1476 }
1477
1478 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1480 pub async fn join_by_external_commit(
1481 &self,
1482 group_info: Vec<u8>,
1483 custom_configuration: CustomConfiguration,
1484 credential_type: MlsCredentialType,
1485 ) -> CoreCryptoResult<ConversationInitBundle> {
1486 let group_info = VerifiableGroupInfo::tls_deserialize(&mut group_info.as_slice())
1487 .map_err(core_crypto::MlsError::from)
1488 .map_err(CryptoError::from)?;
1489 self.deprecated_transaction(|context| async move {
1490 context
1491 .join_by_external_commit(group_info, custom_configuration.into(), credential_type.into())
1492 .await
1493 })
1494 .await?
1495 .try_into()
1496 }
1497
1498 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1500 pub async fn merge_pending_group_from_external_commit(
1501 &self,
1502 conversation_id: Vec<u8>,
1503 ) -> CoreCryptoResult<Option<Vec<BufferedDecryptedMessage>>> {
1504 let maybe_buffered_messages = self
1505 .deprecated_transaction(|context| async move {
1506 context.merge_pending_group_from_external_commit(&conversation_id).await
1507 })
1508 .await?;
1509 let Some(buffered_messages) = maybe_buffered_messages else {
1510 return Ok(None);
1511 };
1512 Ok(Some(
1513 buffered_messages
1514 .into_iter()
1515 .map(TryInto::try_into)
1516 .collect::<CoreCryptoResult<Vec<_>>>()?,
1517 ))
1518 }
1519
1520 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1522 pub async fn clear_pending_group_from_external_commit(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<()> {
1523 self.deprecated_transaction(|context| async move {
1524 context.clear_pending_group_from_external_commit(&conversation_id).await
1525 })
1526 .await
1527 }
1528
1529 pub async fn random_bytes(&self, len: u32) -> CoreCryptoResult<Vec<u8>> {
1531 Ok(self.central.random_bytes(len.try_into().map_err(CryptoError::from)?)?)
1532 }
1533
1534 pub async fn reseed_rng(&self, seed: Vec<u8>) -> CoreCryptoResult<()> {
1536 let seed = EntropySeed::try_from_slice(&seed).map_err(CryptoError::from)?;
1537 self.central.reseed(Some(seed)).await?;
1538
1539 Ok(())
1540 }
1541
1542 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1544 pub async fn commit_accepted(
1545 &self,
1546 conversation_id: Vec<u8>,
1547 ) -> CoreCryptoResult<Option<Vec<BufferedDecryptedMessage>>> {
1548 let maybe_buffered_messages = self
1549 .deprecated_transaction(|context| async move { context.commit_accepted(&conversation_id).await })
1550 .await?;
1551 let Some(buffered_messages) = maybe_buffered_messages else {
1552 return Ok(None);
1553 };
1554 Ok(Some(
1555 buffered_messages
1556 .into_iter()
1557 .map(TryInto::try_into)
1558 .collect::<CoreCryptoResult<Vec<_>>>()?,
1559 ))
1560 }
1561
1562 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1564 pub async fn clear_pending_proposal(
1565 &self,
1566 conversation_id: Vec<u8>,
1567 proposal_ref: Vec<u8>,
1568 ) -> CoreCryptoResult<()> {
1569 self.deprecated_transaction(|context| async move {
1570 context
1571 .clear_pending_proposal(&conversation_id, proposal_ref.into())
1572 .await
1573 })
1574 .await
1575 }
1576
1577 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1579 pub async fn clear_pending_commit(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<()> {
1580 self.deprecated_transaction(|context| async move { context.clear_pending_commit(&conversation_id).await })
1581 .await
1582 }
1583
1584 pub async fn get_client_ids(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<Vec<ClientId>> {
1586 Ok(self
1587 .central
1588 .get_client_ids(&conversation_id)
1589 .await
1590 .map(|cids| cids.into_iter().map(ClientId).collect())?)
1591 }
1592
1593 pub async fn export_secret_key(&self, conversation_id: Vec<u8>, key_length: u32) -> CoreCryptoResult<Vec<u8>> {
1595 Ok(self
1596 .central
1597 .export_secret_key(&conversation_id, key_length as usize)
1598 .await?)
1599 }
1600
1601 pub async fn get_external_sender(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<Vec<u8>> {
1603 Ok(self.central.get_external_sender(&conversation_id).await?)
1604 }
1605}
1606
1607#[derive(Debug, Copy, Clone, uniffi::Enum)]
1608#[repr(u8)]
1609pub enum E2eiConversationState {
1610 Verified = 1,
1612 NotVerified,
1614 NotEnabled,
1616}
1617
1618impl From<core_crypto::prelude::E2eiConversationState> for E2eiConversationState {
1619 fn from(value: core_crypto::prelude::E2eiConversationState) -> Self {
1620 match value {
1621 core_crypto::prelude::E2eiConversationState::Verified => Self::Verified,
1622 core_crypto::prelude::E2eiConversationState::NotVerified => Self::NotVerified,
1623 core_crypto::prelude::E2eiConversationState::NotEnabled => Self::NotEnabled,
1624 }
1625 }
1626}
1627
1628#[cfg_attr(not(feature = "proteus"), allow(unused_variables))]
1629#[uniffi::export]
1630impl CoreCrypto {
1631 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1633 pub async fn proteus_init(&self) -> CoreCryptoResult<()> {
1634 proteus_impl! { self.proteus_last_error_code => {
1635 self.deprecated_transaction(|context| async move {
1636 context.proteus_init().await?;
1637 Ok(())
1638 }).await
1639 }}
1640 }
1641
1642 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1644 pub async fn proteus_session_from_prekey(&self, session_id: String, prekey: Vec<u8>) -> CoreCryptoResult<()> {
1645 proteus_impl! { self.proteus_last_error_code => {
1646 self.deprecated_transaction(|context| async move {
1647 context.proteus_session_from_prekey(&session_id, &prekey).await?;
1648 Ok(())
1649 }).await
1650 }}
1651 }
1652
1653 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1655 pub async fn proteus_session_from_message(
1656 &self,
1657 session_id: String,
1658 envelope: Vec<u8>,
1659 ) -> CoreCryptoResult<Vec<u8>> {
1660 proteus_impl! { self.proteus_last_error_code => {
1661 self.deprecated_transaction(|context| async move {
1662 let (_, payload) = context
1663 .proteus_session_from_message(&session_id, &envelope).await?;
1664 Ok(payload)
1665 }).await
1666 }}
1667 }
1668
1669 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1672 pub async fn proteus_session_save(&self, session_id: String) -> CoreCryptoResult<()> {
1673 proteus_impl! { self.proteus_last_error_code => {
1674 self.deprecated_transaction(|context| async move {
1675 context.proteus_session_save(&session_id).await
1676 }).await
1677 }}
1678 }
1679
1680 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1682 pub async fn proteus_session_delete(&self, session_id: String) -> CoreCryptoResult<()> {
1683 proteus_impl! { self.proteus_last_error_code => {
1684 self.deprecated_transaction(|context| async move {
1685 context.proteus_session_delete(&session_id).await
1686 }).await
1687 }}
1688 }
1689
1690 pub async fn proteus_session_exists(&self, session_id: String) -> CoreCryptoResult<bool> {
1692 proteus_impl! { self.proteus_last_error_code => {
1693 Ok(self.central
1694 .proteus_session_exists(&session_id)
1695 .await?)
1696 }}
1697 }
1698
1699 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1701 pub async fn proteus_decrypt(&self, session_id: String, ciphertext: Vec<u8>) -> CoreCryptoResult<Vec<u8>> {
1702 proteus_impl! { self.proteus_last_error_code => {
1703 self.deprecated_transaction(|context| async move {
1704 context.proteus_decrypt(&session_id, &ciphertext).await
1705 }).await
1706 }}
1707 }
1708
1709 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1711 pub async fn proteus_encrypt(&self, session_id: String, plaintext: Vec<u8>) -> CoreCryptoResult<Vec<u8>> {
1712 proteus_impl! { self.proteus_last_error_code => {
1713 self.deprecated_transaction(|context| async move {
1714 context.proteus_encrypt(&session_id, &plaintext).await
1715 }).await
1716 }}
1717 }
1718
1719 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1721 pub async fn proteus_encrypt_batched(
1722 &self,
1723 sessions: Vec<String>,
1724 plaintext: Vec<u8>,
1725 ) -> CoreCryptoResult<std::collections::HashMap<String, Vec<u8>>> {
1726 proteus_impl! { self.proteus_last_error_code => {
1727 self.deprecated_transaction(|context| async move {
1728 context.proteus_encrypt_batched(&sessions, &plaintext).await
1729 }).await
1730 }}
1731 }
1732
1733 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1735 pub async fn proteus_new_prekey(&self, prekey_id: u16) -> CoreCryptoResult<Vec<u8>> {
1736 proteus_impl! { self.proteus_last_error_code => {
1737 self.deprecated_transaction(|context| async move {
1738 context.proteus_new_prekey(prekey_id).await
1739 }).await
1740 }}
1741 }
1742
1743 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1745 pub async fn proteus_new_prekey_auto(&self) -> CoreCryptoResult<ProteusAutoPrekeyBundle> {
1746 proteus_impl! { self.proteus_last_error_code => {
1747 self.deprecated_transaction(|context| async move {
1748 let (id, pkb) = context
1749 .proteus_new_prekey_auto()
1750 .await?;
1751 Ok(ProteusAutoPrekeyBundle { id, pkb })
1752 }).await
1753 }}
1754 }
1755
1756 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1758 pub async fn proteus_last_resort_prekey(&self) -> CoreCryptoResult<Vec<u8>> {
1759 proteus_impl! { self.proteus_last_error_code => {
1760 self.deprecated_transaction(|context| async move {
1761 context.proteus_last_resort_prekey().await}).await
1762 }}
1763 }
1764
1765 pub fn proteus_last_resort_prekey_id(&self) -> CoreCryptoResult<u16> {
1767 proteus_impl!({ Ok(core_crypto::CoreCrypto::proteus_last_resort_prekey_id()) })
1768 }
1769
1770 pub async fn proteus_fingerprint(&self) -> CoreCryptoResult<String> {
1772 proteus_impl! { self.proteus_last_error_code => {
1773 Ok(self.central
1774 .proteus_fingerprint().await?)
1775 }}
1776 }
1777
1778 pub async fn proteus_fingerprint_local(&self, session_id: String) -> CoreCryptoResult<String> {
1780 proteus_impl! { self.proteus_last_error_code => {
1781 Ok(self.central
1782 .proteus_fingerprint_local(&session_id)
1783 .await?)
1784 }}
1785 }
1786
1787 pub async fn proteus_fingerprint_remote(&self, session_id: String) -> CoreCryptoResult<String> {
1789 proteus_impl! { self.proteus_last_error_code => {
1790 Ok(self.central
1791 .proteus_fingerprint_remote(&session_id)
1792 .await?)
1793 }}
1794 }
1795
1796 pub fn proteus_fingerprint_prekeybundle(&self, prekey: Vec<u8>) -> CoreCryptoResult<String> {
1799 proteus_impl!({ Ok(core_crypto::proteus::ProteusCentral::fingerprint_prekeybundle(&prekey)?) })
1800 }
1801
1802 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1804 pub async fn proteus_cryptobox_migrate(&self, path: String) -> CoreCryptoResult<()> {
1805 proteus_impl! { self.proteus_last_error_code => {
1806 self.deprecated_transaction(|context| async move {
1807 context.proteus_cryptobox_migrate(&path).await
1808 }).await
1809 }}
1810 }
1811
1812 pub fn proteus_last_error_code(&self) -> Option<u16> {
1816 let raw_error_code = self
1817 .proteus_last_error_code
1818 .swap(0, std::sync::atomic::Ordering::SeqCst);
1819 (raw_error_code != 0).then_some(raw_error_code)
1820 }
1821}
1822
1823#[allow(dead_code, unused_variables)]
1825#[uniffi::export]
1826impl CoreCrypto {
1827 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1829 pub async fn e2ei_new_enrollment(
1830 &self,
1831 client_id: String,
1832 display_name: String,
1833 handle: String,
1834 team: Option<String>,
1835 expiry_sec: u32,
1836 ciphersuite: Ciphersuite,
1837 ) -> CoreCryptoResult<E2eiEnrollment> {
1838 self.deprecated_transaction(|context| async move {
1839 context
1840 .e2ei_new_enrollment(
1841 client_id.into_bytes().into(),
1842 display_name,
1843 handle,
1844 team,
1845 expiry_sec,
1846 ciphersuite.into(),
1847 )
1848 .await
1849 .map(async_lock::RwLock::new)
1850 .map(std::sync::Arc::new)
1851 .map(E2eiEnrollment)
1852 })
1853 .await
1854 }
1855
1856 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1858 pub async fn e2ei_new_activation_enrollment(
1859 &self,
1860 display_name: String,
1861 handle: String,
1862 team: Option<String>,
1863 expiry_sec: u32,
1864 ciphersuite: Ciphersuite,
1865 ) -> CoreCryptoResult<E2eiEnrollment> {
1866 self.deprecated_transaction(|context| async move {
1867 context
1868 .e2ei_new_activation_enrollment(display_name, handle, team, expiry_sec, ciphersuite.into())
1869 .await
1870 .map(async_lock::RwLock::new)
1871 .map(std::sync::Arc::new)
1872 .map(E2eiEnrollment)
1873 })
1874 .await
1875 }
1876
1877 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1879 pub async fn e2ei_new_rotate_enrollment(
1880 &self,
1881 display_name: Option<String>,
1882 handle: Option<String>,
1883 team: Option<String>,
1884 expiry_sec: u32,
1885 ciphersuite: Ciphersuite,
1886 ) -> CoreCryptoResult<E2eiEnrollment> {
1887 self.deprecated_transaction(|context| async move {
1888 context
1889 .e2ei_new_rotate_enrollment(display_name, handle, team, expiry_sec, ciphersuite.into())
1890 .await
1891 .map(async_lock::RwLock::new)
1892 .map(std::sync::Arc::new)
1893 .map(E2eiEnrollment)
1894 })
1895 .await
1896 }
1897
1898 pub async fn e2ei_dump_pki_env(&self) -> CoreCryptoResult<Option<E2eiDumpedPkiEnv>> {
1899 Ok(self.central.e2ei_dump_pki_env().await?.map(Into::into))
1900 }
1901
1902 pub async fn e2ei_is_pki_env_setup(&self) -> bool {
1904 self.central.e2ei_is_pki_env_setup().await
1905 }
1906
1907 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1909 pub async fn e2ei_register_acme_ca(&self, trust_anchor_pem: String) -> CoreCryptoResult<()> {
1910 self.deprecated_transaction(|context| async move { context.e2ei_register_acme_ca(trust_anchor_pem).await })
1911 .await
1912 }
1913
1914 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1916 pub async fn e2ei_register_intermediate_ca(&self, cert_pem: String) -> CoreCryptoResult<Option<Vec<String>>> {
1917 self.deprecated_transaction(|context| async move {
1918 Ok(context.e2ei_register_intermediate_ca_pem(cert_pem).await?.into())
1919 })
1920 .await
1921 }
1922
1923 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1925 pub async fn e2ei_register_crl(&self, crl_dp: String, crl_der: Vec<u8>) -> CoreCryptoResult<CrlRegistration> {
1926 self.deprecated_transaction(
1927 |context| async move { Ok(context.e2ei_register_crl(crl_dp, crl_der).await?.into()) },
1928 )
1929 .await
1930 }
1931
1932 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1934 pub async fn e2ei_mls_init_only(
1935 &self,
1936 enrollment: std::sync::Arc<E2eiEnrollment>,
1937 certificate_chain: String,
1938 nb_key_package: Option<u32>,
1939 ) -> CoreCryptoResult<Option<Vec<String>>> {
1940 let nb_key_package = nb_key_package
1941 .map(usize::try_from)
1942 .transpose()
1943 .map_err(CryptoError::from)?;
1944
1945 self.deprecated_transaction(|context| async move {
1946 Ok(context
1947 .e2ei_mls_init_only(
1948 enrollment.0.write().await.deref_mut(),
1949 certificate_chain,
1950 nb_key_package,
1951 )
1952 .await?
1953 .into())
1954 })
1955 .await
1956 }
1957
1958 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1960 pub async fn e2ei_rotate(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<CommitBundle> {
1961 self.deprecated_transaction(|context| async move { context.e2ei_rotate(&conversation_id, None).await })
1962 .await?
1963 .try_into()
1964 }
1965
1966 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1968 pub async fn e2ei_rotate_all(
1969 &self,
1970 enrollment: std::sync::Arc<E2eiEnrollment>,
1971 certificate_chain: String,
1972 new_key_packages_count: u32,
1973 ) -> CoreCryptoResult<RotateBundle> {
1974 self.deprecated_transaction(|context| async move {
1975 context
1976 .e2ei_rotate_all(
1977 enrollment.0.write().await.deref_mut(),
1978 certificate_chain,
1979 new_key_packages_count as usize,
1980 )
1981 .await
1982 })
1983 .await?
1984 .try_into()
1985 }
1986
1987 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
1989 pub async fn e2ei_enrollment_stash(&self, enrollment: std::sync::Arc<E2eiEnrollment>) -> CoreCryptoResult<Vec<u8>> {
1990 let enrollment = std::sync::Arc::into_inner(enrollment).ok_or_else(|| CryptoError::LockPoisonError)?;
1991 let enrollment = std::sync::Arc::into_inner(enrollment.0)
1992 .ok_or_else(|| CryptoError::LockPoisonError)?
1993 .into_inner();
1994
1995 self.deprecated_transaction(|context| async move { context.e2ei_enrollment_stash(enrollment).await })
1996 .await
1997 }
1998
1999 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
2001 pub async fn e2ei_enrollment_stash_pop(&self, handle: Vec<u8>) -> CoreCryptoResult<E2eiEnrollment> {
2002 self.deprecated_transaction(|context| async move {
2003 context
2004 .e2ei_enrollment_stash_pop(handle)
2005 .await
2006 .map(async_lock::RwLock::new)
2007 .map(std::sync::Arc::new)
2008 .map(E2eiEnrollment)
2009 })
2010 .await
2011 }
2012
2013 #[deprecated = "Please create a transaction in Core Crypto and call this method from it."]
2015 pub async fn e2ei_conversation_state(&self, conversation_id: Vec<u8>) -> CoreCryptoResult<E2eiConversationState> {
2016 self.deprecated_transaction(|context| async move {
2017 context.e2ei_conversation_state(&conversation_id).await.map(Into::into)
2018 })
2019 .await
2020 }
2021
2022 pub async fn e2ei_is_enabled(&self, ciphersuite: Ciphersuite) -> CoreCryptoResult<bool> {
2024 let sc = core_crypto::prelude::MlsCiphersuite::from(core_crypto::prelude::CiphersuiteName::from(ciphersuite))
2025 .signature_algorithm();
2026 Ok(self.central.e2ei_is_enabled(sc).await?)
2027 }
2028
2029 pub async fn get_device_identities(
2031 &self,
2032 conversation_id: Vec<u8>,
2033 device_ids: Vec<ClientId>,
2034 ) -> CoreCryptoResult<Vec<WireIdentity>> {
2035 let device_ids = device_ids.into_iter().map(|cid| cid.0).collect::<Vec<_>>();
2036 Ok(self
2037 .central
2038 .get_device_identities(&conversation_id, &device_ids[..])
2039 .await?
2040 .into_iter()
2041 .map(Into::into)
2042 .collect::<Vec<_>>())
2043 }
2044
2045 pub async fn get_user_identities(
2047 &self,
2048 conversation_id: Vec<u8>,
2049 user_ids: Vec<String>,
2050 ) -> CoreCryptoResult<HashMap<String, Vec<WireIdentity>>> {
2051 Ok(self
2052 .central
2053 .get_user_identities(&conversation_id, &user_ids[..])
2054 .await?
2055 .into_iter()
2056 .map(|(k, v)| (k, v.into_iter().map(Into::into).collect()))
2057 .collect::<HashMap<String, Vec<WireIdentity>>>())
2058 }
2059
2060 pub async fn get_credential_in_use(
2062 &self,
2063 group_info: Vec<u8>,
2064 credential_type: MlsCredentialType,
2065 ) -> CoreCryptoResult<E2eiConversationState> {
2066 let group_info = VerifiableGroupInfo::tls_deserialize(&mut group_info.as_slice())
2067 .map_err(core_crypto::MlsError::from)
2068 .map_err(CryptoError::from)?;
2069 Ok(self
2070 .central
2071 .get_credential_in_use(group_info, credential_type.into())
2072 .await?
2073 .into())
2074 }
2075}
2076
2077#[derive(Debug, uniffi::Object)]
2078pub struct E2eiEnrollment(std::sync::Arc<async_lock::RwLock<core_crypto::prelude::E2eiEnrollment>>);
2080
2081#[uniffi::export]
2082impl E2eiEnrollment {
2083 pub async fn directory_response(&self, directory: Vec<u8>) -> CoreCryptoResult<AcmeDirectory> {
2085 Ok(self
2086 .0
2087 .write()
2088 .await
2089 .directory_response(directory)
2090 .map(AcmeDirectory::from)?)
2091 }
2092
2093 pub async fn new_account_request(&self, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2095 Ok(self.0.read().await.new_account_request(previous_nonce)?)
2096 }
2097
2098 pub async fn new_account_response(&self, account: Vec<u8>) -> CoreCryptoResult<()> {
2100 Ok(self.0.write().await.new_account_response(account)?)
2101 }
2102
2103 #[allow(clippy::too_many_arguments)]
2105 pub async fn new_order_request(&self, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2106 Ok(self.0.read().await.new_order_request(previous_nonce)?)
2107 }
2108
2109 pub async fn new_order_response(&self, order: Vec<u8>) -> CoreCryptoResult<NewAcmeOrder> {
2111 Ok(self.0.read().await.new_order_response(order)?.into())
2112 }
2113
2114 pub async fn new_authz_request(&self, url: String, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2116 Ok(self.0.read().await.new_authz_request(url, previous_nonce)?)
2117 }
2118
2119 pub async fn new_authz_response(&self, authz: Vec<u8>) -> CoreCryptoResult<NewAcmeAuthz> {
2121 Ok(self.0.write().await.new_authz_response(authz)?.into())
2122 }
2123
2124 #[allow(clippy::too_many_arguments)]
2125 pub async fn create_dpop_token(&self, expiry_secs: u32, backend_nonce: String) -> CoreCryptoResult<String> {
2127 Ok(self.0.read().await.create_dpop_token(expiry_secs, backend_nonce)?)
2128 }
2129
2130 pub async fn new_dpop_challenge_request(
2132 &self,
2133 access_token: String,
2134 previous_nonce: String,
2135 ) -> CoreCryptoResult<Vec<u8>> {
2136 Ok(self
2137 .0
2138 .read()
2139 .await
2140 .new_dpop_challenge_request(access_token, previous_nonce)?)
2141 }
2142
2143 pub async fn new_dpop_challenge_response(&self, challenge: Vec<u8>) -> CoreCryptoResult<()> {
2145 Ok(self.0.read().await.new_dpop_challenge_response(challenge)?)
2146 }
2147
2148 pub async fn new_oidc_challenge_request(
2150 &self,
2151 id_token: String,
2152 refresh_token: String,
2153 previous_nonce: String,
2154 ) -> CoreCryptoResult<Vec<u8>> {
2155 Ok(self
2156 .0
2157 .write()
2158 .await
2159 .new_oidc_challenge_request(id_token, refresh_token, previous_nonce)?)
2160 }
2161
2162 #[deprecated = "Please create a transaction in Core Crypto and call Self::context_newoidc_challenge_response."]
2164 pub async fn new_oidc_challenge_response(
2165 &self,
2166 cc: std::sync::Arc<CoreCrypto>,
2167 challenge: Vec<u8>,
2168 ) -> CoreCryptoResult<()> {
2169 cc.deprecated_transaction(|context| async move {
2170 self.0
2171 .write()
2172 .await
2173 .new_oidc_challenge_response(&context.mls_provider().await?, challenge)
2174 .await
2175 .map_err(Into::into)
2176 })
2177 .await
2178 }
2179
2180 pub async fn context_new_oidc_challenge_response(
2182 &self,
2183 cc: std::sync::Arc<CoreCryptoContext>,
2184 challenge: Vec<u8>,
2185 ) -> CoreCryptoResult<()> {
2186 self.0
2187 .write()
2188 .await
2189 .new_oidc_challenge_response(&cc.context.mls_provider().await?, challenge)
2190 .await?;
2191 Ok(())
2192 }
2193
2194 pub async fn check_order_request(&self, order_url: String, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2196 Ok(self.0.read().await.check_order_request(order_url, previous_nonce)?)
2197 }
2198
2199 pub async fn check_order_response(&self, order: Vec<u8>) -> CoreCryptoResult<String> {
2201 Ok(self.0.write().await.check_order_response(order)?)
2202 }
2203
2204 pub async fn finalize_request(&self, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2206 Ok(self.0.write().await.finalize_request(previous_nonce)?)
2207 }
2208
2209 pub async fn finalize_response(&self, finalize: Vec<u8>) -> CoreCryptoResult<String> {
2211 Ok(self.0.write().await.finalize_response(finalize)?)
2212 }
2213
2214 pub async fn certificate_request(&self, previous_nonce: String) -> CoreCryptoResult<Vec<u8>> {
2216 Ok(self.0.write().await.certificate_request(previous_nonce)?)
2217 }
2218
2219 pub async fn get_refresh_token(&self) -> CoreCryptoResult<String> {
2221 Ok(self.0.read().await.get_refresh_token().map(Into::into)?)
2222 }
2223}
2224
2225#[derive(Debug, uniffi::Record)]
2226pub struct AcmeDirectory {
2228 pub new_nonce: String,
2229 pub new_account: String,
2230 pub new_order: String,
2231 pub revoke_cert: String,
2232}
2233
2234impl From<core_crypto::prelude::E2eiAcmeDirectory> for AcmeDirectory {
2235 fn from(directory: core_crypto::prelude::E2eiAcmeDirectory) -> Self {
2236 Self {
2237 new_nonce: directory.new_nonce,
2238 new_account: directory.new_account,
2239 new_order: directory.new_order,
2240 revoke_cert: directory.revoke_cert,
2241 }
2242 }
2243}
2244
2245impl From<AcmeDirectory> for core_crypto::prelude::E2eiAcmeDirectory {
2246 fn from(directory: AcmeDirectory) -> Self {
2247 Self {
2248 new_nonce: directory.new_nonce,
2249 new_account: directory.new_account,
2250 new_order: directory.new_order,
2251 revoke_cert: directory.revoke_cert,
2252 }
2253 }
2254}
2255
2256#[derive(Debug, uniffi::Record)]
2257pub struct NewAcmeOrder {
2259 pub delegate: Vec<u8>,
2260 pub authorizations: Vec<String>,
2261}
2262
2263impl From<core_crypto::prelude::E2eiNewAcmeOrder> for NewAcmeOrder {
2264 fn from(new_order: core_crypto::prelude::E2eiNewAcmeOrder) -> Self {
2265 Self {
2266 delegate: new_order.delegate,
2267 authorizations: new_order.authorizations,
2268 }
2269 }
2270}
2271
2272impl From<NewAcmeOrder> for core_crypto::prelude::E2eiNewAcmeOrder {
2273 fn from(new_order: NewAcmeOrder) -> Self {
2274 Self {
2275 delegate: new_order.delegate,
2276 authorizations: new_order.authorizations,
2277 }
2278 }
2279}
2280
2281#[derive(Debug, uniffi::Record)]
2282pub struct NewAcmeAuthz {
2284 pub identifier: String,
2285 pub keyauth: Option<String>,
2286 pub challenge: AcmeChallenge,
2287}
2288
2289impl From<core_crypto::prelude::E2eiNewAcmeAuthz> for NewAcmeAuthz {
2290 fn from(new_authz: core_crypto::prelude::E2eiNewAcmeAuthz) -> Self {
2291 Self {
2292 identifier: new_authz.identifier,
2293 keyauth: new_authz.keyauth,
2294 challenge: new_authz.challenge.into(),
2295 }
2296 }
2297}
2298
2299impl From<NewAcmeAuthz> for core_crypto::prelude::E2eiNewAcmeAuthz {
2300 fn from(new_authz: NewAcmeAuthz) -> Self {
2301 Self {
2302 identifier: new_authz.identifier,
2303 keyauth: new_authz.keyauth,
2304 challenge: new_authz.challenge.into(),
2305 }
2306 }
2307}
2308
2309#[derive(Debug, uniffi::Record)]
2310pub struct AcmeChallenge {
2312 pub delegate: Vec<u8>,
2313 pub url: String,
2314 pub target: String,
2315}
2316
2317impl From<core_crypto::prelude::E2eiAcmeChallenge> for AcmeChallenge {
2318 fn from(chall: core_crypto::prelude::E2eiAcmeChallenge) -> Self {
2319 Self {
2320 delegate: chall.delegate,
2321 url: chall.url,
2322 target: chall.target,
2323 }
2324 }
2325}
2326
2327impl From<AcmeChallenge> for core_crypto::prelude::E2eiAcmeChallenge {
2328 fn from(chall: AcmeChallenge) -> Self {
2329 Self {
2330 delegate: chall.delegate,
2331 url: chall.url,
2332 target: chall.target,
2333 }
2334 }
2335}