Skip to main content

matrix_sdk/authentication/oauth/qrcode/
login.rs

1// Copyright 2024 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 vodozemac::Curve25519PublicKey;
31#[cfg(doc)]
32use vodozemac::ecies::CheckCode;
33
34use super::{
35    DeviceAuthorizationOAuthError, QRCodeLoginError, SecureChannelError,
36    messages::{LoginFailureReason, QrAuthMessage},
37    secure_channel::{EstablishedSecureChannel, SecureChannel},
38};
39use crate::{
40    Client,
41    authentication::oauth::{
42        ClientRegistrationData, OAuth, OAuthError,
43        qrcode::{CheckCodeSender, GeneratedQrProgress, LoginProtocolType, QrProgress},
44    },
45};
46
47async fn send_unexpected_message_error(
48    channel: &mut EstablishedSecureChannel,
49) -> Result<(), SecureChannelError> {
50    channel
51        .send_json(QrAuthMessage::LoginFailure {
52            reason: LoginFailureReason::UnexpectedMessageReceived,
53            homeserver: None,
54        })
55        .await
56}
57
58async fn finish_login<Q>(
59    client: &Client,
60    mut channel: EstablishedSecureChannel,
61    registration_data: Option<&ClientRegistrationData>,
62    state: SharedObservable<LoginProgress<Q>>,
63) -> Result<(), QRCodeLoginError> {
64    let oauth = client.oauth();
65
66    // Register the client with the OAuth 2.0 authorization server.
67    trace!("Registering the client with the OAuth 2.0 authorization server.");
68    let server_metadata = register_client(&oauth, registration_data).await?;
69
70    // We want to use the Curve25519 public key for the device ID, so let's
71    // generate a new vodozemac `Account` now.
72    let account = vodozemac::olm::Account::new();
73    let public_key = account.identity_keys().curve25519;
74    let device_id = public_key;
75
76    // Let's tell the OAuth 2.0 authorization server that we want to log in
77    // using the device authorization grant described in
78    // [RFC8628](https://datatracker.ietf.org/doc/html/rfc8628).
79    trace!("Requesting device authorization.");
80    let auth_grant_response =
81        request_device_authorization(&oauth, &server_metadata, device_id).await?;
82
83    // Now we need to inform the other device of the login protocols we picked
84    // and the URL they should use to log us in.
85    trace!("Letting the existing device know about the device authorization grant.");
86    let message =
87        QrAuthMessage::authorization_grant_login_protocol((&auth_grant_response).into(), device_id);
88    channel.send_json(&message).await?;
89
90    // Let's see if the other device agreed to our proposed protocols.
91    match channel.receive_json().await? {
92        QrAuthMessage::LoginProtocolAccepted => (),
93        QrAuthMessage::LoginFailure { reason, homeserver } => {
94            return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
95        }
96        message => {
97            send_unexpected_message_error(&mut channel).await?;
98
99            return Err(QRCodeLoginError::UnexpectedMessage {
100                expected: "m.login.protocol_accepted",
101                received: Box::new(message),
102            });
103        }
104    }
105
106    // The OAuth 2.0 authorization server may or may not show this user code to
107    // double check that we're talking to the right server. Let us display this,
108    // so the other device can double check this as well.
109    let user_code = auth_grant_response.user_code();
110    state.set(LoginProgress::WaitingForToken { user_code: user_code.secret().to_owned() });
111
112    // Let's now wait for the access token to be provided to use by the OAuth
113    // 2.0 authorization server.
114    trace!("Waiting for the OAuth 2.0 authorization server to give us the access token.");
115    if let Err(e) = wait_for_tokens(&oauth, &server_metadata, &auth_grant_response).await {
116        // If we received an error, and it's one of the ones we should report to
117        // the other side, do so now.
118        if let Some(e) = e.as_request_token_error() {
119            match e {
120                DeviceCodeErrorResponseType::AccessDenied => {
121                    channel.send_json(QrAuthMessage::LoginDeclined).await?;
122                }
123                DeviceCodeErrorResponseType::ExpiredToken => {
124                    channel
125                        .send_json(QrAuthMessage::LoginFailure {
126                            reason: LoginFailureReason::AuthorizationExpired,
127                            homeserver: None,
128                        })
129                        .await?;
130                }
131                _ => (),
132            }
133        }
134
135        return Err(e.into());
136    }
137
138    // We only received an access token from the OAuth 2.0 authorization server,
139    // we have no clue who we are, so we need to figure out our user ID now.
140    // TODO: This snippet is almost the same as the
141    // OAuth::finish_login_method(), why is that method even a public method and
142    // not called as part of the set session tokens method.
143    trace!("Discovering our own user id.");
144    let whoami_response = client.whoami().await.map_err(QRCodeLoginError::UserIdDiscovery)?;
145    client
146        .base_client()
147        .activate(
148            SessionMeta {
149                user_id: whoami_response.user_id,
150                device_id: OwnedDeviceId::from(device_id.to_base64()),
151            },
152            RoomLoadSettings::default(),
153            Some(account),
154        )
155        .await
156        .map_err(|error| QRCodeLoginError::SessionTokens(error.into()))?;
157
158    client.oauth().enable_cross_process_lock().await?;
159
160    state.set(LoginProgress::SyncingSecrets);
161
162    // Tell the existing device that we're logged in.
163    trace!("Telling the existing device that we successfully logged in.");
164    let message = QrAuthMessage::LoginSuccess;
165    channel.send_json(&message).await?;
166
167    // Let's wait for the secrets bundle to be sent to us, otherwise we won't be
168    // a fully E2EE enabled device.
169    trace!("Waiting for the secrets bundle.");
170    let bundle = match channel.receive_json().await? {
171        QrAuthMessage::LoginSecrets(bundle) => bundle,
172        QrAuthMessage::LoginFailure { reason, homeserver } => {
173            return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
174        }
175        message => {
176            send_unexpected_message_error(&mut channel).await?;
177
178            return Err(QRCodeLoginError::UnexpectedMessage {
179                expected: "m.login.secrets",
180                received: Box::new(message),
181            });
182        }
183    };
184
185    // Import the secrets bundle, this will allow us to sign the device keys
186    // with the master key when we upload them.
187    client.encryption().import_secrets_bundle_impl(&bundle).await?;
188
189    // Upload the device keys, this will ensure that other devices see us as a
190    // fully verified device ass soon as this method returns.
191    client
192        .encryption()
193        .ensure_device_keys_upload()
194        .await
195        .map_err(QRCodeLoginError::DeviceKeyUpload)?;
196
197    // Run and wait for the E2EE initialization tasks, this will ensure that we
198    // ourselves see us as verified and the recovery/backup states will be
199    // known. If we did receive all the secrets in the secrets bundle, then
200    // backups will be enabled after this step as well.
201    client.encryption().spawn_initialization_task(None).await;
202    client.encryption().wait_for_e2ee_initialization_tasks().await;
203
204    trace!("successfully logged in and enabled E2EE.");
205
206    // Tell our listener that we're done.
207    state.set(LoginProgress::Done);
208
209    // And indeed, we are done with the login.
210    Ok(())
211}
212
213/// Register the client with the OAuth 2.0 authorization server.
214///
215/// Returns the authorization server metadata.
216async fn register_client(
217    oauth: &OAuth,
218    registration_data: Option<&ClientRegistrationData>,
219) -> Result<AuthorizationServerMetadata, DeviceAuthorizationOAuthError> {
220    let server_metadata = oauth.server_metadata().await.map_err(OAuthError::from)?;
221    oauth.use_registration_data(&server_metadata, registration_data).await?;
222
223    Ok(server_metadata)
224}
225
226async fn request_device_authorization(
227    oauth: &OAuth,
228    server_metadata: &AuthorizationServerMetadata,
229    device_id: Curve25519PublicKey,
230) -> Result<StandardDeviceAuthorizationResponse, DeviceAuthorizationOAuthError> {
231    let response = oauth
232        .request_device_authorization(server_metadata, Some(device_id.to_base64().into()))
233        .await?;
234    Ok(response)
235}
236
237async fn wait_for_tokens(
238    oauth: &OAuth,
239    server_metadata: &AuthorizationServerMetadata,
240    auth_response: &StandardDeviceAuthorizationResponse,
241) -> Result<(), DeviceAuthorizationOAuthError> {
242    oauth.exchange_device_code(server_metadata, auth_response).await?;
243    Ok(())
244}
245
246/// Type telling us about the progress of the QR code login.
247#[derive(Clone, Debug, Default)]
248pub enum LoginProgress<Q> {
249    /// We're just starting up, this is the default and initial state.
250    #[default]
251    Starting,
252    /// We have established the secure channel, but need to exchange the
253    /// [`CheckCode`] so the channel can be verified to indeed be secure.
254    EstablishingSecureChannel(Q),
255    /// We're waiting for the OAuth 2.0 authorization server to give us the
256    /// access token. This will only happen if the other device allows the OAuth
257    /// 2.0 authorization server to do so.
258    WaitingForToken {
259        /// The user code the OAuth 2.0 authorization server has given us, the
260        /// OAuth 2.0 authorization server might ask the other device to enter
261        /// this code.
262        user_code: String,
263    },
264    /// We are syncing secrets.
265    SyncingSecrets,
266    /// The login process has completed.
267    Done,
268}
269
270/// Named future for logging in by scanning a QR code with the
271/// [`OAuth::login_with_qr_code()`] method.
272#[derive(Debug)]
273pub struct LoginWithQrCode<'a> {
274    client: &'a Client,
275    registration_data: Option<&'a ClientRegistrationData>,
276    qr_code_data: &'a QrCodeData,
277    state: SharedObservable<LoginProgress<QrProgress>>,
278}
279
280impl LoginWithQrCode<'_> {
281    /// Subscribe to the progress of QR code login.
282    ///
283    /// It's usually necessary to subscribe to this to let the existing device
284    /// know about the [`CheckCode`] which is used to verify that the two
285    /// devices are communicating in a secure manner.
286    pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress<QrProgress>> + use<> {
287        self.state.subscribe()
288    }
289}
290
291impl<'a> IntoFuture for LoginWithQrCode<'a> {
292    type Output = Result<(), QRCodeLoginError>;
293    boxed_into_future!(extra_bounds: 'a);
294
295    fn into_future(self) -> Self::IntoFuture {
296        Box::pin(async move {
297            // Before we get here, the other device has created a new rendezvous
298            // session and presented a QR code which this device has scanned.
299            //
300            // -- MSC4108 Secure channel setup steps 1-3
301
302            // First things first, establish the secure channel. Since we're the
303            // one that scanned the QR code, we're certain that the secure
304            // channel is secure, under the assumption that we didn't scan the
305            // wrong QR code.
306            //
307            // -- MSC4108 Secure channel setup steps 3-5
308            let channel = self.establish_secure_channel().await?;
309
310            trace!("Established the secure channel.");
311
312            // The other side isn't yet sure that it's talking to the right
313            // device, show a check code so they can confirm.
314            //
315            // -- MSC4108 Secure channel setup step 6
316            let check_code = channel.check_code().to_owned();
317            self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
318
319            // The user now enters the checkcode on the other device which
320            // verifies it and will only facilitate the login if the code
321            // matches.
322            //
323            // -- MSC4108 Secure channel setup step 7
324
325            // Now attempt to finish the login.
326            //
327            // -- MSC4108 OAuth 2.0 login all steps
328            finish_login(self.client, channel, self.registration_data, self.state).await
329        })
330    }
331}
332
333impl<'a> LoginWithQrCode<'a> {
334    pub(crate) fn new(
335        client: &'a Client,
336        qr_code_data: &'a QrCodeData,
337        registration_data: Option<&'a ClientRegistrationData>,
338    ) -> LoginWithQrCode<'a> {
339        LoginWithQrCode { client, registration_data, qr_code_data, state: Default::default() }
340    }
341
342    async fn establish_secure_channel(
343        &self,
344    ) -> Result<EstablishedSecureChannel, SecureChannelError> {
345        let http_client = self.client.inner.http_client.inner.clone();
346
347        let channel = EstablishedSecureChannel::from_qr_code(
348            http_client,
349            self.qr_code_data,
350            QrCodeIntent::Login,
351        )
352        .await?;
353
354        Ok(channel)
355    }
356}
357
358/// Named future for logging in by generating a QR code with the
359/// [`OAuth::login_with_qr_code()`] method.
360#[derive(Debug)]
361pub struct LoginWithGeneratedQrCode<'a> {
362    client: &'a Client,
363    registration_data: Option<&'a ClientRegistrationData>,
364    state: SharedObservable<LoginProgress<GeneratedQrProgress>>,
365}
366
367impl LoginWithGeneratedQrCode<'_> {
368    /// Subscribe to the progress of QR code login.
369    ///
370    /// It's necessary to subscribe to this to show the QR code to the existing
371    /// device so it can send the check code back to this device.
372    pub fn subscribe_to_progress(
373        &self,
374    ) -> impl Stream<Item = LoginProgress<GeneratedQrProgress>> + use<> {
375        self.state.subscribe()
376    }
377}
378
379impl<'a> IntoFuture for LoginWithGeneratedQrCode<'a> {
380    type Output = Result<(), QRCodeLoginError>;
381    boxed_into_future!(extra_bounds: 'a);
382
383    fn into_future(self) -> Self::IntoFuture {
384        Box::pin(async move {
385            // Establish and verify the secure channel.
386            //
387            // -- MSC4108 Secure channel setup all steps
388            let mut channel = self.establish_secure_channel().await?;
389
390            trace!("Established the secure channel.");
391
392            // Wait for the other device to send us the m.login.protocols
393            // message so that we can discover the homeserver to use for logging
394            // in.
395            //
396            // -- MSC4108 OAuth 2.0 login step 1
397            let message = channel.receive_json().await?;
398
399            // Verify that the device authorization grant is supported and
400            // extract the homeserver URL.
401            let homeserver = match message {
402                QrAuthMessage::LoginProtocols { protocols, homeserver } => {
403                    if !protocols.contains(&LoginProtocolType::DeviceAuthorizationGrant) {
404                        channel
405                            .send_json(QrAuthMessage::LoginFailure {
406                                reason: LoginFailureReason::UnsupportedProtocol,
407                                homeserver: None,
408                            })
409                            .await?;
410
411                        return Err(QRCodeLoginError::LoginFailure {
412                            reason: LoginFailureReason::UnsupportedProtocol,
413                            homeserver: None,
414                        });
415                    }
416
417                    homeserver
418                }
419                _ => {
420                    send_unexpected_message_error(&mut channel).await?;
421
422                    return Err(QRCodeLoginError::UnexpectedMessage {
423                        expected: "m.login.protocols",
424                        received: Box::new(message),
425                    });
426                }
427            };
428
429            // Change the login homeserver if it is different from the server
430            // hosting the secure channel.
431            if self.client.homeserver() != homeserver {
432                self.client
433                    .switch_homeserver_and_re_resolve_well_known(homeserver)
434                    .await
435                    .map_err(QRCodeLoginError::ServerReset)?;
436            }
437
438            // Proceed with logging in.
439            //
440            // -- MSC4108 OAuth 2.0 login remaining steps
441            finish_login(self.client, channel, self.registration_data, self.state).await
442        })
443    }
444}
445
446impl<'a> LoginWithGeneratedQrCode<'a> {
447    pub(crate) fn new(
448        client: &'a Client,
449        registration_data: Option<&'a ClientRegistrationData>,
450    ) -> Self {
451        Self { client, registration_data, state: Default::default() }
452    }
453
454    async fn establish_secure_channel(
455        &self,
456    ) -> Result<EstablishedSecureChannel, SecureChannelError> {
457        let http_client = self.client.inner.http_client.clone();
458
459        // Create a new ephemeral key pair and a rendezvous session to request a
460        // login with.
461        //
462        // -- MSC4108 Secure channel setup steps 1 & 2
463        let secure_channel = SecureChannel::login(http_client, &self.client.homeserver()).await?;
464
465        // Extract the QR code data and emit a progress update so that the
466        // caller can present the QR code for scanning by the other device.
467        //
468        // -- MSC4108 Secure channel setup step 3
469        let qr_code_data = secure_channel.qr_code_data().clone();
470        trace!("Generated QR code.");
471        self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(
472            qr_code_data,
473        )));
474
475        // Wait for the secure channel to connect. The other device now needs to
476        // scan the QR code and send us the LoginInitiateMessage which we
477        // respond to with the LoginOkMessage.
478        //
479        // -- MSC4108 step 4 & 5
480        let channel = secure_channel.connect().await?;
481
482        // The other device now verifies our message, computes the checkcode and
483        // displays it. We emit a progress update to let the caller prompt the
484        // user to enter the checkcode and feed it back to us.
485        //
486        // -- MSC4108 Secure channel setup step 6
487        trace!("Waiting for checkcode.");
488        let (tx, rx) = tokio::sync::oneshot::channel();
489        self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
490            CheckCodeSender::new(tx),
491        )));
492
493        // Retrieve the entered checkcode and verify it to confirm that the
494        // channel is actually secure.
495        //
496        // -- MSC4108 Secure channel setup step 7
497        let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
498        trace!("Received check code.");
499        channel.confirm(check_code)
500    }
501}
502
503#[cfg(all(test, not(target_family = "wasm")))]
504mod test {
505    use std::{assert_matches, time::Duration};
506
507    use futures_util::StreamExt;
508    use matrix_sdk_base::crypto::types::{
509        SecretsBundle,
510        qr_login::{Msc4108IntentData, QrCodeIntentData},
511    };
512    use matrix_sdk_common::executor::spawn;
513    use matrix_sdk_test::async_test;
514    use serde_json::json;
515    use strass::assert_let;
516
517    use super::*;
518    use crate::{
519        authentication::oauth::qrcode::{
520            messages::LoginProtocolType,
521            secure_channel::{SecureChannel, test::MockedRendezvousServer},
522        },
523        config::RequestConfig,
524        http_client::HttpClient,
525        test_utils::{client::oauth::mock_client_metadata, mocks::MatrixMockServer},
526    };
527
528    enum AliceBehaviour {
529        HappyPath,
530        DeclinedProtocol,
531        UnexpectedMessage,
532        UnexpectedMessageInsteadOfSecrets,
533        RefuseSecrets,
534        LetSessionExpire,
535    }
536
537    /// The possible token responses.
538    enum TokenResponse {
539        Ok,
540        AccessDenied,
541        ExpiredToken,
542    }
543
544    fn secrets_bundle() -> SecretsBundle {
545        let json = json!({
546            "cross_signing": {
547                "master_key": "rTtSv67XGS6k/rg6/yTG/m573cyFTPFRqluFhQY+hSw",
548                "self_signing_key": "4jbPt7jh5D2iyM4U+3IDa+WthgJB87IQN1ATdkau+xk",
549                "user_signing_key": "YkFKtkjcsTxF6UAzIIG/l6Nog/G2RigCRfWj3cjNWeM",
550            },
551        });
552
553        serde_json::from_value(json).expect("We should be able to deserialize a secrets bundle")
554    }
555
556    /// This is most of the code that is required to be the other side, the
557    /// existing device, of the QR login dance.
558    async fn grant_login(
559        alice: SecureChannel,
560        check_code_receiver: tokio::sync::oneshot::Receiver<u8>,
561        behavior: AliceBehaviour,
562    ) {
563        let alice = alice.connect().await.expect("Alice should be able to connect the channel");
564
565        let check_code =
566            check_code_receiver.await.expect("We should receive the check code from bob");
567
568        let mut alice =
569            alice.confirm(check_code).expect("Alice should be able to confirm the secure channel");
570
571        let message = alice
572            .receive_json()
573            .await
574            .expect("Alice should be able to receive the initial message from Bob");
575
576        assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
577        assert_eq!(protocol, LoginProtocolType::DeviceAuthorizationGrant);
578
579        let message = match behavior {
580            AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
581                reason: LoginFailureReason::UnsupportedProtocol,
582                homeserver: None,
583            },
584            AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
585            _ => QrAuthMessage::LoginProtocolAccepted,
586        };
587
588        alice.send_json(message).await.unwrap();
589
590        let message: QrAuthMessage = alice.receive_json().await.unwrap();
591        assert_let!(QrAuthMessage::LoginSuccess = message);
592
593        let message = match behavior {
594            AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
595            AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
596                reason: LoginFailureReason::DeviceNotFound,
597                homeserver: None,
598            },
599            _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
600        };
601
602        alice.send_json(message).await.unwrap();
603    }
604
605    #[async_test]
606    async fn test_qr_login() {
607        let server = MatrixMockServer::new().await;
608        let rendezvous_server =
609            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
610        let (sender, receiver) = tokio::sync::oneshot::channel();
611
612        let oauth_server = server.oauth();
613        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
614        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
615        oauth_server
616            .mock_device_authorization()
617            .ok()
618            .expect(1)
619            .named("device_authorization")
620            .mount()
621            .await;
622        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
623
624        server.mock_versions().ok().expect(1..).named("versions").mount().await;
625        server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
626        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
627        server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
628
629        let client = HttpClient::new(reqwest::Client::new(), Default::default());
630        let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
631            .await
632            .expect("Alice should be able to create a secure channel.");
633
634        assert_let!(
635            QrCodeIntentData::Msc4108 {
636                data: Msc4108IntentData::Reciprocate { server_name },
637                ..
638            } = &alice.qr_code_data().intent_data()
639        );
640
641        let bob = Client::builder()
642            .server_name_or_homeserver_url(server_name)
643            .request_config(RequestConfig::new().disable_retry())
644            .build()
645            .await
646            .expect("We should be able to build the Client object from the URL in the QR code");
647
648        let qr_code = alice.qr_code_data().clone();
649
650        let oauth = bob.oauth();
651        let registration_data = mock_client_metadata().into();
652        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
653        let mut updates = login_bob.subscribe_to_progress();
654
655        let updates_task = spawn(async move {
656            let mut sender = Some(sender);
657
658            while let Some(update) = updates.next().await {
659                match update {
660                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
661                        sender
662                            .take()
663                            .expect("The establishing secure channel update should be received only once")
664                            .send(check_code)
665                            .expect("Bob should be able to send the check code to Alice");
666                    }
667                    LoginProgress::Done => break,
668                    _ => (),
669                }
670            }
671        });
672        let alice_task =
673            spawn(async { grant_login(alice, receiver, AliceBehaviour::HappyPath).await });
674
675        // Wait for all tasks to finish.
676        login_bob.await.expect("Bob should be able to login");
677        alice_task.await.expect("Alice should have completed it's task successfully");
678        updates_task.await.unwrap();
679
680        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
681        let own_identity =
682            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
683
684        assert!(own_identity.is_verified());
685    }
686
687    async fn grant_login_with_generated_qr(
688        alice: &Client,
689        qr_receiver: tokio::sync::oneshot::Receiver<QrCodeData>,
690        cctx_receiver: tokio::sync::oneshot::Receiver<CheckCodeSender>,
691        behavior: AliceBehaviour,
692    ) {
693        let qr_code_data = qr_receiver.await.expect("Alice should receive the QR code");
694
695        let mut channel = EstablishedSecureChannel::from_qr_code(
696            alice.inner.http_client.inner.clone(),
697            &qr_code_data,
698            QrCodeIntent::Reciprocate,
699        )
700        .await
701        .expect("Alice should be able to establish the secure channel");
702
703        trace!("Established the secure channel.");
704
705        // The other side isn't yet sure that it's talking to the right device,
706        // show a check code so they can confirm.
707        let check_code = channel.check_code();
708
709        let check_code_sender =
710            cctx_receiver.await.expect("Alice should receive the CheckCodeSender");
711
712        check_code_sender
713            .send(check_code)
714            .await
715            .expect("Alice should be able to send the check code to Bob");
716
717        // Alice sends m.login.protocols message
718        let message = QrAuthMessage::LoginProtocols {
719            protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
720            homeserver: alice.homeserver(),
721        };
722        channel
723            .send_json(message)
724            .await
725            .expect("Alice should be able to send the `m.login.protocols` message to Bob");
726
727        // Alice receives m.login.protocol message
728        let message: QrAuthMessage = channel
729            .receive_json()
730            .await
731            .expect("Alice should be able to receive the `m.login.protocol` message from Bob");
732        assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
733        assert_eq!(protocol, LoginProtocolType::DeviceAuthorizationGrant);
734
735        // Alice sends m.login.protocol_accepted message
736        let message = match behavior {
737            AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
738                reason: LoginFailureReason::UnsupportedProtocol,
739                homeserver: None,
740            },
741            AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
742            _ => QrAuthMessage::LoginProtocolAccepted,
743        };
744        channel
745            .send_json(message)
746            .await
747            .expect("Alice should be able to send the `m.login.protocol_accepted` message to Bob");
748
749        let message: QrAuthMessage = channel
750            .receive_json()
751            .await
752            .expect("Alice should be able to receive the `m.login.success` message from Bob");
753        assert_let!(QrAuthMessage::LoginSuccess = message);
754
755        // Alice sends m.login.secrets message
756        let message = match behavior {
757            AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
758            AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
759                reason: LoginFailureReason::DeviceNotFound,
760                homeserver: None,
761            },
762            _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
763        };
764        channel
765            .send_json(message)
766            .await
767            .expect("Alice should be able to send the `m.login.secrets` message to Bob");
768    }
769
770    #[async_test]
771    async fn test_generated_qr_login() {
772        let server = MatrixMockServer::new().await;
773        let rendezvous_server =
774            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
775        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
776        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
777
778        let oauth_server = server.oauth();
779        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
780        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
781        oauth_server
782            .mock_device_authorization()
783            .ok()
784            .expect(1)
785            .named("device_authorization")
786            .mount()
787            .await;
788        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
789
790        server.mock_versions().ok().expect(1..).named("versions").mount().await;
791        server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
792        server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
793        server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
794
795        let homeserver_url = rendezvous_server.homeserver_url.clone();
796
797        // Create Alice, the existing client, as a logged-in client. They will
798        // scan the QR code generated by Bob.
799        let alice = server.client_builder().logged_in_with_oauth().build().await;
800        assert!(alice.session_meta().is_some(), "Alice should be logged in");
801
802        // Create Bob, the new client. They will generate the QR code.
803        let bob = Client::builder()
804            .server_name_or_homeserver_url(&homeserver_url)
805            .request_config(RequestConfig::new().disable_retry())
806            .build()
807            .await
808            .expect("Should be able to create a client for Bob");
809
810        let secure_channel = SecureChannel::login(bob.inner.http_client.clone(), &homeserver_url)
811            .await
812            .expect("Bob should be able to create a secure channel");
813
814        assert_matches!(
815            secure_channel.qr_code_data().intent_data(),
816            QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
817        );
818
819        let registration_data = mock_client_metadata().into();
820        let bob_oauth = bob.oauth();
821        let bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
822        let mut bob_updates = bob_login.subscribe_to_progress();
823
824        let updates_task = spawn(async move {
825            let mut qr_sender = Some(qr_sender);
826            let mut cctx_sender = Some(cctx_sender);
827
828            while let Some(update) = bob_updates.next().await {
829                match update {
830                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
831                        qr_sender
832                            .take()
833                            .expect("The establishing secure channel update with a qr code should be received only once")
834                            .send(qr)
835                            .expect("Bob should be able to send the qr code code to Alice");
836                    }
837                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
838                        cctx,
839                    )) => {
840                        cctx_sender
841                            .take()
842                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
843                            .send(cctx)
844                            .expect("Bob should be able to send the qr code code to Alice");
845                    }
846                    LoginProgress::Done => break,
847                    _ => (),
848                }
849            }
850        });
851
852        let alice_task = spawn(async move {
853            grant_login_with_generated_qr(
854                &alice,
855                qr_receiver,
856                cctx_receiver,
857                AliceBehaviour::HappyPath,
858            )
859            .await
860        });
861
862        // Wait for all tasks to finish.
863        bob_login.await.expect("Bob should be able to login");
864        alice_task.await.expect("Alice should have completed it's task successfully");
865        updates_task.await.unwrap();
866
867        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
868        let own_identity =
869            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
870
871        assert!(own_identity.is_verified());
872    }
873
874    #[async_test]
875    async fn test_generated_qr_login_with_homeserver_swap() {
876        let initial_server = MatrixMockServer::new().await;
877        let rendezvous_server =
878            MockedRendezvousServer::new(initial_server.server(), "abcdEFG12345", Duration::MAX)
879                .await;
880        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
881        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
882
883        let login_server = MatrixMockServer::new().await;
884        let oauth_server = login_server.oauth();
885        oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
886        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
887        oauth_server
888            .mock_device_authorization()
889            .ok()
890            .expect(1)
891            .named("device_authorization")
892            .mount()
893            .await;
894        oauth_server.mock_token().ok().expect(1).named("token").mount().await;
895
896        initial_server.mock_versions().ok().expect(1..).named("versions").mount().await;
897
898        login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
899        login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
900        login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
901        login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
902        login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
903
904        let rendezvous_homeserver_url = rendezvous_server.homeserver_url.clone();
905
906        // Create Alice, the existing client, as a logged-in client. They will
907        // scan the QR code generated by Bob.
908        let alice = login_server.client_builder().logged_in_with_oauth().build().await;
909        assert!(alice.session_meta().is_some(), "Alice should be logged in");
910
911        // Create Bob, the new client. They will generate the QR code.
912        let bob = Client::builder()
913            .server_name_or_homeserver_url(&rendezvous_homeserver_url)
914            .request_config(RequestConfig::new().disable_retry())
915            .build()
916            .await
917            .expect("Should be able to create a client for Bob");
918
919        let secure_channel =
920            SecureChannel::login(bob.inner.http_client.clone(), &rendezvous_homeserver_url)
921                .await
922                .expect("Bob should be able to create a secure channel");
923
924        assert_matches!(
925            secure_channel.qr_code_data().intent_data(),
926            QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
927        );
928
929        // Alice and Bob should have different homeservers configured at the
930        // start.
931        let initial_server_url = initial_server.server().uri().parse().unwrap();
932        assert_eq!(bob.homeserver(), initial_server_url);
933        let login_server_url = login_server.server().uri().parse().unwrap();
934        assert_eq!(alice.homeserver(), login_server_url);
935        assert_ne!(initial_server_url, login_server_url);
936
937        let registration_data = mock_client_metadata().into();
938        let bob_oauth = bob.oauth();
939        let bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
940        let mut bob_updates = bob_login.subscribe_to_progress();
941
942        let updates_task = spawn(async move {
943            let mut qr_sender = Some(qr_sender);
944            let mut cctx_sender = Some(cctx_sender);
945
946            while let Some(update) = bob_updates.next().await {
947                match update {
948                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
949                        qr_sender
950                            .take()
951                            .expect("The establishing secure channel update with a qr code should be received only once")
952                            .send(qr)
953                            .expect("Bob should be able to send the qr code code to Alice");
954                    }
955                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
956                        cctx,
957                    )) => {
958                        cctx_sender
959                            .take()
960                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
961                            .send(cctx)
962                            .expect("Bob should be able to send the qr code code to Alice");
963                    }
964                    LoginProgress::Done => break,
965                    _ => (),
966                }
967            }
968        });
969
970        let alice_task = spawn(async move {
971            grant_login_with_generated_qr(
972                &alice,
973                qr_receiver,
974                cctx_receiver,
975                AliceBehaviour::HappyPath,
976            )
977            .await
978        });
979
980        // Wait for all tasks to finish.
981        bob_login.await.expect("Bob should be able to login");
982        alice_task.await.expect("Alice should have completed it's task successfully");
983        updates_task.await.unwrap();
984
985        assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
986        let own_identity =
987            bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
988
989        assert!(own_identity.is_verified());
990
991        // After login, Bob should have switched to the new homeserver.
992        assert_eq!(bob.homeserver(), login_server_url);
993    }
994
995    async fn test_failure(
996        token_response: TokenResponse,
997        alice_behavior: AliceBehaviour,
998    ) -> Result<(), QRCodeLoginError> {
999        let server = MatrixMockServer::new().await;
1000        let expiration = match alice_behavior {
1001            AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1002            _ => Duration::MAX,
1003        };
1004        let rendezvous_server =
1005            MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration).await;
1006        let (sender, receiver) = tokio::sync::oneshot::channel();
1007
1008        let oauth_server = server.oauth();
1009        let expected_calls = match alice_behavior {
1010            AliceBehaviour::LetSessionExpire => 0,
1011            _ => 1,
1012        };
1013        oauth_server
1014            .mock_server_metadata()
1015            .ok()
1016            .expect(expected_calls)
1017            .named("server_metadata")
1018            .mount()
1019            .await;
1020        oauth_server
1021            .mock_registration()
1022            .ok()
1023            .expect(expected_calls)
1024            .named("registration")
1025            .mount()
1026            .await;
1027        oauth_server
1028            .mock_device_authorization()
1029            .ok()
1030            .expect(expected_calls)
1031            .named("device_authorization")
1032            .mount()
1033            .await;
1034
1035        let token_mock = oauth_server.mock_token();
1036        let token_mock = match token_response {
1037            TokenResponse::Ok => token_mock.ok(),
1038            TokenResponse::AccessDenied => token_mock.access_denied(),
1039            TokenResponse::ExpiredToken => token_mock.expired_token(),
1040        };
1041        token_mock.named("token").mount().await;
1042
1043        server.mock_versions().ok().named("versions").mount().await;
1044        server.mock_who_am_i().ok().named("whoami").mount().await;
1045
1046        let client = HttpClient::new(reqwest::Client::new(), Default::default());
1047        let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
1048            .await
1049            .expect("Alice should be able to create a secure channel.");
1050
1051        assert_let!(
1052            QrCodeIntentData::Msc4108 {
1053                data: Msc4108IntentData::Reciprocate { server_name },
1054                ..
1055            } = &alice.qr_code_data().intent_data()
1056        );
1057
1058        let bob = Client::builder()
1059            .server_name_or_homeserver_url(server_name)
1060            .request_config(RequestConfig::new().disable_retry())
1061            .build()
1062            .await
1063            .expect("We should be able to build the Client object from the URL in the QR code");
1064
1065        let qr_code = alice.qr_code_data().clone();
1066
1067        let oauth = bob.oauth();
1068        let registration_data = mock_client_metadata().into();
1069        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
1070        let mut updates = login_bob.subscribe_to_progress();
1071
1072        let _updates_task = spawn(async move {
1073            let mut sender = Some(sender);
1074
1075            while let Some(update) = updates.next().await {
1076                match update {
1077                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1078                        sender
1079                            .take()
1080                            .expect("The establishing secure channel update should be received only once")
1081                            .send(check_code)
1082                            .expect("Bob should be able to send the check code to Alice");
1083                    }
1084                    LoginProgress::Done => break,
1085                    _ => (),
1086                }
1087            }
1088        });
1089
1090        if !matches!(alice_behavior, AliceBehaviour::LetSessionExpire) {
1091            let _alice_task =
1092                spawn(async move { grant_login(alice, receiver, alice_behavior).await });
1093        }
1094
1095        login_bob.await
1096    }
1097
1098    async fn test_generated_failure(
1099        token_response: TokenResponse,
1100        alice_behavior: AliceBehaviour,
1101    ) -> Result<(), QRCodeLoginError> {
1102        let server = MatrixMockServer::new().await;
1103        let expiration = match alice_behavior {
1104            AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1105            _ => Duration::MAX,
1106        };
1107        let rendezvous_server =
1108            MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration).await;
1109
1110        let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1111        let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1112
1113        let oauth_server = server.oauth();
1114        let expected_calls = match alice_behavior {
1115            AliceBehaviour::LetSessionExpire => 0,
1116            _ => 1,
1117        };
1118        oauth_server
1119            .mock_server_metadata()
1120            .ok()
1121            .expect(expected_calls)
1122            .named("server_metadata")
1123            .mount()
1124            .await;
1125        oauth_server
1126            .mock_registration()
1127            .ok()
1128            .expect(expected_calls)
1129            .named("registration")
1130            .mount()
1131            .await;
1132        oauth_server
1133            .mock_device_authorization()
1134            .ok()
1135            .expect(expected_calls)
1136            .named("device_authorization")
1137            .mount()
1138            .await;
1139
1140        let token_mock = oauth_server.mock_token();
1141        let token_mock = match token_response {
1142            TokenResponse::Ok => token_mock.ok(),
1143            TokenResponse::AccessDenied => token_mock.access_denied(),
1144            TokenResponse::ExpiredToken => token_mock.expired_token(),
1145        };
1146        token_mock.named("token").mount().await;
1147
1148        server.mock_versions().ok().named("versions").mount().await;
1149        server.mock_who_am_i().ok().named("whoami").mount().await;
1150
1151        let homeserver_url = rendezvous_server.homeserver_url.clone();
1152
1153        // Create Alice, the existing client, as a logged-in client. They will
1154        // scan the QR code generated by Bob.
1155        let alice = server.client_builder().logged_in_with_oauth().build().await;
1156        assert!(alice.session_meta().is_some(), "Alice should be logged in");
1157
1158        // Create Bob, the new client. They will generate the QR code.
1159        let bob = Client::builder()
1160            .server_name_or_homeserver_url(&homeserver_url)
1161            .request_config(RequestConfig::new().disable_retry())
1162            .build()
1163            .await
1164            .expect("Should be able to create a client for Bob");
1165
1166        let secure_channel = SecureChannel::login(bob.inner.http_client.clone(), &homeserver_url)
1167            .await
1168            .expect("Bob should be able to create a secure channel");
1169
1170        assert_matches!(
1171            secure_channel.qr_code_data().intent_data(),
1172            QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1173        );
1174
1175        let registration_data = mock_client_metadata().into();
1176        let bob_oauth = bob.oauth();
1177        let bob_login = bob_oauth.login_with_qr_code(Some(&registration_data)).generate();
1178        let mut bob_updates = bob_login.subscribe_to_progress();
1179
1180        let _updates_task = spawn(async move {
1181            let mut qr_sender = Some(qr_sender);
1182            let mut cctx_sender = Some(cctx_sender);
1183
1184            while let Some(update) = bob_updates.next().await {
1185                match update {
1186                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1187                        qr_sender
1188                            .take()
1189                            .expect("The establishing secure channel update with a qr code should be received only once")
1190                            .send(qr)
1191                            .expect("Bob should be able to send the qr code code to Alice");
1192                    }
1193                    LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1194                        cctx,
1195                    )) => {
1196                        cctx_sender
1197                            .take()
1198                            .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1199                            .send(cctx)
1200                            .expect("Bob should be able to send the qr code code to Alice");
1201                    }
1202                    LoginProgress::Done => break,
1203                    _ => (),
1204                }
1205            }
1206        });
1207
1208        if !matches!(alice_behavior, AliceBehaviour::LetSessionExpire) {
1209            let _alice_task = spawn(async move {
1210                grant_login_with_generated_qr(&alice, qr_receiver, cctx_receiver, alice_behavior)
1211                    .await
1212            });
1213        }
1214
1215        bob_login.await
1216    }
1217
1218    #[async_test]
1219    async fn test_qr_login_refused_access_token() {
1220        let result = test_failure(TokenResponse::AccessDenied, AliceBehaviour::HappyPath).await;
1221
1222        assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1223        assert_eq!(
1224            e.as_request_token_error(),
1225            Some(&DeviceCodeErrorResponseType::AccessDenied),
1226            "The server should have told us that access has been denied."
1227        );
1228    }
1229
1230    #[async_test]
1231    async fn test_generated_qr_login_refused_access_token() {
1232        let result =
1233            test_generated_failure(TokenResponse::AccessDenied, AliceBehaviour::HappyPath).await;
1234
1235        assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1236        assert_eq!(
1237            e.as_request_token_error(),
1238            Some(&DeviceCodeErrorResponseType::AccessDenied),
1239            "The server should have told us that access has been denied."
1240        );
1241    }
1242
1243    #[async_test]
1244    async fn test_qr_login_expired_token() {
1245        let result = test_failure(TokenResponse::ExpiredToken, AliceBehaviour::HappyPath).await;
1246
1247        assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1248        assert_eq!(
1249            e.as_request_token_error(),
1250            Some(&DeviceCodeErrorResponseType::ExpiredToken),
1251            "The server should have told us that access has been denied."
1252        );
1253    }
1254
1255    #[async_test]
1256    async fn test_generated_qr_login_expired_token() {
1257        let result =
1258            test_generated_failure(TokenResponse::ExpiredToken, AliceBehaviour::HappyPath).await;
1259
1260        assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1261        assert_eq!(
1262            e.as_request_token_error(),
1263            Some(&DeviceCodeErrorResponseType::ExpiredToken),
1264            "The server should have told us that access has been denied."
1265        );
1266    }
1267
1268    #[async_test]
1269    async fn test_qr_login_declined_protocol() {
1270        let result = test_failure(TokenResponse::Ok, AliceBehaviour::DeclinedProtocol).await;
1271
1272        assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1273        assert_eq!(
1274            reason,
1275            LoginFailureReason::UnsupportedProtocol,
1276            "Alice should have told us that the protocol is unsupported."
1277        );
1278    }
1279
1280    #[async_test]
1281    async fn test_generated_qr_login_declined_protocol() {
1282        let result =
1283            test_generated_failure(TokenResponse::Ok, AliceBehaviour::DeclinedProtocol).await;
1284
1285        assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1286        assert_eq!(
1287            reason,
1288            LoginFailureReason::UnsupportedProtocol,
1289            "Alice should have told us that the protocol is unsupported."
1290        );
1291    }
1292
1293    #[async_test]
1294    async fn test_qr_login_unexpected_message() {
1295        let result = test_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessage).await;
1296
1297        assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1298        assert_eq!(expected, "m.login.protocol_accepted");
1299    }
1300
1301    #[async_test]
1302    async fn test_generated_qr_login_unexpected_message() {
1303        let result =
1304            test_generated_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessage).await;
1305
1306        assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1307        assert_eq!(expected, "m.login.protocol_accepted");
1308    }
1309
1310    #[async_test]
1311    async fn test_qr_login_unexpected_message_instead_of_secrets() {
1312        let result =
1313            test_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessageInsteadOfSecrets)
1314                .await;
1315
1316        assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1317        assert_eq!(expected, "m.login.secrets");
1318    }
1319
1320    #[async_test]
1321    async fn test_generated_qr_login_unexpected_message_instead_of_secrets() {
1322        let result = test_generated_failure(
1323            TokenResponse::Ok,
1324            AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
1325        )
1326        .await;
1327
1328        assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1329        assert_eq!(expected, "m.login.secrets");
1330    }
1331
1332    #[async_test]
1333    async fn test_qr_login_refuse_secrets() {
1334        let result = test_failure(TokenResponse::Ok, AliceBehaviour::RefuseSecrets).await;
1335
1336        assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1337        assert_eq!(reason, LoginFailureReason::DeviceNotFound);
1338    }
1339
1340    #[async_test]
1341    async fn test_generated_qr_login_refuse_secrets() {
1342        let result = test_generated_failure(TokenResponse::Ok, AliceBehaviour::RefuseSecrets).await;
1343
1344        assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1345        assert_eq!(reason, LoginFailureReason::DeviceNotFound);
1346    }
1347
1348    #[async_test]
1349    async fn test_qr_login_session_expired() {
1350        let result = test_failure(TokenResponse::Ok, AliceBehaviour::LetSessionExpire).await;
1351
1352        assert_matches!(result, Err(QRCodeLoginError::NotFound));
1353    }
1354
1355    #[async_test]
1356    async fn test_generated_qr_login_session_expired() {
1357        let result =
1358            test_generated_failure(TokenResponse::Ok, AliceBehaviour::LetSessionExpire).await;
1359
1360        assert_matches!(result, Err(QRCodeLoginError::NotFound));
1361    }
1362
1363    #[async_test]
1364    async fn test_device_authorization_endpoint_missing() {
1365        let server = MatrixMockServer::new().await;
1366        let rendezvous_server =
1367            MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1368        let (sender, receiver) = tokio::sync::oneshot::channel();
1369
1370        let oauth_server = server.oauth();
1371        oauth_server
1372            .mock_server_metadata()
1373            .ok_without_device_authorization()
1374            .expect(1)
1375            .named("server_metadata")
1376            .mount()
1377            .await;
1378        oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1379
1380        server.mock_versions().ok().named("versions").mount().await;
1381        server.mock_who_am_i().ok().named("whoami").mount().await;
1382
1383        let client = HttpClient::new(reqwest::Client::new(), Default::default());
1384        let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
1385            .await
1386            .expect("Alice should be able to create a secure channel.");
1387
1388        assert_let!(
1389            QrCodeIntentData::Msc4108 {
1390                data: Msc4108IntentData::Reciprocate { server_name },
1391                ..
1392            } = &alice.qr_code_data().intent_data()
1393        );
1394
1395        let bob = Client::builder()
1396            .server_name_or_homeserver_url(server_name)
1397            .request_config(RequestConfig::new().disable_retry())
1398            .build()
1399            .await
1400            .expect("We should be able to build the Client object from the URL in the QR code");
1401
1402        let qr_code = alice.qr_code_data().clone();
1403
1404        let oauth = bob.oauth();
1405        let registration_data = mock_client_metadata().into();
1406        let login_bob = oauth.login_with_qr_code(Some(&registration_data)).scan(&qr_code);
1407        let mut updates = login_bob.subscribe_to_progress();
1408
1409        let _updates_task = spawn(async move {
1410            let mut sender = Some(sender);
1411
1412            while let Some(update) = updates.next().await {
1413                match update {
1414                    LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1415                        sender
1416                                .take()
1417                                .expect("The establishing secure channel update should be received only once")
1418                                .send(check_code)
1419                                .expect("Bob should be able to send the check code to Alice");
1420                    }
1421                    LoginProgress::Done => break,
1422                    _ => (),
1423                }
1424            }
1425        });
1426        let _alice_task =
1427            spawn(async move { grant_login(alice, receiver, AliceBehaviour::HappyPath).await });
1428        let error = login_bob.await.unwrap_err();
1429
1430        assert_matches!(
1431            error,
1432            QRCodeLoginError::OAuth(DeviceAuthorizationOAuthError::NoDeviceAuthorizationEndpoint)
1433        );
1434    }
1435}