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.");
79 let auth_grant_response =
80 request_device_authorization(&oauth, &server_metadata, device_id).await?;
81
82 trace!("Letting the existing device know about the device authorization grant.");
85 let message =
86 QrAuthMessage::authorization_grant_login_protocol((&auth_grant_response).into(), device_id);
87 channel.send_json(&message).await?;
88
89 match channel.receive_json().await? {
91 QrAuthMessage::LoginProtocolAccepted => (),
92 QrAuthMessage::LoginFailure { reason, homeserver } => {
93 return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
94 }
95 message => {
96 send_unexpected_message_error(&mut channel).await?;
97
98 return Err(QRCodeLoginError::UnexpectedMessage {
99 expected: "m.login.protocol_accepted",
100 received: Box::new(message),
101 });
102 }
103 }
104
105 let user_code = auth_grant_response.user_code();
109 state.set(LoginProgress::WaitingForToken { user_code: user_code.secret().to_owned() });
110
111 trace!("Waiting for the OAuth 2.0 authorization server to give us the access token.");
114 if let Err(e) = wait_for_tokens(&oauth, &server_metadata, &auth_grant_response).await {
115 if let Some(e) = e.as_request_token_error() {
118 match e {
119 DeviceCodeErrorResponseType::AccessDenied => {
120 channel.send_json(QrAuthMessage::LoginDeclined).await?;
121 }
122 DeviceCodeErrorResponseType::ExpiredToken => {
123 channel
124 .send_json(QrAuthMessage::LoginFailure {
125 reason: LoginFailureReason::AuthorizationExpired,
126 homeserver: None,
127 })
128 .await?;
129 }
130 _ => (),
131 }
132 }
133
134 return Err(e.into());
135 }
136
137 trace!("Discovering our own user id.");
143 let whoami_response = client.whoami().await.map_err(QRCodeLoginError::UserIdDiscovery)?;
144 client
145 .base_client()
146 .activate(
147 SessionMeta {
148 user_id: whoami_response.user_id,
149 device_id: OwnedDeviceId::from(device_id.to_base64()),
150 },
151 RoomLoadSettings::default(),
152 Some(account),
153 )
154 .await
155 .map_err(|error| QRCodeLoginError::SessionTokens(error.into()))?;
156
157 client.oauth().enable_cross_process_lock().await?;
158
159 state.set(LoginProgress::SyncingSecrets);
160
161 trace!("Telling the existing device that we successfully logged in.");
163 let message = QrAuthMessage::LoginSuccess;
164 channel.send_json(&message).await?;
165
166 trace!("Waiting for the secrets bundle.");
169 let bundle = match channel.receive_json().await? {
170 QrAuthMessage::LoginSecrets(bundle) => bundle,
171 QrAuthMessage::LoginFailure { reason, homeserver } => {
172 return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
173 }
174 message => {
175 send_unexpected_message_error(&mut channel).await?;
176
177 return Err(QRCodeLoginError::UnexpectedMessage {
178 expected: "m.login.secrets",
179 received: Box::new(message),
180 });
181 }
182 };
183
184 client.encryption().import_secrets_bundle_impl(&bundle).await?;
187
188 client
191 .encryption()
192 .ensure_device_keys_upload()
193 .await
194 .map_err(QRCodeLoginError::DeviceKeyUpload)?;
195
196 client.encryption().spawn_initialization_task(None).await;
201 client.encryption().wait_for_e2ee_initialization_tasks().await;
202
203 trace!("successfully logged in and enabled E2EE.");
204
205 state.set(LoginProgress::Done);
207
208 Ok(())
210}
211
212async fn register_client(
216 oauth: &OAuth,
217 registration_data: Option<&ClientRegistrationData>,
218) -> Result<AuthorizationServerMetadata, DeviceAuthorizationOAuthError> {
219 let server_metadata = oauth.server_metadata().await.map_err(OAuthError::from)?;
220 oauth.use_registration_data(&server_metadata, registration_data).await?;
221
222 Ok(server_metadata)
223}
224
225async fn request_device_authorization(
226 oauth: &OAuth,
227 server_metadata: &AuthorizationServerMetadata,
228 device_id: Curve25519PublicKey,
229) -> Result<StandardDeviceAuthorizationResponse, DeviceAuthorizationOAuthError> {
230 let response = oauth
231 .request_device_authorization(server_metadata, Some(device_id.to_base64().into()))
232 .await?;
233 Ok(response)
234}
235
236async fn wait_for_tokens(
237 oauth: &OAuth,
238 server_metadata: &AuthorizationServerMetadata,
239 auth_response: &StandardDeviceAuthorizationResponse,
240) -> Result<(), DeviceAuthorizationOAuthError> {
241 oauth.exchange_device_code(server_metadata, auth_response).await?;
242 Ok(())
243}
244
245#[derive(Clone, Debug, Default)]
247pub enum LoginProgress<Q> {
248 #[default]
250 Starting,
251 EstablishingSecureChannel(Q),
254 WaitingForToken {
258 user_code: String,
262 },
263 SyncingSecrets,
265 Done,
267}
268
269#[derive(Debug)]
272pub struct LoginWithQrCode<'a> {
273 client: &'a Client,
274 registration_data: Option<&'a ClientRegistrationData>,
275 qr_code_data: &'a QrCodeData,
276 state: SharedObservable<LoginProgress<QrProgress>>,
277}
278
279impl LoginWithQrCode<'_> {
280 pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress<QrProgress>> + use<> {
286 self.state.subscribe()
287 }
288}
289
290impl<'a> IntoFuture for LoginWithQrCode<'a> {
291 type Output = Result<(), QRCodeLoginError>;
292 boxed_into_future!(extra_bounds: 'a);
293
294 fn into_future(self) -> Self::IntoFuture {
295 Box::pin(async move {
296 let channel = self.establish_secure_channel().await?;
305
306 trace!("Established the secure channel.");
307
308 let check_code = channel.check_code().to_owned();
312 self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
313
314 finish_login(self.client, channel, self.registration_data, self.state).await
321 })
322 }
323}
324
325impl<'a> LoginWithQrCode<'a> {
326 pub(crate) fn new(
327 client: &'a Client,
328 qr_code_data: &'a QrCodeData,
329 registration_data: Option<&'a ClientRegistrationData>,
330 ) -> LoginWithQrCode<'a> {
331 LoginWithQrCode { client, registration_data, qr_code_data, state: Default::default() }
332 }
333
334 async fn establish_secure_channel(
335 &self,
336 ) -> Result<EstablishedSecureChannel, SecureChannelError> {
337 let http_client = self.client.inner.http_client.inner.clone();
338
339 let channel = EstablishedSecureChannel::from_qr_code(
340 http_client,
341 self.qr_code_data,
342 QrCodeIntent::Login,
343 )
344 .await?;
345
346 Ok(channel)
347 }
348}
349
350#[derive(Debug)]
353pub struct LoginWithGeneratedQrCode<'a> {
354 client: &'a Client,
355 registration_data: Option<&'a ClientRegistrationData>,
356 state: SharedObservable<LoginProgress<GeneratedQrProgress>>,
357}
358
359impl LoginWithGeneratedQrCode<'_> {
360 pub fn subscribe_to_progress(
365 &self,
366 ) -> impl Stream<Item = LoginProgress<GeneratedQrProgress>> + use<> {
367 self.state.subscribe()
368 }
369}
370
371impl<'a> IntoFuture for LoginWithGeneratedQrCode<'a> {
372 type Output = Result<(), QRCodeLoginError>;
373 boxed_into_future!(extra_bounds: 'a);
374
375 fn into_future(self) -> Self::IntoFuture {
376 Box::pin(async move {
377 let mut channel = self.establish_secure_channel().await?;
380
381 trace!("Established the secure channel.");
382
383 let message = channel.receive_json().await?;
387
388 let homeserver = match message {
391 QrAuthMessage::LoginProtocols { protocols, homeserver } => {
392 if !protocols.contains(&LoginProtocolType::DeviceAuthorizationGrant) {
393 channel
394 .send_json(QrAuthMessage::LoginFailure {
395 reason: LoginFailureReason::UnsupportedProtocol,
396 homeserver: None,
397 })
398 .await?;
399
400 return Err(QRCodeLoginError::LoginFailure {
401 reason: LoginFailureReason::UnsupportedProtocol,
402 homeserver: None,
403 });
404 }
405
406 homeserver
407 }
408 _ => {
409 send_unexpected_message_error(&mut channel).await?;
410
411 return Err(QRCodeLoginError::UnexpectedMessage {
412 expected: "m.login.protocols",
413 received: Box::new(message),
414 });
415 }
416 };
417
418 if self.client.homeserver() != homeserver {
421 self.client
422 .switch_homeserver_and_re_resolve_well_known(homeserver)
423 .await
424 .map_err(QRCodeLoginError::ServerReset)?;
425 }
426
427 finish_login(self.client, channel, self.registration_data, self.state).await
430 })
431 }
432}
433
434impl<'a> LoginWithGeneratedQrCode<'a> {
435 pub(crate) fn new(
436 client: &'a Client,
437 registration_data: Option<&'a ClientRegistrationData>,
438 ) -> Self {
439 Self { client, registration_data, state: Default::default() }
440 }
441
442 async fn establish_secure_channel(
443 &self,
444 ) -> Result<EstablishedSecureChannel, SecureChannelError> {
445 let http_client = self.client.inner.http_client.clone();
446
447 let secure_channel = SecureChannel::login(http_client, &self.client.homeserver()).await?;
451
452 let qr_code_data = secure_channel.qr_code_data().clone();
456 trace!("Generated QR code.");
457 self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(
458 qr_code_data,
459 )));
460
461 let channel = secure_channel.connect().await?;
465
466 trace!("Waiting for checkcode.");
471 let (tx, rx) = tokio::sync::oneshot::channel();
472 self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
473 CheckCodeSender::new(tx),
474 )));
475
476 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
480 trace!("Received check code.");
481 channel.confirm(check_code)
482 }
483}
484
485#[cfg(all(test, not(target_family = "wasm")))]
486mod test {
487 use std::time::Duration;
488
489 use assert_matches2::{assert_let, assert_matches};
490 use futures_util::StreamExt;
491 use matrix_sdk_base::crypto::types::{
492 SecretsBundle,
493 qr_login::{Msc4108IntentData, QrCodeIntentData},
494 };
495 use matrix_sdk_common::executor::spawn;
496 use matrix_sdk_test::async_test;
497 use serde_json::json;
498
499 use super::*;
500 use crate::{
501 authentication::oauth::qrcode::{
502 messages::LoginProtocolType,
503 secure_channel::{SecureChannel, test::MockedRendezvousServer},
504 },
505 config::RequestConfig,
506 http_client::HttpClient,
507 test_utils::{client::oauth::mock_client_metadata, mocks::MatrixMockServer},
508 };
509
510 enum AliceBehaviour {
511 HappyPath,
512 DeclinedProtocol,
513 UnexpectedMessage,
514 UnexpectedMessageInsteadOfSecrets,
515 RefuseSecrets,
516 LetSessionExpire,
517 }
518
519 enum TokenResponse {
521 Ok,
522 AccessDenied,
523 ExpiredToken,
524 }
525
526 fn secrets_bundle() -> SecretsBundle {
527 let json = json!({
528 "cross_signing": {
529 "master_key": "rTtSv67XGS6k/rg6/yTG/m573cyFTPFRqluFhQY+hSw",
530 "self_signing_key": "4jbPt7jh5D2iyM4U+3IDa+WthgJB87IQN1ATdkau+xk",
531 "user_signing_key": "YkFKtkjcsTxF6UAzIIG/l6Nog/G2RigCRfWj3cjNWeM",
532 },
533 });
534
535 serde_json::from_value(json).expect("We should be able to deserialize a secrets bundle")
536 }
537
538 async fn grant_login(
541 alice: SecureChannel,
542 check_code_receiver: tokio::sync::oneshot::Receiver<u8>,
543 behavior: AliceBehaviour,
544 ) {
545 let alice = alice.connect().await.expect("Alice should be able to connect the channel");
546
547 let check_code =
548 check_code_receiver.await.expect("We should receive the check code from bob");
549
550 let mut alice =
551 alice.confirm(check_code).expect("Alice should be able to confirm the secure channel");
552
553 let message = alice
554 .receive_json()
555 .await
556 .expect("Alice should be able to receive the initial message from Bob");
557
558 assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
559 assert_eq!(protocol, LoginProtocolType::DeviceAuthorizationGrant);
560
561 let message = match behavior {
562 AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
563 reason: LoginFailureReason::UnsupportedProtocol,
564 homeserver: None,
565 },
566 AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
567 _ => QrAuthMessage::LoginProtocolAccepted,
568 };
569
570 alice.send_json(message).await.unwrap();
571
572 let message: QrAuthMessage = alice.receive_json().await.unwrap();
573 assert_let!(QrAuthMessage::LoginSuccess = message);
574
575 let message = match behavior {
576 AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
577 AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
578 reason: LoginFailureReason::DeviceNotFound,
579 homeserver: None,
580 },
581 _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
582 };
583
584 alice.send_json(message).await.unwrap();
585 }
586
587 #[async_test]
588 async fn test_qr_login() {
589 let server = MatrixMockServer::new().await;
590 let rendezvous_server =
591 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
592 let (sender, receiver) = tokio::sync::oneshot::channel();
593
594 let oauth_server = server.oauth();
595 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
596 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
597 oauth_server
598 .mock_device_authorization()
599 .ok()
600 .expect(1)
601 .named("device_authorization")
602 .mount()
603 .await;
604 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
605
606 server.mock_versions().ok().expect(1..).named("versions").mount().await;
607 server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
608 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
609 server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
610
611 let client = HttpClient::new(reqwest::Client::new(), Default::default());
612 let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
613 .await
614 .expect("Alice should be able to create a secure channel.");
615
616 assert_let!(
617 QrCodeIntentData::Msc4108 {
618 data: Msc4108IntentData::Reciprocate { server_name },
619 ..
620 } = &alice.qr_code_data().intent_data()
621 );
622
623 let bob = Client::builder()
624 .server_name_or_homeserver_url(server_name)
625 .request_config(RequestConfig::new().disable_retry())
626 .build()
627 .await
628 .expect("We should be able to build the Client object from the URL in the QR code");
629
630 let qr_code = alice.qr_code_data().clone();
631
632 let oauth = bob.oauth();
633 let registration_data = mock_client_metadata().into();
634 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
635 let mut updates = login_bob.subscribe_to_progress();
636
637 let updates_task = spawn(async move {
638 let mut sender = Some(sender);
639
640 while let Some(update) = updates.next().await {
641 match update {
642 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
643 sender
644 .take()
645 .expect("The establishing secure channel update should be received only once")
646 .send(check_code)
647 .expect("Bob should be able to send the check code to Alice");
648 }
649 LoginProgress::Done => break,
650 _ => (),
651 }
652 }
653 });
654 let alice_task =
655 spawn(async { grant_login(alice, receiver, AliceBehaviour::HappyPath).await });
656
657 login_bob.await.expect("Bob should be able to login");
659 alice_task.await.expect("Alice should have completed it's task successfully");
660 updates_task.await.unwrap();
661
662 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
663 let own_identity =
664 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
665
666 assert!(own_identity.is_verified());
667 }
668
669 async fn grant_login_with_generated_qr(
670 alice: &Client,
671 qr_receiver: tokio::sync::oneshot::Receiver<QrCodeData>,
672 cctx_receiver: tokio::sync::oneshot::Receiver<CheckCodeSender>,
673 behavior: AliceBehaviour,
674 ) {
675 let qr_code_data = qr_receiver.await.expect("Alice should receive the QR code");
676
677 let mut channel = EstablishedSecureChannel::from_qr_code(
678 alice.inner.http_client.inner.clone(),
679 &qr_code_data,
680 QrCodeIntent::Reciprocate,
681 )
682 .await
683 .expect("Alice should be able to establish the secure channel");
684
685 trace!("Established the secure channel.");
686
687 let check_code = channel.check_code();
690
691 let check_code_sender =
692 cctx_receiver.await.expect("Alice should receive the CheckCodeSender");
693
694 check_code_sender
695 .send(check_code)
696 .await
697 .expect("Alice should be able to send the check code to Bob");
698
699 let message = QrAuthMessage::LoginProtocols {
701 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
702 homeserver: alice.homeserver(),
703 };
704 channel
705 .send_json(message)
706 .await
707 .expect("Alice should be able to send the `m.login.protocols` message to Bob");
708
709 let message: QrAuthMessage = channel
711 .receive_json()
712 .await
713 .expect("Alice should be able to receive the `m.login.protocol` message from Bob");
714 assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
715 assert_eq!(protocol, LoginProtocolType::DeviceAuthorizationGrant);
716
717 let message = match behavior {
719 AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
720 reason: LoginFailureReason::UnsupportedProtocol,
721 homeserver: None,
722 },
723 AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
724 _ => QrAuthMessage::LoginProtocolAccepted,
725 };
726 channel
727 .send_json(message)
728 .await
729 .expect("Alice should be able to send the `m.login.protocol_accepted` message to Bob");
730
731 let message: QrAuthMessage = channel
732 .receive_json()
733 .await
734 .expect("Alice should be able to receive the `m.login.success` message from Bob");
735 assert_let!(QrAuthMessage::LoginSuccess = message);
736
737 let message = match behavior {
739 AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
740 AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
741 reason: LoginFailureReason::DeviceNotFound,
742 homeserver: None,
743 },
744 _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
745 };
746 channel
747 .send_json(message)
748 .await
749 .expect("Alice should be able to send the `m.login.secrets` message to Bob");
750 }
751
752 #[async_test]
753 async fn test_generated_qr_login() {
754 let server = MatrixMockServer::new().await;
755 let rendezvous_server =
756 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
757 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
758 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
759
760 let oauth_server = server.oauth();
761 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
762 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
763 oauth_server
764 .mock_device_authorization()
765 .ok()
766 .expect(1)
767 .named("device_authorization")
768 .mount()
769 .await;
770 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
771
772 server.mock_versions().ok().expect(1..).named("versions").mount().await;
773 server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
774 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
775 server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
776
777 let homeserver_url = rendezvous_server.homeserver_url.clone();
778
779 let alice = server.client_builder().logged_in_with_oauth().build().await;
782 assert!(alice.session_meta().is_some(), "Alice should be logged in");
783
784 let bob = Client::builder()
786 .server_name_or_homeserver_url(&homeserver_url)
787 .request_config(RequestConfig::new().disable_retry())
788 .build()
789 .await
790 .expect("Should be able to create a client for Bob");
791
792 let secure_channel = SecureChannel::login(bob.inner.http_client.clone(), &homeserver_url)
793 .await
794 .expect("Bob should be able to create a secure channel");
795
796 assert_matches!(
797 secure_channel.qr_code_data().intent_data(),
798 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
799 );
800
801 let registration_data = mock_client_metadata().into();
802 let bob_oauth = bob.oauth();
803 let bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
804 let mut bob_updates = bob_login.subscribe_to_progress();
805
806 let updates_task = spawn(async move {
807 let mut qr_sender = Some(qr_sender);
808 let mut cctx_sender = Some(cctx_sender);
809
810 while let Some(update) = bob_updates.next().await {
811 match update {
812 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
813 qr_sender
814 .take()
815 .expect("The establishing secure channel update with a qr code should be received only once")
816 .send(qr)
817 .expect("Bob should be able to send the qr code code to Alice");
818 }
819 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
820 cctx,
821 )) => {
822 cctx_sender
823 .take()
824 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
825 .send(cctx)
826 .expect("Bob should be able to send the qr code code to Alice");
827 }
828 LoginProgress::Done => break,
829 _ => (),
830 }
831 }
832 });
833
834 let alice_task = spawn(async move {
835 grant_login_with_generated_qr(
836 &alice,
837 qr_receiver,
838 cctx_receiver,
839 AliceBehaviour::HappyPath,
840 )
841 .await
842 });
843
844 bob_login.await.expect("Bob should be able to login");
846 alice_task.await.expect("Alice should have completed it's task successfully");
847 updates_task.await.unwrap();
848
849 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
850 let own_identity =
851 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
852
853 assert!(own_identity.is_verified());
854 }
855
856 #[async_test]
857 async fn test_generated_qr_login_with_homeserver_swap() {
858 let initial_server = MatrixMockServer::new().await;
859 let rendezvous_server =
860 MockedRendezvousServer::new(initial_server.server(), "abcdEFG12345", Duration::MAX)
861 .await;
862 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
863 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
864
865 let login_server = MatrixMockServer::new().await;
866 let oauth_server = login_server.oauth();
867 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
868 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
869 oauth_server
870 .mock_device_authorization()
871 .ok()
872 .expect(1)
873 .named("device_authorization")
874 .mount()
875 .await;
876 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
877
878 initial_server.mock_versions().ok().expect(1..).named("versions").mount().await;
879
880 login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
881 login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
882 login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
883 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
884 login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
885
886 let rendezvous_homeserver_url = rendezvous_server.homeserver_url.clone();
887
888 let alice = login_server.client_builder().logged_in_with_oauth().build().await;
891 assert!(alice.session_meta().is_some(), "Alice should be logged in");
892
893 let bob = Client::builder()
895 .server_name_or_homeserver_url(&rendezvous_homeserver_url)
896 .request_config(RequestConfig::new().disable_retry())
897 .build()
898 .await
899 .expect("Should be able to create a client for Bob");
900
901 let secure_channel =
902 SecureChannel::login(bob.inner.http_client.clone(), &rendezvous_homeserver_url)
903 .await
904 .expect("Bob should be able to create a secure channel");
905
906 assert_matches!(
907 secure_channel.qr_code_data().intent_data(),
908 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
909 );
910
911 let initial_server_url = initial_server.server().uri().parse().unwrap();
913 assert_eq!(bob.homeserver(), initial_server_url);
914 let login_server_url = login_server.server().uri().parse().unwrap();
915 assert_eq!(alice.homeserver(), login_server_url);
916 assert_ne!(initial_server_url, login_server_url);
917
918 let registration_data = mock_client_metadata().into();
919 let bob_oauth = bob.oauth();
920 let bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
921 let mut bob_updates = bob_login.subscribe_to_progress();
922
923 let updates_task = spawn(async move {
924 let mut qr_sender = Some(qr_sender);
925 let mut cctx_sender = Some(cctx_sender);
926
927 while let Some(update) = bob_updates.next().await {
928 match update {
929 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
930 qr_sender
931 .take()
932 .expect("The establishing secure channel update with a qr code should be received only once")
933 .send(qr)
934 .expect("Bob should be able to send the qr code code to Alice");
935 }
936 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
937 cctx,
938 )) => {
939 cctx_sender
940 .take()
941 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
942 .send(cctx)
943 .expect("Bob should be able to send the qr code code to Alice");
944 }
945 LoginProgress::Done => break,
946 _ => (),
947 }
948 }
949 });
950
951 let alice_task = spawn(async move {
952 grant_login_with_generated_qr(
953 &alice,
954 qr_receiver,
955 cctx_receiver,
956 AliceBehaviour::HappyPath,
957 )
958 .await
959 });
960
961 bob_login.await.expect("Bob should be able to login");
963 alice_task.await.expect("Alice should have completed it's task successfully");
964 updates_task.await.unwrap();
965
966 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
967 let own_identity =
968 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
969
970 assert!(own_identity.is_verified());
971
972 assert_eq!(bob.homeserver(), login_server_url);
974 }
975
976 async fn test_failure(
977 token_response: TokenResponse,
978 alice_behavior: AliceBehaviour,
979 ) -> Result<(), QRCodeLoginError> {
980 let server = MatrixMockServer::new().await;
981 let expiration = match alice_behavior {
982 AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
983 _ => Duration::MAX,
984 };
985 let rendezvous_server =
986 MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration).await;
987 let (sender, receiver) = tokio::sync::oneshot::channel();
988
989 let oauth_server = server.oauth();
990 let expected_calls = match alice_behavior {
991 AliceBehaviour::LetSessionExpire => 0,
992 _ => 1,
993 };
994 oauth_server
995 .mock_server_metadata()
996 .ok()
997 .expect(expected_calls)
998 .named("server_metadata")
999 .mount()
1000 .await;
1001 oauth_server
1002 .mock_registration()
1003 .ok()
1004 .expect(expected_calls)
1005 .named("registration")
1006 .mount()
1007 .await;
1008 oauth_server
1009 .mock_device_authorization()
1010 .ok()
1011 .expect(expected_calls)
1012 .named("device_authorization")
1013 .mount()
1014 .await;
1015
1016 let token_mock = oauth_server.mock_token();
1017 let token_mock = match token_response {
1018 TokenResponse::Ok => token_mock.ok(),
1019 TokenResponse::AccessDenied => token_mock.access_denied(),
1020 TokenResponse::ExpiredToken => token_mock.expired_token(),
1021 };
1022 token_mock.named("token").mount().await;
1023
1024 server.mock_versions().ok().named("versions").mount().await;
1025 server.mock_who_am_i().ok().named("whoami").mount().await;
1026
1027 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1028 let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
1029 .await
1030 .expect("Alice should be able to create a secure channel.");
1031
1032 assert_let!(
1033 QrCodeIntentData::Msc4108 {
1034 data: Msc4108IntentData::Reciprocate { server_name },
1035 ..
1036 } = &alice.qr_code_data().intent_data()
1037 );
1038
1039 let bob = Client::builder()
1040 .server_name_or_homeserver_url(server_name)
1041 .request_config(RequestConfig::new().disable_retry())
1042 .build()
1043 .await
1044 .expect("We should be able to build the Client object from the URL in the QR code");
1045
1046 let qr_code = alice.qr_code_data().clone();
1047
1048 let oauth = bob.oauth();
1049 let registration_data = mock_client_metadata().into();
1050 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
1051 let mut updates = login_bob.subscribe_to_progress();
1052
1053 let _updates_task = spawn(async move {
1054 let mut sender = Some(sender);
1055
1056 while let Some(update) = updates.next().await {
1057 match update {
1058 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1059 sender
1060 .take()
1061 .expect("The establishing secure channel update should be received only once")
1062 .send(check_code)
1063 .expect("Bob should be able to send the check code to Alice");
1064 }
1065 LoginProgress::Done => break,
1066 _ => (),
1067 }
1068 }
1069 });
1070
1071 if !matches!(alice_behavior, AliceBehaviour::LetSessionExpire) {
1072 let _alice_task =
1073 spawn(async move { grant_login(alice, receiver, alice_behavior).await });
1074 }
1075
1076 login_bob.await
1077 }
1078
1079 async fn test_generated_failure(
1080 token_response: TokenResponse,
1081 alice_behavior: AliceBehaviour,
1082 ) -> Result<(), QRCodeLoginError> {
1083 let server = MatrixMockServer::new().await;
1084 let expiration = match alice_behavior {
1085 AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1086 _ => Duration::MAX,
1087 };
1088 let rendezvous_server =
1089 MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration).await;
1090
1091 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1092 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1093
1094 let oauth_server = server.oauth();
1095 let expected_calls = match alice_behavior {
1096 AliceBehaviour::LetSessionExpire => 0,
1097 _ => 1,
1098 };
1099 oauth_server
1100 .mock_server_metadata()
1101 .ok()
1102 .expect(expected_calls)
1103 .named("server_metadata")
1104 .mount()
1105 .await;
1106 oauth_server
1107 .mock_registration()
1108 .ok()
1109 .expect(expected_calls)
1110 .named("registration")
1111 .mount()
1112 .await;
1113 oauth_server
1114 .mock_device_authorization()
1115 .ok()
1116 .expect(expected_calls)
1117 .named("device_authorization")
1118 .mount()
1119 .await;
1120
1121 let token_mock = oauth_server.mock_token();
1122 let token_mock = match token_response {
1123 TokenResponse::Ok => token_mock.ok(),
1124 TokenResponse::AccessDenied => token_mock.access_denied(),
1125 TokenResponse::ExpiredToken => token_mock.expired_token(),
1126 };
1127 token_mock.named("token").mount().await;
1128
1129 server.mock_versions().ok().named("versions").mount().await;
1130 server.mock_who_am_i().ok().named("whoami").mount().await;
1131
1132 let homeserver_url = rendezvous_server.homeserver_url.clone();
1133
1134 let alice = server.client_builder().logged_in_with_oauth().build().await;
1137 assert!(alice.session_meta().is_some(), "Alice should be logged in");
1138
1139 let bob = Client::builder()
1141 .server_name_or_homeserver_url(&homeserver_url)
1142 .request_config(RequestConfig::new().disable_retry())
1143 .build()
1144 .await
1145 .expect("Should be able to create a client for Bob");
1146
1147 let secure_channel = SecureChannel::login(bob.inner.http_client.clone(), &homeserver_url)
1148 .await
1149 .expect("Bob should be able to create a secure channel");
1150
1151 assert_matches!(
1152 secure_channel.qr_code_data().intent_data(),
1153 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1154 );
1155
1156 let registration_data = mock_client_metadata().into();
1157 let bob_oauth = bob.oauth();
1158 let bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
1159 let mut bob_updates = bob_login.subscribe_to_progress();
1160
1161 let _updates_task = spawn(async move {
1162 let mut qr_sender = Some(qr_sender);
1163 let mut cctx_sender = Some(cctx_sender);
1164
1165 while let Some(update) = bob_updates.next().await {
1166 match update {
1167 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1168 qr_sender
1169 .take()
1170 .expect("The establishing secure channel update with a qr code should be received only once")
1171 .send(qr)
1172 .expect("Bob should be able to send the qr code code to Alice");
1173 }
1174 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1175 cctx,
1176 )) => {
1177 cctx_sender
1178 .take()
1179 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1180 .send(cctx)
1181 .expect("Bob should be able to send the qr code code to Alice");
1182 }
1183 LoginProgress::Done => break,
1184 _ => (),
1185 }
1186 }
1187 });
1188
1189 if !matches!(alice_behavior, AliceBehaviour::LetSessionExpire) {
1190 let _alice_task = spawn(async move {
1191 grant_login_with_generated_qr(&alice, qr_receiver, cctx_receiver, alice_behavior)
1192 .await
1193 });
1194 }
1195
1196 bob_login.await
1197 }
1198
1199 #[async_test]
1200 async fn test_qr_login_refused_access_token() {
1201 let result = test_failure(TokenResponse::AccessDenied, AliceBehaviour::HappyPath).await;
1202
1203 assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1204 assert_eq!(
1205 e.as_request_token_error(),
1206 Some(&DeviceCodeErrorResponseType::AccessDenied),
1207 "The server should have told us that access has been denied."
1208 );
1209 }
1210
1211 #[async_test]
1212 async fn test_generated_qr_login_refused_access_token() {
1213 let result =
1214 test_generated_failure(TokenResponse::AccessDenied, AliceBehaviour::HappyPath).await;
1215
1216 assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1217 assert_eq!(
1218 e.as_request_token_error(),
1219 Some(&DeviceCodeErrorResponseType::AccessDenied),
1220 "The server should have told us that access has been denied."
1221 );
1222 }
1223
1224 #[async_test]
1225 async fn test_qr_login_expired_token() {
1226 let result = test_failure(TokenResponse::ExpiredToken, AliceBehaviour::HappyPath).await;
1227
1228 assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1229 assert_eq!(
1230 e.as_request_token_error(),
1231 Some(&DeviceCodeErrorResponseType::ExpiredToken),
1232 "The server should have told us that access has been denied."
1233 );
1234 }
1235
1236 #[async_test]
1237 async fn test_generated_qr_login_expired_token() {
1238 let result =
1239 test_generated_failure(TokenResponse::ExpiredToken, AliceBehaviour::HappyPath).await;
1240
1241 assert_let!(Err(QRCodeLoginError::OAuth(e)) = result);
1242 assert_eq!(
1243 e.as_request_token_error(),
1244 Some(&DeviceCodeErrorResponseType::ExpiredToken),
1245 "The server should have told us that access has been denied."
1246 );
1247 }
1248
1249 #[async_test]
1250 async fn test_qr_login_declined_protocol() {
1251 let result = test_failure(TokenResponse::Ok, AliceBehaviour::DeclinedProtocol).await;
1252
1253 assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1254 assert_eq!(
1255 reason,
1256 LoginFailureReason::UnsupportedProtocol,
1257 "Alice should have told us that the protocol is unsupported."
1258 );
1259 }
1260
1261 #[async_test]
1262 async fn test_generated_qr_login_declined_protocol() {
1263 let result =
1264 test_generated_failure(TokenResponse::Ok, AliceBehaviour::DeclinedProtocol).await;
1265
1266 assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1267 assert_eq!(
1268 reason,
1269 LoginFailureReason::UnsupportedProtocol,
1270 "Alice should have told us that the protocol is unsupported."
1271 );
1272 }
1273
1274 #[async_test]
1275 async fn test_qr_login_unexpected_message() {
1276 let result = test_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessage).await;
1277
1278 assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1279 assert_eq!(expected, "m.login.protocol_accepted");
1280 }
1281
1282 #[async_test]
1283 async fn test_generated_qr_login_unexpected_message() {
1284 let result =
1285 test_generated_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessage).await;
1286
1287 assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1288 assert_eq!(expected, "m.login.protocol_accepted");
1289 }
1290
1291 #[async_test]
1292 async fn test_qr_login_unexpected_message_instead_of_secrets() {
1293 let result =
1294 test_failure(TokenResponse::Ok, AliceBehaviour::UnexpectedMessageInsteadOfSecrets)
1295 .await;
1296
1297 assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1298 assert_eq!(expected, "m.login.secrets");
1299 }
1300
1301 #[async_test]
1302 async fn test_generated_qr_login_unexpected_message_instead_of_secrets() {
1303 let result = test_generated_failure(
1304 TokenResponse::Ok,
1305 AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
1306 )
1307 .await;
1308
1309 assert_let!(Err(QRCodeLoginError::UnexpectedMessage { expected, .. }) = result);
1310 assert_eq!(expected, "m.login.secrets");
1311 }
1312
1313 #[async_test]
1314 async fn test_qr_login_refuse_secrets() {
1315 let result = test_failure(TokenResponse::Ok, AliceBehaviour::RefuseSecrets).await;
1316
1317 assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1318 assert_eq!(reason, LoginFailureReason::DeviceNotFound);
1319 }
1320
1321 #[async_test]
1322 async fn test_generated_qr_login_refuse_secrets() {
1323 let result = test_generated_failure(TokenResponse::Ok, AliceBehaviour::RefuseSecrets).await;
1324
1325 assert_let!(Err(QRCodeLoginError::LoginFailure { reason, .. }) = result);
1326 assert_eq!(reason, LoginFailureReason::DeviceNotFound);
1327 }
1328
1329 #[async_test]
1330 async fn test_qr_login_session_expired() {
1331 let result = test_failure(TokenResponse::Ok, AliceBehaviour::LetSessionExpire).await;
1332
1333 assert_matches!(result, Err(QRCodeLoginError::NotFound));
1334 }
1335
1336 #[async_test]
1337 async fn test_generated_qr_login_session_expired() {
1338 let result =
1339 test_generated_failure(TokenResponse::Ok, AliceBehaviour::LetSessionExpire).await;
1340
1341 assert_matches!(result, Err(QRCodeLoginError::NotFound));
1342 }
1343
1344 #[async_test]
1345 async fn test_device_authorization_endpoint_missing() {
1346 let server = MatrixMockServer::new().await;
1347 let rendezvous_server =
1348 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1349 let (sender, receiver) = tokio::sync::oneshot::channel();
1350
1351 let oauth_server = server.oauth();
1352 oauth_server
1353 .mock_server_metadata()
1354 .ok_without_device_authorization()
1355 .expect(1)
1356 .named("server_metadata")
1357 .mount()
1358 .await;
1359 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1360
1361 server.mock_versions().ok().named("versions").mount().await;
1362 server.mock_who_am_i().ok().named("whoami").mount().await;
1363
1364 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1365 let alice = SecureChannel::reciprocate(client, &rendezvous_server.homeserver_url)
1366 .await
1367 .expect("Alice should be able to create a secure channel.");
1368
1369 assert_let!(
1370 QrCodeIntentData::Msc4108 {
1371 data: Msc4108IntentData::Reciprocate { server_name },
1372 ..
1373 } = &alice.qr_code_data().intent_data()
1374 );
1375
1376 let bob = Client::builder()
1377 .server_name_or_homeserver_url(server_name)
1378 .request_config(RequestConfig::new().disable_retry())
1379 .build()
1380 .await
1381 .expect("We should be able to build the Client object from the URL in the QR code");
1382
1383 let qr_code = alice.qr_code_data().clone();
1384
1385 let oauth = bob.oauth();
1386 let registration_data = mock_client_metadata().into();
1387 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
1388 let mut updates = login_bob.subscribe_to_progress();
1389
1390 let _updates_task = spawn(async move {
1391 let mut sender = Some(sender);
1392
1393 while let Some(update) = updates.next().await {
1394 match update {
1395 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1396 sender
1397 .take()
1398 .expect("The establishing secure channel update should be received only once")
1399 .send(check_code)
1400 .expect("Bob should be able to send the check code to Alice");
1401 }
1402 LoginProgress::Done => break,
1403 _ => (),
1404 }
1405 }
1406 });
1407 let _alice_task =
1408 spawn(async move { grant_login(alice, receiver, AliceBehaviour::HappyPath).await });
1409 let error = login_bob.await.unwrap_err();
1410
1411 assert_matches!(
1412 error,
1413 QRCodeLoginError::OAuth(DeviceAuthorizationOAuthError::NoDeviceAuthorizationEndpoint)
1414 );
1415 }
1416}