1use std::time::Duration;
16
17use eyeball::SharedObservable;
18use futures_core::Stream;
19use matrix_sdk_base::{
20 boxed_into_future,
21 crypto::types::{
22 SecretsBundle,
23 qr_login::{QrCodeData, QrCodeIntent},
24 },
25};
26use oauth2::VerificationUriComplete;
27use ruma::time::Instant;
28use url::Url;
29#[cfg(doc)]
30use vodozemac::ecies::CheckCode;
31
32use super::{
33 LoginProtocolType, QrAuthMessage,
34 secure_channel::{EstablishedSecureChannel, SecureChannel},
35};
36use crate::{
37 Client,
38 authentication::oauth::qrcode::{
39 CheckCodeSender, CloneableSender, ContinuationMessage, ContinuationMessageSender,
40 GeneratedQrProgress, LoginFailureReason, QRCodeGrantLoginError, QrProgress,
41 SecureChannelError,
42 },
43};
44
45async fn export_secrets_bundle(client: &Client) -> Result<SecretsBundle, QRCodeGrantLoginError> {
46 let secrets_bundle = client
47 .olm_machine()
48 .await
49 .as_ref()
50 .ok_or_else(|| QRCodeGrantLoginError::MissingSecretsBackup(None))?
51 .store()
52 .export_secrets_bundle()
53 .await?;
54 Ok(secrets_bundle)
55}
56
57async fn finish_login_grant<Q>(
58 client: &Client,
59 channel: &mut EstablishedSecureChannel,
60 device_creation_timeout: Duration,
61 secrets_bundle: &SecretsBundle,
62 state: &SharedObservable<GrantLoginProgress<Q>>,
63) -> Result<(), QRCodeGrantLoginError> {
64 let (device_authorization_grant, protocol, device_id) = match channel.receive_json().await? {
71 QrAuthMessage::LoginProtocol { device_authorization_grant, protocol, device_id } => {
72 (device_authorization_grant, protocol, device_id)
73 }
74 QrAuthMessage::LoginFailure { reason, .. } => {
75 return Err(QRCodeGrantLoginError::LoginFailure { reason });
76 }
77 message => {
78 return Err(QRCodeGrantLoginError::UnexpectedMessage {
79 expected: "m.login.protocol",
80 received: Box::new(message),
81 });
82 }
83 };
84
85 if protocol != LoginProtocolType::DeviceAuthorizationGrant {
88 channel
89 .send_json(QrAuthMessage::LoginFailure {
90 reason: LoginFailureReason::UnsupportedProtocol,
91 homeserver: None,
92 })
93 .await?;
94 return Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol));
95 }
96
97 if !matches!(client.device_exists(device_id.clone().into()).await, Ok(false)) {
100 channel
101 .send_json(QrAuthMessage::LoginFailure {
102 reason: LoginFailureReason::DeviceAlreadyExists,
103 homeserver: None,
104 })
105 .await?;
106 return Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse);
107 }
108
109 let verification_uri = Url::parse(
113 device_authorization_grant
114 .verification_uri_complete
115 .map(VerificationUriComplete::into_secret)
116 .unwrap_or(device_authorization_grant.verification_uri.to_string())
117 .as_str(),
118 )
119 .map_err(|e| QRCodeGrantLoginError::Unknown(e.to_string()))?;
120
121 let (sender, receiver) = tokio::sync::oneshot::channel();
122 state.set(GrantLoginProgress::WaitingForAuth {
123 verification_uri,
124 continuation_sender: ContinuationMessageSender(CloneableSender::new(sender)),
125 });
126
127 match receiver.await {
130 Ok(ContinuationMessage::Confirm) => {}
131 Ok(ContinuationMessage::Cancel) | Err(_) => {
132 channel
133 .send_json(QrAuthMessage::LoginFailure {
134 reason: LoginFailureReason::UserCancelled,
135 homeserver: None,
136 })
137 .await?;
138 return Err(QRCodeGrantLoginError::LoginFailure {
139 reason: LoginFailureReason::UserCancelled,
140 });
141 }
142 }
143 let message = QrAuthMessage::LoginProtocolAccepted;
147 channel.send_json(&message).await?;
148
149 match channel.receive_json().await? {
158 QrAuthMessage::LoginSuccess => (),
159 QrAuthMessage::LoginFailure { reason, .. } => {
160 return Err(QRCodeGrantLoginError::LoginFailure { reason });
161 }
162 message => {
163 return Err(QRCodeGrantLoginError::UnexpectedMessage {
164 expected: "m.login.success",
165 received: Box::new(message),
166 });
167 }
168 }
169
170 let deadline = Instant::now() + device_creation_timeout;
173
174 loop {
175 if matches!(client.device_exists(device_id.clone().into()).await, Ok(true)) {
176 break;
177 } else {
178 if Instant::now() < deadline {
180 matrix_sdk_common::sleep::sleep(Duration::from_millis(500)).await;
181 continue;
182 } else {
183 channel
185 .send_json(QrAuthMessage::LoginFailure {
186 reason: LoginFailureReason::DeviceNotFound,
187 homeserver: None,
188 })
189 .await?;
190 return Err(QRCodeGrantLoginError::DeviceNotFound);
191 }
192 }
193 }
194
195 state.set(GrantLoginProgress::SyncingSecrets);
198 let message = QrAuthMessage::LoginSecrets(secrets_bundle.clone());
199 channel.send_json(&message).await?;
200
201 state.set(GrantLoginProgress::Done);
203
204 Ok(())
205}
206
207#[derive(Clone, Debug, Default)]
209pub enum GrantLoginProgress<Q> {
210 #[default]
212 Starting,
213 EstablishingSecureChannel(Q),
216 WaitingForAuth {
219 verification_uri: Url,
221 continuation_sender: ContinuationMessageSender,
227 },
228 SyncingSecrets,
231 Done,
233}
234
235#[derive(Debug)]
238pub struct GrantLoginWithScannedQrCode<'a> {
239 client: &'a Client,
240 qr_code_data: &'a QrCodeData,
241 device_creation_timeout: Duration,
242 state: SharedObservable<GrantLoginProgress<QrProgress>>,
243}
244
245impl<'a> GrantLoginWithScannedQrCode<'a> {
246 pub(crate) fn new(
247 client: &'a Client,
248 qr_code_data: &'a QrCodeData,
249 device_creation_timeout: Duration,
250 ) -> GrantLoginWithScannedQrCode<'a> {
251 GrantLoginWithScannedQrCode {
252 client,
253 qr_code_data,
254 device_creation_timeout,
255 state: Default::default(),
256 }
257 }
258}
259
260impl GrantLoginWithScannedQrCode<'_> {
261 pub fn subscribe_to_progress(
267 &self,
268 ) -> impl Stream<Item = GrantLoginProgress<QrProgress>> + use<> {
269 self.state.subscribe()
270 }
271}
272
273impl<'a> IntoFuture for GrantLoginWithScannedQrCode<'a> {
274 type Output = Result<(), QRCodeGrantLoginError>;
275 boxed_into_future!(extra_bounds: 'a);
276
277 fn into_future(self) -> Self::IntoFuture {
278 Box::pin(async move {
279 let secrets_bundle = export_secrets_bundle(self.client).await?;
289
290 let mut channel = EstablishedSecureChannel::from_qr_code(
291 self.client.inner.http_client.inner.clone(),
292 self.qr_code_data,
293 QrCodeIntent::Reciprocate,
294 )
295 .await?;
296
297 let check_code = channel.check_code().to_owned();
301 self.state
302 .set(GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
303
304 let message = QrAuthMessage::LoginProtocols {
312 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
313 homeserver: self.client.homeserver(),
314 };
315 channel.send_json(message).await?;
316
317 finish_login_grant(
320 self.client,
321 &mut channel,
322 self.device_creation_timeout,
323 &secrets_bundle,
324 &self.state,
325 )
326 .await
327 })
328 }
329}
330
331#[derive(Debug)]
334pub struct GrantLoginWithGeneratedQrCode<'a> {
335 client: &'a Client,
336 device_creation_timeout: Duration,
337 state: SharedObservable<GrantLoginProgress<GeneratedQrProgress>>,
338}
339
340impl<'a> GrantLoginWithGeneratedQrCode<'a> {
341 pub(crate) fn new(
342 client: &'a Client,
343 device_creation_timeout: Duration,
344 ) -> GrantLoginWithGeneratedQrCode<'a> {
345 GrantLoginWithGeneratedQrCode { client, device_creation_timeout, state: Default::default() }
346 }
347}
348
349impl GrantLoginWithGeneratedQrCode<'_> {
350 pub fn subscribe_to_progress(
357 &self,
358 ) -> impl Stream<Item = GrantLoginProgress<GeneratedQrProgress>> + use<> {
359 self.state.subscribe()
360 }
361}
362
363impl<'a> IntoFuture for GrantLoginWithGeneratedQrCode<'a> {
364 type Output = Result<(), QRCodeGrantLoginError>;
365 boxed_into_future!(extra_bounds: 'a);
366
367 fn into_future(self) -> Self::IntoFuture {
368 Box::pin(async move {
369 let homeserver_url = self.client.homeserver();
373 let http_client = self.client.inner.http_client.clone();
374 let secrets_bundle = export_secrets_bundle(self.client).await?;
375 let channel = SecureChannel::reciprocate(http_client, &homeserver_url).await?;
376
377 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
381 GeneratedQrProgress::QrReady(channel.qr_code_data().clone()),
382 ));
383
384 let channel = channel.connect().await?;
388
389 let (tx, rx) = tokio::sync::oneshot::channel();
394 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
395 GeneratedQrProgress::QrScanned(CheckCodeSender::new(tx)),
396 ));
397 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
398
399 let mut channel = channel.confirm(check_code)?;
402
403 finish_login_grant(
411 self.client,
412 &mut channel,
413 self.device_creation_timeout,
414 &secrets_bundle,
415 &self.state,
416 )
417 .await
418 })
419 }
420}
421
422#[cfg(all(test, not(target_family = "wasm")))]
423mod test {
424 use std::sync::Arc;
425
426 use assert_matches2::{assert_let, assert_matches};
427 use futures_util::StreamExt;
428 use matrix_sdk_base::crypto::types::SecretsBundle;
429 use matrix_sdk_common::executor::spawn;
430 use matrix_sdk_test::async_test;
431 use oauth2::{EndUserVerificationUrl, VerificationUriComplete};
432 use ruma::{owned_device_id, owned_user_id};
433 use tokio::sync::oneshot;
434 use tracing::debug;
435
436 use super::*;
437 use crate::{
438 authentication::oauth::qrcode::{
439 LoginFailureReason, QrAuthMessage,
440 messages::{AuthorizationGrant, LoginProtocolType},
441 secure_channel::{EstablishedSecureChannel, test::MockedRendezvousServer},
442 },
443 http_client::HttpClient,
444 test_utils::mocks::MatrixMockServer,
445 };
446
447 enum BobBehaviour {
448 HappyPath,
449 UnexpectedMessageInsteadOfLoginProtocol,
450 LoginFailureInsteadOfLoginProtocol,
451 UnexpectedMessageInsteadOfLoginSuccess,
452 LoginFailureInsteadOfLoginSuccess,
453 DeviceAlreadyExists,
454 DeviceNotCreated,
455 InvalidJsonMessage,
456 CancelledWhileWaitingForAuth,
457 }
458
459 #[allow(clippy::too_many_arguments)]
460 async fn request_login_with_scanned_qr_code(
461 behaviour: BobBehaviour,
462 qr_code_rx: oneshot::Receiver<QrCodeData>,
463 check_code_tx: oneshot::Sender<u8>,
464 server: Option<MatrixMockServer>,
465 _rendezvous_server: &MockedRendezvousServer,
469 device_authorization_grant: Option<AuthorizationGrant>,
470 secrets_bundle: Option<SecretsBundle>,
471 ) {
472 let qr_code_data = qr_code_rx.await.expect("Bob should receive the QR code");
474
475 let mut bob = EstablishedSecureChannel::from_qr_code(
477 reqwest::Client::new(),
478 &qr_code_data,
479 QrCodeIntent::Login,
480 )
481 .await
482 .expect("Bob should be able to connect the secure channel");
483
484 check_code_tx.send(bob.check_code()).expect("Bob should be able to send the checkcode");
486
487 match behaviour {
488 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
489 let message = QrAuthMessage::LoginSuccess;
491 bob.send_json(message).await.unwrap();
492 return;
493 }
494 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
495 let message = QrAuthMessage::LoginFailure {
497 reason: LoginFailureReason::UserCancelled,
498 homeserver: None,
499 };
500 bob.send_json(message).await.unwrap();
501 return;
502 }
503 BobBehaviour::InvalidJsonMessage => {
504 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
506 return;
507 }
508 BobBehaviour::DeviceAlreadyExists => {
509 server
512 .as_ref()
513 .expect("Bob needs the server for DeviceAlreadyExists")
514 .mock_get_device()
515 .ok()
516 .expect(1..)
517 .named("get_device")
518 .mount()
519 .await;
520
521 let message = QrAuthMessage::LoginProtocol {
523 protocol: LoginProtocolType::DeviceAuthorizationGrant,
524 device_authorization_grant: device_authorization_grant
525 .expect("Bob needs the device authorization grant"),
526 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
527 };
528 bob.send_json(message).await.unwrap();
529
530 let message = bob
532 .receive_json()
533 .await
534 .expect("Bob should receive the LoginFailure message from Alice");
535 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
536 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
537
538 return; }
540 BobBehaviour::CancelledWhileWaitingForAuth => {
541 let message = QrAuthMessage::LoginProtocol {
543 protocol: LoginProtocolType::DeviceAuthorizationGrant,
544 device_authorization_grant: device_authorization_grant
545 .expect("Bob needs the device authorization grant"),
546 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
547 };
548 bob.send_json(message).await.unwrap();
549
550 let message = bob
553 .receive_json()
554 .await
555 .expect("Bob should receive the LoginFailure message from Alice");
556 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
557 assert_matches!(reason, LoginFailureReason::UserCancelled);
558
559 return; }
561 _ => {
562 let message = QrAuthMessage::LoginProtocol {
564 protocol: LoginProtocolType::DeviceAuthorizationGrant,
565 device_authorization_grant: device_authorization_grant
566 .expect("Bob needs the device authorization grant"),
567 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
568 };
569 bob.send_json(message).await.unwrap();
570 }
571 }
572
573 let message = bob
575 .receive_json()
576 .await
577 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
578 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
579
580 match behaviour {
581 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
582 let message = QrAuthMessage::LoginProtocolAccepted;
584 bob.send_json(message).await.unwrap();
585 return;
586 }
587 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
588 let message = QrAuthMessage::LoginFailure {
590 reason: LoginFailureReason::AuthorizationExpired,
591 homeserver: None,
592 };
593 bob.send_json(message).await.unwrap();
594 return;
595 }
596 BobBehaviour::DeviceNotCreated => {
597 let message = QrAuthMessage::LoginSuccess;
602 bob.send_json(message).await.unwrap();
603
604 let message = bob
607 .receive_json()
608 .await
609 .expect("Bob should receive the LoginFailure message from Alice");
610 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
611 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
612
613 return; }
615 _ => {
616 server
619 .as_ref()
620 .expect("Bob needs the server for HappyPath")
621 .mock_get_device()
622 .ok()
623 .expect(1..)
624 .named("get_device")
625 .mount()
626 .await;
627
628 let message = QrAuthMessage::LoginSuccess;
630 bob.send_json(message).await.unwrap();
631 }
632 }
633
634 let message = bob
636 .receive_json()
637 .await
638 .expect("Bob should receive the LoginSecrets message from Alice");
639 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
640
641 assert_eq!(
643 serde_json::to_value(&secrets_bundle).unwrap(),
644 serde_json::to_value(&bundle).unwrap()
645 );
646 }
647
648 #[allow(clippy::too_many_arguments)]
649 async fn request_login_with_generated_qr_code(
650 behaviour: BobBehaviour,
651 channel: SecureChannel,
652 check_code_rx: oneshot::Receiver<u8>,
653 server: Option<MatrixMockServer>,
654 _rendezvous_server: &MockedRendezvousServer,
658 homeserver: Url,
659 device_authorization_grant: Option<AuthorizationGrant>,
660 secrets_bundle: Option<SecretsBundle>,
661 ) {
662 let channel =
664 channel.connect().await.expect("Bob should be able to connect the secure channel");
665
666 let check_code = check_code_rx.await.expect("Bob should receive the checkcode");
668 let mut bob = channel
669 .confirm(check_code)
670 .expect("Bob should be able to confirm the channel is secure");
671
672 let message = bob
674 .receive_json()
675 .await
676 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
677 assert_let!(
678 QrAuthMessage::LoginProtocols { protocols, homeserver: alice_homeserver } = message
679 );
680 assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
681 assert_eq!(alice_homeserver, homeserver);
682
683 match behaviour {
684 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
685 let message = QrAuthMessage::LoginSuccess;
687 bob.send_json(message).await.unwrap();
688 return;
689 }
690 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
691 let message = QrAuthMessage::LoginFailure {
693 reason: LoginFailureReason::UserCancelled,
694 homeserver: None,
695 };
696 bob.send_json(message).await.unwrap();
697 return;
698 }
699 BobBehaviour::InvalidJsonMessage => {
700 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
702 return;
703 }
704 BobBehaviour::DeviceAlreadyExists => {
705 server
708 .as_ref()
709 .expect("Bob needs the MatrixMockServer")
710 .mock_get_device()
711 .ok()
712 .expect(1..)
713 .named("get_device")
714 .mount()
715 .await;
716
717 let message = QrAuthMessage::LoginProtocol {
719 protocol: LoginProtocolType::DeviceAuthorizationGrant,
720 device_authorization_grant: device_authorization_grant
721 .expect("Bob needs the device authorization grant"),
722 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
723 };
724 bob.send_json(message).await.unwrap();
725
726 let message = bob
728 .receive_json()
729 .await
730 .expect("Bob should receive the LoginFailure message from Alice");
731 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
732 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
733
734 return; }
736 BobBehaviour::CancelledWhileWaitingForAuth => {
737 let message = QrAuthMessage::LoginProtocol {
739 protocol: LoginProtocolType::DeviceAuthorizationGrant,
740 device_authorization_grant: device_authorization_grant
741 .expect("Bob needs the device authorization grant"),
742 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
743 };
744 bob.send_json(message).await.unwrap();
745
746 let message = bob
749 .receive_json()
750 .await
751 .expect("Bob should receive the LoginFailure message from Alice");
752 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
753 assert_matches!(reason, LoginFailureReason::UserCancelled);
754
755 return; }
757 _ => {
758 let message = QrAuthMessage::LoginProtocol {
760 protocol: LoginProtocolType::DeviceAuthorizationGrant,
761 device_authorization_grant: device_authorization_grant
762 .expect("Bob needs the device authorization grant"),
763 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
764 };
765 bob.send_json(message).await.unwrap();
766 }
767 }
768
769 let message = bob
771 .receive_json()
772 .await
773 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
774 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
775
776 match behaviour {
777 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
778 let message = QrAuthMessage::LoginProtocolAccepted;
780 bob.send_json(message).await.unwrap();
781 return;
782 }
783 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
784 let message = QrAuthMessage::LoginFailure {
786 reason: LoginFailureReason::AuthorizationExpired,
787 homeserver: None,
788 };
789 bob.send_json(message).await.unwrap();
790 return;
791 }
792 BobBehaviour::DeviceNotCreated => {
793 let message = QrAuthMessage::LoginSuccess;
798 bob.send_json(message).await.unwrap();
799
800 let message = bob
803 .receive_json()
804 .await
805 .expect("Bob should receive the LoginFailure message from Alice");
806 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
807 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
808
809 return; }
811 _ => {
812 server
815 .as_ref()
816 .expect("Bob needs the MatrixMockServer")
817 .mock_get_device()
818 .ok()
819 .expect(1..)
820 .named("get_device")
821 .mount()
822 .await;
823
824 let message = QrAuthMessage::LoginSuccess;
826 bob.send_json(message).await.unwrap();
827 }
828 }
829
830 let message = bob
832 .receive_json()
833 .await
834 .expect("Bob should receive the LoginSecrets message from Alice");
835 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
836
837 assert_eq!(
839 serde_json::to_value(&secrets_bundle).unwrap(),
840 serde_json::to_value(&bundle).unwrap()
841 );
842 }
843
844 #[async_test]
845 async fn test_grant_login_with_generated_qr_code() {
846 let server = MatrixMockServer::new().await;
847 let rendezvous_server =
848 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
849 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
850
851 let device_authorization_grant = AuthorizationGrant {
852 verification_uri_complete: Some(VerificationUriComplete::new(
853 "https://id.matrix.org/device/abcde".to_owned(),
854 )),
855 verification_uri: EndUserVerificationUrl::new(
856 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
857 )
858 .unwrap(),
859 };
860
861 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
862 server
863 .mock_upload_cross_signing_keys()
864 .ok()
865 .expect(1)
866 .named("upload_xsigning_keys")
867 .mount()
868 .await;
869 server
870 .mock_upload_cross_signing_signatures()
871 .ok()
872 .expect(1)
873 .named("upload_xsigning_signatures")
874 .mount()
875 .await;
876
877 let user_id = owned_user_id!("@alice:example.org");
879 let device_id = owned_device_id!("ALICE_DEVICE");
880 let alice = server
881 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
882 .logged_in_with_oauth()
883 .build()
884 .await;
885 alice
886 .encryption()
887 .bootstrap_cross_signing(None)
888 .await
889 .expect("Alice should be able to set up cross signing");
890
891 let oauth = alice.oauth();
893 let grant = oauth
894 .grant_login_with_qr_code()
895 .device_creation_timeout(Duration::from_secs(2))
896 .generate();
897 let secrets_bundle = export_secrets_bundle(&alice)
898 .await
899 .expect("Alice should be able to export the secrets bundle");
900 let (qr_code_tx, qr_code_rx) = oneshot::channel();
901 let (checkcode_tx, checkcode_rx) = oneshot::channel();
902
903 let mut updates = grant.subscribe_to_progress();
905 let mut state = grant.state.get();
906 let verification_uri_complete =
907 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
908 assert_matches!(state.clone(), GrantLoginProgress::Starting);
909 let updates_task = spawn(async move {
910 let mut qr_code_tx = Some(qr_code_tx);
911 let mut checkcode_rx = Some(checkcode_rx);
912
913 while let Some(update) = updates.next().await {
914 match &update {
915 GrantLoginProgress::Starting => {
916 assert_matches!(state, GrantLoginProgress::Starting);
917 }
918 GrantLoginProgress::EstablishingSecureChannel(
919 GeneratedQrProgress::QrReady(qr_code_data),
920 ) => {
921 assert_matches!(state, GrantLoginProgress::Starting);
922 qr_code_tx
923 .take()
924 .expect("The QR code should only be forwarded once")
925 .send(qr_code_data.clone())
926 .expect("Alice should be able to forward the QR code");
927 }
928 GrantLoginProgress::EstablishingSecureChannel(
929 GeneratedQrProgress::QrScanned(checkcode_sender),
930 ) => {
931 assert_matches!(
932 state,
933 GrantLoginProgress::EstablishingSecureChannel(
934 GeneratedQrProgress::QrReady(_)
935 )
936 );
937 let checkcode = checkcode_rx
938 .take()
939 .expect("The checkcode should only be forwarded once")
940 .await
941 .expect("Alice should receive the checkcode");
942 checkcode_sender
943 .send(checkcode)
944 .await
945 .expect("Alice should be able to forward the checkcode");
946 }
947 GrantLoginProgress::WaitingForAuth {
948 verification_uri,
949 continuation_sender,
950 } => {
951 assert_matches!(
952 state,
953 GrantLoginProgress::EstablishingSecureChannel(
954 GeneratedQrProgress::QrScanned(_)
955 )
956 );
957 assert_eq!(verification_uri.as_str(), verification_uri_complete);
958 continuation_sender.confirm().await.expect("should be able to confirm");
959 }
960 GrantLoginProgress::SyncingSecrets => {
961 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
962 }
963 GrantLoginProgress::Done => {
964 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
965 break;
966 }
967 }
968 state = update;
969 }
970 });
971
972 let bob_task = spawn(async move {
974 request_login_with_scanned_qr_code(
975 BobBehaviour::HappyPath,
976 qr_code_rx,
977 checkcode_tx,
978 Some(server),
979 &rendezvous_server,
980 Some(device_authorization_grant),
981 Some(secrets_bundle),
982 )
983 .await;
984 });
985
986 grant.await.expect("Alice should be able to grant the login");
988 updates_task.await.expect("Alice should run through all progress states");
989 bob_task.await.expect("Bob's task should finish");
990 }
991
992 #[async_test]
993 async fn test_grant_login_with_scanned_qr_code() {
994 let server = MatrixMockServer::new().await;
995 let rendezvous_server =
996 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
997 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
998
999 let device_authorization_grant = AuthorizationGrant {
1000 verification_uri_complete: Some(VerificationUriComplete::new(
1001 "https://id.matrix.org/device/abcde".to_owned(),
1002 )),
1003 verification_uri: EndUserVerificationUrl::new(
1004 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1005 )
1006 .unwrap(),
1007 };
1008
1009 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1010 server
1011 .mock_upload_cross_signing_keys()
1012 .ok()
1013 .expect(1)
1014 .named("upload_xsigning_keys")
1015 .mount()
1016 .await;
1017 server
1018 .mock_upload_cross_signing_signatures()
1019 .ok()
1020 .expect(1)
1021 .named("upload_xsigning_signatures")
1022 .mount()
1023 .await;
1024
1025 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1027 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1028 .await
1029 .expect("Bob should be able to create a secure channel.");
1030 let qr_code_data = channel.qr_code_data().clone();
1031
1032 let user_id = owned_user_id!("@alice:example.org");
1034 let device_id = owned_device_id!("ALICE_DEVICE");
1035 let alice = server
1036 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1037 .logged_in_with_oauth()
1038 .build()
1039 .await;
1040 alice
1041 .encryption()
1042 .bootstrap_cross_signing(None)
1043 .await
1044 .expect("Alice should be able to set up cross signing");
1045
1046 let oauth = alice.oauth();
1048 let grant = oauth
1049 .grant_login_with_qr_code()
1050 .device_creation_timeout(Duration::from_secs(2))
1051 .scan(&qr_code_data);
1052 let secrets_bundle = export_secrets_bundle(&alice)
1053 .await
1054 .expect("Alice should be able to export the secrets bundle");
1055 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1056
1057 let mut updates = grant.subscribe_to_progress();
1059 let mut state = grant.state.get();
1060 let verification_uri_complete =
1061 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1062 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1063 let updates_task = spawn(async move {
1064 let mut checkcode_tx = Some(checkcode_tx);
1065
1066 while let Some(update) = updates.next().await {
1067 match &update {
1068 GrantLoginProgress::Starting => {
1069 assert_matches!(state, GrantLoginProgress::Starting);
1070 }
1071 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1072 assert_matches!(state, GrantLoginProgress::Starting);
1073 checkcode_tx
1074 .take()
1075 .expect("The checkcode should only be forwarded once")
1076 .send(*check_code)
1077 .expect("Alice should be able to forward the checkcode");
1078 }
1079 GrantLoginProgress::WaitingForAuth {
1080 verification_uri,
1081 continuation_sender,
1082 } => {
1083 assert_matches!(
1084 state,
1085 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1086 );
1087 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1088 continuation_sender.confirm().await.expect("should be able to confirm");
1089 }
1090 GrantLoginProgress::SyncingSecrets => {
1091 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1092 }
1093 GrantLoginProgress::Done => {
1094 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1095 break;
1096 }
1097 }
1098 state = update;
1099 }
1100 });
1101
1102 let bob_task = spawn(async move {
1104 request_login_with_generated_qr_code(
1105 BobBehaviour::HappyPath,
1106 channel,
1107 checkcode_rx,
1108 Some(server),
1109 &rendezvous_server,
1110 alice.homeserver(),
1111 Some(device_authorization_grant),
1112 Some(secrets_bundle),
1113 )
1114 .await;
1115 });
1116
1117 grant.await.expect("Alice should be able to grant the login");
1119 updates_task.await.expect("Alice should run through all progress states");
1120 bob_task.await.expect("Bob's task should finish");
1121 }
1122
1123 #[async_test]
1124 async fn test_grant_login_with_scanned_qr_code_with_homeserver_swap() {
1125 let server = MatrixMockServer::new().await;
1126 let rendezvous_server =
1127 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1128 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1129
1130 let device_authorization_grant = AuthorizationGrant {
1131 verification_uri_complete: Some(VerificationUriComplete::new(
1132 "https://id.matrix.org/device/abcde".to_owned(),
1133 )),
1134 verification_uri: EndUserVerificationUrl::new(
1135 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1136 )
1137 .unwrap(),
1138 };
1139
1140 let login_server = MatrixMockServer::new().await;
1141
1142 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1143 login_server
1144 .mock_upload_cross_signing_keys()
1145 .ok()
1146 .expect(1)
1147 .named("upload_xsigning_keys")
1148 .mount()
1149 .await;
1150 login_server
1151 .mock_upload_cross_signing_signatures()
1152 .ok()
1153 .expect(1)
1154 .named("upload_xsigning_signatures")
1155 .mount()
1156 .await;
1157
1158 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1160 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1161 .await
1162 .expect("Bob should be able to create a secure channel.");
1163 let qr_code_data = channel.qr_code_data().clone();
1164
1165 let user_id = owned_user_id!("@alice:example.org");
1167 let device_id = owned_device_id!("ALICE_DEVICE");
1168 let alice = login_server
1169 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1170 .logged_in_with_oauth()
1171 .build()
1172 .await;
1173 alice
1174 .encryption()
1175 .bootstrap_cross_signing(None)
1176 .await
1177 .expect("Alice should be able to set up cross signing");
1178
1179 let oauth = alice.oauth();
1181 let grant = oauth
1182 .grant_login_with_qr_code()
1183 .device_creation_timeout(Duration::from_secs(2))
1184 .scan(&qr_code_data);
1185 let secrets_bundle = export_secrets_bundle(&alice)
1186 .await
1187 .expect("Alice should be able to export the secrets bundle");
1188 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1189
1190 let mut updates = grant.subscribe_to_progress();
1192 let mut state = grant.state.get();
1193 let verification_uri_complete =
1194 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1195 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1196 let updates_task = spawn(async move {
1197 let mut checkcode_tx = Some(checkcode_tx);
1198
1199 while let Some(update) = updates.next().await {
1200 match &update {
1201 GrantLoginProgress::Starting => {
1202 assert_matches!(state, GrantLoginProgress::Starting);
1203 }
1204 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1205 assert_matches!(state, GrantLoginProgress::Starting);
1206 checkcode_tx
1207 .take()
1208 .expect("The checkcode should only be forwarded once")
1209 .send(*check_code)
1210 .expect("Alice should be able to forward the checkcode");
1211 }
1212 GrantLoginProgress::WaitingForAuth {
1213 verification_uri,
1214 continuation_sender,
1215 } => {
1216 assert_matches!(
1217 state,
1218 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1219 );
1220 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1221 continuation_sender.confirm().await.expect("should be able to confirm");
1222 }
1223 GrantLoginProgress::SyncingSecrets => {
1224 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1225 }
1226 GrantLoginProgress::Done => {
1227 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1228 break;
1229 }
1230 }
1231 state = update;
1232 }
1233 });
1234
1235 let bob_task = spawn(async move {
1237 request_login_with_generated_qr_code(
1238 BobBehaviour::HappyPath,
1239 channel,
1240 checkcode_rx,
1241 Some(login_server),
1242 &rendezvous_server,
1243 alice.homeserver(),
1244 Some(device_authorization_grant),
1245 Some(secrets_bundle),
1246 )
1247 .await;
1248 });
1249
1250 grant.await.expect("Alice should be able to grant the login");
1252 updates_task.await.expect("Alice should run through all progress states");
1253 bob_task.await.expect("Bob's task should finish");
1254 }
1255
1256 #[async_test]
1257 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_protocol()
1258 {
1259 let server = MatrixMockServer::new().await;
1260 let rendezvous_server = Arc::new(
1261 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1262 );
1263 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1264
1265 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1266 server
1267 .mock_upload_cross_signing_keys()
1268 .ok()
1269 .expect(1)
1270 .named("upload_xsigning_keys")
1271 .mount()
1272 .await;
1273 server
1274 .mock_upload_cross_signing_signatures()
1275 .ok()
1276 .expect(1)
1277 .named("upload_xsigning_signatures")
1278 .mount()
1279 .await;
1280
1281 let user_id = owned_user_id!("@alice:example.org");
1283 let device_id = owned_device_id!("ALICE_DEVICE");
1284 let alice = server
1285 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1286 .logged_in_with_oauth()
1287 .build()
1288 .await;
1289 alice
1290 .encryption()
1291 .bootstrap_cross_signing(None)
1292 .await
1293 .expect("Alice should be able to set up cross signing");
1294
1295 let oauth = alice.oauth();
1297 let grant = oauth
1298 .grant_login_with_qr_code()
1299 .device_creation_timeout(Duration::from_secs(2))
1300 .generate();
1301 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1302 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1303
1304 let mut updates = grant.subscribe_to_progress();
1306 let mut state = grant.state.get();
1307 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1308 let updates_task = spawn(async move {
1309 let mut qr_code_tx = Some(qr_code_tx);
1310 let mut checkcode_rx = Some(checkcode_rx);
1311
1312 while let Some(update) = updates.next().await {
1313 match &update {
1314 GrantLoginProgress::Starting => {
1315 assert_matches!(state, GrantLoginProgress::Starting);
1316 }
1317 GrantLoginProgress::EstablishingSecureChannel(
1318 GeneratedQrProgress::QrReady(qr_code_data),
1319 ) => {
1320 assert_matches!(state, GrantLoginProgress::Starting);
1321 qr_code_tx
1322 .take()
1323 .expect("The QR code should only be forwarded once")
1324 .send(qr_code_data.clone())
1325 .expect("Alice should be able to forward the QR code");
1326 }
1327 GrantLoginProgress::EstablishingSecureChannel(
1328 GeneratedQrProgress::QrScanned(checkcode_sender),
1329 ) => {
1330 assert_matches!(
1331 state,
1332 GrantLoginProgress::EstablishingSecureChannel(
1333 GeneratedQrProgress::QrReady(_)
1334 )
1335 );
1336 let checkcode = checkcode_rx
1337 .take()
1338 .expect("The checkcode should only be forwarded once")
1339 .await
1340 .expect("Alice should receive the checkcode");
1341 checkcode_sender
1342 .send(checkcode)
1343 .await
1344 .expect("Alice should be able to forward the checkcode");
1345 break;
1346 }
1347 _ => {
1348 panic!("Alice should abort the process");
1349 }
1350 }
1351 state = update;
1352 }
1353 });
1354
1355 let rendezvous_server_clone = rendezvous_server.clone();
1357 let bob_task = spawn(async move {
1358 request_login_with_scanned_qr_code(
1359 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1360 qr_code_rx,
1361 checkcode_tx,
1362 None,
1363 &rendezvous_server_clone,
1364 None,
1365 None,
1366 )
1367 .await;
1368 });
1369
1370 assert_let!(
1372 Err(QRCodeGrantLoginError::UnexpectedMessage {
1373 expected: "m.login.protocol",
1374 received,
1375 }) = grant.await,
1376 "Alice should abort the login with expected error variant"
1377 );
1378 assert_matches!(
1379 *received,
1380 QrAuthMessage::LoginSuccess,
1381 "Alice should abort the login with expected error message"
1382 );
1383 updates_task.await.expect("Alice should run through all progress states");
1384 bob_task.await.expect("Bob's task should finish");
1385 }
1386
1387 #[async_test]
1388 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_protocol() {
1389 let server = MatrixMockServer::new().await;
1390 let rendezvous_server = Arc::new(
1391 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1392 );
1393 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1394
1395 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1396 server
1397 .mock_upload_cross_signing_keys()
1398 .ok()
1399 .expect(1)
1400 .named("upload_xsigning_keys")
1401 .mount()
1402 .await;
1403 server
1404 .mock_upload_cross_signing_signatures()
1405 .ok()
1406 .expect(1)
1407 .named("upload_xsigning_signatures")
1408 .mount()
1409 .await;
1410
1411 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1413 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1414 .await
1415 .expect("Bob should be able to create a secure channel.");
1416 let qr_code_data = channel.qr_code_data().clone();
1417
1418 let user_id = owned_user_id!("@alice:example.org");
1420 let device_id = owned_device_id!("ALICE_DEVICE");
1421 let alice = server
1422 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1423 .logged_in_with_oauth()
1424 .build()
1425 .await;
1426 alice
1427 .encryption()
1428 .bootstrap_cross_signing(None)
1429 .await
1430 .expect("Alice should be able to set up cross signing");
1431
1432 let oauth = alice.oauth();
1434 let grant = oauth
1435 .grant_login_with_qr_code()
1436 .device_creation_timeout(Duration::from_secs(2))
1437 .scan(&qr_code_data);
1438 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1439
1440 let mut updates = grant.subscribe_to_progress();
1442 let mut state = grant.state.get();
1443 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1444 let updates_task = spawn(async move {
1445 let mut checkcode_tx = Some(checkcode_tx);
1446
1447 while let Some(update) = updates.next().await {
1448 match &update {
1449 GrantLoginProgress::Starting => {
1450 assert_matches!(state, GrantLoginProgress::Starting);
1451 }
1452 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1453 assert_matches!(state, GrantLoginProgress::Starting);
1454 checkcode_tx
1455 .take()
1456 .expect("The checkcode should only be forwarded once")
1457 .send(*check_code)
1458 .expect("Alice should be able to forward the checkcode");
1459 break;
1460 }
1461 _ => {
1462 panic!("Alice should abort the process");
1463 }
1464 }
1465 state = update;
1466 }
1467 });
1468
1469 let rendezvous_server_clone = rendezvous_server.clone();
1470 let bob_task = spawn(async move {
1472 request_login_with_generated_qr_code(
1473 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1474 channel,
1475 checkcode_rx,
1476 None,
1477 &rendezvous_server_clone,
1478 alice.homeserver(),
1479 None,
1480 None,
1481 )
1482 .await;
1483 });
1484
1485 assert_let!(
1487 Err(QRCodeGrantLoginError::UnexpectedMessage {
1488 expected: "m.login.protocol",
1489 received,
1490 }) = grant.await,
1491 "Alice should abort the login with expected error variant"
1492 );
1493 assert_matches!(
1494 *received,
1495 QrAuthMessage::LoginSuccess,
1496 "Alice should abort the login with expected error message"
1497 );
1498 updates_task.await.expect("Alice should run through all progress states");
1499 bob_task.await.expect("Bob's task should finish");
1500 }
1501
1502 #[async_test]
1503 async fn test_grant_login_with_generated_qr_code_device_already_exists() {
1504 let server = MatrixMockServer::new().await;
1505 let rendezvous_server =
1506 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1507 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1508
1509 let device_authorization_grant = AuthorizationGrant {
1510 verification_uri_complete: Some(VerificationUriComplete::new(
1511 "https://id.matrix.org/device/abcde".to_owned(),
1512 )),
1513 verification_uri: EndUserVerificationUrl::new(
1514 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1515 )
1516 .unwrap(),
1517 };
1518
1519 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1520 server
1521 .mock_upload_cross_signing_keys()
1522 .ok()
1523 .expect(1)
1524 .named("upload_xsigning_keys")
1525 .mount()
1526 .await;
1527 server
1528 .mock_upload_cross_signing_signatures()
1529 .ok()
1530 .expect(1)
1531 .named("upload_xsigning_signatures")
1532 .mount()
1533 .await;
1534
1535 let user_id = owned_user_id!("@alice:example.org");
1537 let device_id = owned_device_id!("ALICE_DEVICE");
1538 let alice = server
1539 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1540 .logged_in_with_oauth()
1541 .build()
1542 .await;
1543 alice
1544 .encryption()
1545 .bootstrap_cross_signing(None)
1546 .await
1547 .expect("Alice should be able to set up cross signing");
1548
1549 let oauth = alice.oauth();
1551 let grant = oauth
1552 .grant_login_with_qr_code()
1553 .device_creation_timeout(Duration::from_secs(2))
1554 .generate();
1555 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1556 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1557
1558 let mut updates = grant.subscribe_to_progress();
1560 let mut state = grant.state.get();
1561 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1562 let updates_task = spawn(async move {
1563 let mut qr_code_tx = Some(qr_code_tx);
1564 let mut checkcode_rx = Some(checkcode_rx);
1565
1566 while let Some(update) = updates.next().await {
1567 match &update {
1568 GrantLoginProgress::Starting => {
1569 assert_matches!(state, GrantLoginProgress::Starting);
1570 }
1571 GrantLoginProgress::EstablishingSecureChannel(
1572 GeneratedQrProgress::QrReady(qr_code_data),
1573 ) => {
1574 assert_matches!(state, GrantLoginProgress::Starting);
1575 qr_code_tx
1576 .take()
1577 .expect("The QR code should only be forwarded once")
1578 .send(qr_code_data.clone())
1579 .expect("Alice should be able to forward the QR code");
1580 }
1581 GrantLoginProgress::EstablishingSecureChannel(
1582 GeneratedQrProgress::QrScanned(checkcode_sender),
1583 ) => {
1584 assert_matches!(
1585 state,
1586 GrantLoginProgress::EstablishingSecureChannel(
1587 GeneratedQrProgress::QrReady(_)
1588 )
1589 );
1590 let checkcode = checkcode_rx
1591 .take()
1592 .expect("The checkcode should only be forwarded once")
1593 .await
1594 .expect("Alice should receive the checkcode");
1595 checkcode_sender
1596 .send(checkcode)
1597 .await
1598 .expect("Alice should be able to forward the checkcode");
1599 }
1600 _ => {
1601 panic!("Alice should abort the process");
1602 }
1603 }
1604 state = update;
1605 }
1606 });
1607
1608 let bob_task = spawn(async move {
1610 request_login_with_scanned_qr_code(
1611 BobBehaviour::DeviceAlreadyExists,
1612 qr_code_rx,
1613 checkcode_tx,
1614 Some(server),
1615 &rendezvous_server,
1616 Some(device_authorization_grant),
1617 None,
1618 )
1619 .await;
1620 });
1621
1622 assert_matches!(
1624 grant.await,
1625 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1626 "Alice should abort the login with expected error"
1627 );
1628 updates_task.await.expect("Alice should run through all progress states");
1629 bob_task.await.expect("Bob's task should finish");
1630 }
1631
1632 #[async_test]
1633 async fn test_grant_login_with_scanned_qr_code_device_already_exists() {
1634 let server = MatrixMockServer::new().await;
1635 let rendezvous_server =
1636 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1637 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1638
1639 let device_authorization_grant = AuthorizationGrant {
1640 verification_uri_complete: Some(VerificationUriComplete::new(
1641 "https://id.matrix.org/device/abcde".to_owned(),
1642 )),
1643 verification_uri: EndUserVerificationUrl::new(
1644 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1645 )
1646 .unwrap(),
1647 };
1648
1649 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1650 server
1651 .mock_upload_cross_signing_keys()
1652 .ok()
1653 .expect(1)
1654 .named("upload_xsigning_keys")
1655 .mount()
1656 .await;
1657 server
1658 .mock_upload_cross_signing_signatures()
1659 .ok()
1660 .expect(1)
1661 .named("upload_xsigning_signatures")
1662 .mount()
1663 .await;
1664
1665 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1667 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1668 .await
1669 .expect("Bob should be able to create a secure channel.");
1670 let qr_code_data = channel.qr_code_data().clone();
1671
1672 let user_id = owned_user_id!("@alice:example.org");
1674 let device_id = owned_device_id!("ALICE_DEVICE");
1675 let alice = server
1676 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1677 .logged_in_with_oauth()
1678 .build()
1679 .await;
1680 alice
1681 .encryption()
1682 .bootstrap_cross_signing(None)
1683 .await
1684 .expect("Alice should be able to set up cross signing");
1685
1686 let oauth = alice.oauth();
1688 let grant = oauth
1689 .grant_login_with_qr_code()
1690 .device_creation_timeout(Duration::from_secs(2))
1691 .scan(&qr_code_data);
1692 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1693
1694 let mut updates = grant.subscribe_to_progress();
1696 let mut state = grant.state.get();
1697 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1698 let updates_task = spawn(async move {
1699 let mut checkcode_tx = Some(checkcode_tx);
1700
1701 while let Some(update) = updates.next().await {
1702 match &update {
1703 GrantLoginProgress::Starting => {
1704 assert_matches!(state, GrantLoginProgress::Starting);
1705 }
1706 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1707 assert_matches!(state, GrantLoginProgress::Starting);
1708 checkcode_tx
1709 .take()
1710 .expect("The checkcode should only be forwarded once")
1711 .send(*check_code)
1712 .expect("Alice should be able to forward the checkcode");
1713 }
1714 _ => {
1715 panic!("Alice should abort the process");
1716 }
1717 }
1718 state = update;
1719 }
1720 });
1721
1722 let bob_task = spawn(async move {
1724 request_login_with_generated_qr_code(
1725 BobBehaviour::DeviceAlreadyExists,
1726 channel,
1727 checkcode_rx,
1728 Some(server),
1729 &rendezvous_server,
1730 alice.homeserver(),
1731 Some(device_authorization_grant),
1732 None,
1733 )
1734 .await;
1735 });
1736
1737 assert_matches!(
1739 grant.await,
1740 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1741 "Alice should abort the login with expected error"
1742 );
1743 updates_task.await.expect("Alice should run through all progress states");
1744 bob_task.await.expect("Bob's task should finish");
1745 }
1746
1747 #[async_test]
1748 async fn test_grant_login_with_generated_qr_code_device_not_found() {
1749 let server = MatrixMockServer::new().await;
1750 let rendezvous_server =
1751 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1752 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1753
1754 let device_authorization_grant = AuthorizationGrant {
1755 verification_uri_complete: Some(VerificationUriComplete::new(
1756 "https://id.matrix.org/device/abcde".to_owned(),
1757 )),
1758 verification_uri: EndUserVerificationUrl::new(
1759 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1760 )
1761 .unwrap(),
1762 };
1763
1764 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1765 server
1766 .mock_upload_cross_signing_keys()
1767 .ok()
1768 .expect(1)
1769 .named("upload_xsigning_keys")
1770 .mount()
1771 .await;
1772 server
1773 .mock_upload_cross_signing_signatures()
1774 .ok()
1775 .expect(1)
1776 .named("upload_xsigning_signatures")
1777 .mount()
1778 .await;
1779
1780 let user_id = owned_user_id!("@alice:example.org");
1782 let device_id = owned_device_id!("ALICE_DEVICE");
1783 let alice = server
1784 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1785 .logged_in_with_oauth()
1786 .build()
1787 .await;
1788 alice
1789 .encryption()
1790 .bootstrap_cross_signing(None)
1791 .await
1792 .expect("Alice should be able to set up cross signing");
1793
1794 let oauth = alice.oauth();
1796 let grant = oauth
1797 .grant_login_with_qr_code()
1798 .device_creation_timeout(Duration::from_secs(2))
1799 .generate();
1800 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1801 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1802
1803 let mut updates = grant.subscribe_to_progress();
1805 let mut state = grant.state.get();
1806 let verification_uri_complete =
1807 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1808 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1809 let updates_task = spawn(async move {
1810 let mut qr_code_tx = Some(qr_code_tx);
1811 let mut checkcode_rx = Some(checkcode_rx);
1812
1813 while let Some(update) = updates.next().await {
1814 match &update {
1815 GrantLoginProgress::Starting => {
1816 assert_matches!(state, GrantLoginProgress::Starting);
1817 }
1818 GrantLoginProgress::EstablishingSecureChannel(
1819 GeneratedQrProgress::QrReady(qr_code_data),
1820 ) => {
1821 assert_matches!(state, GrantLoginProgress::Starting);
1822 qr_code_tx
1823 .take()
1824 .expect("The QR code should only be forwarded once")
1825 .send(qr_code_data.clone())
1826 .expect("Alice should be able to forward the QR code");
1827 }
1828 GrantLoginProgress::EstablishingSecureChannel(
1829 GeneratedQrProgress::QrScanned(checkcode_sender),
1830 ) => {
1831 assert_matches!(
1832 state,
1833 GrantLoginProgress::EstablishingSecureChannel(
1834 GeneratedQrProgress::QrReady(_)
1835 )
1836 );
1837 let checkcode = checkcode_rx
1838 .take()
1839 .expect("The checkcode should only be forwarded once")
1840 .await
1841 .expect("Alice should receive the checkcode");
1842 checkcode_sender
1843 .send(checkcode)
1844 .await
1845 .expect("Alice should be able to forward the checkcode");
1846 }
1847 GrantLoginProgress::WaitingForAuth {
1848 verification_uri,
1849 continuation_sender,
1850 } => {
1851 assert_matches!(
1852 state,
1853 GrantLoginProgress::EstablishingSecureChannel(
1854 GeneratedQrProgress::QrScanned(_)
1855 )
1856 );
1857 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1858 continuation_sender.confirm().await.expect("should be able to confirm");
1859 }
1860 _ => {
1861 panic!("Alice should abort the process");
1862 }
1863 }
1864 state = update;
1865 }
1866 });
1867
1868 let bob_task = spawn(async move {
1870 request_login_with_scanned_qr_code(
1871 BobBehaviour::DeviceNotCreated,
1872 qr_code_rx,
1873 checkcode_tx,
1874 Some(server),
1875 &rendezvous_server,
1876 Some(device_authorization_grant),
1877 None,
1878 )
1879 .await;
1880 });
1881
1882 assert_matches!(
1883 grant.await,
1884 Err(QRCodeGrantLoginError::DeviceNotFound),
1885 "Alice should abort the login with expected error"
1886 );
1887 updates_task.await.expect("Alice should run through all progress states");
1888 bob_task.await.expect("Bob's task should finish");
1889 }
1890
1891 #[async_test]
1892 async fn test_grant_login_with_scanned_qr_code_device_not_found() {
1893 let server = MatrixMockServer::new().await;
1894 let rendezvous_server =
1895 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1896 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1897
1898 let device_authorization_grant = AuthorizationGrant {
1899 verification_uri_complete: Some(VerificationUriComplete::new(
1900 "https://id.matrix.org/device/abcde".to_owned(),
1901 )),
1902 verification_uri: EndUserVerificationUrl::new(
1903 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1904 )
1905 .unwrap(),
1906 };
1907
1908 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1909 server
1910 .mock_upload_cross_signing_keys()
1911 .ok()
1912 .expect(1)
1913 .named("upload_xsigning_keys")
1914 .mount()
1915 .await;
1916 server
1917 .mock_upload_cross_signing_signatures()
1918 .ok()
1919 .expect(1)
1920 .named("upload_xsigning_signatures")
1921 .mount()
1922 .await;
1923
1924 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1926 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1927 .await
1928 .expect("Bob should be able to create a secure channel.");
1929 let qr_code_data = channel.qr_code_data().clone();
1930
1931 let user_id = owned_user_id!("@alice:example.org");
1933 let device_id = owned_device_id!("ALICE_DEVICE");
1934 let alice = server
1935 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1936 .logged_in_with_oauth()
1937 .build()
1938 .await;
1939 alice
1940 .encryption()
1941 .bootstrap_cross_signing(None)
1942 .await
1943 .expect("Alice should be able to set up cross signing");
1944
1945 let oauth = alice.oauth();
1947 let grant = oauth
1948 .grant_login_with_qr_code()
1949 .device_creation_timeout(Duration::from_secs(2))
1950 .scan(&qr_code_data);
1951 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1952
1953 let mut updates = grant.subscribe_to_progress();
1955 let mut state = grant.state.get();
1956 let verification_uri_complete =
1957 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1958 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1959 let updates_task = spawn(async move {
1960 let mut checkcode_tx = Some(checkcode_tx);
1961
1962 while let Some(update) = updates.next().await {
1963 match &update {
1964 GrantLoginProgress::Starting => {
1965 assert_matches!(state, GrantLoginProgress::Starting);
1966 }
1967 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1968 assert_matches!(state, GrantLoginProgress::Starting);
1969 checkcode_tx
1970 .take()
1971 .expect("The checkcode should only be forwarded once")
1972 .send(*check_code)
1973 .expect("Alice should be able to forward the checkcode");
1974 }
1975 GrantLoginProgress::WaitingForAuth {
1976 verification_uri,
1977 continuation_sender,
1978 } => {
1979 assert_matches!(
1980 state,
1981 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1982 );
1983 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1984 continuation_sender.confirm().await.expect("should be able to confirm");
1985 }
1986 _ => {
1987 panic!("Alice should abort the process");
1988 }
1989 }
1990 state = update;
1991 }
1992 });
1993
1994 let bob_task = spawn(async move {
1996 request_login_with_generated_qr_code(
1997 BobBehaviour::DeviceNotCreated,
1998 channel,
1999 checkcode_rx,
2000 None,
2001 &rendezvous_server,
2002 alice.homeserver(),
2003 Some(device_authorization_grant),
2004 None,
2005 )
2006 .await;
2007 });
2008
2009 assert_matches!(
2010 grant.await,
2011 Err(QRCodeGrantLoginError::DeviceNotFound),
2012 "Alice should abort the login with expected error"
2013 );
2014 updates_task.await.expect("Alice should run through all progress states");
2015 bob_task.await.expect("Bob's task should finish");
2016 }
2017
2018 #[async_test]
2019 async fn test_grant_login_with_generated_qr_code_session_expired() {
2020 let server = MatrixMockServer::new().await;
2021 let rendezvous_server =
2022 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
2023 .await;
2024 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2025
2026 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2027 server
2028 .mock_upload_cross_signing_keys()
2029 .ok()
2030 .expect(1)
2031 .named("upload_xsigning_keys")
2032 .mount()
2033 .await;
2034 server
2035 .mock_upload_cross_signing_signatures()
2036 .ok()
2037 .expect(1)
2038 .named("upload_xsigning_signatures")
2039 .mount()
2040 .await;
2041
2042 let user_id = owned_user_id!("@alice:example.org");
2044 let device_id = owned_device_id!("ALICE_DEVICE");
2045 let alice = server
2046 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2047 .logged_in_with_oauth()
2048 .build()
2049 .await;
2050 alice
2051 .encryption()
2052 .bootstrap_cross_signing(None)
2053 .await
2054 .expect("Alice should be able to set up cross signing");
2055
2056 let oauth = alice.oauth();
2058 let grant = oauth
2059 .grant_login_with_qr_code()
2060 .device_creation_timeout(Duration::from_secs(2))
2061 .generate();
2062
2063 let mut updates = grant.subscribe_to_progress();
2065 let mut state = grant.state.get();
2066 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2067 let updates_task = spawn(async move {
2068 while let Some(update) = updates.next().await {
2069 match &update {
2070 GrantLoginProgress::Starting => {
2071 assert_matches!(state, GrantLoginProgress::Starting);
2072 }
2073 GrantLoginProgress::EstablishingSecureChannel(
2074 GeneratedQrProgress::QrReady(_),
2075 ) => {
2076 assert_matches!(state, GrantLoginProgress::Starting);
2077 }
2078 _ => {
2079 panic!("Alice should abort the process");
2080 }
2081 }
2082 state = update;
2083 }
2084 });
2085
2086 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2090 updates_task.await.expect("Alice should run through all progress states");
2091 }
2092
2093 #[async_test]
2094 async fn test_grant_login_with_scanned_qr_code_session_expired() {
2095 let server = MatrixMockServer::new().await;
2096 let rendezvous_server =
2097 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
2098 .await;
2099 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2100
2101 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2102 server
2103 .mock_upload_cross_signing_keys()
2104 .ok()
2105 .expect(1)
2106 .named("upload_xsigning_keys")
2107 .mount()
2108 .await;
2109 server
2110 .mock_upload_cross_signing_signatures()
2111 .ok()
2112 .expect(1)
2113 .named("upload_xsigning_signatures")
2114 .mount()
2115 .await;
2116
2117 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2119 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2120 .await
2121 .expect("Bob should be able to create a secure channel.");
2122 let qr_code_data = channel.qr_code_data().clone();
2123
2124 let user_id = owned_user_id!("@alice:example.org");
2126 let device_id = owned_device_id!("ALICE_DEVICE");
2127 let alice = server
2128 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2129 .logged_in_with_oauth()
2130 .build()
2131 .await;
2132 alice
2133 .encryption()
2134 .bootstrap_cross_signing(None)
2135 .await
2136 .expect("Alice should be able to set up cross signing");
2137
2138 let oauth = alice.oauth();
2140 let grant = oauth
2141 .grant_login_with_qr_code()
2142 .device_creation_timeout(Duration::from_secs(2))
2143 .scan(&qr_code_data);
2144
2145 let mut updates = grant.subscribe_to_progress();
2147 let mut state = grant.state.get();
2148 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2149 let updates_task = spawn(async move {
2150 while let Some(update) = updates.next().await {
2151 match &update {
2152 GrantLoginProgress::Starting => {
2153 assert_matches!(state, GrantLoginProgress::Starting);
2154 }
2155 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. }) => {
2156 assert_matches!(state, GrantLoginProgress::Starting);
2157 }
2158 _ => {
2159 panic!("Alice should abort the process");
2160 }
2161 }
2162 state = update;
2163 }
2164 });
2165
2166 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2170 updates_task.await.expect("Alice should run through all progress states");
2171 }
2172
2173 #[async_test]
2174 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_protocol() {
2175 let server = MatrixMockServer::new().await;
2176 let rendezvous_server = Arc::new(
2177 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2178 );
2179 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2180
2181 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2182 server
2183 .mock_upload_cross_signing_keys()
2184 .ok()
2185 .expect(1)
2186 .named("upload_xsigning_keys")
2187 .mount()
2188 .await;
2189 server
2190 .mock_upload_cross_signing_signatures()
2191 .ok()
2192 .expect(1)
2193 .named("upload_xsigning_signatures")
2194 .mount()
2195 .await;
2196
2197 let user_id = owned_user_id!("@alice:example.org");
2199 let device_id = owned_device_id!("ALICE_DEVICE");
2200 let alice = server
2201 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2202 .logged_in_with_oauth()
2203 .build()
2204 .await;
2205 alice
2206 .encryption()
2207 .bootstrap_cross_signing(None)
2208 .await
2209 .expect("Alice should be able to set up cross signing");
2210
2211 let oauth = alice.oauth();
2213 let grant = oauth
2214 .grant_login_with_qr_code()
2215 .device_creation_timeout(Duration::from_secs(2))
2216 .generate();
2217 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2218 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2219
2220 let mut updates = grant.subscribe_to_progress();
2222 let mut state = grant.state.get();
2223 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2224 let updates_task = spawn(async move {
2225 let mut qr_code_tx = Some(qr_code_tx);
2226 let mut checkcode_rx = Some(checkcode_rx);
2227
2228 while let Some(update) = updates.next().await {
2229 match &update {
2230 GrantLoginProgress::Starting => {
2231 assert_matches!(state, GrantLoginProgress::Starting);
2232 }
2233 GrantLoginProgress::EstablishingSecureChannel(
2234 GeneratedQrProgress::QrReady(qr_code_data),
2235 ) => {
2236 assert_matches!(state, GrantLoginProgress::Starting);
2237 qr_code_tx
2238 .take()
2239 .expect("The QR code should only be forwarded once")
2240 .send(qr_code_data.clone())
2241 .expect("Alice should be able to forward the QR code");
2242 }
2243 GrantLoginProgress::EstablishingSecureChannel(
2244 GeneratedQrProgress::QrScanned(checkcode_sender),
2245 ) => {
2246 assert_matches!(
2247 state,
2248 GrantLoginProgress::EstablishingSecureChannel(
2249 GeneratedQrProgress::QrReady(_)
2250 )
2251 );
2252 let checkcode = checkcode_rx
2253 .take()
2254 .expect("The checkcode should only be forwarded once")
2255 .await
2256 .expect("Alice should receive the checkcode");
2257 checkcode_sender
2258 .send(checkcode)
2259 .await
2260 .expect("Alice should be able to forward the checkcode");
2261 break;
2262 }
2263 _ => {
2264 panic!("Alice should abort the process");
2265 }
2266 }
2267 state = update;
2268 }
2269 });
2270
2271 let rendezvous_server_clone = rendezvous_server.clone();
2273 let bob_task = spawn(async move {
2274 request_login_with_scanned_qr_code(
2275 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2276 qr_code_rx,
2277 checkcode_tx,
2278 None,
2279 &rendezvous_server_clone,
2280 None,
2281 None,
2282 )
2283 .await;
2284 });
2285
2286 assert_matches!(
2288 grant.await,
2289 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2290 "Alice should abort the login with expected error"
2291 );
2292 updates_task.await.expect("Alice should run through all progress states");
2293 bob_task.await.expect("Bob's task should finish");
2294 }
2295
2296 #[async_test]
2297 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_protocol() {
2298 let server = MatrixMockServer::new().await;
2299 let rendezvous_server = Arc::new(
2300 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2301 );
2302 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2303
2304 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2305 server
2306 .mock_upload_cross_signing_keys()
2307 .ok()
2308 .expect(1)
2309 .named("upload_xsigning_keys")
2310 .mount()
2311 .await;
2312 server
2313 .mock_upload_cross_signing_signatures()
2314 .ok()
2315 .expect(1)
2316 .named("upload_xsigning_signatures")
2317 .mount()
2318 .await;
2319
2320 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2322 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2323 .await
2324 .expect("Bob should be able to create a secure channel.");
2325 let qr_code_data = channel.qr_code_data().clone();
2326
2327 let user_id = owned_user_id!("@alice:example.org");
2329 let device_id = owned_device_id!("ALICE_DEVICE");
2330 let alice = server
2331 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2332 .logged_in_with_oauth()
2333 .build()
2334 .await;
2335 alice
2336 .encryption()
2337 .bootstrap_cross_signing(None)
2338 .await
2339 .expect("Alice should be able to set up cross signing");
2340
2341 let oauth = alice.oauth();
2343 let grant = oauth
2344 .grant_login_with_qr_code()
2345 .device_creation_timeout(Duration::from_secs(2))
2346 .scan(&qr_code_data);
2347 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2348
2349 let mut updates = grant.subscribe_to_progress();
2351 let mut state = grant.state.get();
2352 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2353 let updates_task = spawn(async move {
2354 let mut checkcode_tx = Some(checkcode_tx);
2355
2356 while let Some(update) = updates.next().await {
2357 match &update {
2358 GrantLoginProgress::Starting => {
2359 assert_matches!(state, GrantLoginProgress::Starting);
2360 }
2361 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2362 assert_matches!(state, GrantLoginProgress::Starting);
2363 checkcode_tx
2364 .take()
2365 .expect("The checkcode should only be forwarded once")
2366 .send(*check_code)
2367 .expect("Alice should be able to forward the checkcode");
2368 break;
2369 }
2370 _ => {
2371 panic!("Alice should abort the process");
2372 }
2373 }
2374 state = update;
2375 }
2376 });
2377
2378 let rendezvous_server_clone = rendezvous_server.clone();
2379 let bob_task = spawn(async move {
2381 request_login_with_generated_qr_code(
2382 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2383 channel,
2384 checkcode_rx,
2385 None,
2386 &rendezvous_server_clone,
2387 alice.homeserver(),
2388 None,
2389 None,
2390 )
2391 .await;
2392 });
2393
2394 assert_matches!(
2396 grant.await,
2397 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2398 "Alice should abort the login with expected error"
2399 );
2400 updates_task.await.expect("Alice should run through all progress states");
2401 bob_task.await.expect("Bob's task should finish");
2402 }
2403
2404 #[async_test]
2405 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_success() {
2406 let server = MatrixMockServer::new().await;
2407 let rendezvous_server = Arc::new(
2408 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2409 );
2410 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2411
2412 let device_authorization_grant = AuthorizationGrant {
2413 verification_uri_complete: Some(VerificationUriComplete::new(
2414 "https://id.matrix.org/device/abcde".to_owned(),
2415 )),
2416 verification_uri: EndUserVerificationUrl::new(
2417 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2418 )
2419 .unwrap(),
2420 };
2421
2422 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2423 server
2424 .mock_upload_cross_signing_keys()
2425 .ok()
2426 .expect(1)
2427 .named("upload_xsigning_keys")
2428 .mount()
2429 .await;
2430 server
2431 .mock_upload_cross_signing_signatures()
2432 .ok()
2433 .expect(1)
2434 .named("upload_xsigning_signatures")
2435 .mount()
2436 .await;
2437
2438 let user_id = owned_user_id!("@alice:example.org");
2440 let device_id = owned_device_id!("ALICE_DEVICE");
2441 let alice = server
2442 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2443 .logged_in_with_oauth()
2444 .build()
2445 .await;
2446 alice
2447 .encryption()
2448 .bootstrap_cross_signing(None)
2449 .await
2450 .expect("Alice should be able to set up cross signing");
2451
2452 let oauth = alice.oauth();
2454 let grant = oauth
2455 .grant_login_with_qr_code()
2456 .device_creation_timeout(Duration::from_secs(2))
2457 .generate();
2458 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2459 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2460
2461 let mut updates = grant.subscribe_to_progress();
2463 let mut state = grant.state.get();
2464 let verification_uri_complete =
2465 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2466 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2467 let updates_task = spawn(async move {
2468 let mut qr_code_tx = Some(qr_code_tx);
2469 let mut checkcode_rx = Some(checkcode_rx);
2470
2471 while let Some(update) = updates.next().await {
2472 match &update {
2473 GrantLoginProgress::Starting => {
2474 assert_matches!(state, GrantLoginProgress::Starting);
2475 }
2476 GrantLoginProgress::EstablishingSecureChannel(
2477 GeneratedQrProgress::QrReady(qr_code_data),
2478 ) => {
2479 assert_matches!(state, GrantLoginProgress::Starting);
2480 qr_code_tx
2481 .take()
2482 .expect("The QR code should only be forwarded once")
2483 .send(qr_code_data.clone())
2484 .expect("Alice should be able to forward the QR code");
2485 }
2486 GrantLoginProgress::EstablishingSecureChannel(
2487 GeneratedQrProgress::QrScanned(checkcode_sender),
2488 ) => {
2489 assert_matches!(
2490 state,
2491 GrantLoginProgress::EstablishingSecureChannel(
2492 GeneratedQrProgress::QrReady(_)
2493 )
2494 );
2495 let checkcode = checkcode_rx
2496 .take()
2497 .expect("The checkcode should only be forwarded once")
2498 .await
2499 .expect("Alice should receive the checkcode");
2500 checkcode_sender
2501 .send(checkcode)
2502 .await
2503 .expect("Alice should be able to forward the checkcode");
2504 }
2505 GrantLoginProgress::WaitingForAuth {
2506 verification_uri,
2507 continuation_sender,
2508 } => {
2509 assert_matches!(
2510 state,
2511 GrantLoginProgress::EstablishingSecureChannel(
2512 GeneratedQrProgress::QrScanned(_)
2513 )
2514 );
2515 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2516 continuation_sender.confirm().await.expect("should be able to confirm");
2517 }
2518 _ => {
2519 panic!("Alice should abort the process");
2520 }
2521 }
2522 state = update;
2523 }
2524 });
2525
2526 let rendezvous_server_clone = rendezvous_server.clone();
2527 let bob_task = spawn(async move {
2529 request_login_with_scanned_qr_code(
2530 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2531 qr_code_rx,
2532 checkcode_tx,
2533 None,
2534 &rendezvous_server_clone,
2535 Some(device_authorization_grant),
2536 None,
2537 )
2538 .await;
2539 });
2540
2541 assert_matches!(
2543 grant.await,
2544 Err(QRCodeGrantLoginError::LoginFailure {
2545 reason: LoginFailureReason::AuthorizationExpired
2546 }),
2547 "Alice should abort the login with expected error"
2548 );
2549 updates_task.await.expect("Alice should run through all progress states");
2550 bob_task.await.expect("Bob's task should finish");
2551 }
2552
2553 #[async_test]
2554 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_success() {
2555 let server = MatrixMockServer::new().await;
2556 let rendezvous_server = Arc::new(
2557 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2558 );
2559 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2560
2561 let device_authorization_grant = AuthorizationGrant {
2562 verification_uri_complete: Some(VerificationUriComplete::new(
2563 "https://id.matrix.org/device/abcde".to_owned(),
2564 )),
2565 verification_uri: EndUserVerificationUrl::new(
2566 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2567 )
2568 .unwrap(),
2569 };
2570
2571 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2572 server
2573 .mock_upload_cross_signing_keys()
2574 .ok()
2575 .expect(1)
2576 .named("upload_xsigning_keys")
2577 .mount()
2578 .await;
2579 server
2580 .mock_upload_cross_signing_signatures()
2581 .ok()
2582 .expect(1)
2583 .named("upload_xsigning_signatures")
2584 .mount()
2585 .await;
2586
2587 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2589 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2590 .await
2591 .expect("Bob should be able to create a secure channel.");
2592 let qr_code_data = channel.qr_code_data().clone();
2593
2594 let user_id = owned_user_id!("@alice:example.org");
2596 let device_id = owned_device_id!("ALICE_DEVICE");
2597 let alice = server
2598 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2599 .logged_in_with_oauth()
2600 .build()
2601 .await;
2602 alice
2603 .encryption()
2604 .bootstrap_cross_signing(None)
2605 .await
2606 .expect("Alice should be able to set up cross signing");
2607
2608 let oauth = alice.oauth();
2610 let grant = oauth
2611 .grant_login_with_qr_code()
2612 .device_creation_timeout(Duration::from_secs(2))
2613 .scan(&qr_code_data);
2614 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2615
2616 let mut updates = grant.subscribe_to_progress();
2618 let mut state = grant.state.get();
2619 let verification_uri_complete =
2620 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2621 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2622 let updates_task = spawn(async move {
2623 let mut checkcode_tx = Some(checkcode_tx);
2624
2625 while let Some(update) = updates.next().await {
2626 match &update {
2627 GrantLoginProgress::Starting => {
2628 assert_matches!(state, GrantLoginProgress::Starting);
2629 }
2630 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2631 assert_matches!(state, GrantLoginProgress::Starting);
2632 checkcode_tx
2633 .take()
2634 .expect("The checkcode should only be forwarded once")
2635 .send(*check_code)
2636 .expect("Alice should be able to forward the checkcode");
2637 }
2638 GrantLoginProgress::WaitingForAuth {
2639 verification_uri,
2640 continuation_sender,
2641 } => {
2642 assert_matches!(
2643 state,
2644 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2645 );
2646 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2647 continuation_sender.confirm().await.expect("should be able to confirm");
2648 }
2649 _ => {
2650 panic!("Alice should abort the process");
2651 }
2652 }
2653 state = update;
2654 }
2655 });
2656
2657 let rendezvous_server_clone = rendezvous_server.clone();
2658 let bob_task = spawn(async move {
2660 request_login_with_generated_qr_code(
2661 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2662 channel,
2663 checkcode_rx,
2664 None,
2665 &rendezvous_server_clone,
2666 alice.homeserver(),
2667 Some(device_authorization_grant),
2668 None,
2669 )
2670 .await;
2671 });
2672
2673 assert_matches!(
2675 grant.await,
2676 Err(QRCodeGrantLoginError::LoginFailure {
2677 reason: LoginFailureReason::AuthorizationExpired
2678 }),
2679 "Alice should abort the login with expected error"
2680 );
2681 updates_task.await.expect("Alice should run through all progress states");
2682 bob_task.await.expect("Bob's task should finish");
2683 }
2684
2685 #[async_test]
2686 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_success() {
2687 let server = MatrixMockServer::new().await;
2688 let rendezvous_server = Arc::new(
2689 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2690 );
2691 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2692
2693 let device_authorization_grant = AuthorizationGrant {
2694 verification_uri_complete: Some(VerificationUriComplete::new(
2695 "https://id.matrix.org/device/abcde".to_owned(),
2696 )),
2697 verification_uri: EndUserVerificationUrl::new(
2698 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2699 )
2700 .unwrap(),
2701 };
2702
2703 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2704 server
2705 .mock_upload_cross_signing_keys()
2706 .ok()
2707 .expect(1)
2708 .named("upload_xsigning_keys")
2709 .mount()
2710 .await;
2711 server
2712 .mock_upload_cross_signing_signatures()
2713 .ok()
2714 .expect(1)
2715 .named("upload_xsigning_signatures")
2716 .mount()
2717 .await;
2718
2719 let user_id = owned_user_id!("@alice:example.org");
2721 let device_id = owned_device_id!("ALICE_DEVICE");
2722 let alice = server
2723 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2724 .logged_in_with_oauth()
2725 .build()
2726 .await;
2727 alice
2728 .encryption()
2729 .bootstrap_cross_signing(None)
2730 .await
2731 .expect("Alice should be able to set up cross signing");
2732
2733 let oauth = alice.oauth();
2735 let grant = oauth
2736 .grant_login_with_qr_code()
2737 .device_creation_timeout(Duration::from_secs(2))
2738 .generate();
2739 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2740 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2741
2742 let mut updates = grant.subscribe_to_progress();
2744 let mut state = grant.state.get();
2745 let verification_uri_complete =
2746 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2747 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2748 let updates_task = spawn(async move {
2749 let mut qr_code_tx = Some(qr_code_tx);
2750 let mut checkcode_rx = Some(checkcode_rx);
2751
2752 while let Some(update) = updates.next().await {
2753 match &update {
2754 GrantLoginProgress::Starting => {
2755 assert_matches!(state, GrantLoginProgress::Starting);
2756 }
2757 GrantLoginProgress::EstablishingSecureChannel(
2758 GeneratedQrProgress::QrReady(qr_code_data),
2759 ) => {
2760 assert_matches!(state, GrantLoginProgress::Starting);
2761 qr_code_tx
2762 .take()
2763 .expect("The QR code should only be forwarded once")
2764 .send(qr_code_data.clone())
2765 .expect("Alice should be able to forward the QR code");
2766 }
2767 GrantLoginProgress::EstablishingSecureChannel(
2768 GeneratedQrProgress::QrScanned(checkcode_sender),
2769 ) => {
2770 assert_matches!(
2771 state,
2772 GrantLoginProgress::EstablishingSecureChannel(
2773 GeneratedQrProgress::QrReady(_)
2774 )
2775 );
2776 let checkcode = checkcode_rx
2777 .take()
2778 .expect("The checkcode should only be forwarded once")
2779 .await
2780 .expect("Alice should receive the checkcode");
2781 checkcode_sender
2782 .send(checkcode)
2783 .await
2784 .expect("Alice should be able to forward the checkcode");
2785 }
2786 GrantLoginProgress::WaitingForAuth {
2787 verification_uri,
2788 continuation_sender,
2789 } => {
2790 assert_matches!(
2791 state,
2792 GrantLoginProgress::EstablishingSecureChannel(
2793 GeneratedQrProgress::QrScanned(_)
2794 )
2795 );
2796 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2797 continuation_sender.confirm().await.expect("should be able to confirm");
2798 }
2799 _ => {
2800 panic!("Alice should abort the process");
2801 }
2802 }
2803 state = update;
2804 }
2805 });
2806
2807 let rendezvous_server_clone = rendezvous_server.clone();
2809 let bob_task = spawn(async move {
2810 request_login_with_scanned_qr_code(
2811 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
2812 qr_code_rx,
2813 checkcode_tx,
2814 None,
2815 &rendezvous_server_clone,
2816 Some(device_authorization_grant),
2817 None,
2818 )
2819 .await;
2820 });
2821
2822 assert_let!(
2824 Err(QRCodeGrantLoginError::UnexpectedMessage {
2825 expected: "m.login.success",
2826 received,
2827 }) = grant.await,
2828 "Alice should abort the login with expected error variant"
2829 );
2830 assert_matches!(
2831 *received,
2832 QrAuthMessage::LoginProtocolAccepted,
2833 "Alice should abort the login with expected error message"
2834 );
2835 updates_task.await.expect("Alice should run through all progress states");
2836 bob_task.await.expect("Bob's task should finish");
2837 }
2838
2839 #[async_test]
2840 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_success() {
2841 let server = MatrixMockServer::new().await;
2842 let rendezvous_server = Arc::new(
2843 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2844 );
2845 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2846
2847 let device_authorization_grant = AuthorizationGrant {
2848 verification_uri_complete: Some(VerificationUriComplete::new(
2849 "https://id.matrix.org/device/abcde".to_owned(),
2850 )),
2851 verification_uri: EndUserVerificationUrl::new(
2852 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2853 )
2854 .unwrap(),
2855 };
2856
2857 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2858 server
2859 .mock_upload_cross_signing_keys()
2860 .ok()
2861 .expect(1)
2862 .named("upload_xsigning_keys")
2863 .mount()
2864 .await;
2865 server
2866 .mock_upload_cross_signing_signatures()
2867 .ok()
2868 .expect(1)
2869 .named("upload_xsigning_signatures")
2870 .mount()
2871 .await;
2872
2873 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2875 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2876 .await
2877 .expect("Bob should be able to create a secure channel.");
2878 let qr_code_data = channel.qr_code_data().clone();
2879
2880 let user_id = owned_user_id!("@alice:example.org");
2882 let device_id = owned_device_id!("ALICE_DEVICE");
2883 let alice = server
2884 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2885 .logged_in_with_oauth()
2886 .build()
2887 .await;
2888 alice
2889 .encryption()
2890 .bootstrap_cross_signing(None)
2891 .await
2892 .expect("Alice should be able to set up cross signing");
2893
2894 let oauth = alice.oauth();
2896 let grant = oauth
2897 .grant_login_with_qr_code()
2898 .device_creation_timeout(Duration::from_secs(2))
2899 .scan(&qr_code_data);
2900 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2901
2902 let mut updates = grant.subscribe_to_progress();
2904 let mut state = grant.state.get();
2905 let verification_uri_complete =
2906 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2907 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2908 let updates_task = spawn(async move {
2909 let mut checkcode_tx = Some(checkcode_tx);
2910
2911 while let Some(update) = updates.next().await {
2912 match &update {
2913 GrantLoginProgress::Starting => {
2914 assert_matches!(state, GrantLoginProgress::Starting);
2915 }
2916 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2917 assert_matches!(state, GrantLoginProgress::Starting);
2918 checkcode_tx
2919 .take()
2920 .expect("The checkcode should only be forwarded once")
2921 .send(*check_code)
2922 .expect("Alice should be able to forward the checkcode");
2923 }
2924 GrantLoginProgress::WaitingForAuth {
2925 verification_uri,
2926 continuation_sender,
2927 } => {
2928 assert_matches!(
2929 state,
2930 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2931 );
2932 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2933 continuation_sender.confirm().await.expect("should be able to confirm");
2934 }
2935 _ => {
2936 panic!("Alice should abort the process");
2937 }
2938 }
2939 state = update;
2940 }
2941 });
2942
2943 let rendezvous_server_clone = rendezvous_server.clone();
2944 let bob_task = spawn(async move {
2946 request_login_with_generated_qr_code(
2947 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
2948 channel,
2949 checkcode_rx,
2950 None,
2951 &rendezvous_server_clone,
2952 alice.homeserver(),
2953 Some(device_authorization_grant),
2954 None,
2955 )
2956 .await;
2957 });
2958
2959 assert_let!(
2961 Err(QRCodeGrantLoginError::UnexpectedMessage {
2962 expected: "m.login.success",
2963 received,
2964 }) = grant.await,
2965 "Alice should abort the login with expected error variant"
2966 );
2967 assert_matches!(
2968 *received,
2969 QrAuthMessage::LoginProtocolAccepted,
2970 "Alice should abort the login with expected error message"
2971 );
2972 updates_task.await.expect("Alice should run through all progress states");
2973 bob_task.await.expect("Bob's task should finish");
2974 }
2975
2976 #[async_test]
2977 async fn test_grant_login_with_generated_qr_code_secure_channel_error() {
2978 let server = MatrixMockServer::new().await;
2979 let rendezvous_server = Arc::new(
2980 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2981 );
2982 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2983
2984 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2985 server
2986 .mock_upload_cross_signing_keys()
2987 .ok()
2988 .expect(1)
2989 .named("upload_xsigning_keys")
2990 .mount()
2991 .await;
2992 server
2993 .mock_upload_cross_signing_signatures()
2994 .ok()
2995 .expect(1)
2996 .named("upload_xsigning_signatures")
2997 .mount()
2998 .await;
2999
3000 let user_id = owned_user_id!("@alice:example.org");
3002 let device_id = owned_device_id!("ALICE_DEVICE");
3003 let alice = server
3004 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3005 .logged_in_with_oauth()
3006 .build()
3007 .await;
3008 alice
3009 .encryption()
3010 .bootstrap_cross_signing(None)
3011 .await
3012 .expect("Alice should be able to set up cross signing");
3013
3014 let oauth = alice.oauth();
3016 let grant = oauth
3017 .grant_login_with_qr_code()
3018 .device_creation_timeout(Duration::from_secs(2))
3019 .generate();
3020 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3021 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3022
3023 let mut updates = grant.subscribe_to_progress();
3025 let mut state = grant.state.get();
3026 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3027 let updates_task = spawn(async move {
3028 let mut qr_code_tx = Some(qr_code_tx);
3029 let mut checkcode_rx = Some(checkcode_rx);
3030
3031 while let Some(update) = updates.next().await {
3032 match &update {
3033 GrantLoginProgress::Starting => {
3034 assert_matches!(state, GrantLoginProgress::Starting);
3035 }
3036 GrantLoginProgress::EstablishingSecureChannel(
3037 GeneratedQrProgress::QrReady(qr_code_data),
3038 ) => {
3039 assert_matches!(state, GrantLoginProgress::Starting);
3040 qr_code_tx
3041 .take()
3042 .expect("The QR code should only be forwarded once")
3043 .send(qr_code_data.clone())
3044 .expect("Alice should be able to forward the QR code");
3045 }
3046 GrantLoginProgress::EstablishingSecureChannel(
3047 GeneratedQrProgress::QrScanned(checkcode_sender),
3048 ) => {
3049 assert_matches!(
3050 state,
3051 GrantLoginProgress::EstablishingSecureChannel(
3052 GeneratedQrProgress::QrReady(_)
3053 )
3054 );
3055 let checkcode = checkcode_rx
3056 .take()
3057 .expect("The checkcode should only be forwarded once")
3058 .await
3059 .expect("Alice should receive the checkcode");
3060 checkcode_sender
3061 .send(checkcode)
3062 .await
3063 .expect("Alice should be able to forward the checkcode");
3064 break;
3065 }
3066 _ => {
3067 panic!("Alice should abort the process");
3068 }
3069 }
3070 state = update;
3071 }
3072 });
3073
3074 let rendezvous_server_clone = rendezvous_server.clone();
3076 let bob_task = spawn(async move {
3077 request_login_with_scanned_qr_code(
3078 BobBehaviour::InvalidJsonMessage,
3079 qr_code_rx,
3080 checkcode_tx,
3081 None,
3082 &rendezvous_server_clone,
3083 None,
3084 None,
3085 )
3086 .await;
3087 });
3088
3089 assert_matches!(
3091 grant.await,
3092 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::Json(_))),
3093 "Alice should abort the login with a SecureChannel error"
3094 );
3095 updates_task.await.expect("Alice should run through all progress states");
3096 bob_task.await.expect("Bob's task should finish");
3097 }
3098
3099 #[async_test]
3100 async fn test_grant_login_with_scanned_qr_code_secure_channel_error() {
3101 let server = MatrixMockServer::new().await;
3102 let rendezvous_server = Arc::new(
3103 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
3104 );
3105 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3106
3107 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3108 server
3109 .mock_upload_cross_signing_keys()
3110 .ok()
3111 .expect(1)
3112 .named("upload_xsigning_keys")
3113 .mount()
3114 .await;
3115 server
3116 .mock_upload_cross_signing_signatures()
3117 .ok()
3118 .expect(1)
3119 .named("upload_xsigning_signatures")
3120 .mount()
3121 .await;
3122
3123 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3125 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3126 .await
3127 .expect("Bob should be able to create a secure channel.");
3128 let qr_code_data = channel.qr_code_data().clone();
3129
3130 let user_id = owned_user_id!("@alice:example.org");
3132 let device_id = owned_device_id!("ALICE_DEVICE");
3133 let alice = server
3134 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3135 .logged_in_with_oauth()
3136 .build()
3137 .await;
3138 alice
3139 .encryption()
3140 .bootstrap_cross_signing(None)
3141 .await
3142 .expect("Alice should be able to set up cross signing");
3143
3144 let oauth = alice.oauth();
3146 let grant = oauth
3147 .grant_login_with_qr_code()
3148 .device_creation_timeout(Duration::from_secs(2))
3149 .scan(&qr_code_data);
3150 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3151
3152 let mut updates = grant.subscribe_to_progress();
3154 let mut state = grant.state.get();
3155 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3156 let updates_task = spawn(async move {
3157 let mut checkcode_tx = Some(checkcode_tx);
3158
3159 while let Some(update) = updates.next().await {
3160 match &update {
3161 GrantLoginProgress::Starting => {
3162 assert_matches!(state, GrantLoginProgress::Starting);
3163 }
3164 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3165 assert_matches!(state, GrantLoginProgress::Starting);
3166 checkcode_tx
3167 .take()
3168 .expect("The checkcode should only be forwarded once")
3169 .send(*check_code)
3170 .expect("Alice should be able to forward the checkcode");
3171 break;
3172 }
3173 _ => {
3174 panic!("Alice should abort the process");
3175 }
3176 }
3177 state = update;
3178 }
3179 });
3180
3181 let rendezvous_server_clone = rendezvous_server.clone();
3182 let bob_task = spawn(async move {
3184 request_login_with_generated_qr_code(
3185 BobBehaviour::InvalidJsonMessage,
3186 channel,
3187 checkcode_rx,
3188 None,
3189 &rendezvous_server_clone,
3190 alice.homeserver(),
3191 None,
3192 None,
3193 )
3194 .await;
3195 });
3196
3197 assert_matches!(
3199 grant.await,
3200 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::Json(_))),
3201 "Alice should abort the login with a SecureChannel error"
3202 );
3203 updates_task.await.expect("Alice should run through all progress states");
3204 bob_task.await.expect("Bob's task should finish");
3205 }
3206
3207 #[async_test]
3208 async fn test_grant_login_with_generated_qr_code_cancelled_while_waiting_for_auth() {
3209 let server = MatrixMockServer::new().await;
3210 let rendezvous_server =
3211 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
3212 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3213
3214 let device_authorization_grant = AuthorizationGrant {
3215 verification_uri_complete: Some(VerificationUriComplete::new(
3216 "https://id.matrix.org/device/abcde".to_owned(),
3217 )),
3218 verification_uri: EndUserVerificationUrl::new(
3219 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3220 )
3221 .unwrap(),
3222 };
3223
3224 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3225 server
3226 .mock_upload_cross_signing_keys()
3227 .ok()
3228 .expect(1)
3229 .named("upload_xsigning_keys")
3230 .mount()
3231 .await;
3232 server
3233 .mock_upload_cross_signing_signatures()
3234 .ok()
3235 .expect(1)
3236 .named("upload_xsigning_signatures")
3237 .mount()
3238 .await;
3239
3240 let user_id = owned_user_id!("@alice:example.org");
3242 let device_id = owned_device_id!("ALICE_DEVICE");
3243 let alice = server
3244 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3245 .logged_in_with_oauth()
3246 .build()
3247 .await;
3248 alice
3249 .encryption()
3250 .bootstrap_cross_signing(None)
3251 .await
3252 .expect("Alice should be able to set up cross signing");
3253
3254 let oauth = alice.oauth();
3256 let grant = oauth
3257 .grant_login_with_qr_code()
3258 .device_creation_timeout(Duration::from_secs(2))
3259 .generate();
3260 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3261 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3262
3263 let mut updates = grant.subscribe_to_progress();
3265 let mut state = grant.state.get();
3266 let verification_uri_complete =
3267 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3268 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3269 let updates_task = spawn(async move {
3270 let mut qr_code_tx = Some(qr_code_tx);
3271 let mut checkcode_rx = Some(checkcode_rx);
3272
3273 while let Some(update) = updates.next().await {
3274 match &update {
3275 GrantLoginProgress::Starting => {
3276 assert_matches!(state, GrantLoginProgress::Starting);
3277 }
3278 GrantLoginProgress::EstablishingSecureChannel(
3279 GeneratedQrProgress::QrReady(qr_code_data),
3280 ) => {
3281 assert_matches!(state, GrantLoginProgress::Starting);
3282 qr_code_tx
3283 .take()
3284 .expect("The QR code should only be forwarded once")
3285 .send(qr_code_data.clone())
3286 .expect("Alice should be able to forward the QR code");
3287 }
3288 GrantLoginProgress::EstablishingSecureChannel(
3289 GeneratedQrProgress::QrScanned(checkcode_sender),
3290 ) => {
3291 assert_matches!(
3292 state,
3293 GrantLoginProgress::EstablishingSecureChannel(
3294 GeneratedQrProgress::QrReady(_)
3295 )
3296 );
3297 let checkcode = checkcode_rx
3298 .take()
3299 .expect("The checkcode should only be forwarded once")
3300 .await
3301 .expect("Alice should receive the checkcode");
3302 checkcode_sender
3303 .send(checkcode)
3304 .await
3305 .expect("Alice should be able to forward the checkcode");
3306 }
3307 GrantLoginProgress::WaitingForAuth {
3308 verification_uri,
3309 continuation_sender,
3310 } => {
3311 assert_matches!(
3312 state,
3313 GrantLoginProgress::EstablishingSecureChannel(
3314 GeneratedQrProgress::QrScanned(_)
3315 )
3316 );
3317 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3318 continuation_sender.cancel().await.expect("should be able to cancel");
3320 break;
3321 }
3322 _ => {
3323 panic!("Alice should abort the process after being cancelled");
3324 }
3325 }
3326 state = update;
3327 }
3328 });
3329
3330 let bob_task = spawn(async move {
3332 request_login_with_scanned_qr_code(
3333 BobBehaviour::CancelledWhileWaitingForAuth,
3334 qr_code_rx,
3335 checkcode_tx,
3336 Some(server),
3337 &rendezvous_server,
3338 Some(device_authorization_grant),
3339 None,
3340 )
3341 .await;
3342 });
3343
3344 assert_matches!(
3346 grant.await,
3347 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3348 "Alice should abort the login with expected error"
3349 );
3350 updates_task.await.expect("Alice should run through all progress states");
3351 bob_task.await.expect("Bob's task should finish");
3352 }
3353
3354 #[async_test]
3355 async fn test_grant_login_with_scanned_qr_code_cancelled_while_waiting_for_auth() {
3356 let server = MatrixMockServer::new().await;
3357 let rendezvous_server =
3358 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
3359 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3360
3361 let device_authorization_grant = AuthorizationGrant {
3362 verification_uri_complete: Some(VerificationUriComplete::new(
3363 "https://id.matrix.org/device/abcde".to_owned(),
3364 )),
3365 verification_uri: EndUserVerificationUrl::new(
3366 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3367 )
3368 .unwrap(),
3369 };
3370
3371 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3372 server
3373 .mock_upload_cross_signing_keys()
3374 .ok()
3375 .expect(1)
3376 .named("upload_xsigning_keys")
3377 .mount()
3378 .await;
3379 server
3380 .mock_upload_cross_signing_signatures()
3381 .ok()
3382 .expect(1)
3383 .named("upload_xsigning_signatures")
3384 .mount()
3385 .await;
3386
3387 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3389 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3390 .await
3391 .expect("Bob should be able to create a secure channel.");
3392 let qr_code_data = channel.qr_code_data().clone();
3393
3394 let user_id = owned_user_id!("@alice:example.org");
3396 let device_id = owned_device_id!("ALICE_DEVICE");
3397 let alice = server
3398 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3399 .logged_in_with_oauth()
3400 .build()
3401 .await;
3402 alice
3403 .encryption()
3404 .bootstrap_cross_signing(None)
3405 .await
3406 .expect("Alice should be able to set up cross signing");
3407
3408 let oauth = alice.oauth();
3410 let grant = oauth
3411 .grant_login_with_qr_code()
3412 .device_creation_timeout(Duration::from_secs(2))
3413 .scan(&qr_code_data);
3414 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3415
3416 let mut updates = grant.subscribe_to_progress();
3418 let mut state = grant.state.get();
3419 let verification_uri_complete =
3420 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3421 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3422 let updates_task = spawn(async move {
3423 let mut checkcode_tx = Some(checkcode_tx);
3424
3425 while let Some(update) = updates.next().await {
3426 match &update {
3427 GrantLoginProgress::Starting => {
3428 assert_matches!(state, GrantLoginProgress::Starting);
3429 }
3430 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3431 assert_matches!(state, GrantLoginProgress::Starting);
3432 checkcode_tx
3433 .take()
3434 .expect("The checkcode should only be forwarded once")
3435 .send(*check_code)
3436 .expect("Alice should be able to forward the checkcode");
3437 }
3438 GrantLoginProgress::WaitingForAuth {
3439 verification_uri,
3440 continuation_sender,
3441 } => {
3442 assert_matches!(
3443 state,
3444 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3445 );
3446 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3447 continuation_sender.cancel().await.expect("should be able to cancel");
3449 break;
3450 }
3451 _ => {
3452 panic!("Alice should abort the process after being cancelled");
3453 }
3454 }
3455 state = update;
3456 }
3457 });
3458
3459 let bob_task = spawn(async move {
3461 request_login_with_generated_qr_code(
3462 BobBehaviour::CancelledWhileWaitingForAuth,
3463 channel,
3464 checkcode_rx,
3465 Some(server),
3466 &rendezvous_server,
3467 alice.homeserver(),
3468 Some(device_authorization_grant),
3469 None,
3470 )
3471 .await;
3472 });
3473
3474 assert_matches!(
3476 grant.await,
3477 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3478 "Alice should abort the login with expected error"
3479 );
3480 updates_task.await.expect("Alice should run through all progress states");
3481 bob_task.await.expect("Bob's task should finish");
3482 }
3483}