use std::collections::BTreeMap;
use matrix_sdk_base::{
RoomMemberships,
crypto::{CryptoStoreError, UserIdentity as CryptoUserIdentity, types::MasterPubkey},
};
use ruma::{
OwnedUserId, UserId,
events::{key::verification::VerificationMethod, room::message::RoomMessageEventContent},
};
use super::{ManualVerifyError, RequestVerificationError};
use crate::{Client, encryption::verification::VerificationRequest};
#[derive(Clone, Debug, Default)]
pub struct IdentityUpdates {
pub new: BTreeMap<OwnedUserId, UserIdentity>,
pub changed: BTreeMap<OwnedUserId, UserIdentity>,
}
impl IdentityUpdates {
pub(crate) fn new(
client: Client,
updates: matrix_sdk_base::crypto::store::types::IdentityUpdates,
) -> Self {
let new = updates
.new
.into_iter()
.map(|(user_id, identity)| (user_id, UserIdentity::new(client.to_owned(), identity)))
.collect();
let changed = updates
.changed
.into_iter()
.map(|(user_id, identity)| (user_id, UserIdentity::new(client.to_owned(), identity)))
.collect();
Self { new, changed }
}
}
#[derive(Debug, Clone)]
pub struct UserIdentity {
client: Client,
inner: CryptoUserIdentity,
}
impl UserIdentity {
pub(crate) fn new(client: Client, identity: CryptoUserIdentity) -> Self {
Self { inner: identity, client }
}
#[cfg(feature = "e2e-encryption")]
pub(crate) fn underlying_identity(&self) -> CryptoUserIdentity {
self.inner.clone()
}
pub fn user_id(&self) -> &UserId {
match &self.inner {
CryptoUserIdentity::Own(identity) => identity.user_id(),
CryptoUserIdentity::Other(identity) => identity.user_id(),
}
}
pub async fn request_verification(
&self,
) -> Result<VerificationRequest, RequestVerificationError> {
self.request_verification_impl(None).await
}
pub async fn request_verification_with_methods(
&self,
methods: Vec<VerificationMethod>,
) -> Result<VerificationRequest, RequestVerificationError> {
assert!(!methods.is_empty(), "The list of verification methods can't be non-empty");
self.request_verification_impl(Some(methods)).await
}
async fn request_verification_impl(
&self,
methods: Option<Vec<VerificationMethod>>,
) -> Result<VerificationRequest, RequestVerificationError> {
match &self.inner {
CryptoUserIdentity::Own(identity) => {
let (verification, request) = if let Some(methods) = methods {
identity
.request_verification_with_methods(methods)
.await
.map_err(crate::Error::from)?
} else {
identity.request_verification().await.map_err(crate::Error::from)?
};
self.client.send_verification_request(request).await?;
Ok(VerificationRequest { inner: verification, client: self.client.clone() })
}
CryptoUserIdentity::Other(i) => {
let content = i.verification_request_content(methods.clone());
let room = if let Some(room) = self.client.get_dm_room(i.user_id()) {
if !room
.members(RoomMemberships::ACTIVE)
.await?
.iter()
.any(|member| member.user_id() == i.user_id())
{
room.invite_user_by_id(i.user_id()).await?;
}
room.clone()
} else {
self.client.create_dm(i.user_id()).await?
};
let response = room.send(RoomMessageEventContent::new(content)).await?;
let verification =
i.request_verification(room.room_id(), &response.event_id, methods);
Ok(VerificationRequest { inner: verification, client: self.client.clone() })
}
}
}
pub async fn verify(&self) -> Result<(), ManualVerifyError> {
let request = match &self.inner {
CryptoUserIdentity::Own(identity) => identity.verify().await?,
CryptoUserIdentity::Other(identity) => identity.verify().await?,
};
self.client.send(request).await?;
Ok(())
}
pub fn is_verified(&self) -> bool {
self.inner.is_verified()
}
pub fn was_previously_verified(&self) -> bool {
self.inner.was_previously_verified()
}
pub async fn withdraw_verification(&self) -> Result<(), CryptoStoreError> {
self.inner.withdraw_verification().await
}
pub fn has_verification_violation(&self) -> bool {
self.inner.has_verification_violation()
}
pub async fn pin(&self) -> Result<(), CryptoStoreError> {
self.inner.pin().await
}
pub fn master_key(&self) -> &MasterPubkey {
match &self.inner {
CryptoUserIdentity::Own(identity) => identity.master_key(),
CryptoUserIdentity::Other(identity) => identity.master_key(),
}
}
}