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, GeneratedQrProgress, LoginFailureReason, QRCodeGrantLoginError,
40 QrProgress, SecureChannelError,
41 },
42};
43
44async fn export_secrets_bundle(client: &Client) -> Result<SecretsBundle, QRCodeGrantLoginError> {
45 let secrets_bundle = client
46 .olm_machine()
47 .await
48 .as_ref()
49 .ok_or_else(|| QRCodeGrantLoginError::MissingSecretsBackup(None))?
50 .store()
51 .export_secrets_bundle()
52 .await?;
53 Ok(secrets_bundle)
54}
55
56async fn finish_login_grant<Q>(
57 client: &Client,
58 channel: &mut EstablishedSecureChannel,
59 device_creation_timeout: Duration,
60 secrets_bundle: &SecretsBundle,
61 state: &SharedObservable<GrantLoginProgress<Q>>,
62) -> Result<(), QRCodeGrantLoginError> {
63 let (device_authorization_grant, protocol, device_id) = match channel.receive_json().await? {
70 QrAuthMessage::LoginProtocol { device_authorization_grant, protocol, device_id } => {
71 (device_authorization_grant, protocol, device_id)
72 }
73 QrAuthMessage::LoginFailure { reason, .. } => {
74 return Err(QRCodeGrantLoginError::LoginFailure { reason });
75 }
76 message => {
77 return Err(QRCodeGrantLoginError::UnexpectedMessage {
78 expected: "m.login.protocol",
79 received: message,
80 });
81 }
82 };
83
84 if protocol != LoginProtocolType::DeviceAuthorizationGrant {
87 channel
88 .send_json(QrAuthMessage::LoginFailure {
89 reason: LoginFailureReason::UnsupportedProtocol,
90 homeserver: None,
91 })
92 .await?;
93 return Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol));
94 }
95
96 if !matches!(client.device_exists(device_id.clone().into()).await, Ok(false)) {
99 channel
100 .send_json(QrAuthMessage::LoginFailure {
101 reason: LoginFailureReason::DeviceAlreadyExists,
102 homeserver: None,
103 })
104 .await?;
105 return Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse);
106 }
107
108 let verification_uri = Url::parse(
112 device_authorization_grant
113 .verification_uri_complete
114 .map(VerificationUriComplete::into_secret)
115 .unwrap_or(device_authorization_grant.verification_uri.to_string())
116 .as_str(),
117 )
118 .map_err(|e| QRCodeGrantLoginError::Unknown(e.to_string()))?;
119 state.set(GrantLoginProgress::WaitingForAuth { verification_uri });
120
121 let message = QrAuthMessage::LoginProtocolAccepted;
125 channel.send_json(&message).await?;
126
127 match channel.receive_json().await? {
136 QrAuthMessage::LoginSuccess => (),
137 QrAuthMessage::LoginFailure { reason, .. } => {
138 return Err(QRCodeGrantLoginError::LoginFailure { reason });
139 }
140 message => {
141 return Err(QRCodeGrantLoginError::UnexpectedMessage {
142 expected: "m.login.success",
143 received: message,
144 });
145 }
146 }
147
148 let deadline = Instant::now() + device_creation_timeout;
151
152 loop {
153 if matches!(client.device_exists(device_id.clone().into()).await, Ok(true)) {
154 break;
155 } else {
156 if Instant::now() < deadline {
158 tokio::time::sleep(Duration::from_millis(500)).await;
159 continue;
160 } else {
161 channel
163 .send_json(QrAuthMessage::LoginFailure {
164 reason: LoginFailureReason::DeviceNotFound,
165 homeserver: None,
166 })
167 .await?;
168 return Err(QRCodeGrantLoginError::DeviceNotFound);
169 }
170 }
171 }
172
173 state.set(GrantLoginProgress::SyncingSecrets);
176 let message = QrAuthMessage::LoginSecrets(secrets_bundle.clone());
177 channel.send_json(&message).await?;
178
179 state.set(GrantLoginProgress::Done);
181
182 Ok(())
183}
184
185#[derive(Clone, Debug, Default)]
187pub enum GrantLoginProgress<Q> {
188 #[default]
190 Starting,
191 EstablishingSecureChannel(Q),
194 WaitingForAuth {
197 verification_uri: Url,
199 },
200 SyncingSecrets,
203 Done,
205}
206
207#[derive(Debug)]
210pub struct GrantLoginWithScannedQrCode<'a> {
211 client: &'a Client,
212 qr_code_data: &'a QrCodeData,
213 device_creation_timeout: Duration,
214 state: SharedObservable<GrantLoginProgress<QrProgress>>,
215}
216
217impl<'a> GrantLoginWithScannedQrCode<'a> {
218 pub(crate) fn new(
219 client: &'a Client,
220 qr_code_data: &'a QrCodeData,
221 device_creation_timeout: Duration,
222 ) -> GrantLoginWithScannedQrCode<'a> {
223 GrantLoginWithScannedQrCode {
224 client,
225 qr_code_data,
226 device_creation_timeout,
227 state: Default::default(),
228 }
229 }
230}
231
232impl GrantLoginWithScannedQrCode<'_> {
233 pub fn subscribe_to_progress(
239 &self,
240 ) -> impl Stream<Item = GrantLoginProgress<QrProgress>> + use<> {
241 self.state.subscribe()
242 }
243}
244
245impl<'a> IntoFuture for GrantLoginWithScannedQrCode<'a> {
246 type Output = Result<(), QRCodeGrantLoginError>;
247 boxed_into_future!(extra_bounds: 'a);
248
249 fn into_future(self) -> Self::IntoFuture {
250 Box::pin(async move {
251 let secrets_bundle = export_secrets_bundle(self.client).await?;
261
262 let mut channel = EstablishedSecureChannel::from_qr_code(
263 self.client.inner.http_client.inner.clone(),
264 self.qr_code_data,
265 QrCodeIntent::Reciprocate,
266 )
267 .await?;
268
269 let check_code = channel.check_code().to_owned();
273 self.state
274 .set(GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
275
276 let message = QrAuthMessage::LoginProtocols {
284 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
285 homeserver: self.client.homeserver(),
286 };
287 channel.send_json(message).await?;
288
289 finish_login_grant(
292 self.client,
293 &mut channel,
294 self.device_creation_timeout,
295 &secrets_bundle,
296 &self.state,
297 )
298 .await
299 })
300 }
301}
302
303#[derive(Debug)]
306pub struct GrantLoginWithGeneratedQrCode<'a> {
307 client: &'a Client,
308 device_creation_timeout: Duration,
309 state: SharedObservable<GrantLoginProgress<GeneratedQrProgress>>,
310}
311
312impl<'a> GrantLoginWithGeneratedQrCode<'a> {
313 pub(crate) fn new(
314 client: &'a Client,
315 device_creation_timeout: Duration,
316 ) -> GrantLoginWithGeneratedQrCode<'a> {
317 GrantLoginWithGeneratedQrCode { client, device_creation_timeout, state: Default::default() }
318 }
319}
320
321impl GrantLoginWithGeneratedQrCode<'_> {
322 pub fn subscribe_to_progress(
329 &self,
330 ) -> impl Stream<Item = GrantLoginProgress<GeneratedQrProgress>> + use<> {
331 self.state.subscribe()
332 }
333}
334
335impl<'a> IntoFuture for GrantLoginWithGeneratedQrCode<'a> {
336 type Output = Result<(), QRCodeGrantLoginError>;
337 boxed_into_future!(extra_bounds: 'a);
338
339 fn into_future(self) -> Self::IntoFuture {
340 Box::pin(async move {
341 let homeserver_url = self.client.homeserver();
345 let http_client = self.client.inner.http_client.clone();
346 let secrets_bundle = export_secrets_bundle(self.client).await?;
347 let channel = SecureChannel::reciprocate(http_client, &homeserver_url).await?;
348
349 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
353 GeneratedQrProgress::QrReady(channel.qr_code_data().clone()),
354 ));
355
356 let channel = channel.connect().await?;
360
361 let (tx, rx) = tokio::sync::oneshot::channel();
366 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
367 GeneratedQrProgress::QrScanned(CheckCodeSender::new(tx)),
368 ));
369 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
370
371 let mut channel = channel.confirm(check_code)?;
374
375 finish_login_grant(
383 self.client,
384 &mut channel,
385 self.device_creation_timeout,
386 &secrets_bundle,
387 &self.state,
388 )
389 .await
390 })
391 }
392}
393
394#[cfg(all(test, not(target_family = "wasm")))]
395mod test {
396 use std::sync::Arc;
397
398 use assert_matches2::{assert_let, assert_matches};
399 use futures_util::StreamExt;
400 use matrix_sdk_base::crypto::types::SecretsBundle;
401 use matrix_sdk_common::executor::spawn;
402 use matrix_sdk_test::async_test;
403 use oauth2::{EndUserVerificationUrl, VerificationUriComplete};
404 use ruma::{owned_device_id, owned_user_id};
405 use tokio::sync::oneshot;
406 use tracing::debug;
407
408 use super::*;
409 use crate::{
410 authentication::oauth::qrcode::{
411 LoginFailureReason, QrAuthMessage,
412 messages::{AuthorizationGrant, LoginProtocolType},
413 secure_channel::{EstablishedSecureChannel, test::MockedRendezvousServer},
414 },
415 http_client::HttpClient,
416 test_utils::mocks::MatrixMockServer,
417 };
418
419 enum BobBehaviour {
420 HappyPath,
421 UnexpectedMessageInsteadOfLoginProtocol,
422 LoginFailureInsteadOfLoginProtocol,
423 UnexpectedMessageInsteadOfLoginSuccess,
424 LoginFailureInsteadOfLoginSuccess,
425 DeviceAlreadyExists,
426 DeviceNotCreated,
427 InvalidJsonMessage,
428 }
429
430 #[allow(clippy::too_many_arguments)]
431 async fn request_login_with_scanned_qr_code(
432 behaviour: BobBehaviour,
433 qr_code_rx: oneshot::Receiver<QrCodeData>,
434 check_code_tx: oneshot::Sender<u8>,
435 server: Option<MatrixMockServer>,
436 _rendezvous_server: &MockedRendezvousServer,
440 device_authorization_grant: Option<AuthorizationGrant>,
441 secrets_bundle: Option<SecretsBundle>,
442 ) {
443 let qr_code_data = qr_code_rx.await.expect("Bob should receive the QR code");
445
446 let mut bob = EstablishedSecureChannel::from_qr_code(
448 reqwest::Client::new(),
449 &qr_code_data,
450 QrCodeIntent::Login,
451 )
452 .await
453 .expect("Bob should be able to connect the secure channel");
454
455 check_code_tx
457 .send(bob.check_code().to_digit())
458 .expect("Bob should be able to send the checkcode");
459
460 match behaviour {
461 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
462 let message = QrAuthMessage::LoginSuccess;
464 bob.send_json(message).await.unwrap();
465 return;
466 }
467 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
468 let message = QrAuthMessage::LoginFailure {
470 reason: LoginFailureReason::UserCancelled,
471 homeserver: None,
472 };
473 bob.send_json(message).await.unwrap();
474 return;
475 }
476 BobBehaviour::InvalidJsonMessage => {
477 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
479 return;
480 }
481 BobBehaviour::DeviceAlreadyExists => {
482 server
485 .as_ref()
486 .expect("Bob needs the server for DeviceAlreadyExists")
487 .mock_get_device()
488 .ok()
489 .expect(1..)
490 .named("get_device")
491 .mount()
492 .await;
493
494 let message = QrAuthMessage::LoginProtocol {
496 protocol: LoginProtocolType::DeviceAuthorizationGrant,
497 device_authorization_grant: device_authorization_grant
498 .expect("Bob needs the device authorization grant"),
499 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
500 };
501 bob.send_json(message).await.unwrap();
502
503 let message = bob
505 .receive_json()
506 .await
507 .expect("Bob should receive the LoginFailure message from Alice");
508 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
509 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
510
511 return; }
513 _ => {
514 let message = QrAuthMessage::LoginProtocol {
516 protocol: LoginProtocolType::DeviceAuthorizationGrant,
517 device_authorization_grant: device_authorization_grant
518 .expect("Bob needs the device authorization grant"),
519 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
520 };
521 bob.send_json(message).await.unwrap();
522 }
523 }
524
525 let message = bob
527 .receive_json()
528 .await
529 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
530 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
531
532 match behaviour {
533 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
534 let message = QrAuthMessage::LoginProtocolAccepted;
536 bob.send_json(message).await.unwrap();
537 return;
538 }
539 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
540 let message = QrAuthMessage::LoginFailure {
542 reason: LoginFailureReason::AuthorizationExpired,
543 homeserver: None,
544 };
545 bob.send_json(message).await.unwrap();
546 return;
547 }
548 BobBehaviour::DeviceNotCreated => {
549 let message = QrAuthMessage::LoginSuccess;
554 bob.send_json(message).await.unwrap();
555
556 let message = bob
559 .receive_json()
560 .await
561 .expect("Bob should receive the LoginFailure message from Alice");
562 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
563 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
564
565 return; }
567 _ => {
568 server
571 .as_ref()
572 .expect("Bob needs the server for HappyPath")
573 .mock_get_device()
574 .ok()
575 .expect(1..)
576 .named("get_device")
577 .mount()
578 .await;
579
580 let message = QrAuthMessage::LoginSuccess;
582 bob.send_json(message).await.unwrap();
583 }
584 }
585
586 let message = bob
588 .receive_json()
589 .await
590 .expect("Bob should receive the LoginSecrets message from Alice");
591 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
592
593 assert_eq!(
595 serde_json::to_value(&secrets_bundle).unwrap(),
596 serde_json::to_value(&bundle).unwrap()
597 );
598 }
599
600 #[allow(clippy::too_many_arguments)]
601 async fn request_login_with_generated_qr_code(
602 behaviour: BobBehaviour,
603 channel: SecureChannel,
604 check_code_rx: oneshot::Receiver<u8>,
605 server: Option<MatrixMockServer>,
606 _rendezvous_server: &MockedRendezvousServer,
610 homeserver: Url,
611 device_authorization_grant: Option<AuthorizationGrant>,
612 secrets_bundle: Option<SecretsBundle>,
613 ) {
614 let channel =
616 channel.connect().await.expect("Bob should be able to connect the secure channel");
617
618 let check_code = check_code_rx.await.expect("Bob should receive the checkcode");
620 let mut bob = channel
621 .confirm(check_code)
622 .expect("Bob should be able to confirm the channel is secure");
623
624 let message = bob
626 .receive_json()
627 .await
628 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
629 assert_let!(
630 QrAuthMessage::LoginProtocols { protocols, homeserver: alice_homeserver } = message
631 );
632 assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
633 assert_eq!(alice_homeserver, homeserver);
634
635 match behaviour {
636 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
637 let message = QrAuthMessage::LoginSuccess;
639 bob.send_json(message).await.unwrap();
640 return;
641 }
642 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
643 let message = QrAuthMessage::LoginFailure {
645 reason: LoginFailureReason::UserCancelled,
646 homeserver: None,
647 };
648 bob.send_json(message).await.unwrap();
649 return;
650 }
651 BobBehaviour::InvalidJsonMessage => {
652 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
654 return;
655 }
656 BobBehaviour::DeviceAlreadyExists => {
657 server
660 .as_ref()
661 .expect("Bob needs the MatrixMockServer")
662 .mock_get_device()
663 .ok()
664 .expect(1..)
665 .named("get_device")
666 .mount()
667 .await;
668
669 let message = QrAuthMessage::LoginProtocol {
671 protocol: LoginProtocolType::DeviceAuthorizationGrant,
672 device_authorization_grant: device_authorization_grant
673 .expect("Bob needs the device authorization grant"),
674 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
675 };
676 bob.send_json(message).await.unwrap();
677
678 let message = bob
680 .receive_json()
681 .await
682 .expect("Bob should receive the LoginFailure message from Alice");
683 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
684 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
685
686 return; }
688 _ => {
689 let message = QrAuthMessage::LoginProtocol {
691 protocol: LoginProtocolType::DeviceAuthorizationGrant,
692 device_authorization_grant: device_authorization_grant
693 .expect("Bob needs the device authorization grant"),
694 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
695 };
696 bob.send_json(message).await.unwrap();
697 }
698 }
699
700 let message = bob
702 .receive_json()
703 .await
704 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
705 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
706
707 match behaviour {
708 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
709 let message = QrAuthMessage::LoginProtocolAccepted;
711 bob.send_json(message).await.unwrap();
712 return;
713 }
714 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
715 let message = QrAuthMessage::LoginFailure {
717 reason: LoginFailureReason::AuthorizationExpired,
718 homeserver: None,
719 };
720 bob.send_json(message).await.unwrap();
721 return;
722 }
723 BobBehaviour::DeviceNotCreated => {
724 let message = QrAuthMessage::LoginSuccess;
729 bob.send_json(message).await.unwrap();
730
731 let message = bob
734 .receive_json()
735 .await
736 .expect("Bob should receive the LoginFailure message from Alice");
737 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
738 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
739
740 return; }
742 _ => {
743 server
746 .as_ref()
747 .expect("Bob needs the MatrixMockServer")
748 .mock_get_device()
749 .ok()
750 .expect(1..)
751 .named("get_device")
752 .mount()
753 .await;
754
755 let message = QrAuthMessage::LoginSuccess;
757 bob.send_json(message).await.unwrap();
758 }
759 }
760
761 let message = bob
763 .receive_json()
764 .await
765 .expect("Bob should receive the LoginSecrets message from Alice");
766 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
767
768 assert_eq!(
770 serde_json::to_value(&secrets_bundle).unwrap(),
771 serde_json::to_value(&bundle).unwrap()
772 );
773 }
774
775 #[async_test]
776 async fn test_grant_login_with_generated_qr_code() {
777 let server = MatrixMockServer::new().await;
778 let rendezvous_server =
779 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
780 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
781
782 let device_authorization_grant = AuthorizationGrant {
783 verification_uri_complete: Some(VerificationUriComplete::new(
784 "https://id.matrix.org/device/abcde".to_owned(),
785 )),
786 verification_uri: EndUserVerificationUrl::new(
787 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
788 )
789 .unwrap(),
790 };
791
792 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
793 server
794 .mock_upload_cross_signing_keys()
795 .ok()
796 .expect(1)
797 .named("upload_xsigning_keys")
798 .mount()
799 .await;
800 server
801 .mock_upload_cross_signing_signatures()
802 .ok()
803 .expect(1)
804 .named("upload_xsigning_signatures")
805 .mount()
806 .await;
807
808 let user_id = owned_user_id!("@alice:example.org");
810 let device_id = owned_device_id!("ALICE_DEVICE");
811 let alice = server
812 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
813 .logged_in_with_oauth()
814 .build()
815 .await;
816 alice
817 .encryption()
818 .bootstrap_cross_signing(None)
819 .await
820 .expect("Alice should be able to set up cross signing");
821
822 let oauth = alice.oauth();
824 let grant = oauth
825 .grant_login_with_qr_code()
826 .device_creation_timeout(Duration::from_secs(2))
827 .generate();
828 let secrets_bundle = export_secrets_bundle(&alice)
829 .await
830 .expect("Alice should be able to export the secrets bundle");
831 let (qr_code_tx, qr_code_rx) = oneshot::channel();
832 let (checkcode_tx, checkcode_rx) = oneshot::channel();
833
834 let mut updates = grant.subscribe_to_progress();
836 let mut state = grant.state.get();
837 let verification_uri_complete =
838 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
839 assert_matches!(state.clone(), GrantLoginProgress::Starting);
840 let updates_task = spawn(async move {
841 let mut qr_code_tx = Some(qr_code_tx);
842 let mut checkcode_rx = Some(checkcode_rx);
843
844 while let Some(update) = updates.next().await {
845 match &update {
846 GrantLoginProgress::Starting => {
847 assert_matches!(state, GrantLoginProgress::Starting);
848 }
849 GrantLoginProgress::EstablishingSecureChannel(
850 GeneratedQrProgress::QrReady(qr_code_data),
851 ) => {
852 assert_matches!(state, GrantLoginProgress::Starting);
853 qr_code_tx
854 .take()
855 .expect("The QR code should only be forwarded once")
856 .send(qr_code_data.clone())
857 .expect("Alice should be able to forward the QR code");
858 }
859 GrantLoginProgress::EstablishingSecureChannel(
860 GeneratedQrProgress::QrScanned(checkcode_sender),
861 ) => {
862 assert_matches!(
863 state,
864 GrantLoginProgress::EstablishingSecureChannel(
865 GeneratedQrProgress::QrReady(_)
866 )
867 );
868 let checkcode = checkcode_rx
869 .take()
870 .expect("The checkcode should only be forwarded once")
871 .await
872 .expect("Alice should receive the checkcode");
873 checkcode_sender
874 .send(checkcode)
875 .await
876 .expect("Alice should be able to forward the checkcode");
877 }
878 GrantLoginProgress::WaitingForAuth { verification_uri } => {
879 assert_matches!(
880 state,
881 GrantLoginProgress::EstablishingSecureChannel(
882 GeneratedQrProgress::QrScanned(_)
883 )
884 );
885 assert_eq!(verification_uri.as_str(), verification_uri_complete);
886 }
887 GrantLoginProgress::SyncingSecrets => {
888 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
889 }
890 GrantLoginProgress::Done => {
891 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
892 break;
893 }
894 }
895 state = update;
896 }
897 });
898
899 let bob_task = spawn(async move {
901 request_login_with_scanned_qr_code(
902 BobBehaviour::HappyPath,
903 qr_code_rx,
904 checkcode_tx,
905 Some(server),
906 &rendezvous_server,
907 Some(device_authorization_grant),
908 Some(secrets_bundle),
909 )
910 .await;
911 });
912
913 grant.await.expect("Alice should be able to grant the login");
915 updates_task.await.expect("Alice should run through all progress states");
916 bob_task.await.expect("Bob's task should finish");
917 }
918
919 #[async_test]
920 async fn test_grant_login_with_scanned_qr_code() {
921 let server = MatrixMockServer::new().await;
922 let rendezvous_server =
923 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
924 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
925
926 let device_authorization_grant = AuthorizationGrant {
927 verification_uri_complete: Some(VerificationUriComplete::new(
928 "https://id.matrix.org/device/abcde".to_owned(),
929 )),
930 verification_uri: EndUserVerificationUrl::new(
931 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
932 )
933 .unwrap(),
934 };
935
936 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
937 server
938 .mock_upload_cross_signing_keys()
939 .ok()
940 .expect(1)
941 .named("upload_xsigning_keys")
942 .mount()
943 .await;
944 server
945 .mock_upload_cross_signing_signatures()
946 .ok()
947 .expect(1)
948 .named("upload_xsigning_signatures")
949 .mount()
950 .await;
951
952 let client = HttpClient::new(reqwest::Client::new(), Default::default());
954 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
955 .await
956 .expect("Bob should be able to create a secure channel.");
957 let qr_code_data = channel.qr_code_data().clone();
958
959 let user_id = owned_user_id!("@alice:example.org");
961 let device_id = owned_device_id!("ALICE_DEVICE");
962 let alice = server
963 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
964 .logged_in_with_oauth()
965 .build()
966 .await;
967 alice
968 .encryption()
969 .bootstrap_cross_signing(None)
970 .await
971 .expect("Alice should be able to set up cross signing");
972
973 let oauth = alice.oauth();
975 let grant = oauth
976 .grant_login_with_qr_code()
977 .device_creation_timeout(Duration::from_secs(2))
978 .scan(&qr_code_data);
979 let secrets_bundle = export_secrets_bundle(&alice)
980 .await
981 .expect("Alice should be able to export the secrets bundle");
982 let (checkcode_tx, checkcode_rx) = oneshot::channel();
983
984 let mut updates = grant.subscribe_to_progress();
986 let mut state = grant.state.get();
987 let verification_uri_complete =
988 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
989 assert_matches!(state.clone(), GrantLoginProgress::Starting);
990 let updates_task = spawn(async move {
991 let mut checkcode_tx = Some(checkcode_tx);
992
993 while let Some(update) = updates.next().await {
994 match &update {
995 GrantLoginProgress::Starting => {
996 assert_matches!(state, GrantLoginProgress::Starting);
997 }
998 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
999 assert_matches!(state, GrantLoginProgress::Starting);
1000 checkcode_tx
1001 .take()
1002 .expect("The checkcode should only be forwarded once")
1003 .send(check_code.to_digit())
1004 .expect("Alice should be able to forward the checkcode");
1005 }
1006 GrantLoginProgress::WaitingForAuth { verification_uri } => {
1007 assert_matches!(
1008 state,
1009 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1010 );
1011 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1012 }
1013 GrantLoginProgress::SyncingSecrets => {
1014 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1015 }
1016 GrantLoginProgress::Done => {
1017 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1018 break;
1019 }
1020 }
1021 state = update;
1022 }
1023 });
1024
1025 let bob_task = spawn(async move {
1027 request_login_with_generated_qr_code(
1028 BobBehaviour::HappyPath,
1029 channel,
1030 checkcode_rx,
1031 Some(server),
1032 &rendezvous_server,
1033 alice.homeserver(),
1034 Some(device_authorization_grant),
1035 Some(secrets_bundle),
1036 )
1037 .await;
1038 });
1039
1040 grant.await.expect("Alice should be able to grant the login");
1042 updates_task.await.expect("Alice should run through all progress states");
1043 bob_task.await.expect("Bob's task should finish");
1044 }
1045
1046 #[async_test]
1047 async fn test_grant_login_with_scanned_qr_code_with_homeserver_swap() {
1048 let server = MatrixMockServer::new().await;
1049 let rendezvous_server =
1050 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1051 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1052
1053 let device_authorization_grant = AuthorizationGrant {
1054 verification_uri_complete: Some(VerificationUriComplete::new(
1055 "https://id.matrix.org/device/abcde".to_owned(),
1056 )),
1057 verification_uri: EndUserVerificationUrl::new(
1058 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1059 )
1060 .unwrap(),
1061 };
1062
1063 let login_server = MatrixMockServer::new().await;
1064
1065 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1066 login_server
1067 .mock_upload_cross_signing_keys()
1068 .ok()
1069 .expect(1)
1070 .named("upload_xsigning_keys")
1071 .mount()
1072 .await;
1073 login_server
1074 .mock_upload_cross_signing_signatures()
1075 .ok()
1076 .expect(1)
1077 .named("upload_xsigning_signatures")
1078 .mount()
1079 .await;
1080
1081 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1083 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1084 .await
1085 .expect("Bob should be able to create a secure channel.");
1086 let qr_code_data = channel.qr_code_data().clone();
1087
1088 let user_id = owned_user_id!("@alice:example.org");
1090 let device_id = owned_device_id!("ALICE_DEVICE");
1091 let alice = login_server
1092 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1093 .logged_in_with_oauth()
1094 .build()
1095 .await;
1096 alice
1097 .encryption()
1098 .bootstrap_cross_signing(None)
1099 .await
1100 .expect("Alice should be able to set up cross signing");
1101
1102 let oauth = alice.oauth();
1104 let grant = oauth
1105 .grant_login_with_qr_code()
1106 .device_creation_timeout(Duration::from_secs(2))
1107 .scan(&qr_code_data);
1108 let secrets_bundle = export_secrets_bundle(&alice)
1109 .await
1110 .expect("Alice should be able to export the secrets bundle");
1111 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1112
1113 let mut updates = grant.subscribe_to_progress();
1115 let mut state = grant.state.get();
1116 let verification_uri_complete =
1117 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1118 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1119 let updates_task = spawn(async move {
1120 let mut checkcode_tx = Some(checkcode_tx);
1121
1122 while let Some(update) = updates.next().await {
1123 match &update {
1124 GrantLoginProgress::Starting => {
1125 assert_matches!(state, GrantLoginProgress::Starting);
1126 }
1127 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1128 assert_matches!(state, GrantLoginProgress::Starting);
1129 checkcode_tx
1130 .take()
1131 .expect("The checkcode should only be forwarded once")
1132 .send(check_code.to_digit())
1133 .expect("Alice should be able to forward the checkcode");
1134 }
1135 GrantLoginProgress::WaitingForAuth { verification_uri } => {
1136 assert_matches!(
1137 state,
1138 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1139 );
1140 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1141 }
1142 GrantLoginProgress::SyncingSecrets => {
1143 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1144 }
1145 GrantLoginProgress::Done => {
1146 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1147 break;
1148 }
1149 }
1150 state = update;
1151 }
1152 });
1153
1154 let bob_task = spawn(async move {
1156 request_login_with_generated_qr_code(
1157 BobBehaviour::HappyPath,
1158 channel,
1159 checkcode_rx,
1160 Some(login_server),
1161 &rendezvous_server,
1162 alice.homeserver(),
1163 Some(device_authorization_grant),
1164 Some(secrets_bundle),
1165 )
1166 .await;
1167 });
1168
1169 grant.await.expect("Alice should be able to grant the login");
1171 updates_task.await.expect("Alice should run through all progress states");
1172 bob_task.await.expect("Bob's task should finish");
1173 }
1174
1175 #[async_test]
1176 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_protocol()
1177 {
1178 let server = MatrixMockServer::new().await;
1179 let rendezvous_server = Arc::new(
1180 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1181 );
1182 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1183
1184 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1185 server
1186 .mock_upload_cross_signing_keys()
1187 .ok()
1188 .expect(1)
1189 .named("upload_xsigning_keys")
1190 .mount()
1191 .await;
1192 server
1193 .mock_upload_cross_signing_signatures()
1194 .ok()
1195 .expect(1)
1196 .named("upload_xsigning_signatures")
1197 .mount()
1198 .await;
1199
1200 let user_id = owned_user_id!("@alice:example.org");
1202 let device_id = owned_device_id!("ALICE_DEVICE");
1203 let alice = server
1204 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1205 .logged_in_with_oauth()
1206 .build()
1207 .await;
1208 alice
1209 .encryption()
1210 .bootstrap_cross_signing(None)
1211 .await
1212 .expect("Alice should be able to set up cross signing");
1213
1214 let oauth = alice.oauth();
1216 let grant = oauth
1217 .grant_login_with_qr_code()
1218 .device_creation_timeout(Duration::from_secs(2))
1219 .generate();
1220 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1221 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1222
1223 let mut updates = grant.subscribe_to_progress();
1225 let mut state = grant.state.get();
1226 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1227 let updates_task = spawn(async move {
1228 let mut qr_code_tx = Some(qr_code_tx);
1229 let mut checkcode_rx = Some(checkcode_rx);
1230
1231 while let Some(update) = updates.next().await {
1232 match &update {
1233 GrantLoginProgress::Starting => {
1234 assert_matches!(state, GrantLoginProgress::Starting);
1235 }
1236 GrantLoginProgress::EstablishingSecureChannel(
1237 GeneratedQrProgress::QrReady(qr_code_data),
1238 ) => {
1239 assert_matches!(state, GrantLoginProgress::Starting);
1240 qr_code_tx
1241 .take()
1242 .expect("The QR code should only be forwarded once")
1243 .send(qr_code_data.clone())
1244 .expect("Alice should be able to forward the QR code");
1245 }
1246 GrantLoginProgress::EstablishingSecureChannel(
1247 GeneratedQrProgress::QrScanned(checkcode_sender),
1248 ) => {
1249 assert_matches!(
1250 state,
1251 GrantLoginProgress::EstablishingSecureChannel(
1252 GeneratedQrProgress::QrReady(_)
1253 )
1254 );
1255 let checkcode = checkcode_rx
1256 .take()
1257 .expect("The checkcode should only be forwarded once")
1258 .await
1259 .expect("Alice should receive the checkcode");
1260 checkcode_sender
1261 .send(checkcode)
1262 .await
1263 .expect("Alice should be able to forward the checkcode");
1264 break;
1265 }
1266 _ => {
1267 panic!("Alice should abort the process");
1268 }
1269 }
1270 state = update;
1271 }
1272 });
1273
1274 let rendezvous_server_clone = rendezvous_server.clone();
1276 let bob_task = spawn(async move {
1277 request_login_with_scanned_qr_code(
1278 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1279 qr_code_rx,
1280 checkcode_tx,
1281 None,
1282 &rendezvous_server_clone,
1283 None,
1284 None,
1285 )
1286 .await;
1287 });
1288
1289 assert_matches!(
1291 grant.await,
1292 Err(QRCodeGrantLoginError::UnexpectedMessage {
1293 expected: "m.login.protocol",
1294 received: QrAuthMessage::LoginSuccess
1295 }),
1296 "Alice should abort the login with expected error"
1297 );
1298 updates_task.await.expect("Alice should run through all progress states");
1299 bob_task.await.expect("Bob's task should finish");
1300 }
1301
1302 #[async_test]
1303 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_protocol() {
1304 let server = MatrixMockServer::new().await;
1305 let rendezvous_server = Arc::new(
1306 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1307 );
1308 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1309
1310 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1311 server
1312 .mock_upload_cross_signing_keys()
1313 .ok()
1314 .expect(1)
1315 .named("upload_xsigning_keys")
1316 .mount()
1317 .await;
1318 server
1319 .mock_upload_cross_signing_signatures()
1320 .ok()
1321 .expect(1)
1322 .named("upload_xsigning_signatures")
1323 .mount()
1324 .await;
1325
1326 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1328 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1329 .await
1330 .expect("Bob should be able to create a secure channel.");
1331 let qr_code_data = channel.qr_code_data().clone();
1332
1333 let user_id = owned_user_id!("@alice:example.org");
1335 let device_id = owned_device_id!("ALICE_DEVICE");
1336 let alice = server
1337 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1338 .logged_in_with_oauth()
1339 .build()
1340 .await;
1341 alice
1342 .encryption()
1343 .bootstrap_cross_signing(None)
1344 .await
1345 .expect("Alice should be able to set up cross signing");
1346
1347 let oauth = alice.oauth();
1349 let grant = oauth
1350 .grant_login_with_qr_code()
1351 .device_creation_timeout(Duration::from_secs(2))
1352 .scan(&qr_code_data);
1353 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1354
1355 let mut updates = grant.subscribe_to_progress();
1357 let mut state = grant.state.get();
1358 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1359 let updates_task = spawn(async move {
1360 let mut checkcode_tx = Some(checkcode_tx);
1361
1362 while let Some(update) = updates.next().await {
1363 match &update {
1364 GrantLoginProgress::Starting => {
1365 assert_matches!(state, GrantLoginProgress::Starting);
1366 }
1367 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1368 assert_matches!(state, GrantLoginProgress::Starting);
1369 checkcode_tx
1370 .take()
1371 .expect("The checkcode should only be forwarded once")
1372 .send(check_code.to_digit())
1373 .expect("Alice should be able to forward the checkcode");
1374 break;
1375 }
1376 _ => {
1377 panic!("Alice should abort the process");
1378 }
1379 }
1380 state = update;
1381 }
1382 });
1383
1384 let rendezvous_server_clone = rendezvous_server.clone();
1385 let bob_task = spawn(async move {
1387 request_login_with_generated_qr_code(
1388 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1389 channel,
1390 checkcode_rx,
1391 None,
1392 &rendezvous_server_clone,
1393 alice.homeserver(),
1394 None,
1395 None,
1396 )
1397 .await;
1398 });
1399
1400 assert_matches!(
1402 grant.await,
1403 Err(QRCodeGrantLoginError::UnexpectedMessage {
1404 expected: "m.login.protocol",
1405 received: QrAuthMessage::LoginSuccess
1406 }),
1407 "Alice should abort the login with expected error"
1408 );
1409 updates_task.await.expect("Alice should run through all progress states");
1410 bob_task.await.expect("Bob's task should finish");
1411 }
1412
1413 #[async_test]
1414 async fn test_grant_login_with_generated_qr_code_device_already_exists() {
1415 let server = MatrixMockServer::new().await;
1416 let rendezvous_server =
1417 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1418 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1419
1420 let device_authorization_grant = AuthorizationGrant {
1421 verification_uri_complete: Some(VerificationUriComplete::new(
1422 "https://id.matrix.org/device/abcde".to_owned(),
1423 )),
1424 verification_uri: EndUserVerificationUrl::new(
1425 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1426 )
1427 .unwrap(),
1428 };
1429
1430 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1431 server
1432 .mock_upload_cross_signing_keys()
1433 .ok()
1434 .expect(1)
1435 .named("upload_xsigning_keys")
1436 .mount()
1437 .await;
1438 server
1439 .mock_upload_cross_signing_signatures()
1440 .ok()
1441 .expect(1)
1442 .named("upload_xsigning_signatures")
1443 .mount()
1444 .await;
1445
1446 let user_id = owned_user_id!("@alice:example.org");
1448 let device_id = owned_device_id!("ALICE_DEVICE");
1449 let alice = server
1450 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1451 .logged_in_with_oauth()
1452 .build()
1453 .await;
1454 alice
1455 .encryption()
1456 .bootstrap_cross_signing(None)
1457 .await
1458 .expect("Alice should be able to set up cross signing");
1459
1460 let oauth = alice.oauth();
1462 let grant = oauth
1463 .grant_login_with_qr_code()
1464 .device_creation_timeout(Duration::from_secs(2))
1465 .generate();
1466 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1467 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1468
1469 let mut updates = grant.subscribe_to_progress();
1471 let mut state = grant.state.get();
1472 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1473 let updates_task = spawn(async move {
1474 let mut qr_code_tx = Some(qr_code_tx);
1475 let mut checkcode_rx = Some(checkcode_rx);
1476
1477 while let Some(update) = updates.next().await {
1478 match &update {
1479 GrantLoginProgress::Starting => {
1480 assert_matches!(state, GrantLoginProgress::Starting);
1481 }
1482 GrantLoginProgress::EstablishingSecureChannel(
1483 GeneratedQrProgress::QrReady(qr_code_data),
1484 ) => {
1485 assert_matches!(state, GrantLoginProgress::Starting);
1486 qr_code_tx
1487 .take()
1488 .expect("The QR code should only be forwarded once")
1489 .send(qr_code_data.clone())
1490 .expect("Alice should be able to forward the QR code");
1491 }
1492 GrantLoginProgress::EstablishingSecureChannel(
1493 GeneratedQrProgress::QrScanned(checkcode_sender),
1494 ) => {
1495 assert_matches!(
1496 state,
1497 GrantLoginProgress::EstablishingSecureChannel(
1498 GeneratedQrProgress::QrReady(_)
1499 )
1500 );
1501 let checkcode = checkcode_rx
1502 .take()
1503 .expect("The checkcode should only be forwarded once")
1504 .await
1505 .expect("Alice should receive the checkcode");
1506 checkcode_sender
1507 .send(checkcode)
1508 .await
1509 .expect("Alice should be able to forward the checkcode");
1510 }
1511 _ => {
1512 panic!("Alice should abort the process");
1513 }
1514 }
1515 state = update;
1516 }
1517 });
1518
1519 let bob_task = spawn(async move {
1521 request_login_with_scanned_qr_code(
1522 BobBehaviour::DeviceAlreadyExists,
1523 qr_code_rx,
1524 checkcode_tx,
1525 Some(server),
1526 &rendezvous_server,
1527 Some(device_authorization_grant),
1528 None,
1529 )
1530 .await;
1531 });
1532
1533 assert_matches!(
1535 grant.await,
1536 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1537 "Alice should abort the login with expected error"
1538 );
1539 updates_task.await.expect("Alice should run through all progress states");
1540 bob_task.await.expect("Bob's task should finish");
1541 }
1542
1543 #[async_test]
1544 async fn test_grant_login_with_scanned_qr_code_device_already_exists() {
1545 let server = MatrixMockServer::new().await;
1546 let rendezvous_server =
1547 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1548 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1549
1550 let device_authorization_grant = AuthorizationGrant {
1551 verification_uri_complete: Some(VerificationUriComplete::new(
1552 "https://id.matrix.org/device/abcde".to_owned(),
1553 )),
1554 verification_uri: EndUserVerificationUrl::new(
1555 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1556 )
1557 .unwrap(),
1558 };
1559
1560 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1561 server
1562 .mock_upload_cross_signing_keys()
1563 .ok()
1564 .expect(1)
1565 .named("upload_xsigning_keys")
1566 .mount()
1567 .await;
1568 server
1569 .mock_upload_cross_signing_signatures()
1570 .ok()
1571 .expect(1)
1572 .named("upload_xsigning_signatures")
1573 .mount()
1574 .await;
1575
1576 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1578 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1579 .await
1580 .expect("Bob should be able to create a secure channel.");
1581 let qr_code_data = channel.qr_code_data().clone();
1582
1583 let user_id = owned_user_id!("@alice:example.org");
1585 let device_id = owned_device_id!("ALICE_DEVICE");
1586 let alice = server
1587 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1588 .logged_in_with_oauth()
1589 .build()
1590 .await;
1591 alice
1592 .encryption()
1593 .bootstrap_cross_signing(None)
1594 .await
1595 .expect("Alice should be able to set up cross signing");
1596
1597 let oauth = alice.oauth();
1599 let grant = oauth
1600 .grant_login_with_qr_code()
1601 .device_creation_timeout(Duration::from_secs(2))
1602 .scan(&qr_code_data);
1603 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1604
1605 let mut updates = grant.subscribe_to_progress();
1607 let mut state = grant.state.get();
1608 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1609 let updates_task = spawn(async move {
1610 let mut checkcode_tx = Some(checkcode_tx);
1611
1612 while let Some(update) = updates.next().await {
1613 match &update {
1614 GrantLoginProgress::Starting => {
1615 assert_matches!(state, GrantLoginProgress::Starting);
1616 }
1617 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1618 assert_matches!(state, GrantLoginProgress::Starting);
1619 checkcode_tx
1620 .take()
1621 .expect("The checkcode should only be forwarded once")
1622 .send(check_code.to_digit())
1623 .expect("Alice should be able to forward the checkcode");
1624 }
1625 _ => {
1626 panic!("Alice should abort the process");
1627 }
1628 }
1629 state = update;
1630 }
1631 });
1632
1633 let bob_task = spawn(async move {
1635 request_login_with_generated_qr_code(
1636 BobBehaviour::DeviceAlreadyExists,
1637 channel,
1638 checkcode_rx,
1639 Some(server),
1640 &rendezvous_server,
1641 alice.homeserver(),
1642 Some(device_authorization_grant),
1643 None,
1644 )
1645 .await;
1646 });
1647
1648 assert_matches!(
1650 grant.await,
1651 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1652 "Alice should abort the login with expected error"
1653 );
1654 updates_task.await.expect("Alice should run through all progress states");
1655 bob_task.await.expect("Bob's task should finish");
1656 }
1657
1658 #[async_test]
1659 async fn test_grant_login_with_generated_qr_code_device_not_found() {
1660 let server = MatrixMockServer::new().await;
1661 let rendezvous_server =
1662 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1663 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1664
1665 let device_authorization_grant = AuthorizationGrant {
1666 verification_uri_complete: Some(VerificationUriComplete::new(
1667 "https://id.matrix.org/device/abcde".to_owned(),
1668 )),
1669 verification_uri: EndUserVerificationUrl::new(
1670 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1671 )
1672 .unwrap(),
1673 };
1674
1675 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1676 server
1677 .mock_upload_cross_signing_keys()
1678 .ok()
1679 .expect(1)
1680 .named("upload_xsigning_keys")
1681 .mount()
1682 .await;
1683 server
1684 .mock_upload_cross_signing_signatures()
1685 .ok()
1686 .expect(1)
1687 .named("upload_xsigning_signatures")
1688 .mount()
1689 .await;
1690
1691 let user_id = owned_user_id!("@alice:example.org");
1693 let device_id = owned_device_id!("ALICE_DEVICE");
1694 let alice = server
1695 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1696 .logged_in_with_oauth()
1697 .build()
1698 .await;
1699 alice
1700 .encryption()
1701 .bootstrap_cross_signing(None)
1702 .await
1703 .expect("Alice should be able to set up cross signing");
1704
1705 let oauth = alice.oauth();
1707 let grant = oauth
1708 .grant_login_with_qr_code()
1709 .device_creation_timeout(Duration::from_secs(2))
1710 .generate();
1711 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1712 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1713
1714 let mut updates = grant.subscribe_to_progress();
1716 let mut state = grant.state.get();
1717 let verification_uri_complete =
1718 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1719 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1720 let updates_task = spawn(async move {
1721 let mut qr_code_tx = Some(qr_code_tx);
1722 let mut checkcode_rx = Some(checkcode_rx);
1723
1724 while let Some(update) = updates.next().await {
1725 match &update {
1726 GrantLoginProgress::Starting => {
1727 assert_matches!(state, GrantLoginProgress::Starting);
1728 }
1729 GrantLoginProgress::EstablishingSecureChannel(
1730 GeneratedQrProgress::QrReady(qr_code_data),
1731 ) => {
1732 assert_matches!(state, GrantLoginProgress::Starting);
1733 qr_code_tx
1734 .take()
1735 .expect("The QR code should only be forwarded once")
1736 .send(qr_code_data.clone())
1737 .expect("Alice should be able to forward the QR code");
1738 }
1739 GrantLoginProgress::EstablishingSecureChannel(
1740 GeneratedQrProgress::QrScanned(checkcode_sender),
1741 ) => {
1742 assert_matches!(
1743 state,
1744 GrantLoginProgress::EstablishingSecureChannel(
1745 GeneratedQrProgress::QrReady(_)
1746 )
1747 );
1748 let checkcode = checkcode_rx
1749 .take()
1750 .expect("The checkcode should only be forwarded once")
1751 .await
1752 .expect("Alice should receive the checkcode");
1753 checkcode_sender
1754 .send(checkcode)
1755 .await
1756 .expect("Alice should be able to forward the checkcode");
1757 }
1758 GrantLoginProgress::WaitingForAuth { verification_uri } => {
1759 assert_matches!(
1760 state,
1761 GrantLoginProgress::EstablishingSecureChannel(
1762 GeneratedQrProgress::QrScanned(_)
1763 )
1764 );
1765 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1766 }
1767 _ => {
1768 panic!("Alice should abort the process");
1769 }
1770 }
1771 state = update;
1772 }
1773 });
1774
1775 let bob_task = spawn(async move {
1777 request_login_with_scanned_qr_code(
1778 BobBehaviour::DeviceNotCreated,
1779 qr_code_rx,
1780 checkcode_tx,
1781 Some(server),
1782 &rendezvous_server,
1783 Some(device_authorization_grant),
1784 None,
1785 )
1786 .await;
1787 });
1788
1789 assert_matches!(
1790 grant.await,
1791 Err(QRCodeGrantLoginError::DeviceNotFound),
1792 "Alice should abort the login with expected error"
1793 );
1794 updates_task.await.expect("Alice should run through all progress states");
1795 bob_task.await.expect("Bob's task should finish");
1796 }
1797
1798 #[async_test]
1799 async fn test_grant_login_with_scanned_qr_code_device_not_found() {
1800 let server = MatrixMockServer::new().await;
1801 let rendezvous_server =
1802 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1803 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1804
1805 let device_authorization_grant = AuthorizationGrant {
1806 verification_uri_complete: Some(VerificationUriComplete::new(
1807 "https://id.matrix.org/device/abcde".to_owned(),
1808 )),
1809 verification_uri: EndUserVerificationUrl::new(
1810 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1811 )
1812 .unwrap(),
1813 };
1814
1815 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1816 server
1817 .mock_upload_cross_signing_keys()
1818 .ok()
1819 .expect(1)
1820 .named("upload_xsigning_keys")
1821 .mount()
1822 .await;
1823 server
1824 .mock_upload_cross_signing_signatures()
1825 .ok()
1826 .expect(1)
1827 .named("upload_xsigning_signatures")
1828 .mount()
1829 .await;
1830
1831 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1833 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1834 .await
1835 .expect("Bob should be able to create a secure channel.");
1836 let qr_code_data = channel.qr_code_data().clone();
1837
1838 let user_id = owned_user_id!("@alice:example.org");
1840 let device_id = owned_device_id!("ALICE_DEVICE");
1841 let alice = server
1842 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1843 .logged_in_with_oauth()
1844 .build()
1845 .await;
1846 alice
1847 .encryption()
1848 .bootstrap_cross_signing(None)
1849 .await
1850 .expect("Alice should be able to set up cross signing");
1851
1852 let oauth = alice.oauth();
1854 let grant = oauth
1855 .grant_login_with_qr_code()
1856 .device_creation_timeout(Duration::from_secs(2))
1857 .scan(&qr_code_data);
1858 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1859
1860 let mut updates = grant.subscribe_to_progress();
1862 let mut state = grant.state.get();
1863 let verification_uri_complete =
1864 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1865 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1866 let updates_task = spawn(async move {
1867 let mut checkcode_tx = Some(checkcode_tx);
1868
1869 while let Some(update) = updates.next().await {
1870 match &update {
1871 GrantLoginProgress::Starting => {
1872 assert_matches!(state, GrantLoginProgress::Starting);
1873 }
1874 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1875 assert_matches!(state, GrantLoginProgress::Starting);
1876 checkcode_tx
1877 .take()
1878 .expect("The checkcode should only be forwarded once")
1879 .send(check_code.to_digit())
1880 .expect("Alice should be able to forward the checkcode");
1881 }
1882 GrantLoginProgress::WaitingForAuth { verification_uri } => {
1883 assert_matches!(
1884 state,
1885 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1886 );
1887 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1888 }
1889 _ => {
1890 panic!("Alice should abort the process");
1891 }
1892 }
1893 state = update;
1894 }
1895 });
1896
1897 let bob_task = spawn(async move {
1899 request_login_with_generated_qr_code(
1900 BobBehaviour::DeviceNotCreated,
1901 channel,
1902 checkcode_rx,
1903 None,
1904 &rendezvous_server,
1905 alice.homeserver(),
1906 Some(device_authorization_grant),
1907 None,
1908 )
1909 .await;
1910 });
1911
1912 assert_matches!(
1913 grant.await,
1914 Err(QRCodeGrantLoginError::DeviceNotFound),
1915 "Alice should abort the login with expected error"
1916 );
1917 updates_task.await.expect("Alice should run through all progress states");
1918 bob_task.await.expect("Bob's task should finish");
1919 }
1920
1921 #[async_test]
1922 async fn test_grant_login_with_generated_qr_code_session_expired() {
1923 let server = MatrixMockServer::new().await;
1924 let rendezvous_server =
1925 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
1926 .await;
1927 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1928
1929 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1930 server
1931 .mock_upload_cross_signing_keys()
1932 .ok()
1933 .expect(1)
1934 .named("upload_xsigning_keys")
1935 .mount()
1936 .await;
1937 server
1938 .mock_upload_cross_signing_signatures()
1939 .ok()
1940 .expect(1)
1941 .named("upload_xsigning_signatures")
1942 .mount()
1943 .await;
1944
1945 let user_id = owned_user_id!("@alice:example.org");
1947 let device_id = owned_device_id!("ALICE_DEVICE");
1948 let alice = server
1949 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1950 .logged_in_with_oauth()
1951 .build()
1952 .await;
1953 alice
1954 .encryption()
1955 .bootstrap_cross_signing(None)
1956 .await
1957 .expect("Alice should be able to set up cross signing");
1958
1959 let oauth = alice.oauth();
1961 let grant = oauth
1962 .grant_login_with_qr_code()
1963 .device_creation_timeout(Duration::from_secs(2))
1964 .generate();
1965
1966 let mut updates = grant.subscribe_to_progress();
1968 let mut state = grant.state.get();
1969 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1970 let updates_task = spawn(async move {
1971 while let Some(update) = updates.next().await {
1972 match &update {
1973 GrantLoginProgress::Starting => {
1974 assert_matches!(state, GrantLoginProgress::Starting);
1975 }
1976 GrantLoginProgress::EstablishingSecureChannel(
1977 GeneratedQrProgress::QrReady(_),
1978 ) => {
1979 assert_matches!(state, GrantLoginProgress::Starting);
1980 }
1981 _ => {
1982 panic!("Alice should abort the process");
1983 }
1984 }
1985 state = update;
1986 }
1987 });
1988
1989 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
1993 updates_task.await.expect("Alice should run through all progress states");
1994 }
1995
1996 #[async_test]
1997 async fn test_grant_login_with_scanned_qr_code_session_expired() {
1998 let server = MatrixMockServer::new().await;
1999 let rendezvous_server =
2000 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
2001 .await;
2002 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2003
2004 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2005 server
2006 .mock_upload_cross_signing_keys()
2007 .ok()
2008 .expect(1)
2009 .named("upload_xsigning_keys")
2010 .mount()
2011 .await;
2012 server
2013 .mock_upload_cross_signing_signatures()
2014 .ok()
2015 .expect(1)
2016 .named("upload_xsigning_signatures")
2017 .mount()
2018 .await;
2019
2020 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2022 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2023 .await
2024 .expect("Bob should be able to create a secure channel.");
2025 let qr_code_data = channel.qr_code_data().clone();
2026
2027 let user_id = owned_user_id!("@alice:example.org");
2029 let device_id = owned_device_id!("ALICE_DEVICE");
2030 let alice = server
2031 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2032 .logged_in_with_oauth()
2033 .build()
2034 .await;
2035 alice
2036 .encryption()
2037 .bootstrap_cross_signing(None)
2038 .await
2039 .expect("Alice should be able to set up cross signing");
2040
2041 let oauth = alice.oauth();
2043 let grant = oauth
2044 .grant_login_with_qr_code()
2045 .device_creation_timeout(Duration::from_secs(2))
2046 .scan(&qr_code_data);
2047
2048 let mut updates = grant.subscribe_to_progress();
2050 let mut state = grant.state.get();
2051 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2052 let updates_task = spawn(async move {
2053 while let Some(update) = updates.next().await {
2054 match &update {
2055 GrantLoginProgress::Starting => {
2056 assert_matches!(state, GrantLoginProgress::Starting);
2057 }
2058 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. }) => {
2059 assert_matches!(state, GrantLoginProgress::Starting);
2060 }
2061 _ => {
2062 panic!("Alice should abort the process");
2063 }
2064 }
2065 state = update;
2066 }
2067 });
2068
2069 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2073 updates_task.await.expect("Alice should run through all progress states");
2074 }
2075
2076 #[async_test]
2077 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_protocol() {
2078 let server = MatrixMockServer::new().await;
2079 let rendezvous_server = Arc::new(
2080 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2081 );
2082 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2083
2084 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2085 server
2086 .mock_upload_cross_signing_keys()
2087 .ok()
2088 .expect(1)
2089 .named("upload_xsigning_keys")
2090 .mount()
2091 .await;
2092 server
2093 .mock_upload_cross_signing_signatures()
2094 .ok()
2095 .expect(1)
2096 .named("upload_xsigning_signatures")
2097 .mount()
2098 .await;
2099
2100 let user_id = owned_user_id!("@alice:example.org");
2102 let device_id = owned_device_id!("ALICE_DEVICE");
2103 let alice = server
2104 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2105 .logged_in_with_oauth()
2106 .build()
2107 .await;
2108 alice
2109 .encryption()
2110 .bootstrap_cross_signing(None)
2111 .await
2112 .expect("Alice should be able to set up cross signing");
2113
2114 let oauth = alice.oauth();
2116 let grant = oauth
2117 .grant_login_with_qr_code()
2118 .device_creation_timeout(Duration::from_secs(2))
2119 .generate();
2120 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2121 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2122
2123 let mut updates = grant.subscribe_to_progress();
2125 let mut state = grant.state.get();
2126 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2127 let updates_task = spawn(async move {
2128 let mut qr_code_tx = Some(qr_code_tx);
2129 let mut checkcode_rx = Some(checkcode_rx);
2130
2131 while let Some(update) = updates.next().await {
2132 match &update {
2133 GrantLoginProgress::Starting => {
2134 assert_matches!(state, GrantLoginProgress::Starting);
2135 }
2136 GrantLoginProgress::EstablishingSecureChannel(
2137 GeneratedQrProgress::QrReady(qr_code_data),
2138 ) => {
2139 assert_matches!(state, GrantLoginProgress::Starting);
2140 qr_code_tx
2141 .take()
2142 .expect("The QR code should only be forwarded once")
2143 .send(qr_code_data.clone())
2144 .expect("Alice should be able to forward the QR code");
2145 }
2146 GrantLoginProgress::EstablishingSecureChannel(
2147 GeneratedQrProgress::QrScanned(checkcode_sender),
2148 ) => {
2149 assert_matches!(
2150 state,
2151 GrantLoginProgress::EstablishingSecureChannel(
2152 GeneratedQrProgress::QrReady(_)
2153 )
2154 );
2155 let checkcode = checkcode_rx
2156 .take()
2157 .expect("The checkcode should only be forwarded once")
2158 .await
2159 .expect("Alice should receive the checkcode");
2160 checkcode_sender
2161 .send(checkcode)
2162 .await
2163 .expect("Alice should be able to forward the checkcode");
2164 break;
2165 }
2166 _ => {
2167 panic!("Alice should abort the process");
2168 }
2169 }
2170 state = update;
2171 }
2172 });
2173
2174 let rendezvous_server_clone = rendezvous_server.clone();
2176 let bob_task = spawn(async move {
2177 request_login_with_scanned_qr_code(
2178 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2179 qr_code_rx,
2180 checkcode_tx,
2181 None,
2182 &rendezvous_server_clone,
2183 None,
2184 None,
2185 )
2186 .await;
2187 });
2188
2189 assert_matches!(
2191 grant.await,
2192 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2193 "Alice should abort the login with expected error"
2194 );
2195 updates_task.await.expect("Alice should run through all progress states");
2196 bob_task.await.expect("Bob's task should finish");
2197 }
2198
2199 #[async_test]
2200 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_protocol() {
2201 let server = MatrixMockServer::new().await;
2202 let rendezvous_server = Arc::new(
2203 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2204 );
2205 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2206
2207 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2208 server
2209 .mock_upload_cross_signing_keys()
2210 .ok()
2211 .expect(1)
2212 .named("upload_xsigning_keys")
2213 .mount()
2214 .await;
2215 server
2216 .mock_upload_cross_signing_signatures()
2217 .ok()
2218 .expect(1)
2219 .named("upload_xsigning_signatures")
2220 .mount()
2221 .await;
2222
2223 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2225 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2226 .await
2227 .expect("Bob should be able to create a secure channel.");
2228 let qr_code_data = channel.qr_code_data().clone();
2229
2230 let user_id = owned_user_id!("@alice:example.org");
2232 let device_id = owned_device_id!("ALICE_DEVICE");
2233 let alice = server
2234 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2235 .logged_in_with_oauth()
2236 .build()
2237 .await;
2238 alice
2239 .encryption()
2240 .bootstrap_cross_signing(None)
2241 .await
2242 .expect("Alice should be able to set up cross signing");
2243
2244 let oauth = alice.oauth();
2246 let grant = oauth
2247 .grant_login_with_qr_code()
2248 .device_creation_timeout(Duration::from_secs(2))
2249 .scan(&qr_code_data);
2250 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2251
2252 let mut updates = grant.subscribe_to_progress();
2254 let mut state = grant.state.get();
2255 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2256 let updates_task = spawn(async move {
2257 let mut checkcode_tx = Some(checkcode_tx);
2258
2259 while let Some(update) = updates.next().await {
2260 match &update {
2261 GrantLoginProgress::Starting => {
2262 assert_matches!(state, GrantLoginProgress::Starting);
2263 }
2264 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2265 assert_matches!(state, GrantLoginProgress::Starting);
2266 checkcode_tx
2267 .take()
2268 .expect("The checkcode should only be forwarded once")
2269 .send(check_code.to_digit())
2270 .expect("Alice should be able to forward the checkcode");
2271 break;
2272 }
2273 _ => {
2274 panic!("Alice should abort the process");
2275 }
2276 }
2277 state = update;
2278 }
2279 });
2280
2281 let rendezvous_server_clone = rendezvous_server.clone();
2282 let bob_task = spawn(async move {
2284 request_login_with_generated_qr_code(
2285 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2286 channel,
2287 checkcode_rx,
2288 None,
2289 &rendezvous_server_clone,
2290 alice.homeserver(),
2291 None,
2292 None,
2293 )
2294 .await;
2295 });
2296
2297 assert_matches!(
2299 grant.await,
2300 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2301 "Alice should abort the login with expected error"
2302 );
2303 updates_task.await.expect("Alice should run through all progress states");
2304 bob_task.await.expect("Bob's task should finish");
2305 }
2306
2307 #[async_test]
2308 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_success() {
2309 let server = MatrixMockServer::new().await;
2310 let rendezvous_server = Arc::new(
2311 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2312 );
2313 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2314
2315 let device_authorization_grant = AuthorizationGrant {
2316 verification_uri_complete: Some(VerificationUriComplete::new(
2317 "https://id.matrix.org/device/abcde".to_owned(),
2318 )),
2319 verification_uri: EndUserVerificationUrl::new(
2320 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2321 )
2322 .unwrap(),
2323 };
2324
2325 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2326 server
2327 .mock_upload_cross_signing_keys()
2328 .ok()
2329 .expect(1)
2330 .named("upload_xsigning_keys")
2331 .mount()
2332 .await;
2333 server
2334 .mock_upload_cross_signing_signatures()
2335 .ok()
2336 .expect(1)
2337 .named("upload_xsigning_signatures")
2338 .mount()
2339 .await;
2340
2341 let user_id = owned_user_id!("@alice:example.org");
2343 let device_id = owned_device_id!("ALICE_DEVICE");
2344 let alice = server
2345 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2346 .logged_in_with_oauth()
2347 .build()
2348 .await;
2349 alice
2350 .encryption()
2351 .bootstrap_cross_signing(None)
2352 .await
2353 .expect("Alice should be able to set up cross signing");
2354
2355 let oauth = alice.oauth();
2357 let grant = oauth
2358 .grant_login_with_qr_code()
2359 .device_creation_timeout(Duration::from_secs(2))
2360 .generate();
2361 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2362 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2363
2364 let mut updates = grant.subscribe_to_progress();
2366 let mut state = grant.state.get();
2367 let verification_uri_complete =
2368 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2369 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2370 let updates_task = spawn(async move {
2371 let mut qr_code_tx = Some(qr_code_tx);
2372 let mut checkcode_rx = Some(checkcode_rx);
2373
2374 while let Some(update) = updates.next().await {
2375 match &update {
2376 GrantLoginProgress::Starting => {
2377 assert_matches!(state, GrantLoginProgress::Starting);
2378 }
2379 GrantLoginProgress::EstablishingSecureChannel(
2380 GeneratedQrProgress::QrReady(qr_code_data),
2381 ) => {
2382 assert_matches!(state, GrantLoginProgress::Starting);
2383 qr_code_tx
2384 .take()
2385 .expect("The QR code should only be forwarded once")
2386 .send(qr_code_data.clone())
2387 .expect("Alice should be able to forward the QR code");
2388 }
2389 GrantLoginProgress::EstablishingSecureChannel(
2390 GeneratedQrProgress::QrScanned(checkcode_sender),
2391 ) => {
2392 assert_matches!(
2393 state,
2394 GrantLoginProgress::EstablishingSecureChannel(
2395 GeneratedQrProgress::QrReady(_)
2396 )
2397 );
2398 let checkcode = checkcode_rx
2399 .take()
2400 .expect("The checkcode should only be forwarded once")
2401 .await
2402 .expect("Alice should receive the checkcode");
2403 checkcode_sender
2404 .send(checkcode)
2405 .await
2406 .expect("Alice should be able to forward the checkcode");
2407 }
2408 GrantLoginProgress::WaitingForAuth { verification_uri } => {
2409 assert_matches!(
2410 state,
2411 GrantLoginProgress::EstablishingSecureChannel(
2412 GeneratedQrProgress::QrScanned(_)
2413 )
2414 );
2415 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2416 }
2417 _ => {
2418 panic!("Alice should abort the process");
2419 }
2420 }
2421 state = update;
2422 }
2423 });
2424
2425 let rendezvous_server_clone = rendezvous_server.clone();
2426 let bob_task = spawn(async move {
2428 request_login_with_scanned_qr_code(
2429 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2430 qr_code_rx,
2431 checkcode_tx,
2432 None,
2433 &rendezvous_server_clone,
2434 Some(device_authorization_grant),
2435 None,
2436 )
2437 .await;
2438 });
2439
2440 assert_matches!(
2442 grant.await,
2443 Err(QRCodeGrantLoginError::LoginFailure {
2444 reason: LoginFailureReason::AuthorizationExpired
2445 }),
2446 "Alice should abort the login with expected error"
2447 );
2448 updates_task.await.expect("Alice should run through all progress states");
2449 bob_task.await.expect("Bob's task should finish");
2450 }
2451
2452 #[async_test]
2453 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_success() {
2454 let server = MatrixMockServer::new().await;
2455 let rendezvous_server = Arc::new(
2456 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2457 );
2458 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2459
2460 let device_authorization_grant = AuthorizationGrant {
2461 verification_uri_complete: Some(VerificationUriComplete::new(
2462 "https://id.matrix.org/device/abcde".to_owned(),
2463 )),
2464 verification_uri: EndUserVerificationUrl::new(
2465 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2466 )
2467 .unwrap(),
2468 };
2469
2470 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2471 server
2472 .mock_upload_cross_signing_keys()
2473 .ok()
2474 .expect(1)
2475 .named("upload_xsigning_keys")
2476 .mount()
2477 .await;
2478 server
2479 .mock_upload_cross_signing_signatures()
2480 .ok()
2481 .expect(1)
2482 .named("upload_xsigning_signatures")
2483 .mount()
2484 .await;
2485
2486 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2488 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2489 .await
2490 .expect("Bob should be able to create a secure channel.");
2491 let qr_code_data = channel.qr_code_data().clone();
2492
2493 let user_id = owned_user_id!("@alice:example.org");
2495 let device_id = owned_device_id!("ALICE_DEVICE");
2496 let alice = server
2497 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2498 .logged_in_with_oauth()
2499 .build()
2500 .await;
2501 alice
2502 .encryption()
2503 .bootstrap_cross_signing(None)
2504 .await
2505 .expect("Alice should be able to set up cross signing");
2506
2507 let oauth = alice.oauth();
2509 let grant = oauth
2510 .grant_login_with_qr_code()
2511 .device_creation_timeout(Duration::from_secs(2))
2512 .scan(&qr_code_data);
2513 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2514
2515 let mut updates = grant.subscribe_to_progress();
2517 let mut state = grant.state.get();
2518 let verification_uri_complete =
2519 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2520 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2521 let updates_task = spawn(async move {
2522 let mut checkcode_tx = Some(checkcode_tx);
2523
2524 while let Some(update) = updates.next().await {
2525 match &update {
2526 GrantLoginProgress::Starting => {
2527 assert_matches!(state, GrantLoginProgress::Starting);
2528 }
2529 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2530 assert_matches!(state, GrantLoginProgress::Starting);
2531 checkcode_tx
2532 .take()
2533 .expect("The checkcode should only be forwarded once")
2534 .send(check_code.to_digit())
2535 .expect("Alice should be able to forward the checkcode");
2536 }
2537 GrantLoginProgress::WaitingForAuth { verification_uri } => {
2538 assert_matches!(
2539 state,
2540 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2541 );
2542 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2543 }
2544 _ => {
2545 panic!("Alice should abort the process");
2546 }
2547 }
2548 state = update;
2549 }
2550 });
2551
2552 let rendezvous_server_clone = rendezvous_server.clone();
2553 let bob_task = spawn(async move {
2555 request_login_with_generated_qr_code(
2556 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2557 channel,
2558 checkcode_rx,
2559 None,
2560 &rendezvous_server_clone,
2561 alice.homeserver(),
2562 Some(device_authorization_grant),
2563 None,
2564 )
2565 .await;
2566 });
2567
2568 assert_matches!(
2570 grant.await,
2571 Err(QRCodeGrantLoginError::LoginFailure {
2572 reason: LoginFailureReason::AuthorizationExpired
2573 }),
2574 "Alice should abort the login with expected error"
2575 );
2576 updates_task.await.expect("Alice should run through all progress states");
2577 bob_task.await.expect("Bob's task should finish");
2578 }
2579
2580 #[async_test]
2581 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_success() {
2582 let server = MatrixMockServer::new().await;
2583 let rendezvous_server = Arc::new(
2584 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2585 );
2586 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2587
2588 let device_authorization_grant = AuthorizationGrant {
2589 verification_uri_complete: Some(VerificationUriComplete::new(
2590 "https://id.matrix.org/device/abcde".to_owned(),
2591 )),
2592 verification_uri: EndUserVerificationUrl::new(
2593 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2594 )
2595 .unwrap(),
2596 };
2597
2598 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2599 server
2600 .mock_upload_cross_signing_keys()
2601 .ok()
2602 .expect(1)
2603 .named("upload_xsigning_keys")
2604 .mount()
2605 .await;
2606 server
2607 .mock_upload_cross_signing_signatures()
2608 .ok()
2609 .expect(1)
2610 .named("upload_xsigning_signatures")
2611 .mount()
2612 .await;
2613
2614 let user_id = owned_user_id!("@alice:example.org");
2616 let device_id = owned_device_id!("ALICE_DEVICE");
2617 let alice = server
2618 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2619 .logged_in_with_oauth()
2620 .build()
2621 .await;
2622 alice
2623 .encryption()
2624 .bootstrap_cross_signing(None)
2625 .await
2626 .expect("Alice should be able to set up cross signing");
2627
2628 let oauth = alice.oauth();
2630 let grant = oauth
2631 .grant_login_with_qr_code()
2632 .device_creation_timeout(Duration::from_secs(2))
2633 .generate();
2634 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2635 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2636
2637 let mut updates = grant.subscribe_to_progress();
2639 let mut state = grant.state.get();
2640 let verification_uri_complete =
2641 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2642 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2643 let updates_task = spawn(async move {
2644 let mut qr_code_tx = Some(qr_code_tx);
2645 let mut checkcode_rx = Some(checkcode_rx);
2646
2647 while let Some(update) = updates.next().await {
2648 match &update {
2649 GrantLoginProgress::Starting => {
2650 assert_matches!(state, GrantLoginProgress::Starting);
2651 }
2652 GrantLoginProgress::EstablishingSecureChannel(
2653 GeneratedQrProgress::QrReady(qr_code_data),
2654 ) => {
2655 assert_matches!(state, GrantLoginProgress::Starting);
2656 qr_code_tx
2657 .take()
2658 .expect("The QR code should only be forwarded once")
2659 .send(qr_code_data.clone())
2660 .expect("Alice should be able to forward the QR code");
2661 }
2662 GrantLoginProgress::EstablishingSecureChannel(
2663 GeneratedQrProgress::QrScanned(checkcode_sender),
2664 ) => {
2665 assert_matches!(
2666 state,
2667 GrantLoginProgress::EstablishingSecureChannel(
2668 GeneratedQrProgress::QrReady(_)
2669 )
2670 );
2671 let checkcode = checkcode_rx
2672 .take()
2673 .expect("The checkcode should only be forwarded once")
2674 .await
2675 .expect("Alice should receive the checkcode");
2676 checkcode_sender
2677 .send(checkcode)
2678 .await
2679 .expect("Alice should be able to forward the checkcode");
2680 }
2681 GrantLoginProgress::WaitingForAuth { verification_uri } => {
2682 assert_matches!(
2683 state,
2684 GrantLoginProgress::EstablishingSecureChannel(
2685 GeneratedQrProgress::QrScanned(_)
2686 )
2687 );
2688 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2689 }
2690 _ => {
2691 panic!("Alice should abort the process");
2692 }
2693 }
2694 state = update;
2695 }
2696 });
2697
2698 let rendezvous_server_clone = rendezvous_server.clone();
2700 let bob_task = spawn(async move {
2701 request_login_with_scanned_qr_code(
2702 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
2703 qr_code_rx,
2704 checkcode_tx,
2705 None,
2706 &rendezvous_server_clone,
2707 Some(device_authorization_grant),
2708 None,
2709 )
2710 .await;
2711 });
2712
2713 assert_matches!(
2715 grant.await,
2716 Err(QRCodeGrantLoginError::UnexpectedMessage {
2717 expected: "m.login.success",
2718 received: QrAuthMessage::LoginProtocolAccepted
2719 }),
2720 "Alice should abort the login with expected error"
2721 );
2722 updates_task.await.expect("Alice should run through all progress states");
2723 bob_task.await.expect("Bob's task should finish");
2724 }
2725
2726 #[async_test]
2727 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_success() {
2728 let server = MatrixMockServer::new().await;
2729 let rendezvous_server = Arc::new(
2730 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2731 );
2732 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2733
2734 let device_authorization_grant = AuthorizationGrant {
2735 verification_uri_complete: Some(VerificationUriComplete::new(
2736 "https://id.matrix.org/device/abcde".to_owned(),
2737 )),
2738 verification_uri: EndUserVerificationUrl::new(
2739 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2740 )
2741 .unwrap(),
2742 };
2743
2744 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2745 server
2746 .mock_upload_cross_signing_keys()
2747 .ok()
2748 .expect(1)
2749 .named("upload_xsigning_keys")
2750 .mount()
2751 .await;
2752 server
2753 .mock_upload_cross_signing_signatures()
2754 .ok()
2755 .expect(1)
2756 .named("upload_xsigning_signatures")
2757 .mount()
2758 .await;
2759
2760 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2762 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2763 .await
2764 .expect("Bob should be able to create a secure channel.");
2765 let qr_code_data = channel.qr_code_data().clone();
2766
2767 let user_id = owned_user_id!("@alice:example.org");
2769 let device_id = owned_device_id!("ALICE_DEVICE");
2770 let alice = server
2771 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2772 .logged_in_with_oauth()
2773 .build()
2774 .await;
2775 alice
2776 .encryption()
2777 .bootstrap_cross_signing(None)
2778 .await
2779 .expect("Alice should be able to set up cross signing");
2780
2781 let oauth = alice.oauth();
2783 let grant = oauth
2784 .grant_login_with_qr_code()
2785 .device_creation_timeout(Duration::from_secs(2))
2786 .scan(&qr_code_data);
2787 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2788
2789 let mut updates = grant.subscribe_to_progress();
2791 let mut state = grant.state.get();
2792 let verification_uri_complete =
2793 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2794 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2795 let updates_task = spawn(async move {
2796 let mut checkcode_tx = Some(checkcode_tx);
2797
2798 while let Some(update) = updates.next().await {
2799 match &update {
2800 GrantLoginProgress::Starting => {
2801 assert_matches!(state, GrantLoginProgress::Starting);
2802 }
2803 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2804 assert_matches!(state, GrantLoginProgress::Starting);
2805 checkcode_tx
2806 .take()
2807 .expect("The checkcode should only be forwarded once")
2808 .send(check_code.to_digit())
2809 .expect("Alice should be able to forward the checkcode");
2810 }
2811 GrantLoginProgress::WaitingForAuth { verification_uri } => {
2812 assert_matches!(
2813 state,
2814 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2815 );
2816 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2817 }
2818 _ => {
2819 panic!("Alice should abort the process");
2820 }
2821 }
2822 state = update;
2823 }
2824 });
2825
2826 let rendezvous_server_clone = rendezvous_server.clone();
2827 let bob_task = spawn(async move {
2829 request_login_with_generated_qr_code(
2830 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
2831 channel,
2832 checkcode_rx,
2833 None,
2834 &rendezvous_server_clone,
2835 alice.homeserver(),
2836 Some(device_authorization_grant),
2837 None,
2838 )
2839 .await;
2840 });
2841
2842 assert_matches!(
2844 grant.await,
2845 Err(QRCodeGrantLoginError::UnexpectedMessage {
2846 expected: "m.login.success",
2847 received: QrAuthMessage::LoginProtocolAccepted
2848 }),
2849 "Alice should abort the login with expected error"
2850 );
2851 updates_task.await.expect("Alice should run through all progress states");
2852 bob_task.await.expect("Bob's task should finish");
2853 }
2854
2855 #[async_test]
2856 async fn test_grant_login_with_generated_qr_code_secure_channel_error() {
2857 let server = MatrixMockServer::new().await;
2858 let rendezvous_server = Arc::new(
2859 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2860 );
2861 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2862
2863 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2864 server
2865 .mock_upload_cross_signing_keys()
2866 .ok()
2867 .expect(1)
2868 .named("upload_xsigning_keys")
2869 .mount()
2870 .await;
2871 server
2872 .mock_upload_cross_signing_signatures()
2873 .ok()
2874 .expect(1)
2875 .named("upload_xsigning_signatures")
2876 .mount()
2877 .await;
2878
2879 let user_id = owned_user_id!("@alice:example.org");
2881 let device_id = owned_device_id!("ALICE_DEVICE");
2882 let alice = server
2883 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2884 .logged_in_with_oauth()
2885 .build()
2886 .await;
2887 alice
2888 .encryption()
2889 .bootstrap_cross_signing(None)
2890 .await
2891 .expect("Alice should be able to set up cross signing");
2892
2893 let oauth = alice.oauth();
2895 let grant = oauth
2896 .grant_login_with_qr_code()
2897 .device_creation_timeout(Duration::from_secs(2))
2898 .generate();
2899 let (qr_code_tx, qr_code_rx) = oneshot::channel();
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 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2906 let updates_task = spawn(async move {
2907 let mut qr_code_tx = Some(qr_code_tx);
2908 let mut checkcode_rx = Some(checkcode_rx);
2909
2910 while let Some(update) = updates.next().await {
2911 match &update {
2912 GrantLoginProgress::Starting => {
2913 assert_matches!(state, GrantLoginProgress::Starting);
2914 }
2915 GrantLoginProgress::EstablishingSecureChannel(
2916 GeneratedQrProgress::QrReady(qr_code_data),
2917 ) => {
2918 assert_matches!(state, GrantLoginProgress::Starting);
2919 qr_code_tx
2920 .take()
2921 .expect("The QR code should only be forwarded once")
2922 .send(qr_code_data.clone())
2923 .expect("Alice should be able to forward the QR code");
2924 }
2925 GrantLoginProgress::EstablishingSecureChannel(
2926 GeneratedQrProgress::QrScanned(checkcode_sender),
2927 ) => {
2928 assert_matches!(
2929 state,
2930 GrantLoginProgress::EstablishingSecureChannel(
2931 GeneratedQrProgress::QrReady(_)
2932 )
2933 );
2934 let checkcode = checkcode_rx
2935 .take()
2936 .expect("The checkcode should only be forwarded once")
2937 .await
2938 .expect("Alice should receive the checkcode");
2939 checkcode_sender
2940 .send(checkcode)
2941 .await
2942 .expect("Alice should be able to forward the checkcode");
2943 break;
2944 }
2945 _ => {
2946 panic!("Alice should abort the process");
2947 }
2948 }
2949 state = update;
2950 }
2951 });
2952
2953 let rendezvous_server_clone = rendezvous_server.clone();
2955 let bob_task = spawn(async move {
2956 request_login_with_scanned_qr_code(
2957 BobBehaviour::InvalidJsonMessage,
2958 qr_code_rx,
2959 checkcode_tx,
2960 None,
2961 &rendezvous_server_clone,
2962 None,
2963 None,
2964 )
2965 .await;
2966 });
2967
2968 assert_matches!(
2970 grant.await,
2971 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::Json(_))),
2972 "Alice should abort the login with a SecureChannel error"
2973 );
2974 updates_task.await.expect("Alice should run through all progress states");
2975 bob_task.await.expect("Bob's task should finish");
2976 }
2977
2978 #[async_test]
2979 async fn test_grant_login_with_scanned_qr_code_secure_channel_error() {
2980 let server = MatrixMockServer::new().await;
2981 let rendezvous_server = Arc::new(
2982 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2983 );
2984 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2985
2986 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2987 server
2988 .mock_upload_cross_signing_keys()
2989 .ok()
2990 .expect(1)
2991 .named("upload_xsigning_keys")
2992 .mount()
2993 .await;
2994 server
2995 .mock_upload_cross_signing_signatures()
2996 .ok()
2997 .expect(1)
2998 .named("upload_xsigning_signatures")
2999 .mount()
3000 .await;
3001
3002 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3004 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3005 .await
3006 .expect("Bob should be able to create a secure channel.");
3007 let qr_code_data = channel.qr_code_data().clone();
3008
3009 let user_id = owned_user_id!("@alice:example.org");
3011 let device_id = owned_device_id!("ALICE_DEVICE");
3012 let alice = server
3013 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3014 .logged_in_with_oauth()
3015 .build()
3016 .await;
3017 alice
3018 .encryption()
3019 .bootstrap_cross_signing(None)
3020 .await
3021 .expect("Alice should be able to set up cross signing");
3022
3023 let oauth = alice.oauth();
3025 let grant = oauth
3026 .grant_login_with_qr_code()
3027 .device_creation_timeout(Duration::from_secs(2))
3028 .scan(&qr_code_data);
3029 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3030
3031 let mut updates = grant.subscribe_to_progress();
3033 let mut state = grant.state.get();
3034 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3035 let updates_task = spawn(async move {
3036 let mut checkcode_tx = Some(checkcode_tx);
3037
3038 while let Some(update) = updates.next().await {
3039 match &update {
3040 GrantLoginProgress::Starting => {
3041 assert_matches!(state, GrantLoginProgress::Starting);
3042 }
3043 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3044 assert_matches!(state, GrantLoginProgress::Starting);
3045 checkcode_tx
3046 .take()
3047 .expect("The checkcode should only be forwarded once")
3048 .send(check_code.to_digit())
3049 .expect("Alice should be able to forward the checkcode");
3050 break;
3051 }
3052 _ => {
3053 panic!("Alice should abort the process");
3054 }
3055 }
3056 state = update;
3057 }
3058 });
3059
3060 let rendezvous_server_clone = rendezvous_server.clone();
3061 let bob_task = spawn(async move {
3063 request_login_with_generated_qr_code(
3064 BobBehaviour::InvalidJsonMessage,
3065 channel,
3066 checkcode_rx,
3067 None,
3068 &rendezvous_server_clone,
3069 alice.homeserver(),
3070 None,
3071 None,
3072 )
3073 .await;
3074 });
3075
3076 assert_matches!(
3078 grant.await,
3079 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::Json(_))),
3080 "Alice should abort the login with a SecureChannel error"
3081 );
3082 updates_task.await.expect("Alice should run through all progress states");
3083 bob_task.await.expect("Bob's task should finish");
3084 }
3085}