Skip to main content

matrix_sdk/authentication/oauth/qrcode/
grant.rs

1// Copyright 2025, 2026 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::time::Duration;
16
17use eyeball::SharedObservable;
18use futures_core::Stream;
19use matrix_sdk_base::{
20    boxed_into_future,
21    crypto::types::{
22        SecretsBundle,
23        qr_login::{QrCodeData, QrCodeIntent},
24    },
25};
26use oauth2::VerificationUriComplete;
27use ruma::time::Instant;
28use url::Url;
29#[cfg(doc)]
30use vodozemac::ecies::CheckCode;
31
32use super::{
33    LoginProtocolData, LoginProtocolType, QrAuthMessage,
34    secure_channel::{EstablishedSecureChannel, SecureChannel},
35};
36use crate::{
37    Client,
38    authentication::oauth::qrcode::{
39        CheckCodeSender, CloneableSender, ContinuationMessage, ContinuationMessageSender,
40        GeneratedQrProgress, LoginFailureReason, QRCodeGrantLoginError, QrProgress,
41        SecureChannelError, messages::LoginProtocolsMessage, secure_channel::ChannelVariant,
42    },
43};
44
45async fn export_secrets_bundle(client: &Client) -> Result<SecretsBundle, QRCodeGrantLoginError> {
46    let secrets_bundle = client
47        .olm_machine()
48        .await
49        .as_ref()
50        .ok_or_else(|| QRCodeGrantLoginError::MissingSecretsBackup(None))?
51        .store()
52        .export_secrets_bundle()
53        .await?;
54    Ok(secrets_bundle)
55}
56
57async fn finish_login_grant<Q>(
58    client: &Client,
59    channel: &mut EstablishedSecureChannel,
60    device_creation_timeout: Duration,
61    secrets_bundle: &SecretsBundle,
62    state: &SharedObservable<GrantLoginProgress<Q>>,
63) -> Result<(), QRCodeGrantLoginError> {
64    // The new device registers with the authorization server and sends it a
65    // device authorization authorization request.
66    //
67    // -- MSC4108 OAuth 2.0 login step 2
68
69    // We wait for the new device to send us the m.login.protocol message with
70    // the device authorization grant information.
71    //
72    // -- MSC4108 OAuth 2.0 login step 3
73    let (protocol, device_id) = match channel.receive_json().await? {
74        QrAuthMessage::LoginProtocol { protocol, device_id } => (protocol, device_id),
75        QrAuthMessage::LoginFailure { reason, .. } => {
76            return Err(QRCodeGrantLoginError::LoginFailure { reason });
77        }
78        message => {
79            return Err(QRCodeGrantLoginError::UnexpectedMessage {
80                expected: "m.login.protocol",
81                received: Box::new(message),
82            });
83        }
84    };
85
86    // We verify the selected protocol, and that its data uses the layout of
87    // our channel variant.
88    //
89    // -- MSC4108 OAuth 2.0 login step 4
90    let device_authorization_grant = match channel.channel_variant() {
91        ChannelVariant::Msc4108 => match protocol {
92            LoginProtocolData::Msc4108DeviceAuthorizationGrant(device_authorization_grant) => {
93                Ok(device_authorization_grant)
94            }
95            protocol => Err(protocol),
96        },
97        #[cfg(feature = "unstable-msc4388")]
98        ChannelVariant::Msc4388 => match protocol {
99            LoginProtocolData::Msc4388DeviceAuthorizationGrant(device_authorization_grant) => {
100                Ok(device_authorization_grant)
101            }
102            protocol => Err(protocol),
103        },
104    };
105
106    let device_authorization_grant = match device_authorization_grant {
107        Ok(device_authorization_grant) => device_authorization_grant,
108        // The device authorization grant, but using the layout of the other
109        // channel variant.
110        Err(
111            protocol @ (LoginProtocolData::Msc4108DeviceAuthorizationGrant(_)
112            | LoginProtocolData::Msc4388DeviceAuthorizationGrant(_)),
113        ) => {
114            channel
115                .send_json(QrAuthMessage::LoginFailure {
116                    reason: LoginFailureReason::UnexpectedMessageReceived,
117                    homeserver: None,
118                })
119                .await?;
120            return Err(QRCodeGrantLoginError::UnexpectedMessage {
121                expected: "m.login.protocol",
122                received: Box::new(QrAuthMessage::LoginProtocol { protocol, device_id }),
123            });
124        }
125        Err(protocol) => {
126            channel
127                .send_json(QrAuthMessage::LoginFailure {
128                    reason: LoginFailureReason::UnsupportedProtocol,
129                    homeserver: None,
130                })
131                .await?;
132            return Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol.protocol()));
133        }
134    };
135
136    // We check that the device ID is still available.
137    //
138    // -- MSC4108 OAuth 2.0 login step 4 continued
139    if !matches!(client.device_exists(device_id.clone().into()).await, Ok(false)) {
140        channel
141            .send_json(QrAuthMessage::LoginFailure {
142                reason: LoginFailureReason::DeviceAlreadyExists,
143                homeserver: None,
144            })
145            .await?;
146        return Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse);
147    }
148
149    // We emit an update so that the caller can open the verification URI in a
150    // system browser to consent to the login.
151    //
152    // -- MSC4108 OAuth 2.0 login step 4 continued
153    let verification_uri = Url::parse(
154        device_authorization_grant
155            .verification_uri_complete
156            .map(VerificationUriComplete::into_secret)
157            .unwrap_or(device_authorization_grant.verification_uri.to_string())
158            .as_str(),
159    )
160    .map_err(|e| QRCodeGrantLoginError::Unknown(e.to_string()))?;
161
162    // We send the new device the m.login.protocol_accepted message to let it
163    // know that the consent process is in progress.
164    //
165    // -- MSC4108 OAuth 2.0 login step 4 continued
166    let message = QrAuthMessage::LoginProtocolAccepted;
167    channel.send_json(&message).await?;
168
169    let (sender, receiver) = tokio::sync::oneshot::channel();
170    state.set(GrantLoginProgress::WaitingForAuth {
171        verification_uri,
172        continuation_sender: ContinuationMessageSender(CloneableSender::new(sender)),
173    });
174
175    // We wait for this device to confirm that the authorization using the
176    // verification URI has succeeded.
177    match receiver.await {
178        Ok(ContinuationMessage::Confirm) => {}
179        Ok(ContinuationMessage::Cancel) | Err(_) => {
180            channel
181                .send_json(QrAuthMessage::LoginFailure {
182                    reason: LoginFailureReason::UserCancelled,
183                    homeserver: None,
184                })
185                .await?;
186            return Err(QRCodeGrantLoginError::LoginFailure {
187                reason: LoginFailureReason::UserCancelled,
188            });
189        }
190    }
191
192    // The new device displays the user code it received from the authorization
193    // server and starts polling for an access token. In parallel, the user
194    // consents to the new login in the browser on this device, while verifying
195    // the user code displayed on the other device.
196    //
197    // -- MSC4108 OAuth 2.0 login steps 5 & 6
198
199    // We wait for the new device to send us the m.login.success or
200    // m.login.failure message
201    match channel.receive_json().await? {
202        QrAuthMessage::LoginSuccess => (),
203        QrAuthMessage::LoginFailure { reason, .. } => {
204            return Err(QRCodeGrantLoginError::LoginFailure { reason });
205        }
206        message => {
207            return Err(QRCodeGrantLoginError::UnexpectedMessage {
208                expected: "m.login.success",
209                received: Box::new(message),
210            });
211        }
212    }
213
214    // We check that the new device was created successfully, allowing for the
215    // specified delay.
216    //
217    // -- MSC4108 Secret sharing and device verification step 1
218    let deadline = Instant::now() + device_creation_timeout;
219
220    loop {
221        if matches!(client.device_exists(device_id.clone().into()).await, Ok(true)) {
222            break;
223        } else {
224            // If the deadline hasn't yet passed, give it some time and retry
225            // the request.
226            if Instant::now() < deadline {
227                matrix_sdk_common::sleep::sleep(Duration::from_millis(500)).await;
228                continue;
229            } else {
230                // The deadline has passed. Let's fail the login process.
231                channel
232                    .send_json(QrAuthMessage::LoginFailure {
233                        reason: LoginFailureReason::DeviceNotFound,
234                        homeserver: None,
235                    })
236                    .await?;
237                return Err(QRCodeGrantLoginError::DeviceNotFound);
238            }
239        }
240    }
241
242    // We send the new device the secrets bundle.
243    //
244    // -- MSC4108 Secret sharing and device verification step 2
245    state.set(GrantLoginProgress::SyncingSecrets);
246    let message = QrAuthMessage::LoginSecrets(secrets_bundle.clone());
247    channel.send_json(&message).await?;
248
249    // And we're done.
250    state.set(GrantLoginProgress::Done);
251
252    Ok(())
253}
254
255/// The progress of granting the login.
256#[derive(Clone, Debug, Default)]
257pub enum GrantLoginProgress<Q> {
258    /// We're just starting up, this is the default and initial state.
259    #[default]
260    Starting,
261    /// The secure channel is being established by exchanging the QR code and/or
262    /// [`CheckCode`].
263    EstablishingSecureChannel(Q),
264    /// The secure channel has been confirmed using the [`CheckCode`] and this
265    /// device is waiting for the authorization to complete.
266    WaitingForAuth {
267        /// A URI to open in a (secure) system browser to verify the new login.
268        verification_uri: Url,
269        /// A sender to confirm that the verification URI has been opened in
270        /// the browser and the application is ready to proceed, or to cancel.
271        ///
272        /// The new device has already been told to proceed when this state is
273        /// emitted, so confirming only resumes this side of the process. This
274        /// allows applications that suspend or navigate away while the
275        /// verification URI is open to resume explicitly.
276        continuation_sender: ContinuationMessageSender,
277    },
278    /// The new device has been granted access and this device is sending the
279    /// secrets to it.
280    SyncingSecrets,
281    /// The process is complete.
282    Done,
283}
284
285/// Named future for granting login by scanning a QR code on this, existing,
286/// device that was generated by the other, new, device.
287#[derive(Debug)]
288pub struct GrantLoginWithScannedQrCode {
289    client: Client,
290    qr_code_data: QrCodeData,
291    device_creation_timeout: Duration,
292    state: SharedObservable<GrantLoginProgress<QrProgress>>,
293}
294
295impl GrantLoginWithScannedQrCode {
296    pub(crate) fn new(
297        client: &Client,
298        qr_code_data: &QrCodeData,
299        device_creation_timeout: Duration,
300    ) -> GrantLoginWithScannedQrCode {
301        GrantLoginWithScannedQrCode {
302            client: client.clone(),
303            qr_code_data: qr_code_data.clone(),
304            device_creation_timeout,
305            state: Default::default(),
306        }
307    }
308}
309
310impl GrantLoginWithScannedQrCode {
311    /// Subscribe to the progress of QR code login.
312    ///
313    /// It's necessary to subscribe to this to capture the [`CheckCode`] in
314    /// order to display it to the other device and to obtain the verification
315    /// URL for consenting to the login.
316    pub fn subscribe_to_progress(
317        &self,
318    ) -> impl Stream<Item = GrantLoginProgress<QrProgress>> + use<> {
319        self.state.subscribe()
320    }
321}
322
323impl IntoFuture for GrantLoginWithScannedQrCode {
324    type Output = Result<(), QRCodeGrantLoginError>;
325    boxed_into_future!();
326
327    fn into_future(self) -> Self::IntoFuture {
328        Box::pin(async move {
329            // Before we get here, the other device has created a new rendezvous
330            // session and presented a QR code which this device has scanned.
331            //
332            // -- MSC4108 Secure channel setup steps 1-3
333
334            // First things first, export the secrets bundle and establish the
335            // secure channel. Since we're the one that scanned the QR code,
336            // we're certain that the secure channel is secure, under the
337            // assumption that we didn't scan the wrong QR code.
338            //
339            // -- MSC4108 Secure channel setup steps 3-5
340            let secrets_bundle = export_secrets_bundle(&self.client).await?;
341
342            let mut channel = EstablishedSecureChannel::from_qr_code(
343                self.client.inner.http_client.inner.clone(),
344                &self.qr_code_data,
345                QrCodeIntent::Reciprocate,
346            )
347            .await?;
348
349            // The other side isn't yet sure that it's talking to the right
350            // device, show a check code so they can confirm.
351            //
352            // -- MSC4108 Secure channel setup step 6
353            let check_code = channel.check_code().to_owned();
354            self.state
355                .set(GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
356
357            // The user now enters the checkcode on the other device which
358            // verifies it and will only continue requesting the login if the
359            // code matches.
360            //
361            // -- MSC4108 Secure channel setup step 7
362
363            // Inform the other device about the available login protocols and
364            // the homeserver to use.
365            //
366            // -- MSC4108 OAuth 2.0 login step 1
367            let message = match channel.channel_variant() {
368                ChannelVariant::Msc4108 => {
369                    QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
370                        protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
371                        homeserver: self.client.homeserver(),
372                    })
373                }
374                #[cfg(feature = "unstable-msc4388")]
375                ChannelVariant::Msc4388 => {
376                    QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
377                        protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
378                        base_url: self.client.homeserver(),
379                    })
380                }
381            };
382            channel.send_json(message).await?;
383
384            // Proceed with granting the login.
385            //
386            // -- MSC4108 OAuth 2.0 login remaining steps
387            finish_login_grant(
388                &self.client,
389                &mut channel,
390                self.device_creation_timeout,
391                &secrets_bundle,
392                &self.state,
393            )
394            .await
395        })
396    }
397}
398
399/// Named future for granting login by generating a QR code on this, existing,
400/// device to be scanned by the other, new, device.
401#[derive(Debug)]
402pub struct GrantLoginWithGeneratedQrCode {
403    client: Client,
404    device_creation_timeout: Duration,
405    state: SharedObservable<GrantLoginProgress<GeneratedQrProgress>>,
406    msc_4388_support: bool,
407}
408
409impl GrantLoginWithGeneratedQrCode {
410    pub(crate) fn new(
411        client: &Client,
412        device_creation_timeout: Duration,
413    ) -> GrantLoginWithGeneratedQrCode {
414        GrantLoginWithGeneratedQrCode {
415            client: client.clone(),
416            device_creation_timeout,
417            state: Default::default(),
418            msc_4388_support: false,
419        }
420    }
421}
422
423impl GrantLoginWithGeneratedQrCode {
424    /// Subscribe to the progress of QR code login.
425    ///
426    /// It's necessary to subscribe to this to capture the QR code in order to
427    /// display it to the other device, to feed the [`CheckCode`] entered by the
428    /// user back in and to obtain the verification URL for consenting to the
429    /// login.
430    pub fn subscribe_to_progress(
431        &self,
432    ) -> impl Stream<Item = GrantLoginProgress<GeneratedQrProgress>> + use<> {
433        self.state.subscribe()
434    }
435
436    /// Enable and generate a QR code which supports [MSC4388].
437    ///
438    /// [MSC4388]: https://github.com/matrix-org/matrix-spec-proposals/pull/4388
439    #[cfg(feature = "unstable-msc4388")]
440    pub fn with_msc4388_support(&mut self) -> &mut Self {
441        self.msc_4388_support = true;
442        self
443    }
444}
445
446impl IntoFuture for GrantLoginWithGeneratedQrCode {
447    type Output = Result<(), QRCodeGrantLoginError>;
448    boxed_into_future!();
449
450    fn into_future(self) -> Self::IntoFuture {
451        Box::pin(async move {
452            // Create a new ephemeral key pair and a rendezvous session to grant
453            // a login with.
454            //
455            // -- MSC4108 Secure channel setup steps 1 & 2
456            let secrets_bundle = export_secrets_bundle(&self.client).await?;
457            let channel = SecureChannel::reciprocate(&self.client, self.msc_4388_support).await?;
458
459            // Extract the QR code data and emit an update so that the caller
460            // can present the QR code for scanning by the new device.
461            //
462            // -- MSC4108 Secure channel setup step 3
463            self.state.set(GrantLoginProgress::EstablishingSecureChannel(
464                GeneratedQrProgress::QrReady(channel.qr_code_data().clone()),
465            ));
466
467            // Wait for the secure channel to connect. The other device now
468            // needs to scan the QR code and send us the LoginInitiateMessage
469            // which we respond to with the LoginOkMessage.
470            //
471            // -- MSC4108 step 4 & 5
472            let channel = channel.connect().await?;
473
474            // The other device now needs to verify our message, compute the
475            // checkcode and display it. We emit a progress update to let the
476            // caller prompt the user to enter the checkcode and feed it back to
477            // us.
478            //
479            // -- MSC4108 Secure channel setup step 6
480            let (tx, rx) = tokio::sync::oneshot::channel();
481            self.state.set(GrantLoginProgress::EstablishingSecureChannel(
482                GeneratedQrProgress::QrScanned(CheckCodeSender::new(tx)),
483            ));
484            let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
485
486            // Use the checkcode to verify that the channel is actually
487            // secure.
488            //
489            // -- MSC4108 Secure channel setup step 7
490            let mut channel = channel.confirm(check_code)?;
491
492            // Inform the other device about the available login protocols and
493            // the homeserver to use. The MSC requires this message to always be
494            // sent first, but we only do so for the MSC4388 variant: with the
495            // MSC4108 variant the new device derives the homeserver from the
496            // QR code and doesn't expect this message, so we skip it to stay
497            // compatible with existing implementations.
498            //
499            // -- MSC4108 OAuth 2.0 login step 1
500            match channel.channel_variant() {
501                ChannelVariant::Msc4108 => {}
502                #[cfg(feature = "unstable-msc4388")]
503                ChannelVariant::Msc4388 => {
504                    let message = QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
505                        protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
506                        base_url: self.client.homeserver(),
507                    });
508                    channel.send_json(message).await?;
509                }
510            }
511
512            // Proceed with granting the login.
513            //
514            // -- MSC4108 OAuth 2.0 login remaining steps
515            finish_login_grant(
516                &self.client,
517                &mut channel,
518                self.device_creation_timeout,
519                &secrets_bundle,
520                &self.state,
521            )
522            .await
523        })
524    }
525}
526
527#[cfg(all(test, not(target_family = "wasm")))]
528mod test {
529    use std::{assert_matches, sync::Arc};
530
531    use futures_util::StreamExt;
532    use matrix_sdk_base::{
533        CancellableIntoFutureExt,
534        crypto::types::{SecretsBundle, qr_login::QrCodeIntentData},
535    };
536    use matrix_sdk_common::executor::spawn;
537    use matrix_sdk_test::async_test;
538    use oauth2::{EndUserVerificationUrl, VerificationUriComplete};
539    use ruma::{owned_device_id, owned_user_id};
540    use strass::assert_let;
541    use tokio::sync::oneshot;
542    use tracing::debug;
543
544    use super::*;
545    use crate::{
546        authentication::oauth::qrcode::{
547            LoginFailureReason, MessageDecodeError, QrAuthMessage,
548            messages::AuthorizationGrant,
549            secure_channel::{EstablishedSecureChannel, test::MockedRendezvousServer},
550        },
551        test_utils::mocks::MatrixMockServer,
552    };
553
554    enum BobBehaviour {
555        HappyPath,
556        UnexpectedMessageInsteadOfLoginProtocol,
557        LoginFailureInsteadOfLoginProtocol,
558        UnexpectedMessageInsteadOfLoginSuccess,
559        LoginFailureInsteadOfLoginSuccess,
560        DeviceAlreadyExists,
561        DeviceNotCreated,
562        InvalidJsonMessage,
563        /// Alice cancels after Bob signals that he received
564        /// `m.login.protocol_accepted`.
565        CancelledWhileWaitingForAuth(oneshot::Sender<()>),
566        UnsupportedProtocol,
567        UnsupportedProtocolWithDeviceAuthorizationGrant,
568        MissingDeviceAuthorizationGrant,
569        MismatchedDeviceAuthorizationGrantLayout,
570    }
571
572    #[allow(clippy::too_many_arguments)]
573    async fn request_login_with_scanned_qr_code(
574        behaviour: BobBehaviour,
575        qr_code_rx: oneshot::Receiver<QrCodeData>,
576        check_code_tx: oneshot::Sender<u8>,
577        server: Option<MatrixMockServer>,
578        // The rendezvous server is here because it contains MockGuards that are
579        // tied to the lifetime of the MatrixMockServer. Otherwise we might
580        // attempt to drop the MatrixMockServer before the MockGuards.
581        _rendezvous_server: &MockedRendezvousServer,
582        device_authorization_grant: Option<AuthorizationGrant>,
583        secrets_bundle: Option<SecretsBundle>,
584    ) {
585        // Wait for Alice to produce the qr code.
586        let qr_code_data = qr_code_rx.await.expect("Bob should receive the QR code");
587
588        // Use the QR code to establish the secure channel from the new client
589        // (Bob).
590        let mut bob = EstablishedSecureChannel::from_qr_code(
591            reqwest::Client::new(),
592            &qr_code_data,
593            QrCodeIntent::Login,
594        )
595        .await
596        .expect("Bob should be able to connect the secure channel");
597
598        // Let Alice know about the checkcode so she can verify the channel.
599        check_code_tx.send(bob.check_code()).expect("Bob should be able to send the checkcode");
600
601        // With MSC4388, Alice informs us about the available login protocols
602        // even though we already know the homeserver from the QR code.
603        if let QrCodeIntentData::Msc4388 { base_url: qr_base_url, .. } = qr_code_data.intent_data()
604        {
605            let message = bob
606                .receive_json()
607                .await
608                .expect("Bob should receive the LoginProtocols message from Alice");
609
610            assert_let!(
611                QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
612                    protocols,
613                    base_url,
614                }) = message
615            );
616
617            assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
618            assert_eq!(&base_url, qr_base_url.as_url());
619        }
620
621        match behaviour {
622            BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
623                // Send an unexpected message and exit.
624                let message = QrAuthMessage::LoginSuccess;
625                bob.send_json(message).await.unwrap();
626                return;
627            }
628            BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
629                // Send a LoginFailure message instead of LoginProtocol.
630                let message = QrAuthMessage::LoginFailure {
631                    reason: LoginFailureReason::UserCancelled,
632                    homeserver: None,
633                };
634                bob.send_json(message).await.unwrap();
635                return;
636            }
637            BobBehaviour::InvalidJsonMessage => {
638                // Send invalid JSON that cannot be deserialized as
639                // QrAuthMessage.
640                bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
641                return;
642            }
643            BobBehaviour::DeviceAlreadyExists => {
644                // Mock the endpoint for querying devices so that Alice thinks
645                // the device already exists.
646                server
647                    .as_ref()
648                    .expect("Bob needs the server for DeviceAlreadyExists")
649                    .mock_get_device()
650                    .ok()
651                    .expect(1..)
652                    .named("get_device")
653                    .mount()
654                    .await;
655
656                // Now send the LoginProtocol message.
657                let message = QrAuthMessage::LoginProtocol {
658                    protocol: LoginProtocolData::device_authorization_grant(
659                        device_authorization_grant
660                            .expect("Bob needs the device authorization grant"),
661                        bob.channel_variant(),
662                    ),
663                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
664                };
665                bob.send_json(message).await.unwrap();
666
667                // Alice should fail the login with the appropriate reason.
668                let message = bob
669                    .receive_json()
670                    .await
671                    .expect("Bob should receive the LoginFailure message from Alice");
672                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
673                assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
674
675                return; // Exit.
676            }
677            BobBehaviour::UnsupportedProtocol => {
678                // Request a protocol that Alice did not offer.
679                bob.send_json(serde_json::json!({
680                    "type": "m.login.protocol",
681                    "protocol": "m.unknown_protocol",
682                    "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
683                }))
684                .await
685                .unwrap();
686
687                // Alice should reject the protocol.
688                let message = bob
689                    .receive_json()
690                    .await
691                    .expect("Bob should receive the LoginFailure message from Alice");
692                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
693                assert_matches!(reason, LoginFailureReason::UnsupportedProtocol);
694
695                return; // Exit.
696            }
697            BobBehaviour::UnsupportedProtocolWithDeviceAuthorizationGrant => {
698                // Request a protocol that Alice did not offer, while also
699                // including a device authorization grant.
700                bob.send_json(serde_json::json!({
701                    "type": "m.login.protocol",
702                    "protocol": "m.unknown_protocol",
703                    "device_authorization_grant": device_authorization_grant
704                        .expect("Bob needs the device authorization grant"),
705                    "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
706                }))
707                .await
708                .unwrap();
709
710                // Alice should reject the protocol, regardless of the device
711                // authorization grant.
712                let message = bob
713                    .receive_json()
714                    .await
715                    .expect("Bob should receive the LoginFailure message from Alice");
716                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
717                assert_matches!(reason, LoginFailureReason::UnsupportedProtocol);
718
719                return; // Exit.
720            }
721            BobBehaviour::MissingDeviceAuthorizationGrant => {
722                // Request the device authorization grant protocol without
723                // including the device authorization grant.
724                bob.send_json(serde_json::json!({
725                    "type": "m.login.protocol",
726                    "protocol": "device_authorization_grant",
727                    "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
728                }))
729                .await
730                .unwrap();
731
732                return;
733            }
734            BobBehaviour::MismatchedDeviceAuthorizationGrantLayout => {
735                // Send the device authorization grant with the layout of the
736                // other channel variant.
737                let device_authorization_grant =
738                    device_authorization_grant.expect("Bob needs the device authorization grant");
739                let protocol = match bob.channel_variant() {
740                    ChannelVariant::Msc4108 => LoginProtocolData::Msc4388DeviceAuthorizationGrant(
741                        device_authorization_grant,
742                    ),
743                    #[cfg(feature = "unstable-msc4388")]
744                    ChannelVariant::Msc4388 => LoginProtocolData::Msc4108DeviceAuthorizationGrant(
745                        device_authorization_grant,
746                    ),
747                };
748                let message = QrAuthMessage::LoginProtocol {
749                    protocol,
750                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
751                };
752                bob.send_json(message).await.unwrap();
753
754                // Alice should reject the message.
755                let message = bob
756                    .receive_json()
757                    .await
758                    .expect("Bob should receive the LoginFailure message from Alice");
759                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
760                assert_matches!(reason, LoginFailureReason::UnexpectedMessageReceived);
761
762                return; // Exit.
763            }
764            BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx) => {
765                // Send the LoginProtocol message.
766                let message = QrAuthMessage::LoginProtocol {
767                    protocol: LoginProtocolData::device_authorization_grant(
768                        device_authorization_grant
769                            .expect("Bob needs the device authorization grant"),
770                        bob.channel_variant(),
771                    ),
772                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
773                };
774                bob.send_json(message).await.unwrap();
775
776                // Receive the LoginProtocolAccepted message.
777                let message = bob
778                    .receive_json()
779                    .await
780                    .expect("Bob should receive the LoginProtocolAccepted message from Alice");
781                assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
782
783                // Let Alice know she can cancel now.
784                protocol_accepted_tx
785                    .send(())
786                    .expect("Bob should be able to signal that the protocol was accepted");
787
788                // Alice cancels while waiting for the authorization and should
789                // fail the login with the appropriate reason.
790                let message = bob
791                    .receive_json()
792                    .await
793                    .expect("Bob should receive the LoginFailure message from Alice");
794                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
795                assert_matches!(reason, LoginFailureReason::UserCancelled);
796
797                return; // Exit.
798            }
799            _ => {
800                // Send the LoginProtocol message.
801                let message = QrAuthMessage::LoginProtocol {
802                    protocol: LoginProtocolData::device_authorization_grant(
803                        device_authorization_grant
804                            .expect("Bob needs the device authorization grant"),
805                        bob.channel_variant(),
806                    ),
807                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
808                };
809                bob.send_json(message).await.unwrap();
810            }
811        }
812
813        // Receive the LoginProtocolAccepted message.
814        let message = bob
815            .receive_json()
816            .await
817            .expect("Bob should receive the LoginProtocolAccepted message from Alice");
818        assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
819
820        match behaviour {
821            BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
822                // Send an unexpected message instead of LoginSuccess.
823                let message = QrAuthMessage::LoginProtocolAccepted;
824                bob.send_json(message).await.unwrap();
825                return;
826            }
827            BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
828                // Send a LoginFailure message instead of LoginSuccess.
829                let message = QrAuthMessage::LoginFailure {
830                    reason: LoginFailureReason::AuthorizationExpired,
831                    homeserver: None,
832                };
833                bob.send_json(message).await.unwrap();
834                return;
835            }
836            BobBehaviour::DeviceNotCreated => {
837                // Don't mock the endpoint for querying devices so that Alice
838                // cannot verify that we have logged in.
839
840                // Send the LoginSuccess message to claim that we have logged
841                // in.
842                let message = QrAuthMessage::LoginSuccess;
843                bob.send_json(message).await.unwrap();
844
845                // Alice should eventually give up querying our device and fail
846                // the login with the appropriate reason.
847                let message = bob
848                    .receive_json()
849                    .await
850                    .expect("Bob should receive the LoginFailure message from Alice");
851                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
852                assert_matches!(reason, LoginFailureReason::DeviceNotFound);
853
854                return; // Exit.
855            }
856            _ => {
857                // Mock the endpoint for querying devices so that Alice thinks
858                // we have logged in.
859                server
860                    .as_ref()
861                    .expect("Bob needs the server for HappyPath")
862                    .mock_get_device()
863                    .ok()
864                    .expect(1..)
865                    .named("get_device")
866                    .mount()
867                    .await;
868
869                // Send the LoginSuccess message.
870                let message = QrAuthMessage::LoginSuccess;
871                bob.send_json(message).await.unwrap();
872            }
873        }
874
875        // Receive the LoginSecrets message.
876        let message = bob
877            .receive_json()
878            .await
879            .expect("Bob should receive the LoginSecrets message from Alice");
880        assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
881
882        // Verify that we received the correct secrets.
883        assert_eq!(
884            serde_json::to_value(&secrets_bundle).unwrap(),
885            serde_json::to_value(&bundle).unwrap()
886        );
887    }
888
889    #[allow(clippy::too_many_arguments)]
890    async fn request_login_with_generated_qr_code(
891        behaviour: BobBehaviour,
892        channel: SecureChannel,
893        check_code_rx: oneshot::Receiver<u8>,
894        server: Option<MatrixMockServer>,
895        // The rendezvous server is here because it contains MockGuards that are
896        // tied to the lifetime of the MatrixMockServer. Otherwise we might
897        // attempt to drop the MatrixMockServer before the MockGuards.
898        _rendezvous_server: &MockedRendezvousServer,
899        homeserver: Url,
900        device_authorization_grant: Option<AuthorizationGrant>,
901        secrets_bundle: Option<SecretsBundle>,
902    ) {
903        let is_using_msc_4388 = match channel.qr_code_data().intent_data() {
904            QrCodeIntentData::Msc4108 { .. } => false,
905            QrCodeIntentData::Msc4388 { .. } => true,
906        };
907
908        // Wait for Alice to scan the qr code and connect the secure channel.
909        let channel =
910            channel.connect().await.expect("Bob should be able to connect the secure channel");
911
912        // Wait for Alice to send us the checkcode and use it to verify the
913        // channel.
914        let check_code = check_code_rx.await.expect("Bob should receive the checkcode");
915        let mut bob = channel
916            .confirm(check_code)
917            .expect("Bob should be able to confirm the channel is secure");
918
919        // Receive the LoginProtocols message.
920        let message = bob
921            .receive_json()
922            .await
923            .expect("Bob should receive the LoginProtocolAccepted message from Alice");
924
925        let (protocols, alice_homeserver) = if is_using_msc_4388 {
926            assert_let!(
927                QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
928                    protocols,
929                    base_url,
930                }) = message
931            );
932
933            (protocols, base_url)
934        } else {
935            assert_let!(
936                QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
937                    protocols,
938                    homeserver,
939                }) = message
940            );
941
942            (protocols, homeserver)
943        };
944
945        assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
946        assert_eq!(alice_homeserver, homeserver);
947
948        match behaviour {
949            BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
950                // Send an unexpected message and exit.
951                let message = QrAuthMessage::LoginSuccess;
952                bob.send_json(message).await.unwrap();
953                return;
954            }
955            BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
956                // Send a LoginFailure message instead of LoginProtocol.
957                let message = QrAuthMessage::LoginFailure {
958                    reason: LoginFailureReason::UserCancelled,
959                    homeserver: None,
960                };
961                bob.send_json(message).await.unwrap();
962                return;
963            }
964            BobBehaviour::InvalidJsonMessage => {
965                // Send invalid JSON that cannot be deserialized as
966                // QrAuthMessage.
967                bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
968                return;
969            }
970            BobBehaviour::DeviceAlreadyExists => {
971                // Mock the endpoint for querying devices so that Alice thinks
972                // the device already exists.
973                server
974                    .as_ref()
975                    .expect("Bob needs the MatrixMockServer")
976                    .mock_get_device()
977                    .ok()
978                    .expect(1..)
979                    .named("get_device")
980                    .mount()
981                    .await;
982
983                // Now send the LoginProtocol message.
984                let message = QrAuthMessage::LoginProtocol {
985                    protocol: LoginProtocolData::device_authorization_grant(
986                        device_authorization_grant
987                            .expect("Bob needs the device authorization grant"),
988                        bob.channel_variant(),
989                    ),
990                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
991                };
992                bob.send_json(message).await.unwrap();
993
994                // Alice should fail the login with the appropriate reason.
995                let message = bob
996                    .receive_json()
997                    .await
998                    .expect("Bob should receive the LoginFailure message from Alice");
999                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1000                assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
1001
1002                return; // Exit.
1003            }
1004            BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx) => {
1005                // Send the LoginProtocol message.
1006                let message = QrAuthMessage::LoginProtocol {
1007                    protocol: LoginProtocolData::device_authorization_grant(
1008                        device_authorization_grant
1009                            .expect("Bob needs the device authorization grant"),
1010                        bob.channel_variant(),
1011                    ),
1012                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
1013                };
1014                bob.send_json(message).await.unwrap();
1015
1016                // Receive the LoginProtocolAccepted message.
1017                let message = bob
1018                    .receive_json()
1019                    .await
1020                    .expect("Bob should receive the LoginProtocolAccepted message from Alice");
1021                assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
1022
1023                // Let Alice know she can cancel now.
1024                protocol_accepted_tx
1025                    .send(())
1026                    .expect("Bob should be able to signal that the protocol was accepted");
1027
1028                // Alice cancels while waiting for the authorization and should
1029                // fail the login with the appropriate reason.
1030                let message = bob
1031                    .receive_json()
1032                    .await
1033                    .expect("Bob should receive the LoginFailure message from Alice");
1034                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1035                assert_matches!(reason, LoginFailureReason::UserCancelled);
1036
1037                return; // Exit.
1038            }
1039            _ => {
1040                // Send the LoginProtocol message.
1041                let message = QrAuthMessage::LoginProtocol {
1042                    protocol: LoginProtocolData::device_authorization_grant(
1043                        device_authorization_grant
1044                            .expect("Bob needs the device authorization grant"),
1045                        bob.channel_variant(),
1046                    ),
1047                    device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
1048                };
1049                bob.send_json(message).await.unwrap();
1050            }
1051        }
1052
1053        // Receive the LoginProtocolAccepted message.
1054        let message = bob
1055            .receive_json()
1056            .await
1057            .expect("Bob should receive the LoginProtocolAccepted message from Alice");
1058        assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
1059
1060        match behaviour {
1061            BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
1062                // Send an unexpected message instead of LoginSuccess.
1063                let message = QrAuthMessage::LoginProtocolAccepted;
1064                bob.send_json(message).await.unwrap();
1065                return;
1066            }
1067            BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
1068                // Send a LoginFailure message instead of LoginSuccess.
1069                let message = QrAuthMessage::LoginFailure {
1070                    reason: LoginFailureReason::AuthorizationExpired,
1071                    homeserver: None,
1072                };
1073                bob.send_json(message).await.unwrap();
1074                return;
1075            }
1076            BobBehaviour::DeviceNotCreated => {
1077                // Don't mock the endpoint for querying devices so that Alice
1078                // cannot verify that we have logged in.
1079
1080                // Send the LoginSuccess message to claim that we have logged
1081                // in.
1082                let message = QrAuthMessage::LoginSuccess;
1083                bob.send_json(message).await.unwrap();
1084
1085                // Alice should eventually give up querying our device and fail
1086                // the login with the appropriate reason.
1087                let message = bob
1088                    .receive_json()
1089                    .await
1090                    .expect("Bob should receive the LoginFailure message from Alice");
1091                assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1092                assert_matches!(reason, LoginFailureReason::DeviceNotFound);
1093
1094                return; // Exit.
1095            }
1096            _ => {
1097                // Mock the endpoint for querying devices so that Alice thinks
1098                // we have logged in.
1099                server
1100                    .as_ref()
1101                    .expect("Bob needs the MatrixMockServer")
1102                    .mock_get_device()
1103                    .ok()
1104                    .expect(1..)
1105                    .named("get_device")
1106                    .mount()
1107                    .await;
1108
1109                // Send the LoginSuccess message.
1110                let message = QrAuthMessage::LoginSuccess;
1111                bob.send_json(message).await.unwrap();
1112            }
1113        }
1114
1115        // Receive the LoginSecrets message.
1116        let message = bob
1117            .receive_json()
1118            .await
1119            .expect("Bob should receive the LoginSecrets message from Alice");
1120        assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
1121
1122        // Verify that we received the correct secrets.
1123        assert_eq!(
1124            serde_json::to_value(&secrets_bundle).unwrap(),
1125            serde_json::to_value(&bundle).unwrap()
1126        );
1127    }
1128
1129    async fn test_grant_login_with_generated_qr_code(msc_4388: bool) {
1130        let server = MatrixMockServer::new().await;
1131        let rendezvous_server =
1132            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1133                .await;
1134        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1135
1136        let device_authorization_grant = AuthorizationGrant {
1137            verification_uri_complete: Some(VerificationUriComplete::new(
1138                "https://id.matrix.org/device/abcde".to_owned(),
1139            )),
1140            verification_uri: EndUserVerificationUrl::new(
1141                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1142            )
1143            .unwrap(),
1144        };
1145
1146        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1147        server
1148            .mock_upload_cross_signing_keys()
1149            .ok()
1150            .expect(1)
1151            .named("upload_xsigning_keys")
1152            .mount()
1153            .await;
1154        server
1155            .mock_upload_cross_signing_signatures()
1156            .ok()
1157            .expect(1)
1158            .named("upload_xsigning_signatures")
1159            .mount()
1160            .await;
1161
1162        // Create the existing client (Alice).
1163        let user_id = owned_user_id!("@alice:example.org");
1164        let device_id = owned_device_id!("ALICE_DEVICE");
1165        let alice = server
1166            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1167            .logged_in_with_oauth()
1168            .build()
1169            .await;
1170        alice
1171            .encryption()
1172            .bootstrap_cross_signing(None)
1173            .await
1174            .expect("Alice should be able to set up cross signing");
1175
1176        // Prepare the login granting future.
1177        let oauth = alice.oauth();
1178        #[allow(unused_mut)]
1179        let mut grant = oauth
1180            .grant_login_with_qr_code()
1181            .device_creation_timeout(Duration::from_secs(2))
1182            .generate();
1183
1184        #[cfg(feature = "unstable-msc4388")]
1185        if msc_4388 {
1186            grant.with_msc4388_support();
1187        }
1188
1189        let secrets_bundle = export_secrets_bundle(&alice)
1190            .await
1191            .expect("Alice should be able to export the secrets bundle");
1192        let (qr_code_tx, qr_code_rx) = oneshot::channel();
1193        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1194
1195        // Spawn the updates task.
1196        let mut updates = grant.subscribe_to_progress();
1197        let mut state = grant.state.get();
1198        let verification_uri_complete =
1199            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1200        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1201        let updates_task = spawn(async move {
1202            let mut qr_code_tx = Some(qr_code_tx);
1203            let mut checkcode_rx = Some(checkcode_rx);
1204
1205            while let Some(update) = updates.next().await {
1206                match &update {
1207                    GrantLoginProgress::Starting => {
1208                        assert_matches!(state, GrantLoginProgress::Starting);
1209                    }
1210                    GrantLoginProgress::EstablishingSecureChannel(
1211                        GeneratedQrProgress::QrReady(qr_code_data),
1212                    ) => {
1213                        assert_matches!(state, GrantLoginProgress::Starting);
1214                        qr_code_tx
1215                            .take()
1216                            .expect("The QR code should only be forwarded once")
1217                            .send(qr_code_data.clone())
1218                            .expect("Alice should be able to forward the QR code");
1219                    }
1220                    GrantLoginProgress::EstablishingSecureChannel(
1221                        GeneratedQrProgress::QrScanned(checkcode_sender),
1222                    ) => {
1223                        assert_matches!(
1224                            state,
1225                            GrantLoginProgress::EstablishingSecureChannel(
1226                                GeneratedQrProgress::QrReady(_)
1227                            )
1228                        );
1229                        let checkcode = checkcode_rx
1230                            .take()
1231                            .expect("The checkcode should only be forwarded once")
1232                            .await
1233                            .expect("Alice should receive the checkcode");
1234                        checkcode_sender
1235                            .send(checkcode)
1236                            .await
1237                            .expect("Alice should be able to forward the checkcode");
1238                    }
1239                    GrantLoginProgress::WaitingForAuth {
1240                        verification_uri,
1241                        continuation_sender,
1242                    } => {
1243                        assert_matches!(
1244                            state,
1245                            GrantLoginProgress::EstablishingSecureChannel(
1246                                GeneratedQrProgress::QrScanned(_)
1247                            )
1248                        );
1249                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
1250                        continuation_sender.confirm().await.expect("should be able to confirm");
1251                    }
1252                    GrantLoginProgress::SyncingSecrets => {
1253                        assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1254                    }
1255                    GrantLoginProgress::Done => {
1256                        assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1257                        break;
1258                    }
1259                }
1260                state = update;
1261            }
1262        });
1263
1264        // Let Bob request the login and run through the process.
1265        let bob_task = spawn(async move {
1266            request_login_with_scanned_qr_code(
1267                BobBehaviour::HappyPath,
1268                qr_code_rx,
1269                checkcode_tx,
1270                Some(server),
1271                &rendezvous_server,
1272                Some(device_authorization_grant),
1273                Some(secrets_bundle),
1274            )
1275            .await;
1276        });
1277
1278        // Wait for all tasks to finish.
1279        grant.await.expect("Alice should be able to grant the login");
1280        updates_task.await.expect("Alice should run through all progress states");
1281        bob_task.await.expect("Bob's task should finish");
1282    }
1283
1284    #[async_test]
1285    async fn test_grant_login_with_generated_qr_code_msc_4108() {
1286        test_grant_login_with_generated_qr_code(false).await;
1287    }
1288
1289    #[async_test]
1290    #[cfg(feature = "unstable-msc4388")]
1291    async fn test_grant_login_with_generated_qr_code_msc_4388() {
1292        test_grant_login_with_generated_qr_code(true).await;
1293    }
1294
1295    async fn test_grant_login_with_scanned_qr_code(msc_4388: bool) {
1296        let server = MatrixMockServer::new().await;
1297        let rendezvous_server =
1298            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1299                .await;
1300        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1301
1302        let device_authorization_grant = AuthorizationGrant {
1303            verification_uri_complete: Some(VerificationUriComplete::new(
1304                "https://id.matrix.org/device/abcde".to_owned(),
1305            )),
1306            verification_uri: EndUserVerificationUrl::new(
1307                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1308            )
1309            .unwrap(),
1310        };
1311
1312        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1313        server
1314            .mock_upload_cross_signing_keys()
1315            .ok()
1316            .expect(1)
1317            .named("upload_xsigning_keys")
1318            .mount()
1319            .await;
1320        server
1321            .mock_upload_cross_signing_signatures()
1322            .ok()
1323            .expect(1)
1324            .named("upload_xsigning_signatures")
1325            .mount()
1326            .await;
1327
1328        // Create a secure channel on the new client (Bob) and extract the QR
1329        // code.
1330        let client = rendezvous_server.unlogged_client().await;
1331        let channel = SecureChannel::login(&client, msc_4388)
1332            .await
1333            .expect("Bob should be able to create a secure channel.");
1334        let qr_code_data = channel.qr_code_data().clone();
1335
1336        // Create the existing client (Alice).
1337        let user_id = owned_user_id!("@alice:example.org");
1338        let device_id = owned_device_id!("ALICE_DEVICE");
1339        let alice = server
1340            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1341            .logged_in_with_oauth()
1342            .build()
1343            .await;
1344        alice
1345            .encryption()
1346            .bootstrap_cross_signing(None)
1347            .await
1348            .expect("Alice should be able to set up cross signing");
1349
1350        // Prepare the login granting future using the QR code.
1351        let oauth = alice.oauth();
1352        let grant = oauth
1353            .grant_login_with_qr_code()
1354            .device_creation_timeout(Duration::from_secs(2))
1355            .scan(&qr_code_data);
1356        let secrets_bundle = export_secrets_bundle(&alice)
1357            .await
1358            .expect("Alice should be able to export the secrets bundle");
1359        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1360
1361        // Spawn the updates task.
1362        let mut updates = grant.subscribe_to_progress();
1363        let mut state = grant.state.get();
1364        let verification_uri_complete =
1365            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1366        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1367        let updates_task = spawn(async move {
1368            let mut checkcode_tx = Some(checkcode_tx);
1369
1370            while let Some(update) = updates.next().await {
1371                match &update {
1372                    GrantLoginProgress::Starting => {
1373                        assert_matches!(state, GrantLoginProgress::Starting);
1374                    }
1375                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1376                        assert_matches!(state, GrantLoginProgress::Starting);
1377                        checkcode_tx
1378                            .take()
1379                            .expect("The checkcode should only be forwarded once")
1380                            .send(*check_code)
1381                            .expect("Alice should be able to forward the checkcode");
1382                    }
1383                    GrantLoginProgress::WaitingForAuth {
1384                        verification_uri,
1385                        continuation_sender,
1386                    } => {
1387                        assert_matches!(
1388                            state,
1389                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1390                        );
1391                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
1392                        continuation_sender.confirm().await.expect("should be able to confirm");
1393                    }
1394                    GrantLoginProgress::SyncingSecrets => {
1395                        assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1396                    }
1397                    GrantLoginProgress::Done => {
1398                        assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1399                        break;
1400                    }
1401                }
1402                state = update;
1403            }
1404        });
1405
1406        // Let Bob request the login and run through the process.
1407        let bob_task = spawn(async move {
1408            request_login_with_generated_qr_code(
1409                BobBehaviour::HappyPath,
1410                channel,
1411                checkcode_rx,
1412                Some(server),
1413                &rendezvous_server,
1414                alice.homeserver(),
1415                Some(device_authorization_grant),
1416                Some(secrets_bundle),
1417            )
1418            .await;
1419        });
1420
1421        // Wait for all tasks to finish.
1422        grant.await.expect("Alice should be able to grant the login");
1423        updates_task.await.expect("Alice should run through all progress states");
1424        bob_task.await.expect("Bob's task should finish");
1425    }
1426
1427    #[async_test]
1428    async fn test_grant_login_with_scanned_qr_code_msc_4108() {
1429        test_grant_login_with_scanned_qr_code(false).await;
1430    }
1431
1432    #[async_test]
1433    #[cfg(feature = "unstable-msc4388")]
1434    async fn test_grant_login_with_scanned_qr_code_msc_4388() {
1435        test_grant_login_with_scanned_qr_code(true).await;
1436    }
1437
1438    #[async_test]
1439    async fn test_grant_login_with_scanned_qr_code_with_homeserver_swap() {
1440        let server = MatrixMockServer::new().await;
1441        let rendezvous_server =
1442            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1443                .await;
1444        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1445
1446        let device_authorization_grant = AuthorizationGrant {
1447            verification_uri_complete: Some(VerificationUriComplete::new(
1448                "https://id.matrix.org/device/abcde".to_owned(),
1449            )),
1450            verification_uri: EndUserVerificationUrl::new(
1451                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1452            )
1453            .unwrap(),
1454        };
1455
1456        let login_server = MatrixMockServer::new().await;
1457
1458        login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1459        login_server
1460            .mock_upload_cross_signing_keys()
1461            .ok()
1462            .expect(1)
1463            .named("upload_xsigning_keys")
1464            .mount()
1465            .await;
1466        login_server
1467            .mock_upload_cross_signing_signatures()
1468            .ok()
1469            .expect(1)
1470            .named("upload_xsigning_signatures")
1471            .mount()
1472            .await;
1473
1474        // Create a secure channel on the new client (Bob) and extract the QR
1475        // code.
1476        let client = rendezvous_server.unlogged_client().await;
1477        let channel = SecureChannel::login(&client, false)
1478            .await
1479            .expect("Bob should be able to create a secure channel.");
1480        let qr_code_data = channel.qr_code_data().clone();
1481
1482        // Create the existing client (Alice).
1483        let user_id = owned_user_id!("@alice:example.org");
1484        let device_id = owned_device_id!("ALICE_DEVICE");
1485        let alice = login_server
1486            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1487            .logged_in_with_oauth()
1488            .build()
1489            .await;
1490        alice
1491            .encryption()
1492            .bootstrap_cross_signing(None)
1493            .await
1494            .expect("Alice should be able to set up cross signing");
1495
1496        // Prepare the login granting future using the QR code.
1497        let oauth = alice.oauth();
1498        let grant = oauth
1499            .grant_login_with_qr_code()
1500            .device_creation_timeout(Duration::from_secs(2))
1501            .scan(&qr_code_data);
1502        let secrets_bundle = export_secrets_bundle(&alice)
1503            .await
1504            .expect("Alice should be able to export the secrets bundle");
1505        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1506
1507        // Spawn the updates task.
1508        let mut updates = grant.subscribe_to_progress();
1509        let mut state = grant.state.get();
1510        let verification_uri_complete =
1511            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1512        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1513        let updates_task = spawn(async move {
1514            let mut checkcode_tx = Some(checkcode_tx);
1515
1516            while let Some(update) = updates.next().await {
1517                match &update {
1518                    GrantLoginProgress::Starting => {
1519                        assert_matches!(state, GrantLoginProgress::Starting);
1520                    }
1521                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1522                        assert_matches!(state, GrantLoginProgress::Starting);
1523                        checkcode_tx
1524                            .take()
1525                            .expect("The checkcode should only be forwarded once")
1526                            .send(*check_code)
1527                            .expect("Alice should be able to forward the checkcode");
1528                    }
1529                    GrantLoginProgress::WaitingForAuth {
1530                        verification_uri,
1531                        continuation_sender,
1532                    } => {
1533                        assert_matches!(
1534                            state,
1535                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1536                        );
1537                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
1538                        continuation_sender.confirm().await.expect("should be able to confirm");
1539                    }
1540                    GrantLoginProgress::SyncingSecrets => {
1541                        assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1542                    }
1543                    GrantLoginProgress::Done => {
1544                        assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1545                        break;
1546                    }
1547                }
1548                state = update;
1549            }
1550        });
1551
1552        // Let Bob request the login and run through the process.
1553        let bob_task = spawn(async move {
1554            request_login_with_generated_qr_code(
1555                BobBehaviour::HappyPath,
1556                channel,
1557                checkcode_rx,
1558                Some(login_server),
1559                &rendezvous_server,
1560                alice.homeserver(),
1561                Some(device_authorization_grant),
1562                Some(secrets_bundle),
1563            )
1564            .await;
1565        });
1566
1567        // Wait for all tasks to finish.
1568        grant.await.expect("Alice should be able to grant the login");
1569        updates_task.await.expect("Alice should run through all progress states");
1570        bob_task.await.expect("Bob's task should finish");
1571    }
1572
1573    #[async_test]
1574    async fn test_grant_login_with_generated_qr_code_grant_cancelled() {
1575        let server = MatrixMockServer::new().await;
1576        let rendezvous_server = Arc::new(
1577            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1578                .await,
1579        );
1580        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1581
1582        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1583        server
1584            .mock_upload_cross_signing_keys()
1585            .ok()
1586            .expect(1)
1587            .named("upload_xsigning_keys")
1588            .mount()
1589            .await;
1590        server
1591            .mock_upload_cross_signing_signatures()
1592            .ok()
1593            .expect(1)
1594            .named("upload_xsigning_signatures")
1595            .mount()
1596            .await;
1597
1598        // Create the existing client (Alice).
1599        let user_id = owned_user_id!("@alice:example.org");
1600        let device_id = owned_device_id!("ALICE_DEVICE");
1601        let alice = server
1602            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1603            .logged_in_with_oauth()
1604            .build()
1605            .await;
1606        alice
1607            .encryption()
1608            .bootstrap_cross_signing(None)
1609            .await
1610            .expect("Alice should be able to set up cross signing");
1611
1612        // Prepare the login granting future.
1613        let oauth = alice.oauth();
1614
1615        let grant = oauth
1616            .grant_login_with_qr_code()
1617            .device_creation_timeout(Duration::from_secs(2))
1618            .generate();
1619        let (qr_code_tx, qr_code_rx) = oneshot::channel();
1620        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1621
1622        // Spawn the updates task.
1623        let mut updates = grant.subscribe_to_progress();
1624        let mut state = grant.state.get();
1625        let grant = grant.cancellable();
1626        let cancel = grant.cancellation_token();
1627        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1628        let updates_task = spawn(async move {
1629            let mut qr_code_tx = Some(qr_code_tx);
1630            let mut checkcode_rx = Some(checkcode_rx);
1631
1632            while let Some(update) = updates.next().await {
1633                match &update {
1634                    GrantLoginProgress::Starting => {
1635                        assert_matches!(state, GrantLoginProgress::Starting);
1636                    }
1637                    GrantLoginProgress::EstablishingSecureChannel(
1638                        GeneratedQrProgress::QrReady(qr_code_data),
1639                    ) => {
1640                        assert_matches!(state, GrantLoginProgress::Starting);
1641                        qr_code_tx
1642                            .take()
1643                            .expect("The QR code should only be forwarded once")
1644                            .send(qr_code_data.clone())
1645                            .expect("Alice should be able to forward the QR code");
1646                    }
1647                    GrantLoginProgress::EstablishingSecureChannel(
1648                        GeneratedQrProgress::QrScanned(checkcode_sender),
1649                    ) => {
1650                        assert_matches!(
1651                            state,
1652                            GrantLoginProgress::EstablishingSecureChannel(
1653                                GeneratedQrProgress::QrReady(_)
1654                            )
1655                        );
1656                        let checkcode = checkcode_rx
1657                            .take()
1658                            .expect("The checkcode should only be forwarded once")
1659                            .await
1660                            .expect("Alice should receive the checkcode");
1661                        checkcode_sender
1662                            .send(checkcode)
1663                            .await
1664                            .expect("Alice should be able to forward the checkcode");
1665                        cancel.cancel();
1666                        break;
1667                    }
1668                    _ => {
1669                        panic!("Alice should abort the process");
1670                    }
1671                }
1672                state = update;
1673            }
1674        });
1675
1676        // Let Bob request the login and run through the process.
1677        let rendezvous_server_clone = rendezvous_server.clone();
1678        let bob_task = spawn(async move {
1679            request_login_with_scanned_qr_code(
1680                BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1681                qr_code_rx,
1682                checkcode_tx,
1683                None,
1684                &rendezvous_server_clone,
1685                None,
1686                None,
1687            )
1688            .await;
1689        });
1690
1691        // Wait for all tasks to finish / fail.
1692        assert_matches!(grant.await, None, "Alice should abort the login by cancelling it");
1693        updates_task.await.expect("Alice should run through all progress states");
1694        bob_task.await.expect("Bob's task should finish");
1695    }
1696
1697    #[async_test]
1698    async fn test_grant_login_with_scanned_qr_code_grant_cancelled() {
1699        let server = MatrixMockServer::new().await;
1700        let rendezvous_server = Arc::new(
1701            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1702                .await,
1703        );
1704        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1705
1706        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1707        server
1708            .mock_upload_cross_signing_keys()
1709            .ok()
1710            .expect(1)
1711            .named("upload_xsigning_keys")
1712            .mount()
1713            .await;
1714        server
1715            .mock_upload_cross_signing_signatures()
1716            .ok()
1717            .expect(1)
1718            .named("upload_xsigning_signatures")
1719            .mount()
1720            .await;
1721
1722        // Create a secure channel on the new client (Bob) and extract the QR
1723        // code.
1724        let client = rendezvous_server.unlogged_client().await;
1725        let channel = SecureChannel::login(&client, false)
1726            .await
1727            .expect("Bob should be able to create a secure channel.");
1728        let qr_code_data = channel.qr_code_data().clone();
1729
1730        // Create the existing client (Alice).
1731        let user_id = owned_user_id!("@alice:example.org");
1732        let device_id = owned_device_id!("ALICE_DEVICE");
1733        let alice = server
1734            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1735            .logged_in_with_oauth()
1736            .build()
1737            .await;
1738        alice
1739            .encryption()
1740            .bootstrap_cross_signing(None)
1741            .await
1742            .expect("Alice should be able to set up cross signing");
1743
1744        // Prepare the login granting future using the QR code.
1745        let oauth = alice.oauth();
1746        let grant = oauth
1747            .grant_login_with_qr_code()
1748            .device_creation_timeout(Duration::from_secs(2))
1749            .scan(&qr_code_data);
1750        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1751
1752        // Spawn the updates task.
1753        let mut updates = grant.subscribe_to_progress();
1754        let mut state = grant.state.get();
1755        let grant = grant.cancellable();
1756        let cancel = grant.cancellation_token();
1757        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1758        let updates_task = spawn(async move {
1759            let mut checkcode_tx = Some(checkcode_tx);
1760
1761            while let Some(update) = updates.next().await {
1762                match &update {
1763                    GrantLoginProgress::Starting => {
1764                        assert_matches!(state, GrantLoginProgress::Starting);
1765                    }
1766                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1767                        assert_matches!(state, GrantLoginProgress::Starting);
1768                        checkcode_tx
1769                            .take()
1770                            .expect("The checkcode should only be forwarded once")
1771                            .send(*check_code)
1772                            .expect("Alice should be able to forward the checkcode");
1773                        cancel.cancel();
1774                        break;
1775                    }
1776                    _ => {
1777                        panic!("Alice should abort the process");
1778                    }
1779                }
1780                state = update;
1781            }
1782        });
1783
1784        let rendezvous_server_clone = rendezvous_server.clone();
1785        // Let Bob request the login and run through the process.
1786        let bob_task = spawn(async move {
1787            request_login_with_generated_qr_code(
1788                BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1789                channel,
1790                checkcode_rx,
1791                None,
1792                &rendezvous_server_clone,
1793                alice.homeserver(),
1794                None,
1795                None,
1796            )
1797            .await;
1798        });
1799
1800        // Wait for all tasks to finish / fail.
1801        assert_matches!(grant.await, None, "Alice should abort the login by cancelling it");
1802        updates_task.await.expect("Alice should run through all progress states");
1803        bob_task.await.expect("Bob's task should finish");
1804    }
1805
1806    #[async_test]
1807    async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_protocol()
1808    {
1809        let server = MatrixMockServer::new().await;
1810        let rendezvous_server = Arc::new(
1811            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1812                .await,
1813        );
1814        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1815
1816        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1817        server
1818            .mock_upload_cross_signing_keys()
1819            .ok()
1820            .expect(1)
1821            .named("upload_xsigning_keys")
1822            .mount()
1823            .await;
1824        server
1825            .mock_upload_cross_signing_signatures()
1826            .ok()
1827            .expect(1)
1828            .named("upload_xsigning_signatures")
1829            .mount()
1830            .await;
1831
1832        // Create the existing client (Alice).
1833        let user_id = owned_user_id!("@alice:example.org");
1834        let device_id = owned_device_id!("ALICE_DEVICE");
1835        let alice = server
1836            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1837            .logged_in_with_oauth()
1838            .build()
1839            .await;
1840        alice
1841            .encryption()
1842            .bootstrap_cross_signing(None)
1843            .await
1844            .expect("Alice should be able to set up cross signing");
1845
1846        // Prepare the login granting future.
1847        let oauth = alice.oauth();
1848        let grant = oauth
1849            .grant_login_with_qr_code()
1850            .device_creation_timeout(Duration::from_secs(2))
1851            .generate();
1852        let (qr_code_tx, qr_code_rx) = oneshot::channel();
1853        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1854
1855        // Spawn the updates task.
1856        let mut updates = grant.subscribe_to_progress();
1857        let mut state = grant.state.get();
1858        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1859        let updates_task = spawn(async move {
1860            let mut qr_code_tx = Some(qr_code_tx);
1861            let mut checkcode_rx = Some(checkcode_rx);
1862
1863            while let Some(update) = updates.next().await {
1864                match &update {
1865                    GrantLoginProgress::Starting => {
1866                        assert_matches!(state, GrantLoginProgress::Starting);
1867                    }
1868                    GrantLoginProgress::EstablishingSecureChannel(
1869                        GeneratedQrProgress::QrReady(qr_code_data),
1870                    ) => {
1871                        assert_matches!(state, GrantLoginProgress::Starting);
1872                        qr_code_tx
1873                            .take()
1874                            .expect("The QR code should only be forwarded once")
1875                            .send(qr_code_data.clone())
1876                            .expect("Alice should be able to forward the QR code");
1877                    }
1878                    GrantLoginProgress::EstablishingSecureChannel(
1879                        GeneratedQrProgress::QrScanned(checkcode_sender),
1880                    ) => {
1881                        assert_matches!(
1882                            state,
1883                            GrantLoginProgress::EstablishingSecureChannel(
1884                                GeneratedQrProgress::QrReady(_)
1885                            )
1886                        );
1887                        let checkcode = checkcode_rx
1888                            .take()
1889                            .expect("The checkcode should only be forwarded once")
1890                            .await
1891                            .expect("Alice should receive the checkcode");
1892                        checkcode_sender
1893                            .send(checkcode)
1894                            .await
1895                            .expect("Alice should be able to forward the checkcode");
1896                        break;
1897                    }
1898                    _ => {
1899                        panic!("Alice should abort the process");
1900                    }
1901                }
1902                state = update;
1903            }
1904        });
1905
1906        // Let Bob request the login and run through the process.
1907        let rendezvous_server_clone = rendezvous_server.clone();
1908        let bob_task = spawn(async move {
1909            request_login_with_scanned_qr_code(
1910                BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1911                qr_code_rx,
1912                checkcode_tx,
1913                None,
1914                &rendezvous_server_clone,
1915                None,
1916                None,
1917            )
1918            .await;
1919        });
1920
1921        // Wait for all tasks to finish / fail.
1922        assert_let!(
1923            Err(QRCodeGrantLoginError::UnexpectedMessage {
1924                expected: "m.login.protocol",
1925                received,
1926            }) = grant.await,
1927            "Alice should abort the login with expected error variant"
1928        );
1929        assert_matches!(
1930            *received,
1931            QrAuthMessage::LoginSuccess,
1932            "Alice should abort the login with expected error message"
1933        );
1934        updates_task.await.expect("Alice should run through all progress states");
1935        bob_task.await.expect("Bob's task should finish");
1936    }
1937
1938    #[async_test]
1939    async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_protocol() {
1940        let server = MatrixMockServer::new().await;
1941        let rendezvous_server = Arc::new(
1942            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1943                .await,
1944        );
1945        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1946
1947        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1948        server
1949            .mock_upload_cross_signing_keys()
1950            .ok()
1951            .expect(1)
1952            .named("upload_xsigning_keys")
1953            .mount()
1954            .await;
1955        server
1956            .mock_upload_cross_signing_signatures()
1957            .ok()
1958            .expect(1)
1959            .named("upload_xsigning_signatures")
1960            .mount()
1961            .await;
1962
1963        // Create a secure channel on the new client (Bob) and extract the QR
1964        // code.
1965        let client = rendezvous_server.unlogged_client().await;
1966        let channel = SecureChannel::login(&client, false)
1967            .await
1968            .expect("Bob should be able to create a secure channel.");
1969        let qr_code_data = channel.qr_code_data().clone();
1970
1971        // Create the existing client (Alice).
1972        let user_id = owned_user_id!("@alice:example.org");
1973        let device_id = owned_device_id!("ALICE_DEVICE");
1974        let alice = server
1975            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1976            .logged_in_with_oauth()
1977            .build()
1978            .await;
1979        alice
1980            .encryption()
1981            .bootstrap_cross_signing(None)
1982            .await
1983            .expect("Alice should be able to set up cross signing");
1984
1985        // Prepare the login granting future using the QR code.
1986        let oauth = alice.oauth();
1987        let grant = oauth
1988            .grant_login_with_qr_code()
1989            .device_creation_timeout(Duration::from_secs(2))
1990            .scan(&qr_code_data);
1991        let (checkcode_tx, checkcode_rx) = oneshot::channel();
1992
1993        // Spawn the updates task.
1994        let mut updates = grant.subscribe_to_progress();
1995        let mut state = grant.state.get();
1996        assert_matches!(state.clone(), GrantLoginProgress::Starting);
1997        let updates_task = spawn(async move {
1998            let mut checkcode_tx = Some(checkcode_tx);
1999
2000            while let Some(update) = updates.next().await {
2001                match &update {
2002                    GrantLoginProgress::Starting => {
2003                        assert_matches!(state, GrantLoginProgress::Starting);
2004                    }
2005                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2006                        assert_matches!(state, GrantLoginProgress::Starting);
2007                        checkcode_tx
2008                            .take()
2009                            .expect("The checkcode should only be forwarded once")
2010                            .send(*check_code)
2011                            .expect("Alice should be able to forward the checkcode");
2012                        break;
2013                    }
2014                    _ => {
2015                        panic!("Alice should abort the process");
2016                    }
2017                }
2018                state = update;
2019            }
2020        });
2021
2022        let rendezvous_server_clone = rendezvous_server.clone();
2023        // Let Bob request the login and run through the process.
2024        let bob_task = spawn(async move {
2025            request_login_with_generated_qr_code(
2026                BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
2027                channel,
2028                checkcode_rx,
2029                None,
2030                &rendezvous_server_clone,
2031                alice.homeserver(),
2032                None,
2033                None,
2034            )
2035            .await;
2036        });
2037
2038        // Wait for all tasks to finish / fail.
2039        assert_let!(
2040            Err(QRCodeGrantLoginError::UnexpectedMessage {
2041                expected: "m.login.protocol",
2042                received,
2043            }) = grant.await,
2044            "Alice should abort the login with expected error variant"
2045        );
2046        assert_matches!(
2047            *received,
2048            QrAuthMessage::LoginSuccess,
2049            "Alice should abort the login with expected error message"
2050        );
2051        updates_task.await.expect("Alice should run through all progress states");
2052        bob_task.await.expect("Bob's task should finish");
2053    }
2054
2055    /// Let Bob send a `m.login.protocol` message that Alice rejects, and return
2056    /// the error Alice aborts the login with.
2057    async fn grant_login_with_generated_qr_code_rejected_protocol(
2058        behaviour: BobBehaviour,
2059        msc_4388: bool,
2060    ) -> QRCodeGrantLoginError {
2061        let server = MatrixMockServer::new().await;
2062        // Shared with Bob's task, so the rendezvous session outlives it and
2063        // Alice can still read Bob's last message.
2064        let rendezvous_server = Arc::new(
2065            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
2066                .await,
2067        );
2068        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2069
2070        let device_authorization_grant = AuthorizationGrant {
2071            verification_uri_complete: Some(VerificationUriComplete::new(
2072                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2073            )),
2074            verification_uri: EndUserVerificationUrl::new(
2075                "https://id.matrix.org/device/abcde".to_owned(),
2076            )
2077            .unwrap(),
2078        };
2079
2080        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2081        server
2082            .mock_upload_cross_signing_keys()
2083            .ok()
2084            .expect(1)
2085            .named("upload_xsigning_keys")
2086            .mount()
2087            .await;
2088        server
2089            .mock_upload_cross_signing_signatures()
2090            .ok()
2091            .expect(1)
2092            .named("upload_xsigning_signatures")
2093            .mount()
2094            .await;
2095
2096        // Create the existing client (Alice).
2097        let user_id = owned_user_id!("@alice:example.org");
2098        let device_id = owned_device_id!("ALICE_DEVICE");
2099        let alice = server
2100            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2101            .logged_in_with_oauth()
2102            .build()
2103            .await;
2104        alice
2105            .encryption()
2106            .bootstrap_cross_signing(None)
2107            .await
2108            .expect("Alice should be able to set up cross signing");
2109
2110        // Prepare the login granting future.
2111        let oauth = alice.oauth();
2112        #[allow(unused_mut)]
2113        let mut grant = oauth
2114            .grant_login_with_qr_code()
2115            .device_creation_timeout(Duration::from_secs(2))
2116            .generate();
2117
2118        #[cfg(feature = "unstable-msc4388")]
2119        if msc_4388 {
2120            grant.with_msc4388_support();
2121        }
2122
2123        let (qr_code_tx, qr_code_rx) = oneshot::channel();
2124        let (checkcode_tx, checkcode_rx) = oneshot::channel();
2125
2126        // Spawn the updates task.
2127        let mut updates = grant.subscribe_to_progress();
2128        let mut state = grant.state.get();
2129        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2130        let updates_task = spawn(async move {
2131            let mut qr_code_tx = Some(qr_code_tx);
2132            let mut checkcode_rx = Some(checkcode_rx);
2133
2134            while let Some(update) = updates.next().await {
2135                match &update {
2136                    GrantLoginProgress::Starting => {
2137                        assert_matches!(state, GrantLoginProgress::Starting);
2138                    }
2139                    GrantLoginProgress::EstablishingSecureChannel(
2140                        GeneratedQrProgress::QrReady(qr_code_data),
2141                    ) => {
2142                        assert_matches!(state, GrantLoginProgress::Starting);
2143                        qr_code_tx
2144                            .take()
2145                            .expect("The QR code should only be forwarded once")
2146                            .send(qr_code_data.clone())
2147                            .expect("Alice should be able to forward the QR code");
2148                    }
2149                    GrantLoginProgress::EstablishingSecureChannel(
2150                        GeneratedQrProgress::QrScanned(checkcode_sender),
2151                    ) => {
2152                        assert_matches!(
2153                            state,
2154                            GrantLoginProgress::EstablishingSecureChannel(
2155                                GeneratedQrProgress::QrReady(_)
2156                            )
2157                        );
2158                        let checkcode = checkcode_rx
2159                            .take()
2160                            .expect("The checkcode should only be forwarded once")
2161                            .await
2162                            .expect("Alice should receive the checkcode");
2163                        checkcode_sender
2164                            .send(checkcode)
2165                            .await
2166                            .expect("Alice should be able to forward the checkcode");
2167                    }
2168                    _ => {
2169                        panic!("Alice should abort the process");
2170                    }
2171                }
2172                state = update;
2173            }
2174        });
2175
2176        // Let Bob request the login with a m.login.protocol message Alice
2177        // rejects.
2178        let rendezvous_server_clone = rendezvous_server.clone();
2179        let bob_task = spawn(async move {
2180            request_login_with_scanned_qr_code(
2181                behaviour,
2182                qr_code_rx,
2183                checkcode_tx,
2184                None,
2185                &rendezvous_server_clone,
2186                Some(device_authorization_grant),
2187                None,
2188            )
2189            .await;
2190        });
2191
2192        // Wait for all tasks to finish / fail.
2193        let error = grant.await.expect_err("Alice should abort the login");
2194        updates_task.await.expect("Alice should run through all progress states");
2195        bob_task.await.expect("Bob's task should finish");
2196
2197        error
2198    }
2199
2200    async fn test_grant_login_with_generated_qr_code_unsupported_protocol(msc_4388: bool) {
2201        let error = grant_login_with_generated_qr_code_rejected_protocol(
2202            BobBehaviour::UnsupportedProtocol,
2203            msc_4388,
2204        )
2205        .await;
2206        assert_let!(
2207            QRCodeGrantLoginError::UnsupportedProtocol(protocol) = error,
2208            "Alice should abort the login with expected error variant"
2209        );
2210        assert_eq!(protocol.as_str(), "m.unknown_protocol");
2211    }
2212
2213    #[async_test]
2214    async fn test_grant_login_with_generated_qr_code_unsupported_protocol_msc_4108() {
2215        test_grant_login_with_generated_qr_code_unsupported_protocol(false).await;
2216    }
2217
2218    #[async_test]
2219    #[cfg(feature = "unstable-msc4388")]
2220    async fn test_grant_login_with_generated_qr_code_unsupported_protocol_msc_4388() {
2221        test_grant_login_with_generated_qr_code_unsupported_protocol(true).await;
2222    }
2223
2224    async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(
2225        msc_4388: bool,
2226    ) {
2227        let error = grant_login_with_generated_qr_code_rejected_protocol(
2228            BobBehaviour::UnsupportedProtocolWithDeviceAuthorizationGrant,
2229            msc_4388,
2230        )
2231        .await;
2232        assert_let!(
2233            QRCodeGrantLoginError::UnsupportedProtocol(protocol) = error,
2234            "Alice should abort the login with expected error variant"
2235        );
2236        assert_eq!(protocol.as_str(), "m.unknown_protocol");
2237    }
2238
2239    #[async_test]
2240    async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant_msc_4108() {
2241        test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(false).await;
2242    }
2243
2244    #[async_test]
2245    #[cfg(feature = "unstable-msc4388")]
2246    async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant_msc_4388() {
2247        test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(true).await;
2248    }
2249
2250    async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant(
2251        msc_4388: bool,
2252    ) {
2253        let error = grant_login_with_generated_qr_code_rejected_protocol(
2254            BobBehaviour::MissingDeviceAuthorizationGrant,
2255            msc_4388,
2256        )
2257        .await;
2258        assert_matches!(
2259            error,
2260            QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
2261                MessageDecodeError::Json(_)
2262            )),
2263            "Alice should abort the login with expected error variant"
2264        );
2265    }
2266
2267    #[async_test]
2268    async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant_msc_4108() {
2269        test_grant_login_with_generated_qr_code_missing_device_authorization_grant(false).await;
2270    }
2271
2272    #[async_test]
2273    #[cfg(feature = "unstable-msc4388")]
2274    async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant_msc_4388() {
2275        test_grant_login_with_generated_qr_code_missing_device_authorization_grant(true).await;
2276    }
2277
2278    async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(
2279        msc_4388: bool,
2280    ) {
2281        let error = grant_login_with_generated_qr_code_rejected_protocol(
2282            BobBehaviour::MismatchedDeviceAuthorizationGrantLayout,
2283            msc_4388,
2284        )
2285        .await;
2286        assert_let!(
2287            QRCodeGrantLoginError::UnexpectedMessage { expected, received } = error,
2288            "Alice should abort the login with expected error variant"
2289        );
2290        assert_eq!(expected, "m.login.protocol");
2291        assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = *received);
2292        // The layout of the other channel variant is rejected.
2293        if msc_4388 {
2294            assert_matches!(protocol, LoginProtocolData::Msc4108DeviceAuthorizationGrant(_));
2295        } else {
2296            assert_matches!(protocol, LoginProtocolData::Msc4388DeviceAuthorizationGrant(_));
2297        }
2298    }
2299
2300    #[async_test]
2301    async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout_msc_4108()
2302     {
2303        test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(false)
2304            .await;
2305    }
2306
2307    #[async_test]
2308    #[cfg(feature = "unstable-msc4388")]
2309    async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout_msc_4388()
2310     {
2311        test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(true)
2312            .await;
2313    }
2314
2315    #[async_test]
2316    async fn test_grant_login_with_generated_qr_code_device_already_exists() {
2317        let server = MatrixMockServer::new().await;
2318        let rendezvous_server =
2319            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2320                .await;
2321        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2322
2323        let device_authorization_grant = AuthorizationGrant {
2324            verification_uri_complete: Some(VerificationUriComplete::new(
2325                "https://id.matrix.org/device/abcde".to_owned(),
2326            )),
2327            verification_uri: EndUserVerificationUrl::new(
2328                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2329            )
2330            .unwrap(),
2331        };
2332
2333        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2334        server
2335            .mock_upload_cross_signing_keys()
2336            .ok()
2337            .expect(1)
2338            .named("upload_xsigning_keys")
2339            .mount()
2340            .await;
2341        server
2342            .mock_upload_cross_signing_signatures()
2343            .ok()
2344            .expect(1)
2345            .named("upload_xsigning_signatures")
2346            .mount()
2347            .await;
2348
2349        // Create the existing client (Alice).
2350        let user_id = owned_user_id!("@alice:example.org");
2351        let device_id = owned_device_id!("ALICE_DEVICE");
2352        let alice = server
2353            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2354            .logged_in_with_oauth()
2355            .build()
2356            .await;
2357        alice
2358            .encryption()
2359            .bootstrap_cross_signing(None)
2360            .await
2361            .expect("Alice should be able to set up cross signing");
2362
2363        // Prepare the login granting future.
2364        let oauth = alice.oauth();
2365        let grant = oauth
2366            .grant_login_with_qr_code()
2367            .device_creation_timeout(Duration::from_secs(2))
2368            .generate();
2369        let (qr_code_tx, qr_code_rx) = oneshot::channel();
2370        let (checkcode_tx, checkcode_rx) = oneshot::channel();
2371
2372        // Spawn the updates task.
2373        let mut updates = grant.subscribe_to_progress();
2374        let mut state = grant.state.get();
2375        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2376        let updates_task = spawn(async move {
2377            let mut qr_code_tx = Some(qr_code_tx);
2378            let mut checkcode_rx = Some(checkcode_rx);
2379
2380            while let Some(update) = updates.next().await {
2381                match &update {
2382                    GrantLoginProgress::Starting => {
2383                        assert_matches!(state, GrantLoginProgress::Starting);
2384                    }
2385                    GrantLoginProgress::EstablishingSecureChannel(
2386                        GeneratedQrProgress::QrReady(qr_code_data),
2387                    ) => {
2388                        assert_matches!(state, GrantLoginProgress::Starting);
2389                        qr_code_tx
2390                            .take()
2391                            .expect("The QR code should only be forwarded once")
2392                            .send(qr_code_data.clone())
2393                            .expect("Alice should be able to forward the QR code");
2394                    }
2395                    GrantLoginProgress::EstablishingSecureChannel(
2396                        GeneratedQrProgress::QrScanned(checkcode_sender),
2397                    ) => {
2398                        assert_matches!(
2399                            state,
2400                            GrantLoginProgress::EstablishingSecureChannel(
2401                                GeneratedQrProgress::QrReady(_)
2402                            )
2403                        );
2404                        let checkcode = checkcode_rx
2405                            .take()
2406                            .expect("The checkcode should only be forwarded once")
2407                            .await
2408                            .expect("Alice should receive the checkcode");
2409                        checkcode_sender
2410                            .send(checkcode)
2411                            .await
2412                            .expect("Alice should be able to forward the checkcode");
2413                    }
2414                    _ => {
2415                        panic!("Alice should abort the process");
2416                    }
2417                }
2418                state = update;
2419            }
2420        });
2421
2422        // Let Bob request the login and run through the process.
2423        let bob_task = spawn(async move {
2424            request_login_with_scanned_qr_code(
2425                BobBehaviour::DeviceAlreadyExists,
2426                qr_code_rx,
2427                checkcode_tx,
2428                Some(server),
2429                &rendezvous_server,
2430                Some(device_authorization_grant),
2431                None,
2432            )
2433            .await;
2434        });
2435
2436        // Wait for all tasks to finish.
2437        assert_matches!(
2438            grant.await,
2439            Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
2440            "Alice should abort the login with expected error"
2441        );
2442        updates_task.await.expect("Alice should run through all progress states");
2443        bob_task.await.expect("Bob's task should finish");
2444    }
2445
2446    #[async_test]
2447    async fn test_grant_login_with_scanned_qr_code_device_already_exists() {
2448        let server = MatrixMockServer::new().await;
2449        let rendezvous_server =
2450            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2451                .await;
2452        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2453
2454        let device_authorization_grant = AuthorizationGrant {
2455            verification_uri_complete: Some(VerificationUriComplete::new(
2456                "https://id.matrix.org/device/abcde".to_owned(),
2457            )),
2458            verification_uri: EndUserVerificationUrl::new(
2459                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2460            )
2461            .unwrap(),
2462        };
2463
2464        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2465        server
2466            .mock_upload_cross_signing_keys()
2467            .ok()
2468            .expect(1)
2469            .named("upload_xsigning_keys")
2470            .mount()
2471            .await;
2472        server
2473            .mock_upload_cross_signing_signatures()
2474            .ok()
2475            .expect(1)
2476            .named("upload_xsigning_signatures")
2477            .mount()
2478            .await;
2479
2480        // Create a secure channel on the new client (Bob) and extract the QR
2481        // code.
2482        let client = rendezvous_server.unlogged_client().await;
2483        let channel = SecureChannel::login(&client, false)
2484            .await
2485            .expect("Bob should be able to create a secure channel.");
2486        let qr_code_data = channel.qr_code_data().clone();
2487
2488        // Create the existing client (Alice).
2489        let user_id = owned_user_id!("@alice:example.org");
2490        let device_id = owned_device_id!("ALICE_DEVICE");
2491        let alice = server
2492            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2493            .logged_in_with_oauth()
2494            .build()
2495            .await;
2496        alice
2497            .encryption()
2498            .bootstrap_cross_signing(None)
2499            .await
2500            .expect("Alice should be able to set up cross signing");
2501
2502        // Prepare the login granting future using the QR code.
2503        let oauth = alice.oauth();
2504        let grant = oauth
2505            .grant_login_with_qr_code()
2506            .device_creation_timeout(Duration::from_secs(2))
2507            .scan(&qr_code_data);
2508        let (checkcode_tx, checkcode_rx) = oneshot::channel();
2509
2510        // Spawn the updates task.
2511        let mut updates = grant.subscribe_to_progress();
2512        let mut state = grant.state.get();
2513        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2514        let updates_task = spawn(async move {
2515            let mut checkcode_tx = Some(checkcode_tx);
2516
2517            while let Some(update) = updates.next().await {
2518                match &update {
2519                    GrantLoginProgress::Starting => {
2520                        assert_matches!(state, GrantLoginProgress::Starting);
2521                    }
2522                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2523                        assert_matches!(state, GrantLoginProgress::Starting);
2524                        checkcode_tx
2525                            .take()
2526                            .expect("The checkcode should only be forwarded once")
2527                            .send(*check_code)
2528                            .expect("Alice should be able to forward the checkcode");
2529                    }
2530                    _ => {
2531                        panic!("Alice should abort the process");
2532                    }
2533                }
2534                state = update;
2535            }
2536        });
2537
2538        // Let Bob request the login and run through the process.
2539        let bob_task = spawn(async move {
2540            request_login_with_generated_qr_code(
2541                BobBehaviour::DeviceAlreadyExists,
2542                channel,
2543                checkcode_rx,
2544                Some(server),
2545                &rendezvous_server,
2546                alice.homeserver(),
2547                Some(device_authorization_grant),
2548                None,
2549            )
2550            .await;
2551        });
2552
2553        // Wait for all tasks to finish.
2554        assert_matches!(
2555            grant.await,
2556            Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
2557            "Alice should abort the login with expected error"
2558        );
2559        updates_task.await.expect("Alice should run through all progress states");
2560        bob_task.await.expect("Bob's task should finish");
2561    }
2562
2563    #[async_test]
2564    async fn test_grant_login_with_generated_qr_code_device_not_found() {
2565        let server = MatrixMockServer::new().await;
2566        let rendezvous_server =
2567            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2568                .await;
2569        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2570
2571        let device_authorization_grant = AuthorizationGrant {
2572            verification_uri_complete: Some(VerificationUriComplete::new(
2573                "https://id.matrix.org/device/abcde".to_owned(),
2574            )),
2575            verification_uri: EndUserVerificationUrl::new(
2576                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2577            )
2578            .unwrap(),
2579        };
2580
2581        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2582        server
2583            .mock_upload_cross_signing_keys()
2584            .ok()
2585            .expect(1)
2586            .named("upload_xsigning_keys")
2587            .mount()
2588            .await;
2589        server
2590            .mock_upload_cross_signing_signatures()
2591            .ok()
2592            .expect(1)
2593            .named("upload_xsigning_signatures")
2594            .mount()
2595            .await;
2596
2597        // Create the existing client (Alice).
2598        let user_id = owned_user_id!("@alice:example.org");
2599        let device_id = owned_device_id!("ALICE_DEVICE");
2600        let alice = server
2601            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2602            .logged_in_with_oauth()
2603            .build()
2604            .await;
2605        alice
2606            .encryption()
2607            .bootstrap_cross_signing(None)
2608            .await
2609            .expect("Alice should be able to set up cross signing");
2610
2611        // Prepare the login granting future.
2612        let oauth = alice.oauth();
2613        let grant = oauth
2614            .grant_login_with_qr_code()
2615            .device_creation_timeout(Duration::from_secs(2))
2616            .generate();
2617        let (qr_code_tx, qr_code_rx) = oneshot::channel();
2618        let (checkcode_tx, checkcode_rx) = oneshot::channel();
2619
2620        // Spawn the updates task.
2621        let mut updates = grant.subscribe_to_progress();
2622        let mut state = grant.state.get();
2623        let verification_uri_complete =
2624            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2625        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2626        let updates_task = spawn(async move {
2627            let mut qr_code_tx = Some(qr_code_tx);
2628            let mut checkcode_rx = Some(checkcode_rx);
2629
2630            while let Some(update) = updates.next().await {
2631                match &update {
2632                    GrantLoginProgress::Starting => {
2633                        assert_matches!(state, GrantLoginProgress::Starting);
2634                    }
2635                    GrantLoginProgress::EstablishingSecureChannel(
2636                        GeneratedQrProgress::QrReady(qr_code_data),
2637                    ) => {
2638                        assert_matches!(state, GrantLoginProgress::Starting);
2639                        qr_code_tx
2640                            .take()
2641                            .expect("The QR code should only be forwarded once")
2642                            .send(qr_code_data.clone())
2643                            .expect("Alice should be able to forward the QR code");
2644                    }
2645                    GrantLoginProgress::EstablishingSecureChannel(
2646                        GeneratedQrProgress::QrScanned(checkcode_sender),
2647                    ) => {
2648                        assert_matches!(
2649                            state,
2650                            GrantLoginProgress::EstablishingSecureChannel(
2651                                GeneratedQrProgress::QrReady(_)
2652                            )
2653                        );
2654                        let checkcode = checkcode_rx
2655                            .take()
2656                            .expect("The checkcode should only be forwarded once")
2657                            .await
2658                            .expect("Alice should receive the checkcode");
2659                        checkcode_sender
2660                            .send(checkcode)
2661                            .await
2662                            .expect("Alice should be able to forward the checkcode");
2663                    }
2664                    GrantLoginProgress::WaitingForAuth {
2665                        verification_uri,
2666                        continuation_sender,
2667                    } => {
2668                        assert_matches!(
2669                            state,
2670                            GrantLoginProgress::EstablishingSecureChannel(
2671                                GeneratedQrProgress::QrScanned(_)
2672                            )
2673                        );
2674                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
2675                        continuation_sender.confirm().await.expect("should be able to confirm");
2676                    }
2677                    _ => {
2678                        panic!("Alice should abort the process");
2679                    }
2680                }
2681                state = update;
2682            }
2683        });
2684
2685        // Let Bob request the login and run through the process.
2686        let bob_task = spawn(async move {
2687            request_login_with_scanned_qr_code(
2688                BobBehaviour::DeviceNotCreated,
2689                qr_code_rx,
2690                checkcode_tx,
2691                Some(server),
2692                &rendezvous_server,
2693                Some(device_authorization_grant),
2694                None,
2695            )
2696            .await;
2697        });
2698
2699        assert_matches!(
2700            grant.await,
2701            Err(QRCodeGrantLoginError::DeviceNotFound),
2702            "Alice should abort the login with expected error"
2703        );
2704        updates_task.await.expect("Alice should run through all progress states");
2705        bob_task.await.expect("Bob's task should finish");
2706    }
2707
2708    #[async_test]
2709    async fn test_grant_login_with_scanned_qr_code_device_not_found() {
2710        let server = MatrixMockServer::new().await;
2711        let rendezvous_server =
2712            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2713                .await;
2714        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2715
2716        let device_authorization_grant = AuthorizationGrant {
2717            verification_uri_complete: Some(VerificationUriComplete::new(
2718                "https://id.matrix.org/device/abcde".to_owned(),
2719            )),
2720            verification_uri: EndUserVerificationUrl::new(
2721                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2722            )
2723            .unwrap(),
2724        };
2725
2726        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2727        server
2728            .mock_upload_cross_signing_keys()
2729            .ok()
2730            .expect(1)
2731            .named("upload_xsigning_keys")
2732            .mount()
2733            .await;
2734        server
2735            .mock_upload_cross_signing_signatures()
2736            .ok()
2737            .expect(1)
2738            .named("upload_xsigning_signatures")
2739            .mount()
2740            .await;
2741
2742        // Create a secure channel on the new client (Bob) and extract the QR
2743        // code.
2744        let client = rendezvous_server.unlogged_client().await;
2745        let channel = SecureChannel::login(&client, false)
2746            .await
2747            .expect("Bob should be able to create a secure channel.");
2748        let qr_code_data = channel.qr_code_data().clone();
2749
2750        // Create the existing client (Alice).
2751        let user_id = owned_user_id!("@alice:example.org");
2752        let device_id = owned_device_id!("ALICE_DEVICE");
2753        let alice = server
2754            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2755            .logged_in_with_oauth()
2756            .build()
2757            .await;
2758        alice
2759            .encryption()
2760            .bootstrap_cross_signing(None)
2761            .await
2762            .expect("Alice should be able to set up cross signing");
2763
2764        // Prepare the login granting future using the QR code.
2765        let oauth = alice.oauth();
2766        let grant = oauth
2767            .grant_login_with_qr_code()
2768            .device_creation_timeout(Duration::from_secs(2))
2769            .scan(&qr_code_data);
2770        let (checkcode_tx, checkcode_rx) = oneshot::channel();
2771
2772        // Spawn the updates task.
2773        let mut updates = grant.subscribe_to_progress();
2774        let mut state = grant.state.get();
2775        let verification_uri_complete =
2776            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2777        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2778        let updates_task = spawn(async move {
2779            let mut checkcode_tx = Some(checkcode_tx);
2780
2781            while let Some(update) = updates.next().await {
2782                match &update {
2783                    GrantLoginProgress::Starting => {
2784                        assert_matches!(state, GrantLoginProgress::Starting);
2785                    }
2786                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2787                        assert_matches!(state, GrantLoginProgress::Starting);
2788                        checkcode_tx
2789                            .take()
2790                            .expect("The checkcode should only be forwarded once")
2791                            .send(*check_code)
2792                            .expect("Alice should be able to forward the checkcode");
2793                    }
2794                    GrantLoginProgress::WaitingForAuth {
2795                        verification_uri,
2796                        continuation_sender,
2797                    } => {
2798                        assert_matches!(
2799                            state,
2800                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2801                        );
2802                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
2803                        continuation_sender.confirm().await.expect("should be able to confirm");
2804                    }
2805                    _ => {
2806                        panic!("Alice should abort the process");
2807                    }
2808                }
2809                state = update;
2810            }
2811        });
2812
2813        // Let Bob request the login and run through the process.
2814        let bob_task = spawn(async move {
2815            request_login_with_generated_qr_code(
2816                BobBehaviour::DeviceNotCreated,
2817                channel,
2818                checkcode_rx,
2819                None,
2820                &rendezvous_server,
2821                alice.homeserver(),
2822                Some(device_authorization_grant),
2823                None,
2824            )
2825            .await;
2826        });
2827
2828        assert_matches!(
2829            grant.await,
2830            Err(QRCodeGrantLoginError::DeviceNotFound),
2831            "Alice should abort the login with expected error"
2832        );
2833        updates_task.await.expect("Alice should run through all progress states");
2834        bob_task.await.expect("Bob's task should finish");
2835    }
2836
2837    #[async_test]
2838    async fn test_grant_login_with_generated_qr_code_session_expired() {
2839        let server = MatrixMockServer::new().await;
2840        let rendezvous_server = MockedRendezvousServer::new(
2841            server.server(),
2842            "abcdEFG12345",
2843            Duration::from_secs(2),
2844            false,
2845        )
2846        .await;
2847        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2848
2849        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2850        server
2851            .mock_upload_cross_signing_keys()
2852            .ok()
2853            .expect(1)
2854            .named("upload_xsigning_keys")
2855            .mount()
2856            .await;
2857        server
2858            .mock_upload_cross_signing_signatures()
2859            .ok()
2860            .expect(1)
2861            .named("upload_xsigning_signatures")
2862            .mount()
2863            .await;
2864
2865        // Create the existing client (Alice).
2866        let user_id = owned_user_id!("@alice:example.org");
2867        let device_id = owned_device_id!("ALICE_DEVICE");
2868        let alice = server
2869            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2870            .logged_in_with_oauth()
2871            .build()
2872            .await;
2873        alice
2874            .encryption()
2875            .bootstrap_cross_signing(None)
2876            .await
2877            .expect("Alice should be able to set up cross signing");
2878
2879        // Prepare the login granting future.
2880        let oauth = alice.oauth();
2881        let grant = oauth
2882            .grant_login_with_qr_code()
2883            .device_creation_timeout(Duration::from_secs(2))
2884            .generate();
2885
2886        // Spawn the updates task.
2887        let mut updates = grant.subscribe_to_progress();
2888        let mut state = grant.state.get();
2889        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2890        let updates_task = spawn(async move {
2891            while let Some(update) = updates.next().await {
2892                match &update {
2893                    GrantLoginProgress::Starting => {
2894                        assert_matches!(state, GrantLoginProgress::Starting);
2895                    }
2896                    GrantLoginProgress::EstablishingSecureChannel(
2897                        GeneratedQrProgress::QrReady(_),
2898                    ) => {
2899                        assert_matches!(state, GrantLoginProgress::Starting);
2900                    }
2901                    _ => {
2902                        panic!("Alice should abort the process");
2903                    }
2904                }
2905                state = update;
2906            }
2907        });
2908
2909        // Bob does not scan the QR code and the channel is never connected.
2910
2911        // Wait for the rendezvous session to time out.
2912        assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2913        updates_task.await.expect("Alice should run through all progress states");
2914    }
2915
2916    #[async_test]
2917    async fn test_grant_login_with_scanned_qr_code_session_expired() {
2918        let server = MatrixMockServer::new().await;
2919        let rendezvous_server = MockedRendezvousServer::new(
2920            server.server(),
2921            "abcdEFG12345",
2922            Duration::from_secs(2),
2923            false,
2924        )
2925        .await;
2926        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2927
2928        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2929        server
2930            .mock_upload_cross_signing_keys()
2931            .ok()
2932            .expect(1)
2933            .named("upload_xsigning_keys")
2934            .mount()
2935            .await;
2936        server
2937            .mock_upload_cross_signing_signatures()
2938            .ok()
2939            .expect(1)
2940            .named("upload_xsigning_signatures")
2941            .mount()
2942            .await;
2943
2944        // Create a secure channel on the new client (Bob) and extract the QR
2945        // code.
2946        let client = rendezvous_server.unlogged_client().await;
2947        let channel = SecureChannel::login(&client, false)
2948            .await
2949            .expect("Bob should be able to create a secure channel.");
2950        let qr_code_data = channel.qr_code_data().clone();
2951
2952        // Create the existing client (Alice).
2953        let user_id = owned_user_id!("@alice:example.org");
2954        let device_id = owned_device_id!("ALICE_DEVICE");
2955        let alice = server
2956            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2957            .logged_in_with_oauth()
2958            .build()
2959            .await;
2960        alice
2961            .encryption()
2962            .bootstrap_cross_signing(None)
2963            .await
2964            .expect("Alice should be able to set up cross signing");
2965
2966        // Prepare the login granting future using the QR code.
2967        let oauth = alice.oauth();
2968        let grant = oauth
2969            .grant_login_with_qr_code()
2970            .device_creation_timeout(Duration::from_secs(2))
2971            .scan(&qr_code_data);
2972
2973        // Spawn the updates task.
2974        let mut updates = grant.subscribe_to_progress();
2975        let mut state = grant.state.get();
2976        assert_matches!(state.clone(), GrantLoginProgress::Starting);
2977        let updates_task = spawn(async move {
2978            while let Some(update) = updates.next().await {
2979                match &update {
2980                    GrantLoginProgress::Starting => {
2981                        assert_matches!(state, GrantLoginProgress::Starting);
2982                    }
2983                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. }) => {
2984                        assert_matches!(state, GrantLoginProgress::Starting);
2985                    }
2986                    _ => {
2987                        panic!("Alice should abort the process");
2988                    }
2989                }
2990                state = update;
2991            }
2992        });
2993
2994        // Bob does not connect the channel.
2995
2996        // Wait for the rendezvous session to time out.
2997        assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2998        updates_task.await.expect("Alice should run through all progress states");
2999    }
3000
3001    #[async_test]
3002    async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_protocol() {
3003        let server = MatrixMockServer::new().await;
3004        let rendezvous_server = Arc::new(
3005            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3006                .await,
3007        );
3008        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3009
3010        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3011        server
3012            .mock_upload_cross_signing_keys()
3013            .ok()
3014            .expect(1)
3015            .named("upload_xsigning_keys")
3016            .mount()
3017            .await;
3018        server
3019            .mock_upload_cross_signing_signatures()
3020            .ok()
3021            .expect(1)
3022            .named("upload_xsigning_signatures")
3023            .mount()
3024            .await;
3025
3026        // Create the existing client (Alice).
3027        let user_id = owned_user_id!("@alice:example.org");
3028        let device_id = owned_device_id!("ALICE_DEVICE");
3029        let alice = server
3030            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3031            .logged_in_with_oauth()
3032            .build()
3033            .await;
3034        alice
3035            .encryption()
3036            .bootstrap_cross_signing(None)
3037            .await
3038            .expect("Alice should be able to set up cross signing");
3039
3040        // Prepare the login granting future.
3041        let oauth = alice.oauth();
3042        let grant = oauth
3043            .grant_login_with_qr_code()
3044            .device_creation_timeout(Duration::from_secs(2))
3045            .generate();
3046        let (qr_code_tx, qr_code_rx) = oneshot::channel();
3047        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3048
3049        // Spawn the updates task.
3050        let mut updates = grant.subscribe_to_progress();
3051        let mut state = grant.state.get();
3052        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3053        let updates_task = spawn(async move {
3054            let mut qr_code_tx = Some(qr_code_tx);
3055            let mut checkcode_rx = Some(checkcode_rx);
3056
3057            while let Some(update) = updates.next().await {
3058                match &update {
3059                    GrantLoginProgress::Starting => {
3060                        assert_matches!(state, GrantLoginProgress::Starting);
3061                    }
3062                    GrantLoginProgress::EstablishingSecureChannel(
3063                        GeneratedQrProgress::QrReady(qr_code_data),
3064                    ) => {
3065                        assert_matches!(state, GrantLoginProgress::Starting);
3066                        qr_code_tx
3067                            .take()
3068                            .expect("The QR code should only be forwarded once")
3069                            .send(qr_code_data.clone())
3070                            .expect("Alice should be able to forward the QR code");
3071                    }
3072                    GrantLoginProgress::EstablishingSecureChannel(
3073                        GeneratedQrProgress::QrScanned(checkcode_sender),
3074                    ) => {
3075                        assert_matches!(
3076                            state,
3077                            GrantLoginProgress::EstablishingSecureChannel(
3078                                GeneratedQrProgress::QrReady(_)
3079                            )
3080                        );
3081                        let checkcode = checkcode_rx
3082                            .take()
3083                            .expect("The checkcode should only be forwarded once")
3084                            .await
3085                            .expect("Alice should receive the checkcode");
3086                        checkcode_sender
3087                            .send(checkcode)
3088                            .await
3089                            .expect("Alice should be able to forward the checkcode");
3090                        break;
3091                    }
3092                    _ => {
3093                        panic!("Alice should abort the process");
3094                    }
3095                }
3096                state = update;
3097            }
3098        });
3099
3100        // Let Bob request the login and run through the process.
3101        let rendezvous_server_clone = rendezvous_server.clone();
3102        let bob_task = spawn(async move {
3103            request_login_with_scanned_qr_code(
3104                BobBehaviour::LoginFailureInsteadOfLoginProtocol,
3105                qr_code_rx,
3106                checkcode_tx,
3107                None,
3108                &rendezvous_server_clone,
3109                None,
3110                None,
3111            )
3112            .await;
3113        });
3114
3115        // Wait for all tasks to finish / fail.
3116        assert_matches!(
3117            grant.await,
3118            Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3119            "Alice should abort the login with expected error"
3120        );
3121        updates_task.await.expect("Alice should run through all progress states");
3122        bob_task.await.expect("Bob's task should finish");
3123    }
3124
3125    #[async_test]
3126    async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_protocol() {
3127        let server = MatrixMockServer::new().await;
3128        let rendezvous_server = Arc::new(
3129            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3130                .await,
3131        );
3132        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3133
3134        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3135        server
3136            .mock_upload_cross_signing_keys()
3137            .ok()
3138            .expect(1)
3139            .named("upload_xsigning_keys")
3140            .mount()
3141            .await;
3142        server
3143            .mock_upload_cross_signing_signatures()
3144            .ok()
3145            .expect(1)
3146            .named("upload_xsigning_signatures")
3147            .mount()
3148            .await;
3149
3150        // Create a secure channel on the new client (Bob) and extract the QR
3151        // code.
3152        let client = rendezvous_server.unlogged_client().await;
3153        let channel = SecureChannel::login(&client, false)
3154            .await
3155            .expect("Bob should be able to create a secure channel.");
3156        let qr_code_data = channel.qr_code_data().clone();
3157
3158        // Create the existing client (Alice).
3159        let user_id = owned_user_id!("@alice:example.org");
3160        let device_id = owned_device_id!("ALICE_DEVICE");
3161        let alice = server
3162            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3163            .logged_in_with_oauth()
3164            .build()
3165            .await;
3166        alice
3167            .encryption()
3168            .bootstrap_cross_signing(None)
3169            .await
3170            .expect("Alice should be able to set up cross signing");
3171
3172        // Prepare the login granting future using the QR code.
3173        let oauth = alice.oauth();
3174        let grant = oauth
3175            .grant_login_with_qr_code()
3176            .device_creation_timeout(Duration::from_secs(2))
3177            .scan(&qr_code_data);
3178        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3179
3180        // Spawn the updates task.
3181        let mut updates = grant.subscribe_to_progress();
3182        let mut state = grant.state.get();
3183        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3184        let updates_task = spawn(async move {
3185            let mut checkcode_tx = Some(checkcode_tx);
3186
3187            while let Some(update) = updates.next().await {
3188                match &update {
3189                    GrantLoginProgress::Starting => {
3190                        assert_matches!(state, GrantLoginProgress::Starting);
3191                    }
3192                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3193                        assert_matches!(state, GrantLoginProgress::Starting);
3194                        checkcode_tx
3195                            .take()
3196                            .expect("The checkcode should only be forwarded once")
3197                            .send(*check_code)
3198                            .expect("Alice should be able to forward the checkcode");
3199                        break;
3200                    }
3201                    _ => {
3202                        panic!("Alice should abort the process");
3203                    }
3204                }
3205                state = update;
3206            }
3207        });
3208
3209        let rendezvous_server_clone = rendezvous_server.clone();
3210        // Let Bob request the login and run through the process.
3211        let bob_task = spawn(async move {
3212            request_login_with_generated_qr_code(
3213                BobBehaviour::LoginFailureInsteadOfLoginProtocol,
3214                channel,
3215                checkcode_rx,
3216                None,
3217                &rendezvous_server_clone,
3218                alice.homeserver(),
3219                None,
3220                None,
3221            )
3222            .await;
3223        });
3224
3225        // Wait for all tasks to finish / fail.
3226        assert_matches!(
3227            grant.await,
3228            Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3229            "Alice should abort the login with expected error"
3230        );
3231        updates_task.await.expect("Alice should run through all progress states");
3232        bob_task.await.expect("Bob's task should finish");
3233    }
3234
3235    #[async_test]
3236    async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_success() {
3237        let server = MatrixMockServer::new().await;
3238        let rendezvous_server = Arc::new(
3239            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3240                .await,
3241        );
3242        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3243
3244        let device_authorization_grant = AuthorizationGrant {
3245            verification_uri_complete: Some(VerificationUriComplete::new(
3246                "https://id.matrix.org/device/abcde".to_owned(),
3247            )),
3248            verification_uri: EndUserVerificationUrl::new(
3249                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3250            )
3251            .unwrap(),
3252        };
3253
3254        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3255        server
3256            .mock_upload_cross_signing_keys()
3257            .ok()
3258            .expect(1)
3259            .named("upload_xsigning_keys")
3260            .mount()
3261            .await;
3262        server
3263            .mock_upload_cross_signing_signatures()
3264            .ok()
3265            .expect(1)
3266            .named("upload_xsigning_signatures")
3267            .mount()
3268            .await;
3269
3270        // Create the existing client (Alice).
3271        let user_id = owned_user_id!("@alice:example.org");
3272        let device_id = owned_device_id!("ALICE_DEVICE");
3273        let alice = server
3274            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3275            .logged_in_with_oauth()
3276            .build()
3277            .await;
3278        alice
3279            .encryption()
3280            .bootstrap_cross_signing(None)
3281            .await
3282            .expect("Alice should be able to set up cross signing");
3283
3284        // Prepare the login granting future.
3285        let oauth = alice.oauth();
3286        let grant = oauth
3287            .grant_login_with_qr_code()
3288            .device_creation_timeout(Duration::from_secs(2))
3289            .generate();
3290        let (qr_code_tx, qr_code_rx) = oneshot::channel();
3291        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3292
3293        // Spawn the updates task.
3294        let mut updates = grant.subscribe_to_progress();
3295        let mut state = grant.state.get();
3296        let verification_uri_complete =
3297            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3298        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3299        let updates_task = spawn(async move {
3300            let mut qr_code_tx = Some(qr_code_tx);
3301            let mut checkcode_rx = Some(checkcode_rx);
3302
3303            while let Some(update) = updates.next().await {
3304                match &update {
3305                    GrantLoginProgress::Starting => {
3306                        assert_matches!(state, GrantLoginProgress::Starting);
3307                    }
3308                    GrantLoginProgress::EstablishingSecureChannel(
3309                        GeneratedQrProgress::QrReady(qr_code_data),
3310                    ) => {
3311                        assert_matches!(state, GrantLoginProgress::Starting);
3312                        qr_code_tx
3313                            .take()
3314                            .expect("The QR code should only be forwarded once")
3315                            .send(qr_code_data.clone())
3316                            .expect("Alice should be able to forward the QR code");
3317                    }
3318                    GrantLoginProgress::EstablishingSecureChannel(
3319                        GeneratedQrProgress::QrScanned(checkcode_sender),
3320                    ) => {
3321                        assert_matches!(
3322                            state,
3323                            GrantLoginProgress::EstablishingSecureChannel(
3324                                GeneratedQrProgress::QrReady(_)
3325                            )
3326                        );
3327                        let checkcode = checkcode_rx
3328                            .take()
3329                            .expect("The checkcode should only be forwarded once")
3330                            .await
3331                            .expect("Alice should receive the checkcode");
3332                        checkcode_sender
3333                            .send(checkcode)
3334                            .await
3335                            .expect("Alice should be able to forward the checkcode");
3336                    }
3337                    GrantLoginProgress::WaitingForAuth {
3338                        verification_uri,
3339                        continuation_sender,
3340                    } => {
3341                        assert_matches!(
3342                            state,
3343                            GrantLoginProgress::EstablishingSecureChannel(
3344                                GeneratedQrProgress::QrScanned(_)
3345                            )
3346                        );
3347                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
3348                        continuation_sender.confirm().await.expect("should be able to confirm");
3349                    }
3350                    _ => {
3351                        panic!("Alice should abort the process");
3352                    }
3353                }
3354                state = update;
3355            }
3356        });
3357
3358        let rendezvous_server_clone = rendezvous_server.clone();
3359        // Let Bob request the login and run through the process.
3360        let bob_task = spawn(async move {
3361            request_login_with_scanned_qr_code(
3362                BobBehaviour::LoginFailureInsteadOfLoginSuccess,
3363                qr_code_rx,
3364                checkcode_tx,
3365                None,
3366                &rendezvous_server_clone,
3367                Some(device_authorization_grant),
3368                None,
3369            )
3370            .await;
3371        });
3372
3373        // Wait for all tasks to finish / fail.
3374        assert_matches!(
3375            grant.await,
3376            Err(QRCodeGrantLoginError::LoginFailure {
3377                reason: LoginFailureReason::AuthorizationExpired
3378            }),
3379            "Alice should abort the login with expected error"
3380        );
3381        updates_task.await.expect("Alice should run through all progress states");
3382        bob_task.await.expect("Bob's task should finish");
3383    }
3384
3385    #[async_test]
3386    async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_success() {
3387        let server = MatrixMockServer::new().await;
3388        let rendezvous_server = Arc::new(
3389            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3390                .await,
3391        );
3392        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3393
3394        let device_authorization_grant = AuthorizationGrant {
3395            verification_uri_complete: Some(VerificationUriComplete::new(
3396                "https://id.matrix.org/device/abcde".to_owned(),
3397            )),
3398            verification_uri: EndUserVerificationUrl::new(
3399                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3400            )
3401            .unwrap(),
3402        };
3403
3404        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3405        server
3406            .mock_upload_cross_signing_keys()
3407            .ok()
3408            .expect(1)
3409            .named("upload_xsigning_keys")
3410            .mount()
3411            .await;
3412        server
3413            .mock_upload_cross_signing_signatures()
3414            .ok()
3415            .expect(1)
3416            .named("upload_xsigning_signatures")
3417            .mount()
3418            .await;
3419
3420        // Create a secure channel on the new client (Bob) and extract the QR
3421        // code.
3422        let client = rendezvous_server.unlogged_client().await;
3423        let channel = SecureChannel::login(&client, false)
3424            .await
3425            .expect("Bob should be able to create a secure channel.");
3426        let qr_code_data = channel.qr_code_data().clone();
3427
3428        // Create the existing client (Alice).
3429        let user_id = owned_user_id!("@alice:example.org");
3430        let device_id = owned_device_id!("ALICE_DEVICE");
3431        let alice = server
3432            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3433            .logged_in_with_oauth()
3434            .build()
3435            .await;
3436        alice
3437            .encryption()
3438            .bootstrap_cross_signing(None)
3439            .await
3440            .expect("Alice should be able to set up cross signing");
3441
3442        // Prepare the login granting future using the QR code.
3443        let oauth = alice.oauth();
3444        let grant = oauth
3445            .grant_login_with_qr_code()
3446            .device_creation_timeout(Duration::from_secs(2))
3447            .scan(&qr_code_data);
3448        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3449
3450        // Spawn the updates task.
3451        let mut updates = grant.subscribe_to_progress();
3452        let mut state = grant.state.get();
3453        let verification_uri_complete =
3454            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3455        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3456        let updates_task = spawn(async move {
3457            let mut checkcode_tx = Some(checkcode_tx);
3458
3459            while let Some(update) = updates.next().await {
3460                match &update {
3461                    GrantLoginProgress::Starting => {
3462                        assert_matches!(state, GrantLoginProgress::Starting);
3463                    }
3464                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3465                        assert_matches!(state, GrantLoginProgress::Starting);
3466                        checkcode_tx
3467                            .take()
3468                            .expect("The checkcode should only be forwarded once")
3469                            .send(*check_code)
3470                            .expect("Alice should be able to forward the checkcode");
3471                    }
3472                    GrantLoginProgress::WaitingForAuth {
3473                        verification_uri,
3474                        continuation_sender,
3475                    } => {
3476                        assert_matches!(
3477                            state,
3478                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3479                        );
3480                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
3481                        continuation_sender.confirm().await.expect("should be able to confirm");
3482                    }
3483                    _ => {
3484                        panic!("Alice should abort the process");
3485                    }
3486                }
3487                state = update;
3488            }
3489        });
3490
3491        let rendezvous_server_clone = rendezvous_server.clone();
3492        // Let Bob request the login and run through the process.
3493        let bob_task = spawn(async move {
3494            request_login_with_generated_qr_code(
3495                BobBehaviour::LoginFailureInsteadOfLoginSuccess,
3496                channel,
3497                checkcode_rx,
3498                None,
3499                &rendezvous_server_clone,
3500                alice.homeserver(),
3501                Some(device_authorization_grant),
3502                None,
3503            )
3504            .await;
3505        });
3506
3507        // Wait for all tasks to finish / fail.
3508        assert_matches!(
3509            grant.await,
3510            Err(QRCodeGrantLoginError::LoginFailure {
3511                reason: LoginFailureReason::AuthorizationExpired
3512            }),
3513            "Alice should abort the login with expected error"
3514        );
3515        updates_task.await.expect("Alice should run through all progress states");
3516        bob_task.await.expect("Bob's task should finish");
3517    }
3518
3519    #[async_test]
3520    async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_success() {
3521        let server = MatrixMockServer::new().await;
3522        let rendezvous_server = Arc::new(
3523            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3524                .await,
3525        );
3526        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3527
3528        let device_authorization_grant = AuthorizationGrant {
3529            verification_uri_complete: Some(VerificationUriComplete::new(
3530                "https://id.matrix.org/device/abcde".to_owned(),
3531            )),
3532            verification_uri: EndUserVerificationUrl::new(
3533                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3534            )
3535            .unwrap(),
3536        };
3537
3538        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3539        server
3540            .mock_upload_cross_signing_keys()
3541            .ok()
3542            .expect(1)
3543            .named("upload_xsigning_keys")
3544            .mount()
3545            .await;
3546        server
3547            .mock_upload_cross_signing_signatures()
3548            .ok()
3549            .expect(1)
3550            .named("upload_xsigning_signatures")
3551            .mount()
3552            .await;
3553
3554        // Create the existing client (Alice).
3555        let user_id = owned_user_id!("@alice:example.org");
3556        let device_id = owned_device_id!("ALICE_DEVICE");
3557        let alice = server
3558            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3559            .logged_in_with_oauth()
3560            .build()
3561            .await;
3562        alice
3563            .encryption()
3564            .bootstrap_cross_signing(None)
3565            .await
3566            .expect("Alice should be able to set up cross signing");
3567
3568        // Prepare the login granting future.
3569        let oauth = alice.oauth();
3570        let grant = oauth
3571            .grant_login_with_qr_code()
3572            .device_creation_timeout(Duration::from_secs(2))
3573            .generate();
3574        let (qr_code_tx, qr_code_rx) = oneshot::channel();
3575        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3576
3577        // Spawn the updates task.
3578        let mut updates = grant.subscribe_to_progress();
3579        let mut state = grant.state.get();
3580        let verification_uri_complete =
3581            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3582        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3583        let updates_task = spawn(async move {
3584            let mut qr_code_tx = Some(qr_code_tx);
3585            let mut checkcode_rx = Some(checkcode_rx);
3586
3587            while let Some(update) = updates.next().await {
3588                match &update {
3589                    GrantLoginProgress::Starting => {
3590                        assert_matches!(state, GrantLoginProgress::Starting);
3591                    }
3592                    GrantLoginProgress::EstablishingSecureChannel(
3593                        GeneratedQrProgress::QrReady(qr_code_data),
3594                    ) => {
3595                        assert_matches!(state, GrantLoginProgress::Starting);
3596                        qr_code_tx
3597                            .take()
3598                            .expect("The QR code should only be forwarded once")
3599                            .send(qr_code_data.clone())
3600                            .expect("Alice should be able to forward the QR code");
3601                    }
3602                    GrantLoginProgress::EstablishingSecureChannel(
3603                        GeneratedQrProgress::QrScanned(checkcode_sender),
3604                    ) => {
3605                        assert_matches!(
3606                            state,
3607                            GrantLoginProgress::EstablishingSecureChannel(
3608                                GeneratedQrProgress::QrReady(_)
3609                            )
3610                        );
3611                        let checkcode = checkcode_rx
3612                            .take()
3613                            .expect("The checkcode should only be forwarded once")
3614                            .await
3615                            .expect("Alice should receive the checkcode");
3616                        checkcode_sender
3617                            .send(checkcode)
3618                            .await
3619                            .expect("Alice should be able to forward the checkcode");
3620                    }
3621                    GrantLoginProgress::WaitingForAuth {
3622                        verification_uri,
3623                        continuation_sender,
3624                    } => {
3625                        assert_matches!(
3626                            state,
3627                            GrantLoginProgress::EstablishingSecureChannel(
3628                                GeneratedQrProgress::QrScanned(_)
3629                            )
3630                        );
3631                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
3632                        continuation_sender.confirm().await.expect("should be able to confirm");
3633                    }
3634                    _ => {
3635                        panic!("Alice should abort the process");
3636                    }
3637                }
3638                state = update;
3639            }
3640        });
3641
3642        // Let Bob request the login and run through the process.
3643        let rendezvous_server_clone = rendezvous_server.clone();
3644        let bob_task = spawn(async move {
3645            request_login_with_scanned_qr_code(
3646                BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3647                qr_code_rx,
3648                checkcode_tx,
3649                None,
3650                &rendezvous_server_clone,
3651                Some(device_authorization_grant),
3652                None,
3653            )
3654            .await;
3655        });
3656
3657        // Wait for all tasks to finish / fail.
3658        assert_let!(
3659            Err(QRCodeGrantLoginError::UnexpectedMessage {
3660                expected: "m.login.success",
3661                received,
3662            }) = grant.await,
3663            "Alice should abort the login with expected error variant"
3664        );
3665        assert_matches!(
3666            *received,
3667            QrAuthMessage::LoginProtocolAccepted,
3668            "Alice should abort the login with expected error message"
3669        );
3670        updates_task.await.expect("Alice should run through all progress states");
3671        bob_task.await.expect("Bob's task should finish");
3672    }
3673
3674    #[async_test]
3675    async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_success() {
3676        let server = MatrixMockServer::new().await;
3677        let rendezvous_server = Arc::new(
3678            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3679                .await,
3680        );
3681        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3682
3683        let device_authorization_grant = AuthorizationGrant {
3684            verification_uri_complete: Some(VerificationUriComplete::new(
3685                "https://id.matrix.org/device/abcde".to_owned(),
3686            )),
3687            verification_uri: EndUserVerificationUrl::new(
3688                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3689            )
3690            .unwrap(),
3691        };
3692
3693        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3694        server
3695            .mock_upload_cross_signing_keys()
3696            .ok()
3697            .expect(1)
3698            .named("upload_xsigning_keys")
3699            .mount()
3700            .await;
3701        server
3702            .mock_upload_cross_signing_signatures()
3703            .ok()
3704            .expect(1)
3705            .named("upload_xsigning_signatures")
3706            .mount()
3707            .await;
3708
3709        // Create a secure channel on the new client (Bob) and extract the QR
3710        // code.
3711        let client = rendezvous_server.unlogged_client().await;
3712        let channel = SecureChannel::login(&client, false)
3713            .await
3714            .expect("Bob should be able to create a secure channel.");
3715        let qr_code_data = channel.qr_code_data().clone();
3716
3717        // Create the existing client (Alice).
3718        let user_id = owned_user_id!("@alice:example.org");
3719        let device_id = owned_device_id!("ALICE_DEVICE");
3720        let alice = server
3721            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3722            .logged_in_with_oauth()
3723            .build()
3724            .await;
3725        alice
3726            .encryption()
3727            .bootstrap_cross_signing(None)
3728            .await
3729            .expect("Alice should be able to set up cross signing");
3730
3731        // Prepare the login granting future using the QR code.
3732        let oauth = alice.oauth();
3733        let grant = oauth
3734            .grant_login_with_qr_code()
3735            .device_creation_timeout(Duration::from_secs(2))
3736            .scan(&qr_code_data);
3737        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3738
3739        // Spawn the updates task.
3740        let mut updates = grant.subscribe_to_progress();
3741        let mut state = grant.state.get();
3742        let verification_uri_complete =
3743            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3744        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3745        let updates_task = spawn(async move {
3746            let mut checkcode_tx = Some(checkcode_tx);
3747
3748            while let Some(update) = updates.next().await {
3749                match &update {
3750                    GrantLoginProgress::Starting => {
3751                        assert_matches!(state, GrantLoginProgress::Starting);
3752                    }
3753                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3754                        assert_matches!(state, GrantLoginProgress::Starting);
3755                        checkcode_tx
3756                            .take()
3757                            .expect("The checkcode should only be forwarded once")
3758                            .send(*check_code)
3759                            .expect("Alice should be able to forward the checkcode");
3760                    }
3761                    GrantLoginProgress::WaitingForAuth {
3762                        verification_uri,
3763                        continuation_sender,
3764                    } => {
3765                        assert_matches!(
3766                            state,
3767                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3768                        );
3769                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
3770                        continuation_sender.confirm().await.expect("should be able to confirm");
3771                    }
3772                    _ => {
3773                        panic!("Alice should abort the process");
3774                    }
3775                }
3776                state = update;
3777            }
3778        });
3779
3780        let rendezvous_server_clone = rendezvous_server.clone();
3781        // Let Bob request the login and run through the process.
3782        let bob_task = spawn(async move {
3783            request_login_with_generated_qr_code(
3784                BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3785                channel,
3786                checkcode_rx,
3787                None,
3788                &rendezvous_server_clone,
3789                alice.homeserver(),
3790                Some(device_authorization_grant),
3791                None,
3792            )
3793            .await;
3794        });
3795
3796        // Wait for all tasks to finish / fail.
3797        assert_let!(
3798            Err(QRCodeGrantLoginError::UnexpectedMessage {
3799                expected: "m.login.success",
3800                received,
3801            }) = grant.await,
3802            "Alice should abort the login with expected error variant"
3803        );
3804        assert_matches!(
3805            *received,
3806            QrAuthMessage::LoginProtocolAccepted,
3807            "Alice should abort the login with expected error message"
3808        );
3809        updates_task.await.expect("Alice should run through all progress states");
3810        bob_task.await.expect("Bob's task should finish");
3811    }
3812
3813    #[async_test]
3814    async fn test_grant_login_with_generated_qr_code_secure_channel_error() {
3815        let server = MatrixMockServer::new().await;
3816        let rendezvous_server = Arc::new(
3817            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3818                .await,
3819        );
3820        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3821
3822        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3823        server
3824            .mock_upload_cross_signing_keys()
3825            .ok()
3826            .expect(1)
3827            .named("upload_xsigning_keys")
3828            .mount()
3829            .await;
3830        server
3831            .mock_upload_cross_signing_signatures()
3832            .ok()
3833            .expect(1)
3834            .named("upload_xsigning_signatures")
3835            .mount()
3836            .await;
3837
3838        // Create the existing client (Alice).
3839        let user_id = owned_user_id!("@alice:example.org");
3840        let device_id = owned_device_id!("ALICE_DEVICE");
3841        let alice = server
3842            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3843            .logged_in_with_oauth()
3844            .build()
3845            .await;
3846        alice
3847            .encryption()
3848            .bootstrap_cross_signing(None)
3849            .await
3850            .expect("Alice should be able to set up cross signing");
3851
3852        // Prepare the login granting future.
3853        let oauth = alice.oauth();
3854        let grant = oauth
3855            .grant_login_with_qr_code()
3856            .device_creation_timeout(Duration::from_secs(2))
3857            .generate();
3858        let (qr_code_tx, qr_code_rx) = oneshot::channel();
3859        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3860
3861        // Spawn the updates task.
3862        let mut updates = grant.subscribe_to_progress();
3863        let mut state = grant.state.get();
3864        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3865        let updates_task = spawn(async move {
3866            let mut qr_code_tx = Some(qr_code_tx);
3867            let mut checkcode_rx = Some(checkcode_rx);
3868
3869            while let Some(update) = updates.next().await {
3870                match &update {
3871                    GrantLoginProgress::Starting => {
3872                        assert_matches!(state, GrantLoginProgress::Starting);
3873                    }
3874                    GrantLoginProgress::EstablishingSecureChannel(
3875                        GeneratedQrProgress::QrReady(qr_code_data),
3876                    ) => {
3877                        assert_matches!(state, GrantLoginProgress::Starting);
3878                        qr_code_tx
3879                            .take()
3880                            .expect("The QR code should only be forwarded once")
3881                            .send(qr_code_data.clone())
3882                            .expect("Alice should be able to forward the QR code");
3883                    }
3884                    GrantLoginProgress::EstablishingSecureChannel(
3885                        GeneratedQrProgress::QrScanned(checkcode_sender),
3886                    ) => {
3887                        assert_matches!(
3888                            state,
3889                            GrantLoginProgress::EstablishingSecureChannel(
3890                                GeneratedQrProgress::QrReady(_)
3891                            )
3892                        );
3893                        let checkcode = checkcode_rx
3894                            .take()
3895                            .expect("The checkcode should only be forwarded once")
3896                            .await
3897                            .expect("Alice should receive the checkcode");
3898                        checkcode_sender
3899                            .send(checkcode)
3900                            .await
3901                            .expect("Alice should be able to forward the checkcode");
3902                        break;
3903                    }
3904                    _ => {
3905                        panic!("Alice should abort the process");
3906                    }
3907                }
3908                state = update;
3909            }
3910        });
3911
3912        // Let Bob request the login and run through the process.
3913        let rendezvous_server_clone = rendezvous_server.clone();
3914        let bob_task = spawn(async move {
3915            request_login_with_scanned_qr_code(
3916                BobBehaviour::InvalidJsonMessage,
3917                qr_code_rx,
3918                checkcode_tx,
3919                None,
3920                &rendezvous_server_clone,
3921                None,
3922                None,
3923            )
3924            .await;
3925        });
3926
3927        // Wait for all tasks to finish / fail.
3928        assert_matches!(
3929            grant.await,
3930            Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
3931                MessageDecodeError::Json(_)
3932            ))),
3933            "Alice should abort the login with a SecureChannel error"
3934        );
3935        updates_task.await.expect("Alice should run through all progress states");
3936        bob_task.await.expect("Bob's task should finish");
3937    }
3938
3939    #[async_test]
3940    async fn test_grant_login_with_scanned_qr_code_secure_channel_error() {
3941        let server = MatrixMockServer::new().await;
3942        let rendezvous_server = Arc::new(
3943            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3944                .await,
3945        );
3946        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3947
3948        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3949        server
3950            .mock_upload_cross_signing_keys()
3951            .ok()
3952            .expect(1)
3953            .named("upload_xsigning_keys")
3954            .mount()
3955            .await;
3956        server
3957            .mock_upload_cross_signing_signatures()
3958            .ok()
3959            .expect(1)
3960            .named("upload_xsigning_signatures")
3961            .mount()
3962            .await;
3963
3964        // Create a secure channel on the new client (Bob) and extract the QR
3965        // code.
3966        let client = rendezvous_server.unlogged_client().await;
3967        let channel = SecureChannel::login(&client, false)
3968            .await
3969            .expect("Bob should be able to create a secure channel.");
3970        let qr_code_data = channel.qr_code_data().clone();
3971
3972        // Create the existing client (Alice).
3973        let user_id = owned_user_id!("@alice:example.org");
3974        let device_id = owned_device_id!("ALICE_DEVICE");
3975        let alice = server
3976            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3977            .logged_in_with_oauth()
3978            .build()
3979            .await;
3980        alice
3981            .encryption()
3982            .bootstrap_cross_signing(None)
3983            .await
3984            .expect("Alice should be able to set up cross signing");
3985
3986        // Prepare the login granting future using the QR code.
3987        let oauth = alice.oauth();
3988        let grant = oauth
3989            .grant_login_with_qr_code()
3990            .device_creation_timeout(Duration::from_secs(2))
3991            .scan(&qr_code_data);
3992        let (checkcode_tx, checkcode_rx) = oneshot::channel();
3993
3994        // Spawn the updates task.
3995        let mut updates = grant.subscribe_to_progress();
3996        let mut state = grant.state.get();
3997        assert_matches!(state.clone(), GrantLoginProgress::Starting);
3998        let updates_task = spawn(async move {
3999            let mut checkcode_tx = Some(checkcode_tx);
4000
4001            while let Some(update) = updates.next().await {
4002                match &update {
4003                    GrantLoginProgress::Starting => {
4004                        assert_matches!(state, GrantLoginProgress::Starting);
4005                    }
4006                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
4007                        assert_matches!(state, GrantLoginProgress::Starting);
4008                        checkcode_tx
4009                            .take()
4010                            .expect("The checkcode should only be forwarded once")
4011                            .send(*check_code)
4012                            .expect("Alice should be able to forward the checkcode");
4013                        break;
4014                    }
4015                    _ => {
4016                        panic!("Alice should abort the process");
4017                    }
4018                }
4019                state = update;
4020            }
4021        });
4022
4023        let rendezvous_server_clone = rendezvous_server.clone();
4024        // Let Bob request the login and run through the process.
4025        let bob_task = spawn(async move {
4026            request_login_with_generated_qr_code(
4027                BobBehaviour::InvalidJsonMessage,
4028                channel,
4029                checkcode_rx,
4030                None,
4031                &rendezvous_server_clone,
4032                alice.homeserver(),
4033                None,
4034                None,
4035            )
4036            .await;
4037        });
4038
4039        // Wait for all tasks to finish / fail.
4040        assert_matches!(
4041            grant.await,
4042            Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
4043                MessageDecodeError::Json(_)
4044            ))),
4045            "Alice should abort the login with a SecureChannel error"
4046        );
4047        updates_task.await.expect("Alice should run through all progress states");
4048        bob_task.await.expect("Bob's task should finish");
4049    }
4050
4051    #[async_test]
4052    async fn test_grant_login_with_generated_qr_code_cancelled_while_waiting_for_auth() {
4053        let (protocol_accepted_tx, protocol_accepted_rx) = oneshot::channel();
4054        let server = MatrixMockServer::new().await;
4055        let rendezvous_server =
4056            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
4057                .await;
4058        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
4059
4060        let device_authorization_grant = AuthorizationGrant {
4061            verification_uri_complete: Some(VerificationUriComplete::new(
4062                "https://id.matrix.org/device/abcde".to_owned(),
4063            )),
4064            verification_uri: EndUserVerificationUrl::new(
4065                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
4066            )
4067            .unwrap(),
4068        };
4069
4070        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
4071        server
4072            .mock_upload_cross_signing_keys()
4073            .ok()
4074            .expect(1)
4075            .named("upload_xsigning_keys")
4076            .mount()
4077            .await;
4078        server
4079            .mock_upload_cross_signing_signatures()
4080            .ok()
4081            .expect(1)
4082            .named("upload_xsigning_signatures")
4083            .mount()
4084            .await;
4085
4086        // Create the existing client (Alice).
4087        let user_id = owned_user_id!("@alice:example.org");
4088        let device_id = owned_device_id!("ALICE_DEVICE");
4089        let alice = server
4090            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
4091            .logged_in_with_oauth()
4092            .build()
4093            .await;
4094        alice
4095            .encryption()
4096            .bootstrap_cross_signing(None)
4097            .await
4098            .expect("Alice should be able to set up cross signing");
4099
4100        // Prepare the login granting future.
4101        let oauth = alice.oauth();
4102        let grant = oauth
4103            .grant_login_with_qr_code()
4104            .device_creation_timeout(Duration::from_secs(2))
4105            .generate();
4106        let (qr_code_tx, qr_code_rx) = oneshot::channel();
4107        let (checkcode_tx, checkcode_rx) = oneshot::channel();
4108
4109        // Spawn the updates task.
4110        let mut updates = grant.subscribe_to_progress();
4111        let mut state = grant.state.get();
4112        let verification_uri_complete =
4113            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
4114        assert_matches!(state.clone(), GrantLoginProgress::Starting);
4115        let updates_task = spawn(async move {
4116            let mut qr_code_tx = Some(qr_code_tx);
4117            let mut checkcode_rx = Some(checkcode_rx);
4118
4119            while let Some(update) = updates.next().await {
4120                match &update {
4121                    GrantLoginProgress::Starting => {
4122                        assert_matches!(state, GrantLoginProgress::Starting);
4123                    }
4124                    GrantLoginProgress::EstablishingSecureChannel(
4125                        GeneratedQrProgress::QrReady(qr_code_data),
4126                    ) => {
4127                        assert_matches!(state, GrantLoginProgress::Starting);
4128                        qr_code_tx
4129                            .take()
4130                            .expect("The QR code should only be forwarded once")
4131                            .send(qr_code_data.clone())
4132                            .expect("Alice should be able to forward the QR code");
4133                    }
4134                    GrantLoginProgress::EstablishingSecureChannel(
4135                        GeneratedQrProgress::QrScanned(checkcode_sender),
4136                    ) => {
4137                        assert_matches!(
4138                            state,
4139                            GrantLoginProgress::EstablishingSecureChannel(
4140                                GeneratedQrProgress::QrReady(_)
4141                            )
4142                        );
4143                        let checkcode = checkcode_rx
4144                            .take()
4145                            .expect("The checkcode should only be forwarded once")
4146                            .await
4147                            .expect("Alice should receive the checkcode");
4148                        checkcode_sender
4149                            .send(checkcode)
4150                            .await
4151                            .expect("Alice should be able to forward the checkcode");
4152                    }
4153                    GrantLoginProgress::WaitingForAuth {
4154                        verification_uri,
4155                        continuation_sender,
4156                    } => {
4157                        assert_matches!(
4158                            state,
4159                            GrantLoginProgress::EstablishingSecureChannel(
4160                                GeneratedQrProgress::QrScanned(_)
4161                            )
4162                        );
4163                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
4164                        // Wait for Bob to receive LoginProtocolAccepted.
4165                        protocol_accepted_rx
4166                            .await
4167                            .expect("Bob should signal that the protocol was accepted");
4168                        // The user cancels the login instead of confirming it.
4169                        continuation_sender.cancel().await.expect("should be able to cancel");
4170                        break;
4171                    }
4172                    _ => {
4173                        panic!("Alice should abort the process after being cancelled");
4174                    }
4175                }
4176                state = update;
4177            }
4178        });
4179
4180        // Let Bob request the login and run through the process.
4181        let bob_task = spawn(async move {
4182            request_login_with_scanned_qr_code(
4183                BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx),
4184                qr_code_rx,
4185                checkcode_tx,
4186                Some(server),
4187                &rendezvous_server,
4188                Some(device_authorization_grant),
4189                None,
4190            )
4191            .await;
4192        });
4193
4194        // Wait for all tasks to finish / fail.
4195        assert_matches!(
4196            grant.await,
4197            Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
4198            "Alice should abort the login with expected error"
4199        );
4200        updates_task.await.expect("Alice should run through all progress states");
4201        bob_task.await.expect("Bob's task should finish");
4202    }
4203
4204    #[async_test]
4205    async fn test_grant_login_with_scanned_qr_code_cancelled_while_waiting_for_auth() {
4206        let (protocol_accepted_tx, protocol_accepted_rx) = oneshot::channel();
4207        let server = MatrixMockServer::new().await;
4208        let rendezvous_server =
4209            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
4210                .await;
4211        debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
4212
4213        let device_authorization_grant = AuthorizationGrant {
4214            verification_uri_complete: Some(VerificationUriComplete::new(
4215                "https://id.matrix.org/device/abcde".to_owned(),
4216            )),
4217            verification_uri: EndUserVerificationUrl::new(
4218                "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
4219            )
4220            .unwrap(),
4221        };
4222
4223        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
4224        server
4225            .mock_upload_cross_signing_keys()
4226            .ok()
4227            .expect(1)
4228            .named("upload_xsigning_keys")
4229            .mount()
4230            .await;
4231        server
4232            .mock_upload_cross_signing_signatures()
4233            .ok()
4234            .expect(1)
4235            .named("upload_xsigning_signatures")
4236            .mount()
4237            .await;
4238
4239        // Create a secure channel on the new client (Bob) and extract the QR
4240        // code.
4241        let client = rendezvous_server.unlogged_client().await;
4242        let channel = SecureChannel::login(&client, false)
4243            .await
4244            .expect("Bob should be able to create a secure channel.");
4245        let qr_code_data = channel.qr_code_data().clone();
4246
4247        // Create the existing client (Alice).
4248        let user_id = owned_user_id!("@alice:example.org");
4249        let device_id = owned_device_id!("ALICE_DEVICE");
4250        let alice = server
4251            .client_builder_for_crypto_end_to_end(&user_id, &device_id)
4252            .logged_in_with_oauth()
4253            .build()
4254            .await;
4255        alice
4256            .encryption()
4257            .bootstrap_cross_signing(None)
4258            .await
4259            .expect("Alice should be able to set up cross signing");
4260
4261        // Prepare the login granting future using the QR code.
4262        let oauth = alice.oauth();
4263        let grant = oauth
4264            .grant_login_with_qr_code()
4265            .device_creation_timeout(Duration::from_secs(2))
4266            .scan(&qr_code_data);
4267        let (checkcode_tx, checkcode_rx) = oneshot::channel();
4268
4269        // Spawn the updates task.
4270        let mut updates = grant.subscribe_to_progress();
4271        let mut state = grant.state.get();
4272        let verification_uri_complete =
4273            device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
4274        assert_matches!(state.clone(), GrantLoginProgress::Starting);
4275        let updates_task = spawn(async move {
4276            let mut checkcode_tx = Some(checkcode_tx);
4277
4278            while let Some(update) = updates.next().await {
4279                match &update {
4280                    GrantLoginProgress::Starting => {
4281                        assert_matches!(state, GrantLoginProgress::Starting);
4282                    }
4283                    GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
4284                        assert_matches!(state, GrantLoginProgress::Starting);
4285                        checkcode_tx
4286                            .take()
4287                            .expect("The checkcode should only be forwarded once")
4288                            .send(*check_code)
4289                            .expect("Alice should be able to forward the checkcode");
4290                    }
4291                    GrantLoginProgress::WaitingForAuth {
4292                        verification_uri,
4293                        continuation_sender,
4294                    } => {
4295                        assert_matches!(
4296                            state,
4297                            GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
4298                        );
4299                        assert_eq!(verification_uri.as_str(), verification_uri_complete);
4300                        // Wait for Bob to receive LoginProtocolAccepted.
4301                        protocol_accepted_rx
4302                            .await
4303                            .expect("Bob should signal that the protocol was accepted");
4304                        // The user cancels the login instead of confirming it.
4305                        continuation_sender.cancel().await.expect("should be able to cancel");
4306                        break;
4307                    }
4308                    _ => {
4309                        panic!("Alice should abort the process after being cancelled");
4310                    }
4311                }
4312                state = update;
4313            }
4314        });
4315
4316        // Let Bob request the login and run through the process.
4317        let bob_task = spawn(async move {
4318            request_login_with_generated_qr_code(
4319                BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx),
4320                channel,
4321                checkcode_rx,
4322                Some(server),
4323                &rendezvous_server,
4324                alice.homeserver(),
4325                Some(device_authorization_grant),
4326                None,
4327            )
4328            .await;
4329        });
4330
4331        // Wait for all tasks to finish / fail.
4332        assert_matches!(
4333            grant.await,
4334            Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
4335            "Alice should abort the login with expected error"
4336        );
4337        updates_task.await.expect("Alice should run through all progress states");
4338        bob_task.await.expect("Bob's task should finish");
4339    }
4340}