Skip to main content

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