Skip to main content

matrix_sdk/authentication/oauth/qrcode/
login.rs

1// Copyright 2024, 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::future::IntoFuture;
16
17use eyeball::SharedObservable;
18use futures_core::Stream;
19use matrix_sdk_base::{
20    SessionMeta, boxed_into_future,
21    crypto::types::qr_login::{QrCodeData, QrCodeIntent},
22    store::RoomLoadSettings,
23};
24use oauth2::{DeviceCodeErrorResponseType, StandardDeviceAuthorizationResponse};
25use ruma::{
26    OwnedDeviceId,
27    api::client::discovery::get_authorization_server_metadata::v1::AuthorizationServerMetadata,
28};
29use tracing::trace;
30use url::Url;
31use vodozemac::Curve25519PublicKey;
32#[cfg(doc)]
33use vodozemac::ecies::CheckCode;
34
35use super::{
36    DeviceAuthorizationOAuthError, QRCodeLoginError, SecureChannelError,
37    messages::{LoginFailureReason, QrAuthMessage},
38    secure_channel::{EstablishedSecureChannel, SecureChannel},
39};
40use crate::{
41    Client,
42    authentication::oauth::{
43        ClientRegistrationData, OAuth, OAuthError,
44        qrcode::{
45            CheckCodeSender, GeneratedQrProgress, LoginProtocolType, QrProgress,
46            messages::LoginProtocolsMessage, secure_channel::ChannelVariant,
47        },
48    },
49};
50
51async fn send_unexpected_message_error(
52    channel: &mut EstablishedSecureChannel,
53) -> Result<(), SecureChannelError> {
54    channel
55        .send_json(QrAuthMessage::LoginFailure {
56            reason: LoginFailureReason::UnexpectedMessageReceived,
57            homeserver: None,
58        })
59        .await
60}
61
62/// Receive the `m.login.protocols` message from the existing device and verify
63/// that it supports the device authorization grant.
64///
65/// Returns the base URL of the homeserver we're going to log in to.
66async fn receive_login_protocols(
67    channel: &mut EstablishedSecureChannel,
68) -> Result<Url, QRCodeLoginError> {
69    // -- MSC4108 OAuth 2.0 login step 1
70    let message = channel.receive_json().await?;
71
72    // The message needs to use the layout of our channel variant.
73    let login_protocols = match channel.channel_variant() {
74        ChannelVariant::Msc4108 => match message {
75            QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
76                protocols,
77                homeserver,
78            }) => Ok((protocols, homeserver)),
79            message => Err(message),
80        },
81        #[cfg(feature = "unstable-msc4388")]
82        ChannelVariant::Msc4388 => match message {
83            QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
84                protocols,
85                base_url,
86            }) => Ok((protocols, base_url)),
87            message => Err(message),
88        },
89    };
90
91    let (protocols, homeserver) = match login_protocols {
92        Ok(login_protocols) => login_protocols,
93        Err(message) => {
94            send_unexpected_message_error(channel).await?;
95
96            return Err(QRCodeLoginError::UnexpectedMessage {
97                expected: "m.login.protocols",
98                received: Box::new(message),
99            });
100        }
101    };
102
103    // Verify that the device authorization grant is supported.
104    //
105    // -- MSC4108 OAuth 2.0 login step 2
106    if !protocols.contains(&LoginProtocolType::DeviceAuthorizationGrant) {
107        channel
108            .send_json(QrAuthMessage::LoginFailure {
109                reason: LoginFailureReason::UnsupportedProtocol,
110                homeserver: None,
111            })
112            .await?;
113
114        return Err(QRCodeLoginError::LoginFailure {
115            reason: LoginFailureReason::UnsupportedProtocol,
116            homeserver: None,
117        });
118    }
119
120    Ok(homeserver)
121}
122
123async fn finish_login<Q>(
124    client: &Client,
125    mut channel: EstablishedSecureChannel,
126    registration_data: Option<&ClientRegistrationData>,
127    state: SharedObservable<LoginProgress<Q>>,
128) -> Result<(), QRCodeLoginError> {
129    let oauth = client.oauth();
130
131    // Register the client with the OAuth 2.0 authorization server.
132    trace!("Registering the client with the OAuth 2.0 authorization server.");
133    let server_metadata = register_client(&oauth, registration_data).await?;
134
135    // We want to use the Curve25519 public key for the device ID, so let's
136    // generate a new vodozemac `Account` now.
137    let account = vodozemac::olm::Account::new();
138    let public_key = account.identity_keys().curve25519;
139    let device_id = public_key;
140
141    // Let's tell the OAuth 2.0 authorization server that we want to log in
142    // using the device authorization grant described in
143    // [RFC8628](https://datatracker.ietf.org/doc/html/rfc8628).
144    trace!("Requesting device authorization.");
145    let auth_grant_response =
146        request_device_authorization(&oauth, &server_metadata, device_id).await?;
147
148    // Now we need to inform the other device of the login protocols we picked
149    // and the URL they should use to log us in.
150    trace!("Letting the existing device know about the device authorization grant.");
151    let message = QrAuthMessage::authorization_grant_login_protocol(
152        (&auth_grant_response).into(),
153        device_id,
154        channel.channel_variant(),
155    );
156    channel.send_json(&message).await?;
157
158    // Let's see if the other device agreed to our proposed protocols.
159    match channel.receive_json().await? {
160        QrAuthMessage::LoginProtocolAccepted => (),
161        QrAuthMessage::LoginFailure { reason, homeserver } => {
162            return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
163        }
164        message => {
165            send_unexpected_message_error(&mut channel).await?;
166
167            return Err(QRCodeLoginError::UnexpectedMessage {
168                expected: "m.login.protocol_accepted",
169                received: Box::new(message),
170            });
171        }
172    }
173
174    // The OAuth 2.0 authorization server may or may not show this user code to
175    // double check that we're talking to the right server. Let us display this,
176    // so the other device can double check this as well.
177    let user_code = auth_grant_response.user_code();
178    state.set(LoginProgress::WaitingForToken { user_code: user_code.secret().to_owned() });
179
180    // Let's now wait for the access token to be provided to use by the OAuth
181    // 2.0 authorization server.
182    trace!("Waiting for the OAuth 2.0 authorization server to give us the access token.");
183    if let Err(e) = wait_for_tokens(&oauth, &server_metadata, &auth_grant_response).await {
184        // If we received an error, and it's one of the ones we should report to
185        // the other side, do so now.
186        if let Some(e) = e.as_request_token_error() {
187            match e {
188                DeviceCodeErrorResponseType::AccessDenied => {
189                    channel.send_json(QrAuthMessage::LoginDeclined).await?;
190                }
191                DeviceCodeErrorResponseType::ExpiredToken => {
192                    channel
193                        .send_json(QrAuthMessage::LoginFailure {
194                            reason: LoginFailureReason::AuthorizationExpired,
195                            homeserver: None,
196                        })
197                        .await?;
198                }
199                _ => (),
200            }
201        }
202
203        return Err(e.into());
204    }
205
206    // We only received an access token from the OAuth 2.0 authorization server,
207    // we have no clue who we are, so we need to figure out our user ID now.
208    // TODO: This snippet is almost the same as the
209    // OAuth::finish_login_method(), why is that method even a public method and
210    // not called as part of the set session tokens method.
211    trace!("Discovering our own user id.");
212    let whoami_response = client.whoami().await.map_err(QRCodeLoginError::UserIdDiscovery)?;
213    client
214        .activate(
215            SessionMeta {
216                user_id: whoami_response.user_id,
217                device_id: OwnedDeviceId::from(device_id.to_base64()),
218            },
219            RoomLoadSettings::default(),
220            Some(account),
221        )
222        .await
223        .map_err(QRCodeLoginError::SessionTokens)?;
224
225    client.oauth().enable_cross_process_lock().await?;
226
227    state.set(LoginProgress::SyncingSecrets);
228
229    // Tell the existing device that we're logged in.
230    trace!("Telling the existing device that we successfully logged in.");
231    let message = QrAuthMessage::LoginSuccess;
232    channel.send_json(&message).await?;
233
234    // Let's wait for the secrets bundle to be sent to us, otherwise we won't be
235    // a fully E2EE enabled device.
236    trace!("Waiting for the secrets bundle.");
237    let bundle = match channel.receive_json().await? {
238        QrAuthMessage::LoginSecrets(bundle) => bundle,
239        QrAuthMessage::LoginFailure { reason, homeserver } => {
240            return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
241        }
242        message => {
243            send_unexpected_message_error(&mut channel).await?;
244
245            return Err(QRCodeLoginError::UnexpectedMessage {
246                expected: "m.login.secrets",
247                received: Box::new(message),
248            });
249        }
250    };
251
252    // Import the secrets bundle, this will allow us to sign the device keys
253    // with the master key when we upload them.
254    client.encryption().import_secrets_bundle_impl(&bundle).await?;
255
256    // Upload the device keys, this will ensure that other devices see us as a
257    // fully verified device ass soon as this method returns.
258    client
259        .encryption()
260        .ensure_device_keys_upload()
261        .await
262        .map_err(QRCodeLoginError::DeviceKeyUpload)?;
263
264    // Run and wait for the E2EE initialization tasks, this will ensure that we
265    // ourselves see us as verified and the recovery/backup states will be
266    // known. If we did receive all the secrets in the secrets bundle, then
267    // backups will be enabled after this step as well.
268    client.encryption().spawn_initialization_task(None).await;
269    client.encryption().wait_for_e2ee_initialization_tasks().await;
270
271    trace!("successfully logged in and enabled E2EE.");
272
273    // Tell our listener that we're done.
274    state.set(LoginProgress::Done);
275
276    // And indeed, we are done with the login.
277    Ok(())
278}
279
280/// Register the client with the OAuth 2.0 authorization server.
281///
282/// Returns the authorization server metadata.
283async fn register_client(
284    oauth: &OAuth,
285    registration_data: Option<&ClientRegistrationData>,
286) -> Result<AuthorizationServerMetadata, DeviceAuthorizationOAuthError> {
287    let server_metadata = oauth.server_metadata().await.map_err(OAuthError::from)?;
288    oauth.use_registration_data(&server_metadata, registration_data).await?;
289
290    Ok(server_metadata)
291}
292
293async fn request_device_authorization(
294    oauth: &OAuth,
295    server_metadata: &AuthorizationServerMetadata,
296    device_id: Curve25519PublicKey,
297) -> Result<StandardDeviceAuthorizationResponse, DeviceAuthorizationOAuthError> {
298    let response = oauth
299        .request_device_authorization(server_metadata, Some(device_id.to_base64().into()))
300        .await?;
301    Ok(response)
302}
303
304async fn wait_for_tokens(
305    oauth: &OAuth,
306    server_metadata: &AuthorizationServerMetadata,
307    auth_response: &StandardDeviceAuthorizationResponse,
308) -> Result<(), DeviceAuthorizationOAuthError> {
309    oauth.exchange_device_code(server_metadata, auth_response).await?;
310    Ok(())
311}
312
313/// Type telling us about the progress of the QR code login.
314#[derive(Clone, Debug, Default)]
315pub enum LoginProgress<Q> {
316    /// We're just starting up, this is the default and initial state.
317    #[default]
318    Starting,
319    /// We have established the secure channel, but need to exchange the
320    /// [`CheckCode`] so the channel can be verified to indeed be secure.
321    EstablishingSecureChannel(Q),
322    /// We're waiting for the OAuth 2.0 authorization server to give us the
323    /// access token. This will only happen if the other device allows the OAuth
324    /// 2.0 authorization server to do so.
325    WaitingForToken {
326        /// The user code the OAuth 2.0 authorization server has given us, the
327        /// OAuth 2.0 authorization server might ask the other device to enter
328        /// this code.
329        user_code: String,
330    },
331    /// We are syncing secrets.
332    SyncingSecrets,
333    /// The login process has completed.
334    Done,
335}
336
337/// Named future for logging in by scanning a QR code with the
338/// [`OAuth::login_with_qr_code()`] method.
339#[derive(Debug)]
340pub struct LoginWithQrCode {
341    client: Client,
342    registration_data: Option<ClientRegistrationData>,
343    qr_code_data: QrCodeData,
344    state: SharedObservable<LoginProgress<QrProgress>>,
345}
346
347impl LoginWithQrCode {
348    /// Subscribe to the progress of QR code login.
349    ///
350    /// It's usually necessary to subscribe to this to let the existing device
351    /// know about the [`CheckCode`] which is used to verify that the two
352    /// devices are communicating in a secure manner.
353    pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress<QrProgress>> + use<> {
354        self.state.subscribe()
355    }
356}
357
358impl IntoFuture for LoginWithQrCode {
359    type Output = Result<(), QRCodeLoginError>;
360    boxed_into_future!();
361
362    fn into_future(self) -> Self::IntoFuture {
363        Box::pin(async move {
364            // Before we get here, the other device has created a new rendezvous
365            // session and presented a QR code which this device has scanned.
366            //
367            // -- MSC4108 Secure channel setup steps 1-3
368
369            // First things first, establish the secure channel. Since we're the
370            // one that scanned the QR code, we're certain that the
371            // secure channel is secure, under the assumption that
372            // we didn't scan the wrong QR code.
373            //
374            // -- MSC4108 Secure channel setup steps 3-5
375            trace!("Trying to establish the secure channel");
376
377            #[cfg_attr(not(feature = "unstable-msc4388"), allow(unused_mut))]
378            let mut channel = self.establish_secure_channel().await?;
379
380            trace!("Established the secure channel.");
381
382            // The other side isn't yet sure that it's talking to the right
383            // device, show a check code so they can confirm.
384            //
385            // -- MSC4108 Secure channel setup step 6
386            let check_code = channel.check_code().to_owned();
387            self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
388
389            // The user now enters the checkcode on the other device which
390            // verifies it and will only facilitate the login if the code
391            // matches.
392            //
393            // -- MSC4108 Secure channel setup step 7
394
395            match channel.channel_variant() {
396                // With MSC4108, the existing device doesn't send the
397                // m.login.protocols message, the QR code already told us which
398                // homeserver to use.
399                ChannelVariant::Msc4108 => {}
400                // With MSC4388, the existing device always sends the
401                // m.login.protocols message first. The base URL from the QR
402                // code only identifies the rendezvous server, the base URL in
403                // this message is the authoritative homeserver for the login.
404                #[cfg(feature = "unstable-msc4388")]
405                ChannelVariant::Msc4388 => {
406                    let base_url = receive_login_protocols(&mut channel).await?;
407
408                    // Change the login homeserver if it is different from the
409                    // server hosting the rendezvous session.
410                    if self.client.homeserver() != base_url {
411                        self.client
412                            .switch_homeserver_and_re_resolve_well_known(base_url)
413                            .await
414                            .map_err(QRCodeLoginError::ServerReset)?;
415                    }
416                }
417            }
418
419            // Now attempt to finish the login.
420            //
421            // -- MSC4108 OAuth 2.0 login all steps
422            finish_login(&self.client, channel, self.registration_data.as_ref(), self.state).await
423        })
424    }
425}
426
427impl LoginWithQrCode {
428    pub(crate) fn new(
429        client: &Client,
430        qr_code_data: &QrCodeData,
431        registration_data: Option<&ClientRegistrationData>,
432    ) -> LoginWithQrCode {
433        LoginWithQrCode {
434            client: client.clone(),
435            registration_data: registration_data.cloned(),
436            qr_code_data: qr_code_data.clone(),
437            state: Default::default(),
438        }
439    }
440
441    async fn establish_secure_channel(
442        &self,
443    ) -> Result<EstablishedSecureChannel, SecureChannelError> {
444        let http_client = self.client.inner.http_client.inner.clone();
445
446        let channel = EstablishedSecureChannel::from_qr_code(
447            http_client,
448            &self.qr_code_data,
449            QrCodeIntent::Login,
450        )
451        .await?;
452
453        Ok(channel)
454    }
455}
456
457/// Named future for logging in by generating a QR code with the
458/// [`OAuth::login_with_qr_code()`] method.
459#[derive(Debug)]
460pub struct LoginWithGeneratedQrCode {
461    client: Client,
462    registration_data: Option<ClientRegistrationData>,
463    state: SharedObservable<LoginProgress<GeneratedQrProgress>>,
464    msc_4388_support: bool,
465}
466
467impl LoginWithGeneratedQrCode {
468    /// Subscribe to the progress of QR code login.
469    ///
470    /// It's necessary to subscribe to this to show the QR code to the existing
471    /// device so it can send the check code back to this device.
472    pub fn subscribe_to_progress(
473        &self,
474    ) -> impl Stream<Item = LoginProgress<GeneratedQrProgress>> + use<> {
475        self.state.subscribe()
476    }
477
478    /// Enable and generate a QR code which supports [MSC4388].
479    ///
480    /// [MSC4388]: https://github.com/matrix-org/matrix-spec-proposals/pull/4388
481    #[cfg(feature = "unstable-msc4388")]
482    pub fn with_msc4388_support(&mut self) -> &mut Self {
483        self.msc_4388_support = true;
484        self
485    }
486}
487
488impl IntoFuture for LoginWithGeneratedQrCode {
489    type Output = Result<(), QRCodeLoginError>;
490    boxed_into_future!();
491
492    fn into_future(self) -> Self::IntoFuture {
493        Box::pin(async move {
494            // Establish and verify the secure channel.
495            //
496            // -- MSC4108 Secure channel setup all steps
497            trace!("Trying to establish the secure channel");
498
499            let mut channel = self.establish_secure_channel().await?;
500
501            trace!("Established the secure channel.");
502
503            // Wait for the other device to send us the m.login.protocols
504            // message so that we can discover the homeserver to use for logging
505            // in.
506            //
507            // -- MSC4108 OAuth 2.0 login steps 1 & 2
508            let homeserver = receive_login_protocols(&mut channel).await?;
509
510            // Change the login homeserver if it is different from the server
511            // hosting the secure channel.
512            if self.client.homeserver() != homeserver {
513                self.client
514                    .switch_homeserver_and_re_resolve_well_known(homeserver)
515                    .await
516                    .map_err(QRCodeLoginError::ServerReset)?;
517            }
518
519            // Proceed with logging in.
520            //
521            // -- MSC4108 OAuth 2.0 login remaining steps
522            finish_login(&self.client, channel, self.registration_data.as_ref(), self.state).await
523        })
524    }
525}
526
527impl LoginWithGeneratedQrCode {
528    pub(crate) fn new(client: &Client, registration_data: Option<&ClientRegistrationData>) -> Self {
529        Self {
530            client: client.clone(),
531            registration_data: registration_data.cloned(),
532            state: Default::default(),
533            msc_4388_support: false,
534        }
535    }
536
537    async fn establish_secure_channel(
538        &self,
539    ) -> Result<EstablishedSecureChannel, SecureChannelError> {
540        // Create a new ephemeral key pair and a rendezvous session to request a
541        // login with.
542        //
543        // -- MSC4108 Secure channel setup steps 1 & 2
544        let secure_channel = SecureChannel::login(&self.client, self.msc_4388_support).await?;
545
546        // Extract the QR code data and emit a progress update so that the
547        // caller can present the QR code for scanning by the other device.
548        //
549        // -- MSC4108 Secure channel setup step 3
550        let qr_code_data = secure_channel.qr_code_data().clone();
551        trace!("Generated QR code.");
552        self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(
553            qr_code_data,
554        )));
555
556        // Wait for the secure channel to connect. The other device now needs to
557        // scan the QR code and send us the LoginInitiateMessage which we
558        // respond to with the LoginOkMessage.
559        //
560        // -- MSC4108 step 4 & 5
561        let channel = secure_channel.connect().await?;
562
563        // The other device now verifies our message, computes the checkcode and
564        // displays it. We emit a progress update to let the caller prompt the
565        // user to enter the checkcode and feed it back to us.
566        //
567        // -- MSC4108 Secure channel setup step 6
568        trace!("Waiting for checkcode.");
569        let (tx, rx) = tokio::sync::oneshot::channel();
570        self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
571            CheckCodeSender::new(tx),
572        )));
573
574        // Retrieve the entered checkcode and verify it to confirm that the
575        // channel is actually secure.
576        //
577        // -- MSC4108 Secure channel setup step 7
578        let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
579        trace!("Received check code.");
580        channel.confirm(check_code)
581    }
582}
583
584#[cfg(all(test, not(target_family = "wasm")))]
585mod test {
586    use std::{assert_matches, time::Duration};
587
588    use futures_util::StreamExt;
589    use matrix_sdk_base::{
590        CancellableIntoFutureExt,
591        crypto::types::{
592            SecretsBundle,
593            qr_login::{Msc4108IntentData, QrCodeIntentData},
594        },
595    };
596    use matrix_sdk_common::executor::spawn;
597    use matrix_sdk_test::async_test;
598    use serde_json::json;
599    use strass::assert_let;
600    use url::Url;
601
602    use super::*;
603    use crate::{
604        authentication::oauth::qrcode::{
605            messages::{LoginProtocolType, LoginProtocolsMessage},
606            secure_channel::{ChannelVariant, SecureChannel, test::MockedRendezvousServer},
607        },
608        config::RequestConfig,
609        test_utils::{client::oauth::mock_client_metadata, mocks::MatrixMockServer},
610    };
611
612    enum AliceBehaviour {
613        HappyPath,
614        DeclinedProtocol,
615        UnexpectedMessage,
616        UnexpectedMessageInsteadOfSecrets,
617        RefuseSecrets,
618        LetSessionExpire,
619        /// Offer no login protocols in the `m.login.protocols` message.
620        NoProtocols,
621    }
622
623    #[derive(Clone, Copy)]
624    enum BobBehaviour {
625        HappyPath,
626        CancelWhileWaitingForToken,
627    }
628
629    /// The possible token responses.
630    enum TokenResponse {
631        Ok,
632        AccessDenied,
633        ExpiredToken,
634    }
635
636    fn secrets_bundle() -> SecretsBundle {
637        let json = json!({
638            "cross_signing": {
639                "master_key": "rTtSv67XGS6k/rg6/yTG/m573cyFTPFRqluFhQY+hSw",
640                "self_signing_key": "4jbPt7jh5D2iyM4U+3IDa+WthgJB87IQN1ATdkau+xk",
641                "user_signing_key": "YkFKtkjcsTxF6UAzIIG/l6Nog/G2RigCRfWj3cjNWeM",
642            },
643        });
644
645        serde_json::from_value(json).expect("We should be able to deserialize a secrets bundle")
646    }
647
648    /// Receive the message Bob sends in place of `m.login.success` when he
649    /// fails to get a token, and check it.
650    ///
651    /// Returns `true` if Bob logged in successfully.
652    async fn receive_login_outcome(
653        channel: &mut EstablishedSecureChannel,
654        token_response: TokenResponse,
655    ) -> bool {
656        let message: QrAuthMessage = channel
657            .receive_json()
658            .await
659            .expect("Alice should be able to receive the login outcome from Bob");
660
661        match token_response {
662            TokenResponse::Ok => {
663                assert_let!(QrAuthMessage::LoginSuccess = message);
664                true
665            }
666            TokenResponse::AccessDenied => {
667                assert_let!(QrAuthMessage::LoginDeclined = message);
668                false
669            }
670            TokenResponse::ExpiredToken => {
671                assert_matches!(
672                    message,
673                    QrAuthMessage::LoginFailure {
674                        reason: LoginFailureReason::AuthorizationExpired,
675                        homeserver: None
676                    }
677                );
678                false
679            }
680        }
681    }
682
683    /// Check that Bob tells Alice that he received a message he didn't expect.
684    async fn receive_unexpected_message_error(channel: &mut EstablishedSecureChannel) {
685        let message: QrAuthMessage = channel
686            .receive_json()
687            .await
688            .expect("Alice should receive the `m.login.failure` message from Bob");
689        assert_matches!(
690            message,
691            QrAuthMessage::LoginFailure {
692                reason: LoginFailureReason::UnexpectedMessageReceived,
693                homeserver: None
694            }
695        );
696    }
697
698    /// This is most of the code that is required to be the other side, the
699    /// existing device, of the QR login dance.
700    async fn grant_login(
701        alice: SecureChannel,
702        homeserver: Url,
703        check_code_receiver: tokio::sync::oneshot::Receiver<u8>,
704        behaviour: AliceBehaviour,
705        token_response: TokenResponse,
706        msc_4388: bool,
707    ) {
708        let alice = alice.connect().await.expect("Alice should be able to connect the channel");
709
710        let check_code =
711            check_code_receiver.await.expect("We should receive the check code from bob");
712
713        let mut alice =
714            alice.confirm(check_code).expect("Alice should be able to confirm the secure channel");
715
716        if msc_4388 {
717            // With MSC4388, Alice sends the initial login protocols message
718            // first to inform Bob about the available login protocols and the
719            // homeserver to use.
720            let protocols = match behaviour {
721                AliceBehaviour::NoProtocols => vec![],
722                _ => vec![LoginProtocolType::DeviceAuthorizationGrant],
723            };
724            let message = QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
725                protocols,
726                base_url: homeserver,
727            });
728            alice.send_json(message).await.unwrap();
729        }
730
731        if matches!(behaviour, AliceBehaviour::NoProtocols) {
732            // Bob can't use any of the protocols, so he should tell us and
733            // stop.
734            let message: QrAuthMessage = alice
735                .receive_json()
736                .await
737                .expect("Alice should receive the `m.login.failure` message from Bob");
738            assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
739            assert_eq!(reason, LoginFailureReason::UnsupportedProtocol);
740
741            return;
742        }
743
744        let message = alice
745            .receive_json()
746            .await
747            .expect("Alice should be able to receive the initial message from Bob");
748
749        assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
750        assert_eq!(protocol.protocol(), LoginProtocolType::DeviceAuthorizationGrant);
751
752        let message = match behaviour {
753            AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
754                reason: LoginFailureReason::UnsupportedProtocol,
755                homeserver: None,
756            },
757            AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
758            _ => QrAuthMessage::LoginProtocolAccepted,
759        };
760
761        alice.send_json(message).await.unwrap();
762
763        match behaviour {
764            // We declined, so Bob stops without replying.
765            AliceBehaviour::DeclinedProtocol => return,
766            AliceBehaviour::UnexpectedMessage => {
767                receive_unexpected_message_error(&mut alice).await;
768                return;
769            }
770            _ => (),
771        }
772
773        if !receive_login_outcome(&mut alice, token_response).await {
774            return;
775        }
776
777        let message = match behaviour {
778            AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
779            AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
780                reason: LoginFailureReason::DeviceNotFound,
781                homeserver: None,
782            },
783            _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
784        };
785
786        alice.send_json(message).await.unwrap();
787
788        if matches!(behaviour, AliceBehaviour::UnexpectedMessageInsteadOfSecrets) {
789            receive_unexpected_message_error(&mut alice).await;
790        }
791    }
792
793    async fn test_qr_login(msc_4388: bool) {
794        let server = MatrixMockServer::new().await;
795        let rendezvous_server =
796            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
797                .await;
798        let (sender, receiver) = tokio::sync::oneshot::channel();
799
800        let oauth_server = server.oauth();
801        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
802        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
803        oauth_server
804            .mock_device_authorization()
805            .ok()
806            .expect(1)
807            .named("device_authorization")
808            .mount()
809            .await;
810        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
811
812        server.mock_versions().ok().expect(1..).named("versions").mount().await;
813        server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
814        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
815        server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
816
817        let client = rendezvous_server.unlogged_client().await;
818        let alice = SecureChannel::reciprocate(&client, msc_4388)
819            .await
820            .expect("Alice should be able to create a secure channel.");
821
822        assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
823
824        let server_name = if msc_4388 {
825            assert_let!(
826                QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
827            );
828
829            base_url.to_string()
830        } else {
831            assert_let!(
832                QrCodeIntentData::Msc4108 {
833                    data: Msc4108IntentData::Reciprocate { server_name },
834                    ..
835                } = &alice.qr_code_data().intent_data()
836            );
837
838            server_name.to_owned()
839        };
840
841        let bob = Client::builder()
842            .server_name_or_homeserver_url(server_name)
843            .request_config(RequestConfig::new().disable_retry())
844            .build()
845            .await
846            .expect("We should be able to build the Client object from the URL in the QR code");
847
848        let qr_code = alice.qr_code_data().clone();
849
850        let oauth = bob.oauth();
851        let registration_data = mock_client_metadata().into();
852        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
853        let mut updates = login_bob.subscribe_to_progress();
854
855        let updates_task = spawn(async move {
856            let mut sender = Some(sender);
857
858            while let Some(update) = updates.next().await {
859                match update {
860                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
861                        sender
862                            .take()
863                            .expect("The establishing secure channel update should be received only once")
864                            .send(check_code)
865                            .expect("Bob should be able to send the check code to Alice");
866                    }
867                    LoginProgress::Done => break,
868                    _ => (),
869                }
870            }
871        });
872        let alice_homeserver = rendezvous_server.homeserver_url.clone();
873        let alice_task = spawn(async move {
874            grant_login(
875                alice,
876                alice_homeserver,
877                receiver,
878                AliceBehaviour::HappyPath,
879                TokenResponse::Ok,
880                msc_4388,
881            )
882            .await
883        });
884
885        // Wait for all tasks to finish.
886        login_bob.await.expect("Bob should be able to login");
887        alice_task.await.expect("Alice should have completed it's task successfully");
888        updates_task.await.unwrap();
889
890        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
891        let own_identity =
892            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
893
894        assert!(own_identity.is_verified());
895    }
896
897    #[async_test]
898    async fn test_qr_login_msc_4108() {
899        test_qr_login(false).await;
900    }
901
902    #[async_test]
903    #[cfg(feature = "unstable-msc4388")]
904    async fn test_qr_login_msc_4388() {
905        test_qr_login(true).await;
906    }
907
908    /// With MSC4388, the base URL in the QR code only identifies the
909    /// rendezvous server. The homeserver to log in to is the one Alice sends in
910    /// the `m.login.protocols` message, so Bob needs to switch to it.
911    #[async_test]
912    #[cfg(feature = "unstable-msc4388")]
913    async fn test_qr_login_with_homeserver_swap_msc_4388() {
914        let initial_server = MatrixMockServer::new().await;
915        let rendezvous_server = MockedRendezvousServer::new(
916            initial_server.server(),
917            "abcdEFG12345",
918            Duration::MAX,
919            true,
920        )
921        .await;
922        let (sender, receiver) = tokio::sync::oneshot::channel();
923
924        let login_server = MatrixMockServer::new().await;
925        let oauth_server = login_server.oauth();
926        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
927        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
928        oauth_server
929            .mock_device_authorization()
930            .ok()
931            .expect(1)
932            .named("device_authorization")
933            .mount()
934            .await;
935        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
936
937        initial_server.mock_versions().ok().named("versions initial server").mount().await;
938        initial_server
939            .mock_well_known()
940            .ok()
941            .expect(1)
942            .named("well_known-initial-server")
943            .mount()
944            .await;
945
946        login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
947        login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
948        login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
949        login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
950        login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
951
952        // Alice creates the rendezvous session on the initial server.
953        let client = rendezvous_server.unlogged_client().await;
954        let alice = SecureChannel::reciprocate(&client, true)
955            .await
956            .expect("Alice should be able to create a secure channel.");
957
958        assert_let!(
959            QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
960        );
961        let initial_server_url: Url = initial_server.server().uri().parse().unwrap();
962        assert_eq!(base_url.as_url(), &initial_server_url);
963
964        // Bob builds his client from the URL in the QR code, i.e. the initial
965        // server.
966        let bob = Client::builder()
967            .server_name_or_homeserver_url(base_url.as_str())
968            .request_config(RequestConfig::new().disable_retry())
969            .build()
970            .await
971            .expect("We should be able to build the Client object from the URL in the QR code");
972        assert_eq!(bob.homeserver(), initial_server_url);
973
974        let login_server_url: Url = login_server.server().uri().parse().unwrap();
975        assert_ne!(initial_server_url, login_server_url);
976
977        let qr_code = alice.qr_code_data().clone();
978
979        let oauth = bob.oauth();
980        let registration_data = mock_client_metadata().into();
981        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
982        let mut updates = login_bob.subscribe_to_progress();
983
984        let updates_task = spawn(async move {
985            let mut sender = Some(sender);
986
987            while let Some(update) = updates.next().await {
988                match update {
989                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
990                        sender
991                            .take()
992                            .expect("The establishing secure channel update should be received only once")
993                            .send(check_code)
994                            .expect("Bob should be able to send the check code to Alice");
995                    }
996                    LoginProgress::Done => break,
997                    _ => (),
998                }
999            }
1000        });
1001
1002        // Alice tells Bob to log in to the login server, not the server
1003        // hosting the rendezvous session.
1004        let alice_homeserver = login_server_url.clone();
1005        let alice_task = spawn(async move {
1006            grant_login(
1007                alice,
1008                alice_homeserver,
1009                receiver,
1010                AliceBehaviour::HappyPath,
1011                TokenResponse::Ok,
1012                true,
1013            )
1014            .await
1015        });
1016
1017        // Wait for all tasks to finish.
1018        login_bob.await.expect("Bob should be able to login");
1019        alice_task.await.expect("Alice should have completed it's task successfully");
1020        updates_task.await.unwrap();
1021
1022        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1023        let own_identity =
1024            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1025
1026        assert!(own_identity.is_verified());
1027
1028        // After login, Bob should have switched to the login server.
1029        assert_eq!(bob.homeserver(), login_server_url);
1030    }
1031
1032    async fn grant_login_with_generated_qr(
1033        alice: &Client,
1034        qr_receiver: tokio::sync::oneshot::Receiver<QrCodeData>,
1035        cctx_receiver: tokio::sync::oneshot::Receiver<CheckCodeSender>,
1036        behaviour: AliceBehaviour,
1037        token_response: TokenResponse,
1038    ) {
1039        let qr_code_data = qr_receiver.await.expect("Alice should receive the QR code");
1040
1041        let mut channel = EstablishedSecureChannel::from_qr_code(
1042            alice.inner.http_client.inner.clone(),
1043            &qr_code_data,
1044            QrCodeIntent::Reciprocate,
1045        )
1046        .await
1047        .expect("Alice should be able to establish the secure channel");
1048
1049        trace!("Established the secure channel.");
1050
1051        // The other side isn't yet sure that it's talking to the right device,
1052        // show a check code so they can confirm.
1053        let check_code = channel.check_code();
1054
1055        let check_code_sender =
1056            cctx_receiver.await.expect("Alice should receive the CheckCodeSender");
1057
1058        check_code_sender
1059            .send(check_code)
1060            .await
1061            .expect("Alice should be able to send the check code to Bob");
1062
1063        // Alice sends m.login.protocols message
1064        let protocols = match behaviour {
1065            AliceBehaviour::NoProtocols => vec![],
1066            _ => vec![LoginProtocolType::DeviceAuthorizationGrant],
1067        };
1068        let message = match channel.channel_variant() {
1069            ChannelVariant::Msc4108 => {
1070                QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
1071                    protocols,
1072                    homeserver: alice.homeserver(),
1073                })
1074            }
1075            #[cfg(feature = "unstable-msc4388")]
1076            ChannelVariant::Msc4388 => {
1077                QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
1078                    protocols,
1079                    base_url: alice.homeserver(),
1080                })
1081            }
1082        };
1083
1084        channel
1085            .send_json(message)
1086            .await
1087            .expect("Alice should be able to send the `m.login.protocols` message to Bob");
1088
1089        if matches!(behaviour, AliceBehaviour::NoProtocols) {
1090            // Bob can't use any of the protocols, so he should tell us and
1091            // stop.
1092            let message: QrAuthMessage = channel
1093                .receive_json()
1094                .await
1095                .expect("Alice should receive the `m.login.failure` message from Bob");
1096            assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1097            assert_eq!(reason, LoginFailureReason::UnsupportedProtocol);
1098
1099            return;
1100        }
1101
1102        // Alice receives m.login.protocol message
1103        let message: QrAuthMessage = channel
1104            .receive_json()
1105            .await
1106            .expect("Alice should be able to receive the `m.login.protocol` message from Bob");
1107        assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
1108        assert_eq!(protocol.protocol(), LoginProtocolType::DeviceAuthorizationGrant);
1109
1110        // Alice sends m.login.protocol_accepted message
1111        let message = match behaviour {
1112            AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
1113                reason: LoginFailureReason::UnsupportedProtocol,
1114                homeserver: None,
1115            },
1116            AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
1117            _ => QrAuthMessage::LoginProtocolAccepted,
1118        };
1119        channel
1120            .send_json(message)
1121            .await
1122            .expect("Alice should be able to send the `m.login.protocol_accepted` message to Bob");
1123
1124        match behaviour {
1125            // We declined, so Bob stops without replying.
1126            AliceBehaviour::DeclinedProtocol => return,
1127            AliceBehaviour::UnexpectedMessage => {
1128                receive_unexpected_message_error(&mut channel).await;
1129                return;
1130            }
1131            _ => (),
1132        }
1133
1134        if !receive_login_outcome(&mut channel, token_response).await {
1135            return;
1136        }
1137
1138        // Alice sends m.login.secrets message
1139        let message = match behaviour {
1140            AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
1141            AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
1142                reason: LoginFailureReason::DeviceNotFound,
1143                homeserver: None,
1144            },
1145            _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
1146        };
1147        channel
1148            .send_json(message)
1149            .await
1150            .expect("Alice should be able to send the `m.login.secrets` message to Bob");
1151
1152        if matches!(behaviour, AliceBehaviour::UnexpectedMessageInsteadOfSecrets) {
1153            receive_unexpected_message_error(&mut channel).await;
1154        }
1155    }
1156
1157    async fn test_generated_qr_login(msc_4388: bool) {
1158        let server = MatrixMockServer::new().await;
1159        let rendezvous_server =
1160            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1161                .await;
1162        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1163        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1164
1165        let oauth_server = server.oauth();
1166        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
1167        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1168        oauth_server
1169            .mock_device_authorization()
1170            .ok()
1171            .expect(1)
1172            .named("device_authorization")
1173            .mount()
1174            .await;
1175        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
1176
1177        server.mock_versions().ok().expect(1..).named("versions").mount().await;
1178        server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
1179        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1180        server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
1181
1182        let homeserver_url = rendezvous_server.homeserver_url.clone();
1183
1184        // Create Alice, the existing client, as a logged-in client. They will
1185        // scan the QR code generated by Bob.
1186        let alice = server.client_builder().logged_in_with_oauth().build().await;
1187        assert!(alice.session_meta().is_some(), "Alice should be logged in");
1188
1189        // Create Bob, the new client. They will generate the QR code.
1190        let bob = Client::builder()
1191            .server_name_or_homeserver_url(&homeserver_url)
1192            .request_config(RequestConfig::new().disable_retry())
1193            .build()
1194            .await
1195            .expect("Should be able to create a client for Bob");
1196
1197        let secure_channel = SecureChannel::login(&bob, msc_4388)
1198            .await
1199            .expect("Bob should be able to create a secure channel");
1200
1201        assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1202
1203        if msc_4388 {
1204            assert_matches!(
1205                secure_channel.qr_code_data().intent_data(),
1206                QrCodeIntentData::Msc4388 { .. }
1207            );
1208        } else {
1209            assert_matches!(
1210                secure_channel.qr_code_data().intent_data(),
1211                QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1212            );
1213        }
1214
1215        let registration_data = mock_client_metadata().into();
1216        let bob_oauth = bob.oauth();
1217        #[allow(unused_mut)]
1218        let mut bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
1219
1220        #[cfg(feature = "unstable-msc4388")]
1221        if msc_4388 {
1222            bob_login.with_msc4388_support();
1223        }
1224
1225        let mut bob_updates = bob_login.subscribe_to_progress();
1226
1227        let updates_task = spawn(async move {
1228            let mut qr_sender = Some(qr_sender);
1229            let mut cctx_sender = Some(cctx_sender);
1230
1231            while let Some(update) = bob_updates.next().await {
1232                match update {
1233                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1234                        qr_sender
1235                            .take()
1236                            .expect("The establishing secure channel update with a qr code should be received only once")
1237                            .send(qr)
1238                            .expect("Bob should be able to send the qr code code to Alice");
1239                    }
1240                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1241                        cctx,
1242                    )) => {
1243                        cctx_sender
1244                            .take()
1245                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1246                            .send(cctx)
1247                            .expect("Bob should be able to send the qr code code to Alice");
1248                    }
1249                    LoginProgress::Done => break,
1250                    _ => (),
1251                }
1252            }
1253        });
1254
1255        let alice_task = spawn(async move {
1256            grant_login_with_generated_qr(
1257                &alice,
1258                qr_receiver,
1259                cctx_receiver,
1260                AliceBehaviour::HappyPath,
1261                TokenResponse::Ok,
1262            )
1263            .await
1264        });
1265
1266        // Wait for all tasks to finish.
1267        bob_login.await.expect("Bob should be able to login");
1268        alice_task.await.expect("Alice should have completed it's task successfully");
1269        updates_task.await.unwrap();
1270
1271        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1272        let own_identity =
1273            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1274
1275        assert!(own_identity.is_verified());
1276    }
1277
1278    #[async_test]
1279    async fn test_generated_qr_login_msc_4108() {
1280        test_generated_qr_login(false).await;
1281    }
1282
1283    #[async_test]
1284    #[cfg(feature = "unstable-msc4388")]
1285    async fn test_generated_qr_login_msc_4388() {
1286        test_generated_qr_login(true).await;
1287    }
1288
1289    async fn test_generated_qr_login_with_homeserver_swap(msc_4388: bool) {
1290        let initial_server = MatrixMockServer::new().await;
1291        let rendezvous_server = MockedRendezvousServer::new(
1292            initial_server.server(),
1293            "abcdEFG12345",
1294            Duration::MAX,
1295            msc_4388,
1296        )
1297        .await;
1298        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1299        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1300
1301        let login_server = MatrixMockServer::new().await;
1302        let oauth_server = login_server.oauth();
1303        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
1304        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1305        oauth_server
1306            .mock_device_authorization()
1307            .ok()
1308            .expect(1)
1309            .named("device_authorization")
1310            .mount()
1311            .await;
1312        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
1313
1314        initial_server.mock_versions().ok().named("versions initial server").mount().await;
1315        initial_server
1316            .mock_well_known()
1317            .ok()
1318            .expect(1)
1319            .named("well_known-initial-server")
1320            .mount()
1321            .await;
1322
1323        login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
1324        login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
1325        login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
1326        login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1327        login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
1328
1329        let rendezvous_homeserver_url = rendezvous_server.homeserver_url.clone();
1330
1331        // Create Alice, the existing client, as a logged-in client. They will
1332        // scan the QR code generated by Bob.
1333        let alice = login_server.client_builder().logged_in_with_oauth().build().await;
1334        assert!(alice.session_meta().is_some(), "Alice should be logged in");
1335
1336        // Create Bob, the new client. They will generate the QR code.
1337        let bob = Client::builder()
1338            .server_name_or_homeserver_url(&rendezvous_homeserver_url)
1339            .request_config(RequestConfig::new().disable_retry())
1340            .build()
1341            .await
1342            .expect("Should be able to create a client for Bob");
1343
1344        let secure_channel = SecureChannel::login(&bob, msc_4388)
1345            .await
1346            .expect("Bob should be able to create a secure channel");
1347
1348        assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1349
1350        if msc_4388 {
1351            assert_matches!(
1352                secure_channel.qr_code_data().intent_data(),
1353                QrCodeIntentData::Msc4388 { .. }
1354            );
1355        } else {
1356            assert_matches!(
1357                secure_channel.qr_code_data().intent_data(),
1358                QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1359            );
1360        }
1361
1362        // Alice and Bob should have different homeservers configured at the
1363        // start.
1364        let initial_server_url = initial_server.server().uri().parse().unwrap();
1365        assert_eq!(bob.homeserver(), initial_server_url);
1366        let login_server_url = login_server.server().uri().parse().unwrap();
1367        assert_eq!(alice.homeserver(), login_server_url);
1368        assert_ne!(rendezvous_homeserver_url, login_server_url);
1369
1370        let registration_data = mock_client_metadata().into();
1371        let bob_oauth = bob.oauth();
1372        #[allow(unused_mut)]
1373        let mut bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
1374
1375        #[cfg(feature = "unstable-msc4388")]
1376        if msc_4388 {
1377            bob_login.with_msc4388_support();
1378        }
1379
1380        let mut bob_updates = bob_login.subscribe_to_progress();
1381
1382        let updates_task = spawn(async move {
1383            let mut qr_sender = Some(qr_sender);
1384            let mut cctx_sender = Some(cctx_sender);
1385
1386            while let Some(update) = bob_updates.next().await {
1387                match update {
1388                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1389                        qr_sender
1390                            .take()
1391                            .expect("The establishing secure channel update with a qr code should be received only once")
1392                            .send(qr)
1393                            .expect("Bob should be able to send the qr code code to Alice");
1394                    }
1395                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1396                        cctx,
1397                    )) => {
1398                        cctx_sender
1399                            .take()
1400                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1401                            .send(cctx)
1402                            .expect("Bob should be able to send the qr code code to Alice");
1403                    }
1404                    LoginProgress::Done => break,
1405                    _ => (),
1406                }
1407            }
1408        });
1409
1410        let alice_task = spawn(async move {
1411            grant_login_with_generated_qr(
1412                &alice,
1413                qr_receiver,
1414                cctx_receiver,
1415                AliceBehaviour::HappyPath,
1416                TokenResponse::Ok,
1417            )
1418            .await
1419        });
1420
1421        // Wait for all tasks to finish.
1422        bob_login.await.expect("Bob should be able to login");
1423        alice_task.await.expect("Alice should have completed it's task successfully");
1424        updates_task.await.unwrap();
1425
1426        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1427        let own_identity =
1428            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1429
1430        assert!(own_identity.is_verified());
1431
1432        // After login, Bob should have switched to the new homeserver.
1433        assert_eq!(bob.homeserver(), login_server_url);
1434    }
1435
1436    #[async_test]
1437    async fn test_generated_qr_login_with_homeserver_swap_msc_4108() {
1438        test_generated_qr_login_with_homeserver_swap(false).await;
1439    }
1440
1441    #[async_test]
1442    #[cfg(feature = "unstable-msc4388")]
1443    async fn test_generated_qr_login_with_homeserver_swap_msc_4388() {
1444        test_generated_qr_login_with_homeserver_swap(true).await;
1445    }
1446
1447    async fn test_failure(
1448        token_response: TokenResponse,
1449        alice_behaviour: AliceBehaviour,
1450        bob_behavior: BobBehaviour,
1451        msc_4388: bool,
1452    ) -> Option<Result<(), QRCodeLoginError>> {
1453        let server = MatrixMockServer::new().await;
1454        let expiration = match alice_behaviour {
1455            AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1456            _ => Duration::MAX,
1457        };
1458        let rendezvous_server =
1459            MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration, msc_4388)
1460                .await;
1461        let (sender, receiver) = tokio::sync::oneshot::channel();
1462
1463        let oauth_server = server.oauth();
1464        let expected_calls = match alice_behaviour {
1465            AliceBehaviour::LetSessionExpire | AliceBehaviour::NoProtocols => 0,
1466            _ => 1,
1467        };
1468        oauth_server
1469            .mock_server_metadata()
1470            .ok()
1471            .expect(expected_calls)
1472            .named("server_metadata")
1473            .mount()
1474            .await;
1475        oauth_server
1476            .mock_registration()
1477            .ok()
1478            .expect(expected_calls)
1479            .named("registration")
1480            .mount()
1481            .await;
1482        oauth_server
1483            .mock_device_authorization()
1484            .ok()
1485            .expect(expected_calls)
1486            .named("device_authorization")
1487            .mount()
1488            .await;
1489
1490        let token_mock = oauth_server.mock_token();
1491        let token_mock = match token_response {
1492            TokenResponse::Ok => token_mock.ok(),
1493            TokenResponse::AccessDenied => token_mock.access_denied(),
1494            TokenResponse::ExpiredToken => token_mock.expired_token(),
1495        };
1496        token_mock.named("token").mount().await;
1497
1498        server.mock_versions().ok().named("versions").mount().await;
1499        server.mock_who_am_i().ok().named("whoami").mount().await;
1500
1501        let client = rendezvous_server.unlogged_client().await;
1502        let alice = SecureChannel::reciprocate(&client, msc_4388)
1503            .await
1504            .expect("Alice should be able to create a secure channel.");
1505
1506        assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
1507
1508        let server_name = if msc_4388 {
1509            assert_let!(
1510                QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
1511            );
1512
1513            base_url.to_string()
1514        } else {
1515            assert_let!(
1516                QrCodeIntentData::Msc4108 {
1517                    data: Msc4108IntentData::Reciprocate { server_name },
1518                    ..
1519                } = &alice.qr_code_data().intent_data()
1520            );
1521
1522            server_name.to_owned()
1523        };
1524
1525        assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
1526
1527        let bob = Client::builder()
1528            .server_name_or_homeserver_url(server_name)
1529            .request_config(RequestConfig::new().disable_retry())
1530            .build()
1531            .await
1532            .expect("We should be able to build the Client object from the URL in the QR code");
1533
1534        let qr_code = alice.qr_code_data().clone();
1535
1536        let oauth = bob.oauth();
1537        let registration_data = mock_client_metadata().into();
1538        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
1539        let mut updates = login_bob.subscribe_to_progress();
1540
1541        let login_bob = login_bob.cancellable();
1542        let cancel = login_bob.cancellation_token();
1543
1544        let _updates_task = spawn(async move {
1545            let mut sender = Some(sender);
1546
1547            while let Some(update) = updates.next().await {
1548                match update {
1549                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1550                        sender
1551                            .take()
1552                            .expect("The establishing secure channel update should be received only once")
1553                            .send(check_code)
1554                            .expect("Bob should be able to send the check code to Alice");
1555                    }
1556                    LoginProgress::WaitingForToken { .. } => {
1557                        if let BobBehaviour::CancelWhileWaitingForToken = bob_behavior {
1558                            cancel.cancel();
1559                        }
1560                    }
1561                    LoginProgress::Done => break,
1562                    _ => (),
1563                }
1564            }
1565        });
1566
1567        let alice_homeserver = rendezvous_server.homeserver_url.clone();
1568        let alice_task =
1569            (!matches!(alice_behaviour, AliceBehaviour::LetSessionExpire)).then(|| {
1570                spawn(async move {
1571                    grant_login(
1572                        alice,
1573                        alice_homeserver,
1574                        receiver,
1575                        alice_behaviour,
1576                        token_response,
1577                        msc_4388,
1578                    )
1579                    .await
1580                })
1581            });
1582
1583        let result = login_bob.await;
1584
1585        if let Some(alice_task) = alice_task {
1586            if matches!(bob_behavior, BobBehaviour::CancelWhileWaitingForToken) {
1587                alice_task.abort();
1588            } else {
1589                alice_task.await.expect("Alice should have completed her task successfully");
1590            }
1591        }
1592
1593        result
1594    }
1595
1596    async fn test_generated_failure(
1597        token_response: TokenResponse,
1598        alice_behaviour: AliceBehaviour,
1599        bob_behavior: BobBehaviour,
1600        msc_4388: bool,
1601    ) -> Option<Result<(), QRCodeLoginError>> {
1602        let server = MatrixMockServer::new().await;
1603        let expiration = match alice_behaviour {
1604            AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1605            _ => Duration::MAX,
1606        };
1607        let rendezvous_server =
1608            MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration, msc_4388)
1609                .await;
1610
1611        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1612        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1613
1614        let oauth_server = server.oauth();
1615        let expected_calls = match alice_behaviour {
1616            AliceBehaviour::LetSessionExpire | AliceBehaviour::NoProtocols => 0,
1617            _ => 1,
1618        };
1619        oauth_server
1620            .mock_server_metadata()
1621            .ok()
1622            .expect(expected_calls)
1623            .named("server_metadata")
1624            .mount()
1625            .await;
1626        oauth_server
1627            .mock_registration()
1628            .ok()
1629            .expect(expected_calls)
1630            .named("registration")
1631            .mount()
1632            .await;
1633        oauth_server
1634            .mock_device_authorization()
1635            .ok()
1636            .expect(expected_calls)
1637            .named("device_authorization")
1638            .mount()
1639            .await;
1640
1641        let token_mock = oauth_server.mock_token();
1642        let token_mock = match token_response {
1643            TokenResponse::Ok => token_mock.ok(),
1644            TokenResponse::AccessDenied => token_mock.access_denied(),
1645            TokenResponse::ExpiredToken => token_mock.expired_token(),
1646        };
1647        token_mock.named("token").mount().await;
1648
1649        server.mock_versions().ok().named("versions").mount().await;
1650        server.mock_who_am_i().ok().named("whoami").mount().await;
1651
1652        let homeserver_url = rendezvous_server.homeserver_url.clone();
1653
1654        // Create Alice, the existing client, as a logged-in client. They will
1655        // scan the QR code generated by Bob.
1656        let alice = server.client_builder().logged_in_with_oauth().build().await;
1657        assert!(alice.session_meta().is_some(), "Alice should be logged in");
1658
1659        // Create Bob, the new client. They will generate the QR code.
1660        let bob = Client::builder()
1661            .server_name_or_homeserver_url(&homeserver_url)
1662            .request_config(RequestConfig::new().disable_retry())
1663            .build()
1664            .await
1665            .expect("Should be able to create a client for Bob");
1666
1667        let secure_channel = SecureChannel::login(&bob, msc_4388)
1668            .await
1669            .expect("Bob should be able to create a secure channel");
1670
1671        assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1672
1673        if msc_4388 {
1674            assert_matches!(
1675                secure_channel.qr_code_data().intent_data(),
1676                QrCodeIntentData::Msc4388 { .. }
1677            );
1678        } else {
1679            assert_matches!(
1680                secure_channel.qr_code_data().intent_data(),
1681                QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1682            );
1683        }
1684
1685        let registration_data = mock_client_metadata().into();
1686        let bob_oauth = bob.oauth();
1687        #[allow(unused_mut)]
1688        let mut bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
1689
1690        #[cfg(feature = "unstable-msc4388")]
1691        if msc_4388 {
1692            bob_login.with_msc4388_support();
1693        }
1694
1695        let mut bob_updates = bob_login.subscribe_to_progress();
1696
1697        let bob_login = bob_login.cancellable();
1698        let cancel = bob_login.cancellation_token();
1699
1700        let _updates_task = spawn(async move {
1701            let mut qr_sender = Some(qr_sender);
1702            let mut cctx_sender = Some(cctx_sender);
1703
1704            while let Some(update) = bob_updates.next().await {
1705                match update {
1706                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1707                        qr_sender
1708                            .take()
1709                            .expect("The establishing secure channel update with a qr code should be received only once")
1710                            .send(qr)
1711                            .expect("Bob should be able to send the qr code code to Alice");
1712                    }
1713                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1714                        cctx,
1715                    )) => {
1716                        cctx_sender
1717                            .take()
1718                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1719                            .send(cctx)
1720                            .expect("Bob should be able to send the qr code code to Alice");
1721                    }
1722                    LoginProgress::WaitingForToken { .. } => {
1723                        if let BobBehaviour::CancelWhileWaitingForToken = bob_behavior {
1724                            cancel.cancel();
1725                        }
1726                    }
1727                    LoginProgress::Done => break,
1728                    _ => (),
1729                }
1730            }
1731        });
1732
1733        let alice_task =
1734            (!matches!(alice_behaviour, AliceBehaviour::LetSessionExpire)).then(|| {
1735                spawn(async move {
1736                    grant_login_with_generated_qr(
1737                        &alice,
1738                        qr_receiver,
1739                        cctx_receiver,
1740                        alice_behaviour,
1741                        token_response,
1742                    )
1743                    .await
1744                })
1745            });
1746
1747        let result = bob_login.await;
1748
1749        if let Some(alice_task) = alice_task {
1750            if matches!(bob_behavior, BobBehaviour::CancelWhileWaitingForToken) {
1751                alice_task.abort();
1752            } else {
1753                alice_task.await.expect("Alice should have completed her task successfully");
1754            }
1755        }
1756
1757        result
1758    }
1759
1760    async fn test_qr_login_refused_access_token(msc_4388: bool) {
1761        let result = test_failure(
1762            TokenResponse::AccessDenied,
1763            AliceBehaviour::HappyPath,
1764            BobBehaviour::HappyPath,
1765            msc_4388,
1766        )
1767        .await;
1768
1769        assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1770        assert_eq!(
1771            e.as_request_token_error(),
1772            Some(&DeviceCodeErrorResponseType::AccessDenied),
1773            "The server should have told us that access has been denied."
1774        );
1775    }
1776
1777    #[async_test]
1778    async fn test_qr_login_refused_access_token_msc_4108() {
1779        test_qr_login_refused_access_token(false).await
1780    }
1781
1782    #[async_test]
1783    #[cfg(feature = "unstable-msc4388")]
1784    async fn test_qr_login_refused_access_token_msc_4388() {
1785        test_qr_login_refused_access_token(true).await
1786    }
1787
1788    async fn test_generated_qr_login_refused_access_token(msc_4388: bool) {
1789        let result = test_generated_failure(
1790            TokenResponse::AccessDenied,
1791            AliceBehaviour::HappyPath,
1792            BobBehaviour::HappyPath,
1793            msc_4388,
1794        )
1795        .await;
1796
1797        assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1798        assert_eq!(
1799            e.as_request_token_error(),
1800            Some(&DeviceCodeErrorResponseType::AccessDenied),
1801            "The server should have told us that access has been denied."
1802        );
1803    }
1804
1805    #[async_test]
1806    async fn test_generated_qr_login_refused_access_token_msc_4108() {
1807        test_generated_qr_login_refused_access_token(false).await;
1808    }
1809
1810    #[async_test]
1811    #[cfg(feature = "unstable-msc4388")]
1812    async fn test_generated_qr_login_refused_access_token_msc_4388() {
1813        test_generated_qr_login_refused_access_token(true).await;
1814    }
1815
1816    async fn test_qr_login_expired_token(msc_4388: bool) {
1817        let result = test_failure(
1818            TokenResponse::ExpiredToken,
1819            AliceBehaviour::HappyPath,
1820            BobBehaviour::HappyPath,
1821            msc_4388,
1822        )
1823        .await;
1824
1825        assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1826        assert_eq!(
1827            e.as_request_token_error(),
1828            Some(&DeviceCodeErrorResponseType::ExpiredToken),
1829            "The server should have told us that access has been denied."
1830        );
1831    }
1832
1833    #[async_test]
1834    async fn test_qr_login_expired_token_msc_4108() {
1835        test_qr_login_expired_token(false).await;
1836    }
1837
1838    #[async_test]
1839    #[cfg(feature = "unstable-msc4388")]
1840    async fn test_qr_login_expired_token_msc_4388() {
1841        test_qr_login_expired_token(true).await;
1842    }
1843
1844    async fn test_generated_qr_login_expired_token(msc_4388: bool) {
1845        let result = test_generated_failure(
1846            TokenResponse::ExpiredToken,
1847            AliceBehaviour::HappyPath,
1848            BobBehaviour::HappyPath,
1849            msc_4388,
1850        )
1851        .await;
1852
1853        assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1854        assert_eq!(
1855            e.as_request_token_error(),
1856            Some(&DeviceCodeErrorResponseType::ExpiredToken),
1857            "The server should have told us that access has been denied."
1858        );
1859    }
1860
1861    #[async_test]
1862    async fn test_generated_qr_login_expired_token_msc_4108() {
1863        test_generated_qr_login_expired_token(false).await;
1864    }
1865
1866    #[async_test]
1867    #[cfg(feature = "unstable-msc4388")]
1868    async fn test_generated_qr_login_expired_token_msc_4388() {
1869        test_generated_qr_login_expired_token(true).await;
1870    }
1871
1872    async fn test_qr_login_declined_protocol(msc_4388: bool) {
1873        let result = test_failure(
1874            TokenResponse::Ok,
1875            AliceBehaviour::DeclinedProtocol,
1876            BobBehaviour::HappyPath,
1877            msc_4388,
1878        )
1879        .await;
1880
1881        assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
1882        assert_eq!(
1883            reason,
1884            LoginFailureReason::UnsupportedProtocol,
1885            "Alice should have told us that the protocol is unsupported."
1886        );
1887    }
1888
1889    #[async_test]
1890    async fn test_qr_login_declined_protocol_msc_4108() {
1891        test_qr_login_declined_protocol(false).await;
1892    }
1893
1894    #[async_test]
1895    #[cfg(feature = "unstable-msc4388")]
1896    async fn test_qr_login_declined_protocol_msc_4388() {
1897        test_qr_login_declined_protocol(true).await;
1898    }
1899
1900    #[async_test]
1901    #[cfg(feature = "unstable-msc4388")]
1902    async fn test_qr_login_no_protocols_msc_4388() {
1903        let result = test_failure(
1904            TokenResponse::Ok,
1905            AliceBehaviour::NoProtocols,
1906            BobBehaviour::HappyPath,
1907            true,
1908        )
1909        .await;
1910
1911        assert_matches!(
1912            result,
1913            Some(Err(QRCodeLoginError::LoginFailure {
1914                reason: LoginFailureReason::UnsupportedProtocol,
1915                homeserver: None
1916            }))
1917        );
1918    }
1919
1920    async fn test_generated_qr_login_no_protocols(msc_4388: bool) {
1921        let result = test_generated_failure(
1922            TokenResponse::Ok,
1923            AliceBehaviour::NoProtocols,
1924            BobBehaviour::HappyPath,
1925            msc_4388,
1926        )
1927        .await;
1928
1929        assert_matches!(
1930            result,
1931            Some(Err(QRCodeLoginError::LoginFailure {
1932                reason: LoginFailureReason::UnsupportedProtocol,
1933                homeserver: None
1934            }))
1935        );
1936    }
1937
1938    #[async_test]
1939    async fn test_generated_qr_login_no_protocols_msc_4108() {
1940        test_generated_qr_login_no_protocols(false).await;
1941    }
1942
1943    #[async_test]
1944    #[cfg(feature = "unstable-msc4388")]
1945    async fn test_generated_qr_login_no_protocols_msc_4388() {
1946        test_generated_qr_login_no_protocols(true).await;
1947    }
1948
1949    async fn test_generated_qr_login_declined_protocol(msc_4388: bool) {
1950        let result = test_generated_failure(
1951            TokenResponse::Ok,
1952            AliceBehaviour::DeclinedProtocol,
1953            BobBehaviour::HappyPath,
1954            msc_4388,
1955        )
1956        .await;
1957
1958        assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
1959        assert_eq!(
1960            reason,
1961            LoginFailureReason::UnsupportedProtocol,
1962            "Alice should have told us that the protocol is unsupported."
1963        );
1964    }
1965
1966    #[async_test]
1967    async fn test_generated_qr_login_declined_protocol_msc_4108() {
1968        test_generated_qr_login_declined_protocol(false).await;
1969    }
1970
1971    #[async_test]
1972    #[cfg(feature = "unstable-msc4388")]
1973    async fn test_generated_qr_login_declined_protocol_msc_4388() {
1974        test_generated_qr_login_declined_protocol(true).await;
1975    }
1976
1977    async fn test_qr_login_unexpected_message(msc_4388: bool) {
1978        let result = test_failure(
1979            TokenResponse::Ok,
1980            AliceBehaviour::UnexpectedMessage,
1981            BobBehaviour::HappyPath,
1982            msc_4388,
1983        )
1984        .await;
1985
1986        assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
1987        assert_eq!(expected, "m.login.protocol_accepted");
1988    }
1989
1990    #[async_test]
1991    async fn test_qr_login_unexpected_message_msc_4108() {
1992        test_qr_login_unexpected_message(false).await;
1993    }
1994
1995    #[async_test]
1996    #[cfg(feature = "unstable-msc4388")]
1997    async fn test_qr_login_unexpected_message_msc_4388() {
1998        test_qr_login_unexpected_message(true).await;
1999    }
2000
2001    async fn test_generated_qr_login_unexpected_message(msc_4388: bool) {
2002        let result = test_generated_failure(
2003            TokenResponse::Ok,
2004            AliceBehaviour::UnexpectedMessage,
2005            BobBehaviour::HappyPath,
2006            msc_4388,
2007        )
2008        .await;
2009
2010        assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2011        assert_eq!(expected, "m.login.protocol_accepted");
2012    }
2013
2014    #[async_test]
2015    async fn test_generated_qr_login_unexpected_message_msc_4108() {
2016        test_generated_qr_login_unexpected_message(false).await;
2017    }
2018
2019    #[async_test]
2020    #[cfg(feature = "unstable-msc4388")]
2021    async fn test_generated_qr_login_unexpected_message_msc_4388() {
2022        test_generated_qr_login_unexpected_message(true).await;
2023    }
2024
2025    async fn test_qr_login_unexpected_message_instead_of_secrets(msc_4388: bool) {
2026        let result = test_failure(
2027            TokenResponse::Ok,
2028            AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2029            BobBehaviour::HappyPath,
2030            msc_4388,
2031        )
2032        .await;
2033
2034        assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2035        assert_eq!(expected, "m.login.secrets");
2036    }
2037
2038    #[async_test]
2039    async fn test_qr_login_unexpected_message_instead_of_secrets_msc_4108() {
2040        test_qr_login_unexpected_message_instead_of_secrets(false).await;
2041    }
2042
2043    #[async_test]
2044    #[cfg(feature = "unstable-msc4388")]
2045    async fn test_qr_login_unexpected_message_instead_of_secrets_msc_4388() {
2046        test_qr_login_unexpected_message_instead_of_secrets(true).await;
2047    }
2048
2049    async fn test_generated_qr_login_unexpected_message_instead_of_secrets(msc_4388: bool) {
2050        let result = test_generated_failure(
2051            TokenResponse::Ok,
2052            AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2053            BobBehaviour::HappyPath,
2054            msc_4388,
2055        )
2056        .await;
2057
2058        assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2059        assert_eq!(expected, "m.login.secrets");
2060    }
2061
2062    #[async_test]
2063    async fn test_generated_qr_login_unexpected_message_instead_of_secrets_msc_4108() {
2064        test_generated_qr_login_unexpected_message_instead_of_secrets(false).await;
2065    }
2066
2067    #[async_test]
2068    #[cfg(feature = "unstable-msc4388")]
2069    async fn test_generated_qr_login_unexpected_message_instead_of_secrets_msc_4388() {
2070        test_generated_qr_login_unexpected_message_instead_of_secrets(true).await;
2071    }
2072
2073    async fn test_qr_login_refuse_secrets(msc_4388: bool) {
2074        let result = test_failure(
2075            TokenResponse::Ok,
2076            AliceBehaviour::RefuseSecrets,
2077            BobBehaviour::HappyPath,
2078            msc_4388,
2079        )
2080        .await;
2081
2082        assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
2083        assert_eq!(reason, LoginFailureReason::DeviceNotFound);
2084    }
2085
2086    #[async_test]
2087    async fn test_qr_login_refuse_secrets_msc_4108() {
2088        test_qr_login_refuse_secrets(false).await
2089    }
2090
2091    #[async_test]
2092    #[cfg(feature = "unstable-msc4388")]
2093    async fn test_qr_login_refuse_secrets_msc_4388() {
2094        test_qr_login_refuse_secrets(true).await
2095    }
2096
2097    async fn test_generated_qr_login_refuse_secrets(msc_4388: bool) {
2098        let result = test_generated_failure(
2099            TokenResponse::Ok,
2100            AliceBehaviour::RefuseSecrets,
2101            BobBehaviour::HappyPath,
2102            msc_4388,
2103        )
2104        .await;
2105
2106        assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
2107        assert_eq!(reason, LoginFailureReason::DeviceNotFound);
2108    }
2109
2110    #[async_test]
2111    async fn test_generated_qr_login_refuse_secrets_msc_4108() {
2112        test_generated_qr_login_refuse_secrets(false).await;
2113    }
2114
2115    #[async_test]
2116    #[cfg(feature = "unstable-msc4388")]
2117    async fn test_generated_qr_login_refuse_secrets_msc_4388() {
2118        test_generated_qr_login_refuse_secrets(true).await;
2119    }
2120
2121    async fn test_qr_login_session_expired(msc_4388: bool) {
2122        let result = test_failure(
2123            TokenResponse::Ok,
2124            AliceBehaviour::LetSessionExpire,
2125            BobBehaviour::HappyPath,
2126            msc_4388,
2127        )
2128        .await;
2129
2130        assert_matches!(result, Some(Err(QRCodeLoginError::NotFound)));
2131    }
2132
2133    #[async_test]
2134    async fn test_qr_login_session_expired_msc_4108() {
2135        test_qr_login_session_expired(false).await;
2136    }
2137
2138    #[async_test]
2139    #[cfg(feature = "unstable-msc4388")]
2140    async fn test_qr_login_session_expired_msc_4388() {
2141        test_qr_login_session_expired(true).await;
2142    }
2143
2144    async fn test_generated_qr_login_session_expired(msc_4388: bool) {
2145        let result = test_generated_failure(
2146            TokenResponse::Ok,
2147            AliceBehaviour::LetSessionExpire,
2148            BobBehaviour::HappyPath,
2149            msc_4388,
2150        )
2151        .await;
2152
2153        assert_matches!(result, Some(Err(QRCodeLoginError::NotFound)));
2154    }
2155
2156    #[async_test]
2157    async fn test_generated_qr_login_session_expired_msc_4108() {
2158        test_generated_qr_login_session_expired(false).await;
2159    }
2160
2161    #[async_test]
2162    #[cfg(feature = "unstable-msc4388")]
2163    async fn test_generated_qr_login_session_expired_msc_4388() {
2164        test_generated_qr_login_session_expired(true).await;
2165    }
2166
2167    #[async_test]
2168    async fn test_qr_login_cancelled() {
2169        let result = test_failure(
2170            TokenResponse::Ok,
2171            AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2172            BobBehaviour::CancelWhileWaitingForToken,
2173            false,
2174        )
2175        .await;
2176
2177        assert_matches!(result, None);
2178    }
2179
2180    #[async_test]
2181    async fn test_generated_qr_login_cancelled() {
2182        let result = test_generated_failure(
2183            TokenResponse::Ok,
2184            AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2185            BobBehaviour::CancelWhileWaitingForToken,
2186            false,
2187        )
2188        .await;
2189
2190        assert_matches!(result, None);
2191    }
2192
2193    #[async_test]
2194    async fn test_device_authorization_endpoint_missing() {
2195        let server = MatrixMockServer::new().await;
2196        let rendezvous_server =
2197            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2198                .await;
2199        let (sender, receiver) = tokio::sync::oneshot::channel();
2200
2201        let oauth_server = server.oauth();
2202        oauth_server
2203            .mock_server_metadata()
2204            .ok_without_device_authorization()
2205            .expect(1)
2206            .named("server_metadata")
2207            .mount()
2208            .await;
2209        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
2210
2211        server.mock_versions().ok().named("versions").mount().await;
2212        server.mock_who_am_i().ok().named("whoami").mount().await;
2213
2214        let client = rendezvous_server.unlogged_client().await;
2215        let alice = SecureChannel::reciprocate(&client, false)
2216            .await
2217            .expect("Alice should be able to create a secure channel.");
2218
2219        assert_let!(
2220            QrCodeIntentData::Msc4108 {
2221                data: Msc4108IntentData::Reciprocate { server_name },
2222                ..
2223            } = &alice.qr_code_data().intent_data()
2224        );
2225
2226        let bob = Client::builder()
2227            .server_name_or_homeserver_url(server_name)
2228            .request_config(RequestConfig::new().disable_retry())
2229            .build()
2230            .await
2231            .expect("We should be able to build the Client object from the URL in the QR code");
2232
2233        let qr_code = alice.qr_code_data().clone();
2234
2235        let oauth = bob.oauth();
2236        let registration_data = mock_client_metadata().into();
2237        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
2238        let mut updates = login_bob.subscribe_to_progress();
2239
2240        let _updates_task = spawn(async move {
2241            let mut sender = Some(sender);
2242
2243            while let Some(update) = updates.next().await {
2244                match update {
2245                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2246                        sender
2247                                .take()
2248                                .expect("The establishing secure channel update should be received only once")
2249                                .send(check_code)
2250                                .expect("Bob should be able to send the check code to Alice");
2251                    }
2252                    LoginProgress::Done => break,
2253                    _ => (),
2254                }
2255            }
2256        });
2257        let alice_homeserver = rendezvous_server.homeserver_url.clone();
2258        let _alice_task = spawn(async move {
2259            grant_login(
2260                alice,
2261                alice_homeserver,
2262                receiver,
2263                AliceBehaviour::HappyPath,
2264                TokenResponse::Ok,
2265                false,
2266            )
2267            .await
2268        });
2269        let error = login_bob.await.unwrap_err();
2270
2271        assert_matches!(
2272            error,
2273            QRCodeLoginError::OAuth(DeviceAuthorizationOAuthError::NoDeviceAuthorizationEndpoint)
2274        );
2275    }
2276}