Skip to content

Commit

Permalink
crypto: Provide a way to subscribe to identity status changes
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam committed Oct 3, 2024
1 parent b16104c commit 78c8f13
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 3 deletions.
1 change: 1 addition & 0 deletions crates/matrix-sdk/src/encryption/identities/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ impl UserIdentity {
Self { inner: identity, client }
}

#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
pub(crate) fn underlying_identity(&self) -> CryptoUserIdentities {
self.inner.clone()
}
Expand Down
7 changes: 4 additions & 3 deletions crates/matrix-sdk/src/room/identity_status_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

//! Facility to track changes to the identity of members of rooms.
#![cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]

use std::collections::BTreeMap;

Expand Down Expand Up @@ -62,7 +63,7 @@ impl IdentityStatusChanges {
/// For example, if an identity is "pinned" i.e. not manually verified, but
/// known, and it becomes a "unpinned" i.e. unknown, because the
/// encryption keys are different and the user has not acknowledged
/// this, then this constitues a status change. Also, if an identity is
/// this, then this constitutes a status change. Also, if an identity is
/// "unpinned" and becomes "pinned", this is also a status change.
///
/// The supplied stream is intended to provide enough information for a
Expand Down Expand Up @@ -612,7 +613,7 @@ mod tests {
.respond_with(
ResponseTemplate::new(200).set_body_json(&*test_json::members::MEMBERS),
)
.mount(&server)
.mount(server)
.await;
}

Expand All @@ -623,7 +624,7 @@ mod tests {
))
.and(header("authorization", "Bearer 1234"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({})))
.mount(&server)
.mount(server)
.await;
}

Expand Down
68 changes: 68 additions & 0 deletions crates/matrix-sdk/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@ use std::{
time::Duration,
};

#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
use async_trait::async_trait;
use eyeball::SharedObservable;
use futures_core::Stream;
use futures_util::{
future::{try_join, try_join_all},
stream::FuturesUnordered,
};
#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
pub use identity_status_changes::IdentityStatusChanges;
#[cfg(feature = "e2e-encryption")]
use matrix_sdk_base::crypto::DecryptionSettings;
#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
use matrix_sdk_base::crypto::{IdentityStatusChange, RoomIdentityProvider, UserIdentity};
use matrix_sdk_base::{
deserialized_responses::{
RawAnySyncOrStrippedState, RawSyncOrStrippedState, SyncOrStrippedState, TimelineEvent,
Expand Down Expand Up @@ -114,6 +120,7 @@ use crate::{

pub mod edit;
pub mod futures;
pub mod identity_status_changes;
mod member;
mod messages;
pub mod power_levels;
Expand Down Expand Up @@ -367,6 +374,35 @@ impl Room {
(drop_guard, receiver)
}

/// Subscribe to updates about users who are in "pin violation" i.e. their
/// identity has changed and the user has not yet acknowledged this.
///
/// The returned receiver will receive a new vector of
/// [`IdentityStatusChange`] each time a /keys/query response shows a
/// changed identity for a member of this room, or a sync shows a change
/// to the membership of an affected user. (Changes to the current user are
/// not directly included, but some changes to the current user's identity
/// can trigger changes to how we see other users' identities, which
/// will be included.)
///
/// The first item in the stream provides the current state of the room:
/// each member of the room who is not in "pinned" state will be
/// included (except the current user).
///
/// If the `changed_to` property of an [`IdentityStatusChange`] is set to
/// `PinViolation` then a warning should be displayed to the user. If it is
/// set to `Pinned` then no warning should be displayed.
///
/// Note that if a user who is in pin violation leaves the room, a `Pinned`
/// update is sent, to indicate that the warning should be removed, even
/// though the user's identity is not necessarily pinned.
#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
pub async fn subscribe_to_identity_status_changes(
&self,
) -> Result<impl Stream<Item = Vec<IdentityStatusChange>>> {
IdentityStatusChanges::create_stream(self.clone()).await
}

/// Returns a wrapping `TimelineEvent` for the input `AnyTimelineEvent`,
/// decrypted if needs be.
///
Expand Down Expand Up @@ -2925,6 +2961,38 @@ impl Room {
}
}

#[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
#[async_trait]
impl RoomIdentityProvider for Room {
async fn is_member(&self, user_id: &UserId) -> bool {
self.get_member(user_id).await.unwrap_or(None).is_some()
}

async fn member_identities(&self) -> Vec<UserIdentity> {
let members = self
.members(RoomMemberships::JOIN | RoomMemberships::INVITE)
.await
.unwrap_or_else(|_| Default::default());

let mut ret: Vec<UserIdentity> = Vec::new();
for member in members {
if let Some(i) = self.user_identity(member.user_id()).await {
ret.push(i);
}
}
ret
}

async fn user_identity(&self, user_id: &UserId) -> Option<UserIdentity> {
self.client
.encryption()
.get_user_identity(user_id)
.await
.unwrap_or(None)
.map(|u| u.underlying_identity())
}
}

/// A wrapper for a weak client and a room id that allows to lazily retrieve a
/// room, only when needed.
#[derive(Clone)]
Expand Down

0 comments on commit 78c8f13

Please sign in to comment.