ffi: Expose identity reset mechanism
This commit is contained in:
@@ -9,7 +9,7 @@ use thiserror::Error;
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use super::RUNTIME;
|
||||
use crate::{client::Client, error::ClientError, task_handle::TaskHandle};
|
||||
use crate::{client::Client, error::ClientError, ruma::AuthData, task_handle::TaskHandle};
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct Encryption {
|
||||
@@ -357,6 +357,22 @@ impl Encryption {
|
||||
Ok(result?)
|
||||
}
|
||||
|
||||
/// Completely reset the current user's crypto identity: reset the cross
|
||||
/// signing keys, delete the existing backup and recovery key.
|
||||
pub async fn reset_identity(&self) -> Result<Option<Arc<IdentityResetHandle>>, ClientError> {
|
||||
if let Some(reset_handle) = self
|
||||
.inner
|
||||
.recovery()
|
||||
.reset_identity()
|
||||
.await
|
||||
.map_err(|e| ClientError::Generic { msg: e.to_string() })?
|
||||
{
|
||||
return Ok(Some(Arc::new(IdentityResetHandle { inner: reset_handle })));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn recover(&self, mut recovery_key: String) -> Result<()> {
|
||||
let result = self.inner.recovery().recover(&recovery_key).await;
|
||||
|
||||
@@ -387,3 +403,70 @@ impl Encryption {
|
||||
self.inner.wait_for_e2ee_initialization_tasks().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Object)]
|
||||
pub struct IdentityResetHandle {
|
||||
pub(crate) inner: matrix_sdk::encryption::recovery::IdentityResetHandle,
|
||||
}
|
||||
|
||||
#[uniffi::export(async_runtime = "tokio")]
|
||||
impl IdentityResetHandle {
|
||||
/// Get the underlying [`CrossSigningResetAuthType`] this identity reset
|
||||
/// process is using.
|
||||
pub fn auth_type(&self) -> CrossSigningResetAuthType {
|
||||
self.inner.auth_type().into()
|
||||
}
|
||||
|
||||
/// This method starts the identity reset process and
|
||||
/// will go through the following steps:
|
||||
///
|
||||
/// 1. Disable backing up room keys and delete the active backup
|
||||
/// 2. Disable recovery and delete secret storage
|
||||
/// 3. Go through the cross-signing key reset flow
|
||||
/// 4. Finally, re-enable key backups only if they were enabled before
|
||||
pub async fn reset(&self, auth: Option<AuthData>) -> Result<(), ClientError> {
|
||||
if let Some(auth) = auth {
|
||||
self.inner
|
||||
.reset(Some(auth.into()))
|
||||
.await
|
||||
.map_err(|e| ClientError::Generic { msg: e.to_string() })
|
||||
} else {
|
||||
self.inner.reset(None).await.map_err(|e| ClientError::Generic { msg: e.to_string() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Enum)]
|
||||
pub enum CrossSigningResetAuthType {
|
||||
/// The homeserver requires user-interactive authentication.
|
||||
Uiaa,
|
||||
// /// OIDC is used for authentication and the user needs to open a URL to
|
||||
// /// approve the upload of cross-signing keys.
|
||||
Oidc {
|
||||
info: OidcCrossSigningResetInfo,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<&matrix_sdk::encryption::CrossSigningResetAuthType> for CrossSigningResetAuthType {
|
||||
fn from(value: &matrix_sdk::encryption::CrossSigningResetAuthType) -> Self {
|
||||
match value {
|
||||
encryption::CrossSigningResetAuthType::Uiaa(_) => Self::Uiaa,
|
||||
encryption::CrossSigningResetAuthType::Oidc(info) => Self::Oidc { info: info.into() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(uniffi::Record)]
|
||||
pub struct OidcCrossSigningResetInfo {
|
||||
/// The error message we received from the homeserver after we attempted to
|
||||
/// reset the cross-signing keys.
|
||||
pub error: String,
|
||||
/// The URL where the user can approve the reset of the cross-signing keys.
|
||||
pub approval_url: String,
|
||||
}
|
||||
|
||||
impl From<&matrix_sdk::encryption::OidcCrossSigningResetInfo> for OidcCrossSigningResetInfo {
|
||||
fn from(value: &matrix_sdk::encryption::OidcCrossSigningResetInfo) -> Self {
|
||||
Self { error: value.error.to_owned(), approval_url: value.approval_url.to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,36 @@ use crate::{
|
||||
utils::u64_to_uint,
|
||||
};
|
||||
|
||||
#[derive(uniffi::Enum)]
|
||||
pub enum AuthData {
|
||||
/// Password-based authentication (`m.login.password`).
|
||||
Password { password_details: AuthDataPasswordDetails },
|
||||
}
|
||||
|
||||
#[derive(uniffi::Record)]
|
||||
pub struct AuthDataPasswordDetails {
|
||||
/// One of the user's identifiers.
|
||||
identifier: String,
|
||||
|
||||
/// The plaintext password.
|
||||
password: String,
|
||||
}
|
||||
|
||||
impl From<AuthData> for ruma::api::client::uiaa::AuthData {
|
||||
fn from(value: AuthData) -> ruma::api::client::uiaa::AuthData {
|
||||
match value {
|
||||
AuthData::Password { password_details } => {
|
||||
let user_id = ruma::UserId::parse(password_details.identifier).unwrap();
|
||||
|
||||
ruma::api::client::uiaa::AuthData::Password(ruma::api::client::uiaa::Password::new(
|
||||
user_id.into(),
|
||||
password_details.password,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a matrix entity from a given URI, be it either
|
||||
/// a `matrix.to` link or a `matrix:` URI
|
||||
#[uniffi::export]
|
||||
|
||||
Reference in New Issue
Block a user