Skip to content

Commit f75470e

Browse files
committed
feat(ffi): Allow passing in a SecretsBundle while logging in
1 parent 6c18f73 commit f75470e

File tree

3 files changed

+79
-5
lines changed

3 files changed

+79
-5
lines changed

bindings/matrix-sdk-ffi/src/authentication.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use matrix_sdk::{
2929
use ruma::serde::Raw;
3030
use url::Url;
3131

32-
use crate::client::{Client, OidcPrompt, SlidingSyncVersion};
32+
use crate::client::{Client, OidcPrompt, SecretsBundle, SlidingSyncVersion};
3333

3434
#[derive(uniffi::Object)]
3535
pub struct HomeserverLoginDetails {
@@ -95,12 +95,24 @@ impl SsoHandler {
9595
}
9696

9797
/// Completes the SSO login process.
98-
pub async fn finish(&self, callback_url: String) -> Result<(), SsoError> {
98+
pub async fn finish(
99+
&self,
100+
callback_url: String,
101+
secrets_bundle: Option<Arc<SecretsBundle>>,
102+
) -> Result<(), SsoError> {
99103
let auth = self.client.inner.matrix_auth();
100104
let url = Url::parse(&callback_url).map_err(|_| SsoError::CallbackUrlInvalid)?;
101105
let builder =
102106
auth.login_with_sso_callback(url).map_err(|_| SsoError::CallbackUrlInvalid)?;
103107
builder.await.map_err(|_| SsoError::LoginWithTokenFailed)?;
108+
109+
if let Some(bundle) = secrets_bundle {
110+
self.client
111+
.import_secrets_bundle(&bundle)
112+
.await
113+
.map_err(|e| SsoError::Generic { message: e.to_string() })?;
114+
}
115+
104116
Ok(())
105117
}
106118
}

bindings/matrix-sdk-ffi/src/client.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,26 @@ impl From<PushFormat> for RumaPushFormat {
203203
}
204204
}
205205

206+
#[derive(uniffi::Object)]
207+
pub struct SecretsBundle {
208+
inner: matrix_sdk_base::crypto::types::SecretsBundle,
209+
}
210+
211+
#[matrix_sdk_ffi_macros::export]
212+
impl SecretsBundle {
213+
#[uniffi::constructor]
214+
pub fn from_str(bundle: &str) -> Result<Arc<Self>, ClientError> {
215+
let bundle = serde_json::from_str(bundle)?;
216+
217+
Ok(Self { inner: bundle }.into())
218+
}
219+
220+
#[uniffi::constructor]
221+
pub fn from_database(database_path: &str) -> Result<Arc<Self>, ClientError> {
222+
todo!()
223+
}
224+
}
225+
206226
#[matrix_sdk_ffi_macros::export(callback_interface)]
207227
pub trait ClientDelegate: SyncOutsideWasm + SendOutsideWasm {
208228
/// A callback invoked whenever the SDK runs into an unknown token error.
@@ -418,6 +438,24 @@ impl Client {
418438

419439
Ok(client)
420440
}
441+
442+
pub(crate) async fn import_secrets_bundle(
443+
&self,
444+
secrets_bundle: &SecretsBundle,
445+
) -> Result<(), ClientError> {
446+
self.inner
447+
.encryption()
448+
.import_secrets_bundle(&secrets_bundle.inner)
449+
.await
450+
.map_err(|e| ClientError::from_err(e))?;
451+
452+
// Upload the device keys, this will ensure that other devices see us as a fully
453+
// verified device ass soon as this method returns.
454+
self.inner.encryption().ensure_device_keys_upload().await?;
455+
self.inner.encryption().wait_for_e2ee_initialization_tasks().await;
456+
457+
Ok(())
458+
}
421459
}
422460

423461
#[matrix_sdk_ffi_macros::export]
@@ -486,15 +524,24 @@ impl Client {
486524
password: String,
487525
initial_device_name: Option<String>,
488526
device_id: Option<String>,
527+
secrets_bundle: Option<Arc<SecretsBundle>>,
489528
) -> Result<(), ClientError> {
490529
let mut builder = self.inner.matrix_auth().login_username(&username, &password);
530+
491531
if let Some(initial_device_name) = initial_device_name.as_ref() {
492532
builder = builder.initial_device_display_name(initial_device_name);
493533
}
534+
494535
if let Some(device_id) = device_id.as_ref() {
495536
builder = builder.device_id(device_id);
496537
}
538+
497539
builder.send().await?;
540+
541+
if let Some(bundle) = secrets_bundle {
542+
self.import_secrets_bundle(&bundle).await?;
543+
}
544+
498545
Ok(())
499546
}
500547

@@ -506,6 +553,7 @@ impl Client {
506553
jwt: String,
507554
initial_device_name: Option<String>,
508555
device_id: Option<String>,
556+
secrets_bundle: Option<Arc<SecretsBundle>>,
509557
) -> Result<(), ClientError> {
510558
let data = json!({ "token": jwt }).as_object().unwrap().clone();
511559

@@ -520,6 +568,11 @@ impl Client {
520568
}
521569

522570
builder.send().await?;
571+
572+
if let Some(bundle) = secrets_bundle {
573+
self.import_secrets_bundle(&bundle).await?;
574+
}
575+
523576
Ok(())
524577
}
525578

@@ -530,6 +583,7 @@ impl Client {
530583
password: String,
531584
initial_device_name: Option<String>,
532585
device_id: Option<String>,
586+
secrets_bundle: Option<Arc<SecretsBundle>>,
533587
) -> Result<(), ClientError> {
534588
let mut builder = self
535589
.inner
@@ -546,6 +600,10 @@ impl Client {
546600

547601
builder.send().await?;
548602

603+
if let Some(bundle) = secrets_bundle {
604+
self.import_secrets_bundle(&bundle).await?;
605+
}
606+
549607
Ok(())
550608
}
551609

@@ -637,7 +695,11 @@ impl Client {
637695
}
638696

639697
/// Completes the OIDC login process.
640-
pub async fn login_with_oidc_callback(&self, callback_url: String) -> Result<(), OidcError> {
698+
pub async fn login_with_oidc_callback(
699+
&self,
700+
callback_url: String,
701+
secrets_bundle: Option<Arc<SecretsBundle>>,
702+
) -> Result<(), OidcError> {
641703
let url = Url::parse(&callback_url).or(Err(OidcError::CallbackUrlInvalid))?;
642704

643705
self.inner.oauth().finish_login(url.into()).await?;

crates/matrix-sdk/src/encryption/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -826,7 +826,7 @@ impl Encryption {
826826
}
827827
}
828828

829-
pub(crate) async fn import_secrets_bundle(
829+
pub async fn import_secrets_bundle(
830830
&self,
831831
bundle: &matrix_sdk_base::crypto::types::SecretsBundle,
832832
) -> Result<(), SecretImportError> {
@@ -1890,7 +1890,7 @@ impl Encryption {
18901890
/// **Warning**: Do not use this method if we're already calling
18911891
/// [`Client::send_outgoing_request()`]. This method is intended for
18921892
/// explicitly uploading the device keys before starting a sync.
1893-
pub(crate) async fn ensure_device_keys_upload(&self) -> Result<()> {
1893+
pub async fn ensure_device_keys_upload(&self) -> Result<()> {
18941894
let olm = self.client.olm_machine().await;
18951895
let olm = olm.as_ref().ok_or(Error::NoOlmMachine)?;
18961896

0 commit comments

Comments
 (0)