1use 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 trace!("Registering the client with the OAuth 2.0 authorization server.");
68 let server_metadata = register_client(&oauth, registration_data).await?;
69
70 let account = vodozemac::olm::Account::new();
73 let public_key = account.identity_keys().curve25519;
74 let device_id = public_key;
75
76 trace!("Requesting device authorization.");
80 let auth_grant_response =
81 request_device_authorization(&oauth, &server_metadata, device_id).await?;
82
83 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 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 let user_code = auth_grant_response.user_code();
110 state.set(LoginProgress::WaitingForToken { user_code: user_code.secret().to_owned() });
111
112 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 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 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 trace!("Telling the existing device that we successfully logged in.");
164 let message = QrAuthMessage::LoginSuccess;
165 channel.send_json(&message).await?;
166
167 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 client.encryption().import_secrets_bundle_impl(&bundle).await?;
188
189 client
192 .encryption()
193 .ensure_device_keys_upload()
194 .await
195 .map_err(QRCodeLoginError::DeviceKeyUpload)?;
196
197 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 state.set(LoginProgress::Done);
208
209 Ok(())
211}
212
213async 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#[derive(Clone, Debug, Default)]
248pub enum LoginProgress<Q> {
249 #[default]
251 Starting,
252 EstablishingSecureChannel(Q),
255 WaitingForToken {
259 user_code: String,
263 },
264 SyncingSecrets,
266 Done,
268}
269
270#[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 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 let channel = self.establish_secure_channel().await?;
309
310 trace!("Established the secure channel.");
311
312 let check_code = channel.check_code().to_owned();
317 self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
318
319 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#[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 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 let mut channel = self.establish_secure_channel().await?;
389
390 trace!("Established the secure channel.");
391
392 let message = channel.receive_json().await?;
398
399 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 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 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 let secure_channel = SecureChannel::login(http_client, &self.client.homeserver()).await?;
464
465 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 let channel = secure_channel.connect().await?;
481
482 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 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 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 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(®istration_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 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 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 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 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 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 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 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 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(®istration_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 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 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 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 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(®istration_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 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 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(®istration_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 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 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(®istration_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(®istration_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}