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