matrix_sdk/encryption/identities/
users.rs

1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::BTreeMap;
16
17use matrix_sdk_base::{
18    crypto::{types::MasterPubkey, CryptoStoreError, UserIdentity as CryptoUserIdentity},
19    RoomMemberships,
20};
21use ruma::{
22    events::{
23        key::verification::VerificationMethod,
24        room::message::{MessageType, RoomMessageEventContent},
25    },
26    OwnedUserId, UserId,
27};
28
29use super::{ManualVerifyError, RequestVerificationError};
30use crate::{encryption::verification::VerificationRequest, Client};
31
32/// Updates about [`UserIdentity`]s which got received over the `/keys/query`
33/// endpoint.
34#[derive(Clone, Debug, Default)]
35pub struct IdentityUpdates {
36    /// The list of newly discovered user identities .
37    ///
38    /// A identity being in this list does not necessarily mean that the
39    /// identity was just created, it just means that it's the first time
40    /// we're seeing this identity.
41    pub new: BTreeMap<OwnedUserId, UserIdentity>,
42    /// The list of changed identities.
43    pub changed: BTreeMap<OwnedUserId, UserIdentity>,
44}
45
46impl IdentityUpdates {
47    pub(crate) fn new(
48        client: Client,
49        updates: matrix_sdk_base::crypto::store::IdentityUpdates,
50    ) -> Self {
51        let new = updates
52            .new
53            .into_iter()
54            .map(|(user_id, identity)| (user_id, UserIdentity::new(client.to_owned(), identity)))
55            .collect();
56
57        let changed = updates
58            .changed
59            .into_iter()
60            .map(|(user_id, identity)| (user_id, UserIdentity::new(client.to_owned(), identity)))
61            .collect();
62
63        Self { new, changed }
64    }
65}
66
67/// A struct representing a E2EE capable identity of a user.
68///
69/// The identity is backed by public [cross signing] keys that users upload. If
70/// our own user doesn't yet have such an identity, a new one can be created and
71/// uploaded to the server using [`Encryption::bootstrap_cross_signing()`]. The
72/// user identity can be also reset using the same method.
73///
74/// The user identity consists of three separate `Ed25519` keypairs:
75///
76/// ```text
77///           ┌──────────────────────────────────────────────────────┐
78///           │                    User Identity                     │
79///           ├────────────────┬──────────────────┬──────────────────┤
80///           │   Master Key   │ Self-signing Key │ User-signing key │
81///           └────────────────┴──────────────────┴──────────────────┘
82/// ```
83///
84/// The identity consists of a Master key and two sub-keys, the Self-signing key
85/// and the User-signing key.
86///
87/// Each key has a separate role:
88/// * Master key, signs only the sub-keys, can be used as a fingerprint of the
89///   identity.
90/// * Self-signing key, signs devices belonging to the user that owns this
91///   identity.
92/// * User-signing key, signs Master keys belonging to other users.
93///
94/// The User-signing key and its signatures of other user's Master keys are
95/// hidden from us by the homeserver. This is done to preserve privacy and not
96/// let us know whom the user verified.
97///
98/// [cross signing]: https://spec.matrix.org/unstable/client-server-api/#cross-signing
99/// [`Encryption::bootstrap_cross_signing()`]: crate::encryption::Encryption::bootstrap_cross_signing
100#[derive(Debug, Clone)]
101pub struct UserIdentity {
102    client: Client,
103    inner: CryptoUserIdentity,
104}
105
106impl UserIdentity {
107    pub(crate) fn new(client: Client, identity: CryptoUserIdentity) -> Self {
108        Self { inner: identity, client }
109    }
110
111    #[cfg(all(feature = "e2e-encryption", not(target_arch = "wasm32")))]
112    pub(crate) fn underlying_identity(&self) -> CryptoUserIdentity {
113        self.inner.clone()
114    }
115
116    /// The ID of the user this identity belongs to.
117    ///
118    /// # Examples
119    ///
120    /// ```no_run
121    /// # use matrix_sdk::{Client, ruma::user_id};
122    /// # use url::Url;
123    /// # let alice = user_id!("@alice:example.org");
124    /// # let homeserver = Url::parse("http://example.com").unwrap();
125    /// # async {
126    /// # let client = Client::new(homeserver).await.unwrap();
127    /// let user = client.encryption().get_user_identity(alice).await?;
128    ///
129    /// if let Some(user) = user {
130    ///     println!("This user identity belongs to {}", user.user_id());
131    /// }
132    ///
133    /// # anyhow::Ok(()) };
134    /// ```
135    pub fn user_id(&self) -> &UserId {
136        match &self.inner {
137            CryptoUserIdentity::Own(identity) => identity.user_id(),
138            CryptoUserIdentity::Other(identity) => identity.user_id(),
139        }
140    }
141
142    /// Request an interactive verification with this `UserIdentity`.
143    ///
144    /// Returns a [`VerificationRequest`] object that can be used to control the
145    /// verification flow.
146    ///
147    /// This will send out a `m.key.verification.request` event. Who such an
148    /// event will be sent to depends on if we're verifying our own identity or
149    /// someone else's:
150    ///
151    /// * Our own identity - All our E2EE capable devices will receive the event
152    ///   over to-device messaging.
153    /// * Someone else's identity - The event will be sent to a DM room we share
154    ///   with the user, if we don't share a DM with the user, one will be
155    ///   created.
156    ///
157    /// The default methods that are supported are:
158    ///
159    /// * `m.sas.v1` - Short auth string, or emoji based verification
160    /// * `m.qr_code.show.v1` - QR code based verification
161    ///
162    /// [`request_verification_with_methods()`] method can be
163    /// used to override this. The `m.qr_code.show.v1` method is only available
164    /// if the `qrcode` feature is enabled, which it is by default.
165    ///
166    /// Check out the [`verification`] module for more info on how to handle
167    /// interactive verifications.
168    ///
169    /// # Examples
170    ///
171    /// ```no_run
172    /// # use matrix_sdk::{Client, ruma::user_id};
173    /// # use url::Url;
174    /// # let alice = user_id!("@alice:example.org");
175    /// # let homeserver = Url::parse("http://example.com").unwrap();
176    /// # async {
177    /// # let client = Client::new(homeserver).await.unwrap();
178    /// let user = client.encryption().get_user_identity(alice).await?;
179    ///
180    /// if let Some(user) = user {
181    ///     let verification = user.request_verification().await?;
182    /// }
183    ///
184    /// # anyhow::Ok(()) };
185    /// ```
186    ///
187    /// [`request_verification_with_methods()`]:
188    /// #method.request_verification_with_methods
189    /// [`verification`]: crate::encryption::verification
190    pub async fn request_verification(
191        &self,
192    ) -> Result<VerificationRequest, RequestVerificationError> {
193        self.request_verification_impl(None).await
194    }
195
196    /// Request an interactive verification with this `UserIdentity` using the
197    /// selected methods.
198    ///
199    /// Returns a [`VerificationRequest`] object that can be used to control the
200    /// verification flow.
201    ///
202    /// This methods behaves the same way as [`request_verification()`],
203    /// but the advertised verification methods can be manually selected.
204    ///
205    /// Check out the [`verification`] module for more info on how to handle
206    /// interactive verifications.
207    ///
208    /// # Arguments
209    ///
210    /// * `methods` - The verification methods that we want to support. Must be
211    ///   non-empty.
212    ///
213    /// # Panics
214    ///
215    /// This method will panic if `methods` is empty.
216    ///
217    /// # Examples
218    ///
219    /// ```no_run
220    /// # use matrix_sdk::{
221    /// #    Client,
222    /// #    ruma::{
223    /// #        user_id,
224    /// #        events::key::verification::VerificationMethod,
225    /// #    }
226    /// # };
227    /// # use url::Url;
228    /// # let alice = user_id!("@alice:example.org");
229    /// # let homeserver = Url::parse("http://example.com").unwrap();
230    /// # async {
231    /// # let client = Client::new(homeserver).await.unwrap();
232    /// let user = client.encryption().get_user_identity(alice).await?;
233    ///
234    /// // We don't want to support showing a QR code, we only support SAS
235    /// // verification
236    /// let methods = vec![VerificationMethod::SasV1];
237    ///
238    /// if let Some(user) = user {
239    ///     let verification =
240    ///         user.request_verification_with_methods(methods).await?;
241    /// }
242    /// # anyhow::Ok(()) };
243    /// ```
244    ///
245    /// [`request_verification()`]: #method.request_verification
246    /// [`verification`]: crate::encryption::verification
247    pub async fn request_verification_with_methods(
248        &self,
249        methods: Vec<VerificationMethod>,
250    ) -> Result<VerificationRequest, RequestVerificationError> {
251        assert!(!methods.is_empty(), "The list of verification methods can't be non-empty");
252        self.request_verification_impl(Some(methods)).await
253    }
254
255    async fn request_verification_impl(
256        &self,
257        methods: Option<Vec<VerificationMethod>>,
258    ) -> Result<VerificationRequest, RequestVerificationError> {
259        match &self.inner {
260            CryptoUserIdentity::Own(identity) => {
261                let (verification, request) = if let Some(methods) = methods {
262                    identity
263                        .request_verification_with_methods(methods)
264                        .await
265                        .map_err(crate::Error::from)?
266                } else {
267                    identity.request_verification().await.map_err(crate::Error::from)?
268                };
269
270                self.client.send_verification_request(request).await?;
271
272                Ok(VerificationRequest { inner: verification, client: self.client.clone() })
273            }
274            CryptoUserIdentity::Other(i) => {
275                let content = i.verification_request_content(methods.clone());
276
277                let room = if let Some(room) = self.client.get_dm_room(i.user_id()) {
278                    // Make sure that the user, to be verified, is still in the room
279                    if !room
280                        .members(RoomMemberships::ACTIVE)
281                        .await?
282                        .iter()
283                        .any(|member| member.user_id() == i.user_id())
284                    {
285                        room.invite_user_by_id(i.user_id()).await?;
286                    }
287                    room.clone()
288                } else {
289                    self.client.create_dm(i.user_id()).await?
290                };
291
292                let response = room
293                    .send(RoomMessageEventContent::new(MessageType::VerificationRequest(content)))
294                    .await?;
295
296                let verification =
297                    i.request_verification(room.room_id(), &response.event_id, methods);
298
299                Ok(VerificationRequest { inner: verification, client: self.client.clone() })
300            }
301        }
302    }
303
304    /// Manually verify this [`UserIdentity`].
305    ///
306    /// This method will do different things depending on if the user identity
307    /// belongs to us, or if the user identity belongs to someone else. Users
308    /// that chose to manually verify a user identity should make sure that the
309    /// Master key does match to to the `Ed25519` they expect.
310    ///
311    /// The Master key can be inspected using the [`UserIdentity::master_key()`]
312    /// method.
313    ///
314    /// ### Manually verifying other users
315    ///
316    /// This method will attempt to sign the user identity using our private
317    /// parts of the cross signing keys. The method will attempt to sign the
318    /// Master key of the user using our own User-signing key. This will of
319    /// course fail if the private part of the User-signing key isn't available.
320    ///
321    /// The availability of the User-signing key can be checked using the
322    /// [`Encryption::cross_signing_status()`] method.
323    ///
324    /// ### Manually verifying our own user
325    ///
326    /// On the other hand, if the user identity belongs to us, it will be
327    /// marked as verified using a local flag, our own device will also sign the
328    /// Master key. Manually verifying our own user identity can't fail.
329    ///
330    /// ### Problems of manual verification
331    ///
332    /// Manual verification may be more convenient to use, i.e. both users need
333    /// to be online and available to interactively verify each other. Despite
334    /// the convenience, interactive verifications should be generally
335    /// preferred. Manually verifying a user won't notify the other user, the
336    /// one being verified, that they should also verify us. This means that
337    /// user `A` will consider user `B` to be verified, but not the other way
338    /// around.
339    ///
340    /// # Examples
341    ///
342    /// ```no_run
343    /// # use matrix_sdk::{
344    /// #    Client,
345    /// #    ruma::{
346    /// #        user_id,
347    /// #        events::key::verification::VerificationMethod,
348    /// #    }
349    /// # };
350    /// # use url::Url;
351    /// # let alice = user_id!("@alice:example.org");
352    /// # let homeserver = Url::parse("http://example.com").unwrap();
353    /// # async {
354    /// # let client = Client::new(homeserver).await.unwrap();
355    /// let user = client.encryption().get_user_identity(alice).await?;
356    ///
357    /// if let Some(user) = user {
358    ///     user.verify().await?;
359    /// }
360    /// # anyhow::Ok(()) };
361    /// ```
362    /// [`Encryption::cross_signing_status()`]: crate::encryption::Encryption::cross_signing_status
363    pub async fn verify(&self) -> Result<(), ManualVerifyError> {
364        let request = match &self.inner {
365            CryptoUserIdentity::Own(identity) => identity.verify().await?,
366            CryptoUserIdentity::Other(identity) => identity.verify().await?,
367        };
368
369        self.client.send(request).await?;
370
371        Ok(())
372    }
373
374    /// Is the user identity considered to be verified.
375    ///
376    /// A user identity is considered to be verified if:
377    ///
378    /// * It has been signed by our User-signing key, if the identity belongs to
379    ///   another user
380    /// * If it has been locally marked as verified, if the user identity
381    ///   belongs to us.
382    ///
383    /// If the identity belongs to another user, our own user identity needs to
384    /// be verified as well for the identity to be considered to be verified.
385    ///
386    /// # Examples
387    ///
388    /// ```no_run
389    /// # use matrix_sdk::{
390    /// #    Client,
391    /// #    ruma::{
392    /// #        user_id,
393    /// #        events::key::verification::VerificationMethod,
394    /// #    }
395    /// # };
396    /// # use url::Url;
397    /// # let alice = user_id!("@alice:example.org");
398    /// # let homeserver = Url::parse("http://example.com").unwrap();
399    /// # async {
400    /// # let client = Client::new(homeserver).await.unwrap();
401    /// let user = client.encryption().get_user_identity(alice).await?;
402    ///
403    /// if let Some(user) = user {
404    ///     if user.is_verified() {
405    ///         println!("User {} is verified", user.user_id());
406    ///     } else {
407    ///         println!("User {} is not verified", user.user_id());
408    ///     }
409    /// }
410    /// # anyhow::Ok(()) };
411    /// ```
412    pub fn is_verified(&self) -> bool {
413        self.inner.is_verified()
414    }
415
416    /// True if we verified this identity at some point in the past.
417    ///
418    /// To reset this latch back to `false`, one must call
419    /// [`UserIdentity::withdraw_verification()`].
420    pub fn was_previously_verified(&self) -> bool {
421        self.inner.was_previously_verified()
422    }
423
424    /// Remove the requirement for this identity to be verified.
425    ///
426    /// If an identity was previously verified and is not anymore it will be
427    /// reported to the user. In order to remove this notice users have to
428    /// verify again or to withdraw the verification requirement.
429    pub async fn withdraw_verification(&self) -> Result<(), CryptoStoreError> {
430        self.inner.withdraw_verification().await
431    }
432
433    /// Was this identity previously verified, and is no longer?
434    pub fn has_verification_violation(&self) -> bool {
435        self.inner.has_verification_violation()
436    }
437
438    /// Remember this identity, ensuring it does not result in a pin violation.
439    ///
440    /// When we first see a user, we assume their cryptographic identity has not
441    /// been tampered with by the homeserver or another entity with
442    /// man-in-the-middle capabilities. We remember this identity and call this
443    /// action "pinning".
444    ///
445    /// If the identity presented for the user changes later on, the newly
446    /// presented identity is considered to be in "pin violation". This
447    /// method explicitly accepts the new identity, allowing it to replace
448    /// the previously pinned one and bringing it out of pin violation.
449    ///
450    /// UIs should display a warning to the user when encountering an identity
451    /// which is not verified and is in pin violation.
452    pub async fn pin(&self) -> Result<(), CryptoStoreError> {
453        self.inner.pin().await
454    }
455
456    /// Get the public part of the Master key of this user identity.
457    ///
458    /// The public part of the Master key is usually used to uniquely identify
459    /// the identity.
460    ///
461    /// # Examples
462    ///
463    /// ```no_run
464    /// # use matrix_sdk::{
465    /// #    Client,
466    /// #    ruma::{
467    /// #        user_id,
468    /// #        events::key::verification::VerificationMethod,
469    /// #    }
470    /// # };
471    /// # use url::Url;
472    /// # let alice = user_id!("@alice:example.org");
473    /// # let homeserver = Url::parse("http://example.com").unwrap();
474    /// # async {
475    /// # let client = Client::new(homeserver).await.unwrap();
476    /// let user = client.encryption().get_user_identity(alice).await?;
477    ///
478    /// if let Some(user) = user {
479    ///     // Let's verify the user after we confirm that the master key
480    ///     // matches what we expect, for this we fetch the first public key we
481    ///     // can find, there's currently only a single key allowed so this is
482    ///     // fine.
483    ///     if user.master_key().get_first_key().map(|k| k.to_base64())
484    ///         == Some("MyMasterKey".to_string())
485    ///     {
486    ///         println!(
487    ///             "Master keys match for user {}, marking the user as verified",
488    ///             user.user_id(),
489    ///         );
490    ///         user.verify().await?;
491    ///     } else {
492    ///         println!("Master keys don't match for user {}", user.user_id());
493    ///     }
494    /// }
495    /// # anyhow::Ok(()) };
496    /// ```
497    pub fn master_key(&self) -> &MasterPubkey {
498        match &self.inner {
499            CryptoUserIdentity::Own(identity) => identity.master_key(),
500            CryptoUserIdentity::Other(identity) => identity.master_key(),
501        }
502    }
503}