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? {
74 QrAuthMessage::LoginProtocol { device_authorization_grant, protocol, device_id } => {
75 (device_authorization_grant, protocol, device_id)
76 }
77 QrAuthMessage::LoginFailure { reason, .. } => {
78 return Err(QRCodeGrantLoginError::LoginFailure { reason });
79 }
80 message => {
81 return Err(QRCodeGrantLoginError::UnexpectedMessage {
82 expected: "m.login.protocol",
83 received: Box::new(message),
84 });
85 }
86 };
87
88 if protocol != LoginProtocolType::DeviceAuthorizationGrant {
92 channel
93 .send_json(QrAuthMessage::LoginFailure {
94 reason: LoginFailureReason::UnsupportedProtocol,
95 homeserver: None,
96 })
97 .await?;
98 return Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol));
99 }
100
101 if !matches!(client.device_exists(device_id.clone().into()).await, Ok(false)) {
105 channel
106 .send_json(QrAuthMessage::LoginFailure {
107 reason: LoginFailureReason::DeviceAlreadyExists,
108 homeserver: None,
109 })
110 .await?;
111 return Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse);
112 }
113
114 let verification_uri = Url::parse(
119 device_authorization_grant
120 .verification_uri_complete
121 .map(VerificationUriComplete::into_secret)
122 .unwrap_or(device_authorization_grant.verification_uri.to_string())
123 .as_str(),
124 )
125 .map_err(|e| QRCodeGrantLoginError::Unknown(e.to_string()))?;
126
127 let (sender, receiver) = tokio::sync::oneshot::channel();
128 state.set(GrantLoginProgress::WaitingForAuth {
129 verification_uri,
130 continuation_sender: ContinuationMessageSender(CloneableSender::new(sender)),
131 });
132
133 match receiver.await {
136 Ok(ContinuationMessage::Confirm) => {}
137 Ok(ContinuationMessage::Cancel) | Err(_) => {
138 channel
139 .send_json(QrAuthMessage::LoginFailure {
140 reason: LoginFailureReason::UserCancelled,
141 homeserver: None,
142 })
143 .await?;
144 return Err(QRCodeGrantLoginError::LoginFailure {
145 reason: LoginFailureReason::UserCancelled,
146 });
147 }
148 }
149 let message = QrAuthMessage::LoginProtocolAccepted;
154 channel.send_json(&message).await?;
155
156 match channel.receive_json().await? {
166 QrAuthMessage::LoginSuccess => (),
167 QrAuthMessage::LoginFailure { reason, .. } => {
168 return Err(QRCodeGrantLoginError::LoginFailure { reason });
169 }
170 message => {
171 return Err(QRCodeGrantLoginError::UnexpectedMessage {
172 expected: "m.login.success",
173 received: Box::new(message),
174 });
175 }
176 }
177
178 let deadline = Instant::now() + device_creation_timeout;
183
184 loop {
185 if matches!(client.device_exists(device_id.clone().into()).await, Ok(true)) {
186 break;
187 } else {
188 if Instant::now() < deadline {
191 matrix_sdk_common::sleep::sleep(Duration::from_millis(500)).await;
192 continue;
193 } else {
194 channel
196 .send_json(QrAuthMessage::LoginFailure {
197 reason: LoginFailureReason::DeviceNotFound,
198 homeserver: None,
199 })
200 .await?;
201 return Err(QRCodeGrantLoginError::DeviceNotFound);
202 }
203 }
204 }
205
206 state.set(GrantLoginProgress::SyncingSecrets);
210 let message = QrAuthMessage::LoginSecrets(secrets_bundle.clone());
211 channel.send_json(&message).await?;
212
213 state.set(GrantLoginProgress::Done);
215
216 Ok(())
217}
218
219#[derive(Clone, Debug, Default)]
221pub enum GrantLoginProgress<Q> {
222 #[default]
224 Starting,
225 EstablishingSecureChannel(Q),
228 WaitingForAuth {
231 verification_uri: Url,
233 continuation_sender: ContinuationMessageSender,
239 },
240 SyncingSecrets,
243 Done,
245}
246
247#[derive(Debug)]
250pub struct GrantLoginWithScannedQrCode<'a> {
251 client: &'a Client,
252 qr_code_data: &'a QrCodeData,
253 device_creation_timeout: Duration,
254 state: SharedObservable<GrantLoginProgress<QrProgress>>,
255}
256
257impl<'a> GrantLoginWithScannedQrCode<'a> {
258 pub(crate) fn new(
259 client: &'a Client,
260 qr_code_data: &'a QrCodeData,
261 device_creation_timeout: Duration,
262 ) -> GrantLoginWithScannedQrCode<'a> {
263 GrantLoginWithScannedQrCode {
264 client,
265 qr_code_data,
266 device_creation_timeout,
267 state: Default::default(),
268 }
269 }
270}
271
272impl GrantLoginWithScannedQrCode<'_> {
273 pub fn subscribe_to_progress(
279 &self,
280 ) -> impl Stream<Item = GrantLoginProgress<QrProgress>> + use<> {
281 self.state.subscribe()
282 }
283}
284
285impl<'a> IntoFuture for GrantLoginWithScannedQrCode<'a> {
286 type Output = Result<(), QRCodeGrantLoginError>;
287 boxed_into_future!(extra_bounds: 'a);
288
289 fn into_future(self) -> Self::IntoFuture {
290 Box::pin(async move {
291 let secrets_bundle = export_secrets_bundle(self.client).await?;
303
304 let mut channel = EstablishedSecureChannel::from_qr_code(
305 self.client.inner.http_client.inner.clone(),
306 self.qr_code_data,
307 QrCodeIntent::Reciprocate,
308 )
309 .await?;
310
311 let check_code = channel.check_code().to_owned();
316 self.state
317 .set(GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
318
319 let message = QrAuthMessage::LoginProtocols {
330 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
331 homeserver: self.client.homeserver(),
332 };
333 channel.send_json(message).await?;
334
335 finish_login_grant(
339 self.client,
340 &mut channel,
341 self.device_creation_timeout,
342 &secrets_bundle,
343 &self.state,
344 )
345 .await
346 })
347 }
348}
349
350#[derive(Debug)]
353pub struct GrantLoginWithGeneratedQrCode<'a> {
354 client: &'a Client,
355 device_creation_timeout: Duration,
356 state: SharedObservable<GrantLoginProgress<GeneratedQrProgress>>,
357}
358
359impl<'a> GrantLoginWithGeneratedQrCode<'a> {
360 pub(crate) fn new(
361 client: &'a Client,
362 device_creation_timeout: Duration,
363 ) -> GrantLoginWithGeneratedQrCode<'a> {
364 GrantLoginWithGeneratedQrCode { client, device_creation_timeout, state: Default::default() }
365 }
366}
367
368impl GrantLoginWithGeneratedQrCode<'_> {
369 pub fn subscribe_to_progress(
376 &self,
377 ) -> impl Stream<Item = GrantLoginProgress<GeneratedQrProgress>> + use<> {
378 self.state.subscribe()
379 }
380}
381
382impl<'a> IntoFuture for GrantLoginWithGeneratedQrCode<'a> {
383 type Output = Result<(), QRCodeGrantLoginError>;
384 boxed_into_future!(extra_bounds: 'a);
385
386 fn into_future(self) -> Self::IntoFuture {
387 Box::pin(async move {
388 let homeserver_url = self.client.homeserver();
393 let http_client = self.client.inner.http_client.clone();
394 let secrets_bundle = export_secrets_bundle(self.client).await?;
395 let channel = SecureChannel::reciprocate(http_client, &homeserver_url).await?;
396
397 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
402 GeneratedQrProgress::QrReady(channel.qr_code_data().clone()),
403 ));
404
405 let channel = channel.connect().await?;
411
412 let (tx, rx) = tokio::sync::oneshot::channel();
419 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
420 GeneratedQrProgress::QrScanned(CheckCodeSender::new(tx)),
421 ));
422 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
423
424 let mut channel = channel.confirm(check_code)?;
429
430 finish_login_grant(
441 self.client,
442 &mut channel,
443 self.device_creation_timeout,
444 &secrets_bundle,
445 &self.state,
446 )
447 .await
448 })
449 }
450}
451
452#[cfg(all(test, not(target_family = "wasm")))]
453mod test {
454 use std::{assert_matches, sync::Arc};
455
456 use futures_util::StreamExt;
457 use matrix_sdk_base::crypto::types::SecretsBundle;
458 use matrix_sdk_common::executor::spawn;
459 use matrix_sdk_test::async_test;
460 use oauth2::{EndUserVerificationUrl, VerificationUriComplete};
461 use ruma::{owned_device_id, owned_user_id};
462 use strass::assert_let;
463 use tokio::sync::oneshot;
464 use tracing::debug;
465
466 use super::*;
467 use crate::{
468 authentication::oauth::qrcode::{
469 LoginFailureReason, MessageDecodeError, QrAuthMessage,
470 messages::{AuthorizationGrant, LoginProtocolType},
471 secure_channel::{EstablishedSecureChannel, test::MockedRendezvousServer},
472 },
473 http_client::HttpClient,
474 test_utils::mocks::MatrixMockServer,
475 };
476
477 enum BobBehaviour {
478 HappyPath,
479 UnexpectedMessageInsteadOfLoginProtocol,
480 LoginFailureInsteadOfLoginProtocol,
481 UnexpectedMessageInsteadOfLoginSuccess,
482 LoginFailureInsteadOfLoginSuccess,
483 DeviceAlreadyExists,
484 DeviceNotCreated,
485 InvalidJsonMessage,
486 CancelledWhileWaitingForAuth,
487 UnsupportedProtocol,
488 }
489
490 #[allow(clippy::too_many_arguments)]
491 async fn request_login_with_scanned_qr_code(
492 behaviour: BobBehaviour,
493 qr_code_rx: oneshot::Receiver<QrCodeData>,
494 check_code_tx: oneshot::Sender<u8>,
495 server: Option<MatrixMockServer>,
496 _rendezvous_server: &MockedRendezvousServer,
500 device_authorization_grant: Option<AuthorizationGrant>,
501 secrets_bundle: Option<SecretsBundle>,
502 ) {
503 let qr_code_data = qr_code_rx.await.expect("Bob should receive the QR code");
505
506 let mut bob = EstablishedSecureChannel::from_qr_code(
509 reqwest::Client::new(),
510 &qr_code_data,
511 QrCodeIntent::Login,
512 )
513 .await
514 .expect("Bob should be able to connect the secure channel");
515
516 check_code_tx.send(bob.check_code()).expect("Bob should be able to send the checkcode");
518
519 match behaviour {
520 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
521 let message = QrAuthMessage::LoginSuccess;
523 bob.send_json(message).await.unwrap();
524 return;
525 }
526 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
527 let message = QrAuthMessage::LoginFailure {
529 reason: LoginFailureReason::UserCancelled,
530 homeserver: None,
531 };
532 bob.send_json(message).await.unwrap();
533 return;
534 }
535 BobBehaviour::InvalidJsonMessage => {
536 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
539 return;
540 }
541 BobBehaviour::DeviceAlreadyExists => {
542 server
545 .as_ref()
546 .expect("Bob needs the server for DeviceAlreadyExists")
547 .mock_get_device()
548 .ok()
549 .expect(1..)
550 .named("get_device")
551 .mount()
552 .await;
553
554 let message = QrAuthMessage::LoginProtocol {
556 protocol: LoginProtocolType::DeviceAuthorizationGrant,
557 device_authorization_grant: device_authorization_grant
558 .expect("Bob needs the device authorization grant"),
559 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
560 };
561 bob.send_json(message).await.unwrap();
562
563 let message = bob
565 .receive_json()
566 .await
567 .expect("Bob should receive the LoginFailure message from Alice");
568 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
569 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
570
571 return; }
573 BobBehaviour::UnsupportedProtocol => {
574 let message = QrAuthMessage::LoginProtocol {
576 protocol: LoginProtocolType::from("m.unknown_protocol"),
577 device_authorization_grant: device_authorization_grant
578 .expect("Bob needs the device authorization grant"),
579 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
580 };
581 bob.send_json(message).await.unwrap();
582
583 let message = bob
585 .receive_json()
586 .await
587 .expect("Bob should receive the LoginFailure message from Alice");
588 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
589 assert_matches!(reason, LoginFailureReason::UnsupportedProtocol);
590
591 return; }
593 BobBehaviour::CancelledWhileWaitingForAuth => {
594 let message = QrAuthMessage::LoginProtocol {
596 protocol: LoginProtocolType::DeviceAuthorizationGrant,
597 device_authorization_grant: device_authorization_grant
598 .expect("Bob needs the device authorization grant"),
599 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
600 };
601 bob.send_json(message).await.unwrap();
602
603 let message = bob
606 .receive_json()
607 .await
608 .expect("Bob should receive the LoginFailure message from Alice");
609 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
610 assert_matches!(reason, LoginFailureReason::UserCancelled);
611
612 return; }
614 _ => {
615 let message = QrAuthMessage::LoginProtocol {
617 protocol: LoginProtocolType::DeviceAuthorizationGrant,
618 device_authorization_grant: device_authorization_grant
619 .expect("Bob needs the device authorization grant"),
620 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
621 };
622 bob.send_json(message).await.unwrap();
623 }
624 }
625
626 let message = bob
628 .receive_json()
629 .await
630 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
631 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
632
633 match behaviour {
634 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
635 let message = QrAuthMessage::LoginProtocolAccepted;
637 bob.send_json(message).await.unwrap();
638 return;
639 }
640 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
641 let message = QrAuthMessage::LoginFailure {
643 reason: LoginFailureReason::AuthorizationExpired,
644 homeserver: None,
645 };
646 bob.send_json(message).await.unwrap();
647 return;
648 }
649 BobBehaviour::DeviceNotCreated => {
650 let message = QrAuthMessage::LoginSuccess;
656 bob.send_json(message).await.unwrap();
657
658 let message = bob
661 .receive_json()
662 .await
663 .expect("Bob should receive the LoginFailure message from Alice");
664 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
665 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
666
667 return; }
669 _ => {
670 server
673 .as_ref()
674 .expect("Bob needs the server for HappyPath")
675 .mock_get_device()
676 .ok()
677 .expect(1..)
678 .named("get_device")
679 .mount()
680 .await;
681
682 let message = QrAuthMessage::LoginSuccess;
684 bob.send_json(message).await.unwrap();
685 }
686 }
687
688 let message = bob
690 .receive_json()
691 .await
692 .expect("Bob should receive the LoginSecrets message from Alice");
693 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
694
695 assert_eq!(
697 serde_json::to_value(&secrets_bundle).unwrap(),
698 serde_json::to_value(&bundle).unwrap()
699 );
700 }
701
702 #[allow(clippy::too_many_arguments)]
703 async fn request_login_with_generated_qr_code(
704 behaviour: BobBehaviour,
705 channel: SecureChannel,
706 check_code_rx: oneshot::Receiver<u8>,
707 server: Option<MatrixMockServer>,
708 _rendezvous_server: &MockedRendezvousServer,
712 homeserver: Url,
713 device_authorization_grant: Option<AuthorizationGrant>,
714 secrets_bundle: Option<SecretsBundle>,
715 ) {
716 let channel =
718 channel.connect().await.expect("Bob should be able to connect the secure channel");
719
720 let check_code = check_code_rx.await.expect("Bob should receive the checkcode");
723 let mut bob = channel
724 .confirm(check_code)
725 .expect("Bob should be able to confirm the channel is secure");
726
727 let message = bob
729 .receive_json()
730 .await
731 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
732 assert_let!(
733 QrAuthMessage::LoginProtocols { protocols, homeserver: alice_homeserver } = message
734 );
735 assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
736 assert_eq!(alice_homeserver, homeserver);
737
738 match behaviour {
739 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
740 let message = QrAuthMessage::LoginSuccess;
742 bob.send_json(message).await.unwrap();
743 return;
744 }
745 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
746 let message = QrAuthMessage::LoginFailure {
748 reason: LoginFailureReason::UserCancelled,
749 homeserver: None,
750 };
751 bob.send_json(message).await.unwrap();
752 return;
753 }
754 BobBehaviour::InvalidJsonMessage => {
755 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
758 return;
759 }
760 BobBehaviour::DeviceAlreadyExists => {
761 server
764 .as_ref()
765 .expect("Bob needs the MatrixMockServer")
766 .mock_get_device()
767 .ok()
768 .expect(1..)
769 .named("get_device")
770 .mount()
771 .await;
772
773 let message = QrAuthMessage::LoginProtocol {
775 protocol: LoginProtocolType::DeviceAuthorizationGrant,
776 device_authorization_grant: device_authorization_grant
777 .expect("Bob needs the device authorization grant"),
778 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
779 };
780 bob.send_json(message).await.unwrap();
781
782 let message = bob
784 .receive_json()
785 .await
786 .expect("Bob should receive the LoginFailure message from Alice");
787 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
788 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
789
790 return; }
792 BobBehaviour::CancelledWhileWaitingForAuth => {
793 let message = QrAuthMessage::LoginProtocol {
795 protocol: LoginProtocolType::DeviceAuthorizationGrant,
796 device_authorization_grant: device_authorization_grant
797 .expect("Bob needs the device authorization grant"),
798 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
799 };
800 bob.send_json(message).await.unwrap();
801
802 let message = bob
805 .receive_json()
806 .await
807 .expect("Bob should receive the LoginFailure message from Alice");
808 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
809 assert_matches!(reason, LoginFailureReason::UserCancelled);
810
811 return; }
813 _ => {
814 let message = QrAuthMessage::LoginProtocol {
816 protocol: LoginProtocolType::DeviceAuthorizationGrant,
817 device_authorization_grant: device_authorization_grant
818 .expect("Bob needs the device authorization grant"),
819 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
820 };
821 bob.send_json(message).await.unwrap();
822 }
823 }
824
825 let message = bob
827 .receive_json()
828 .await
829 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
830 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
831
832 match behaviour {
833 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
834 let message = QrAuthMessage::LoginProtocolAccepted;
836 bob.send_json(message).await.unwrap();
837 return;
838 }
839 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
840 let message = QrAuthMessage::LoginFailure {
842 reason: LoginFailureReason::AuthorizationExpired,
843 homeserver: None,
844 };
845 bob.send_json(message).await.unwrap();
846 return;
847 }
848 BobBehaviour::DeviceNotCreated => {
849 let message = QrAuthMessage::LoginSuccess;
855 bob.send_json(message).await.unwrap();
856
857 let message = bob
860 .receive_json()
861 .await
862 .expect("Bob should receive the LoginFailure message from Alice");
863 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
864 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
865
866 return; }
868 _ => {
869 server
872 .as_ref()
873 .expect("Bob needs the MatrixMockServer")
874 .mock_get_device()
875 .ok()
876 .expect(1..)
877 .named("get_device")
878 .mount()
879 .await;
880
881 let message = QrAuthMessage::LoginSuccess;
883 bob.send_json(message).await.unwrap();
884 }
885 }
886
887 let message = bob
889 .receive_json()
890 .await
891 .expect("Bob should receive the LoginSecrets message from Alice");
892 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
893
894 assert_eq!(
896 serde_json::to_value(&secrets_bundle).unwrap(),
897 serde_json::to_value(&bundle).unwrap()
898 );
899 }
900
901 #[async_test]
902 async fn test_grant_login_with_generated_qr_code() {
903 let server = MatrixMockServer::new().await;
904 let rendezvous_server =
905 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
906 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
907
908 let device_authorization_grant = AuthorizationGrant {
909 verification_uri_complete: Some(VerificationUriComplete::new(
910 "https://id.matrix.org/device/abcde".to_owned(),
911 )),
912 verification_uri: EndUserVerificationUrl::new(
913 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
914 )
915 .unwrap(),
916 };
917
918 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
919 server
920 .mock_upload_cross_signing_keys()
921 .ok()
922 .expect(1)
923 .named("upload_xsigning_keys")
924 .mount()
925 .await;
926 server
927 .mock_upload_cross_signing_signatures()
928 .ok()
929 .expect(1)
930 .named("upload_xsigning_signatures")
931 .mount()
932 .await;
933
934 let user_id = owned_user_id!("@alice:example.org");
936 let device_id = owned_device_id!("ALICE_DEVICE");
937 let alice = server
938 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
939 .logged_in_with_oauth()
940 .build()
941 .await;
942 alice
943 .encryption()
944 .bootstrap_cross_signing(None)
945 .await
946 .expect("Alice should be able to set up cross signing");
947
948 let oauth = alice.oauth();
950 let grant = oauth
951 .grant_login_with_qr_code()
952 .device_creation_timeout(Duration::from_secs(2))
953 .generate();
954 let secrets_bundle = export_secrets_bundle(&alice)
955 .await
956 .expect("Alice should be able to export the secrets bundle");
957 let (qr_code_tx, qr_code_rx) = oneshot::channel();
958 let (checkcode_tx, checkcode_rx) = oneshot::channel();
959
960 let mut updates = grant.subscribe_to_progress();
962 let mut state = grant.state.get();
963 let verification_uri_complete =
964 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
965 assert_matches!(state.clone(), GrantLoginProgress::Starting);
966 let updates_task = spawn(async move {
967 let mut qr_code_tx = Some(qr_code_tx);
968 let mut checkcode_rx = Some(checkcode_rx);
969
970 while let Some(update) = updates.next().await {
971 match &update {
972 GrantLoginProgress::Starting => {
973 assert_matches!(state, GrantLoginProgress::Starting);
974 }
975 GrantLoginProgress::EstablishingSecureChannel(
976 GeneratedQrProgress::QrReady(qr_code_data),
977 ) => {
978 assert_matches!(state, GrantLoginProgress::Starting);
979 qr_code_tx
980 .take()
981 .expect("The QR code should only be forwarded once")
982 .send(qr_code_data.clone())
983 .expect("Alice should be able to forward the QR code");
984 }
985 GrantLoginProgress::EstablishingSecureChannel(
986 GeneratedQrProgress::QrScanned(checkcode_sender),
987 ) => {
988 assert_matches!(
989 state,
990 GrantLoginProgress::EstablishingSecureChannel(
991 GeneratedQrProgress::QrReady(_)
992 )
993 );
994 let checkcode = checkcode_rx
995 .take()
996 .expect("The checkcode should only be forwarded once")
997 .await
998 .expect("Alice should receive the checkcode");
999 checkcode_sender
1000 .send(checkcode)
1001 .await
1002 .expect("Alice should be able to forward the checkcode");
1003 }
1004 GrantLoginProgress::WaitingForAuth {
1005 verification_uri,
1006 continuation_sender,
1007 } => {
1008 assert_matches!(
1009 state,
1010 GrantLoginProgress::EstablishingSecureChannel(
1011 GeneratedQrProgress::QrScanned(_)
1012 )
1013 );
1014 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1015 continuation_sender.confirm().await.expect("should be able to confirm");
1016 }
1017 GrantLoginProgress::SyncingSecrets => {
1018 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1019 }
1020 GrantLoginProgress::Done => {
1021 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1022 break;
1023 }
1024 }
1025 state = update;
1026 }
1027 });
1028
1029 let bob_task = spawn(async move {
1031 request_login_with_scanned_qr_code(
1032 BobBehaviour::HappyPath,
1033 qr_code_rx,
1034 checkcode_tx,
1035 Some(server),
1036 &rendezvous_server,
1037 Some(device_authorization_grant),
1038 Some(secrets_bundle),
1039 )
1040 .await;
1041 });
1042
1043 grant.await.expect("Alice should be able to grant the login");
1045 updates_task.await.expect("Alice should run through all progress states");
1046 bob_task.await.expect("Bob's task should finish");
1047 }
1048
1049 #[async_test]
1050 async fn test_grant_login_with_scanned_qr_code() {
1051 let server = MatrixMockServer::new().await;
1052 let rendezvous_server =
1053 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1054 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1055
1056 let device_authorization_grant = AuthorizationGrant {
1057 verification_uri_complete: Some(VerificationUriComplete::new(
1058 "https://id.matrix.org/device/abcde".to_owned(),
1059 )),
1060 verification_uri: EndUserVerificationUrl::new(
1061 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1062 )
1063 .unwrap(),
1064 };
1065
1066 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1067 server
1068 .mock_upload_cross_signing_keys()
1069 .ok()
1070 .expect(1)
1071 .named("upload_xsigning_keys")
1072 .mount()
1073 .await;
1074 server
1075 .mock_upload_cross_signing_signatures()
1076 .ok()
1077 .expect(1)
1078 .named("upload_xsigning_signatures")
1079 .mount()
1080 .await;
1081
1082 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1085 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1086 .await
1087 .expect("Bob should be able to create a secure channel.");
1088 let qr_code_data = channel.qr_code_data().clone();
1089
1090 let user_id = owned_user_id!("@alice:example.org");
1092 let device_id = owned_device_id!("ALICE_DEVICE");
1093 let alice = server
1094 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1095 .logged_in_with_oauth()
1096 .build()
1097 .await;
1098 alice
1099 .encryption()
1100 .bootstrap_cross_signing(None)
1101 .await
1102 .expect("Alice should be able to set up cross signing");
1103
1104 let oauth = alice.oauth();
1106 let grant = oauth
1107 .grant_login_with_qr_code()
1108 .device_creation_timeout(Duration::from_secs(2))
1109 .scan(&qr_code_data);
1110 let secrets_bundle = export_secrets_bundle(&alice)
1111 .await
1112 .expect("Alice should be able to export the secrets bundle");
1113 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1114
1115 let mut updates = grant.subscribe_to_progress();
1117 let mut state = grant.state.get();
1118 let verification_uri_complete =
1119 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1120 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1121 let updates_task = spawn(async move {
1122 let mut checkcode_tx = Some(checkcode_tx);
1123
1124 while let Some(update) = updates.next().await {
1125 match &update {
1126 GrantLoginProgress::Starting => {
1127 assert_matches!(state, GrantLoginProgress::Starting);
1128 }
1129 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1130 assert_matches!(state, GrantLoginProgress::Starting);
1131 checkcode_tx
1132 .take()
1133 .expect("The checkcode should only be forwarded once")
1134 .send(*check_code)
1135 .expect("Alice should be able to forward the checkcode");
1136 }
1137 GrantLoginProgress::WaitingForAuth {
1138 verification_uri,
1139 continuation_sender,
1140 } => {
1141 assert_matches!(
1142 state,
1143 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1144 );
1145 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1146 continuation_sender.confirm().await.expect("should be able to confirm");
1147 }
1148 GrantLoginProgress::SyncingSecrets => {
1149 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1150 }
1151 GrantLoginProgress::Done => {
1152 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1153 break;
1154 }
1155 }
1156 state = update;
1157 }
1158 });
1159
1160 let bob_task = spawn(async move {
1162 request_login_with_generated_qr_code(
1163 BobBehaviour::HappyPath,
1164 channel,
1165 checkcode_rx,
1166 Some(server),
1167 &rendezvous_server,
1168 alice.homeserver(),
1169 Some(device_authorization_grant),
1170 Some(secrets_bundle),
1171 )
1172 .await;
1173 });
1174
1175 grant.await.expect("Alice should be able to grant the login");
1177 updates_task.await.expect("Alice should run through all progress states");
1178 bob_task.await.expect("Bob's task should finish");
1179 }
1180
1181 #[async_test]
1182 async fn test_grant_login_with_scanned_qr_code_with_homeserver_swap() {
1183 let server = MatrixMockServer::new().await;
1184 let rendezvous_server =
1185 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1186 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1187
1188 let device_authorization_grant = AuthorizationGrant {
1189 verification_uri_complete: Some(VerificationUriComplete::new(
1190 "https://id.matrix.org/device/abcde".to_owned(),
1191 )),
1192 verification_uri: EndUserVerificationUrl::new(
1193 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1194 )
1195 .unwrap(),
1196 };
1197
1198 let login_server = MatrixMockServer::new().await;
1199
1200 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1201 login_server
1202 .mock_upload_cross_signing_keys()
1203 .ok()
1204 .expect(1)
1205 .named("upload_xsigning_keys")
1206 .mount()
1207 .await;
1208 login_server
1209 .mock_upload_cross_signing_signatures()
1210 .ok()
1211 .expect(1)
1212 .named("upload_xsigning_signatures")
1213 .mount()
1214 .await;
1215
1216 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1219 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1220 .await
1221 .expect("Bob should be able to create a secure channel.");
1222 let qr_code_data = channel.qr_code_data().clone();
1223
1224 let user_id = owned_user_id!("@alice:example.org");
1226 let device_id = owned_device_id!("ALICE_DEVICE");
1227 let alice = login_server
1228 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1229 .logged_in_with_oauth()
1230 .build()
1231 .await;
1232 alice
1233 .encryption()
1234 .bootstrap_cross_signing(None)
1235 .await
1236 .expect("Alice should be able to set up cross signing");
1237
1238 let oauth = alice.oauth();
1240 let grant = oauth
1241 .grant_login_with_qr_code()
1242 .device_creation_timeout(Duration::from_secs(2))
1243 .scan(&qr_code_data);
1244 let secrets_bundle = export_secrets_bundle(&alice)
1245 .await
1246 .expect("Alice should be able to export the secrets bundle");
1247 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1248
1249 let mut updates = grant.subscribe_to_progress();
1251 let mut state = grant.state.get();
1252 let verification_uri_complete =
1253 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1254 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1255 let updates_task = spawn(async move {
1256 let mut checkcode_tx = Some(checkcode_tx);
1257
1258 while let Some(update) = updates.next().await {
1259 match &update {
1260 GrantLoginProgress::Starting => {
1261 assert_matches!(state, GrantLoginProgress::Starting);
1262 }
1263 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1264 assert_matches!(state, GrantLoginProgress::Starting);
1265 checkcode_tx
1266 .take()
1267 .expect("The checkcode should only be forwarded once")
1268 .send(*check_code)
1269 .expect("Alice should be able to forward the checkcode");
1270 }
1271 GrantLoginProgress::WaitingForAuth {
1272 verification_uri,
1273 continuation_sender,
1274 } => {
1275 assert_matches!(
1276 state,
1277 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1278 );
1279 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1280 continuation_sender.confirm().await.expect("should be able to confirm");
1281 }
1282 GrantLoginProgress::SyncingSecrets => {
1283 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1284 }
1285 GrantLoginProgress::Done => {
1286 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1287 break;
1288 }
1289 }
1290 state = update;
1291 }
1292 });
1293
1294 let bob_task = spawn(async move {
1296 request_login_with_generated_qr_code(
1297 BobBehaviour::HappyPath,
1298 channel,
1299 checkcode_rx,
1300 Some(login_server),
1301 &rendezvous_server,
1302 alice.homeserver(),
1303 Some(device_authorization_grant),
1304 Some(secrets_bundle),
1305 )
1306 .await;
1307 });
1308
1309 grant.await.expect("Alice should be able to grant the login");
1311 updates_task.await.expect("Alice should run through all progress states");
1312 bob_task.await.expect("Bob's task should finish");
1313 }
1314
1315 #[async_test]
1316 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_protocol()
1317 {
1318 let server = MatrixMockServer::new().await;
1319 let rendezvous_server = Arc::new(
1320 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1321 );
1322 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1323
1324 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1325 server
1326 .mock_upload_cross_signing_keys()
1327 .ok()
1328 .expect(1)
1329 .named("upload_xsigning_keys")
1330 .mount()
1331 .await;
1332 server
1333 .mock_upload_cross_signing_signatures()
1334 .ok()
1335 .expect(1)
1336 .named("upload_xsigning_signatures")
1337 .mount()
1338 .await;
1339
1340 let user_id = owned_user_id!("@alice:example.org");
1342 let device_id = owned_device_id!("ALICE_DEVICE");
1343 let alice = server
1344 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1345 .logged_in_with_oauth()
1346 .build()
1347 .await;
1348 alice
1349 .encryption()
1350 .bootstrap_cross_signing(None)
1351 .await
1352 .expect("Alice should be able to set up cross signing");
1353
1354 let oauth = alice.oauth();
1356 let grant = oauth
1357 .grant_login_with_qr_code()
1358 .device_creation_timeout(Duration::from_secs(2))
1359 .generate();
1360 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1361 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1362
1363 let mut updates = grant.subscribe_to_progress();
1365 let mut state = grant.state.get();
1366 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1367 let updates_task = spawn(async move {
1368 let mut qr_code_tx = Some(qr_code_tx);
1369 let mut checkcode_rx = Some(checkcode_rx);
1370
1371 while let Some(update) = updates.next().await {
1372 match &update {
1373 GrantLoginProgress::Starting => {
1374 assert_matches!(state, GrantLoginProgress::Starting);
1375 }
1376 GrantLoginProgress::EstablishingSecureChannel(
1377 GeneratedQrProgress::QrReady(qr_code_data),
1378 ) => {
1379 assert_matches!(state, GrantLoginProgress::Starting);
1380 qr_code_tx
1381 .take()
1382 .expect("The QR code should only be forwarded once")
1383 .send(qr_code_data.clone())
1384 .expect("Alice should be able to forward the QR code");
1385 }
1386 GrantLoginProgress::EstablishingSecureChannel(
1387 GeneratedQrProgress::QrScanned(checkcode_sender),
1388 ) => {
1389 assert_matches!(
1390 state,
1391 GrantLoginProgress::EstablishingSecureChannel(
1392 GeneratedQrProgress::QrReady(_)
1393 )
1394 );
1395 let checkcode = checkcode_rx
1396 .take()
1397 .expect("The checkcode should only be forwarded once")
1398 .await
1399 .expect("Alice should receive the checkcode");
1400 checkcode_sender
1401 .send(checkcode)
1402 .await
1403 .expect("Alice should be able to forward the checkcode");
1404 break;
1405 }
1406 _ => {
1407 panic!("Alice should abort the process");
1408 }
1409 }
1410 state = update;
1411 }
1412 });
1413
1414 let rendezvous_server_clone = rendezvous_server.clone();
1416 let bob_task = spawn(async move {
1417 request_login_with_scanned_qr_code(
1418 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1419 qr_code_rx,
1420 checkcode_tx,
1421 None,
1422 &rendezvous_server_clone,
1423 None,
1424 None,
1425 )
1426 .await;
1427 });
1428
1429 assert_let!(
1431 Err(QRCodeGrantLoginError::UnexpectedMessage {
1432 expected: "m.login.protocol",
1433 received,
1434 }) = grant.await,
1435 "Alice should abort the login with expected error variant"
1436 );
1437 assert_matches!(
1438 *received,
1439 QrAuthMessage::LoginSuccess,
1440 "Alice should abort the login with expected error message"
1441 );
1442 updates_task.await.expect("Alice should run through all progress states");
1443 bob_task.await.expect("Bob's task should finish");
1444 }
1445
1446 #[async_test]
1447 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_protocol() {
1448 let server = MatrixMockServer::new().await;
1449 let rendezvous_server = Arc::new(
1450 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
1451 );
1452 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1453
1454 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1455 server
1456 .mock_upload_cross_signing_keys()
1457 .ok()
1458 .expect(1)
1459 .named("upload_xsigning_keys")
1460 .mount()
1461 .await;
1462 server
1463 .mock_upload_cross_signing_signatures()
1464 .ok()
1465 .expect(1)
1466 .named("upload_xsigning_signatures")
1467 .mount()
1468 .await;
1469
1470 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1473 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1474 .await
1475 .expect("Bob should be able to create a secure channel.");
1476 let qr_code_data = channel.qr_code_data().clone();
1477
1478 let user_id = owned_user_id!("@alice:example.org");
1480 let device_id = owned_device_id!("ALICE_DEVICE");
1481 let alice = server
1482 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1483 .logged_in_with_oauth()
1484 .build()
1485 .await;
1486 alice
1487 .encryption()
1488 .bootstrap_cross_signing(None)
1489 .await
1490 .expect("Alice should be able to set up cross signing");
1491
1492 let oauth = alice.oauth();
1494 let grant = oauth
1495 .grant_login_with_qr_code()
1496 .device_creation_timeout(Duration::from_secs(2))
1497 .scan(&qr_code_data);
1498 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1499
1500 let mut updates = grant.subscribe_to_progress();
1502 let mut state = grant.state.get();
1503 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1504 let updates_task = spawn(async move {
1505 let mut checkcode_tx = Some(checkcode_tx);
1506
1507 while let Some(update) = updates.next().await {
1508 match &update {
1509 GrantLoginProgress::Starting => {
1510 assert_matches!(state, GrantLoginProgress::Starting);
1511 }
1512 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1513 assert_matches!(state, GrantLoginProgress::Starting);
1514 checkcode_tx
1515 .take()
1516 .expect("The checkcode should only be forwarded once")
1517 .send(*check_code)
1518 .expect("Alice should be able to forward the checkcode");
1519 break;
1520 }
1521 _ => {
1522 panic!("Alice should abort the process");
1523 }
1524 }
1525 state = update;
1526 }
1527 });
1528
1529 let rendezvous_server_clone = rendezvous_server.clone();
1530 let bob_task = spawn(async move {
1532 request_login_with_generated_qr_code(
1533 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1534 channel,
1535 checkcode_rx,
1536 None,
1537 &rendezvous_server_clone,
1538 alice.homeserver(),
1539 None,
1540 None,
1541 )
1542 .await;
1543 });
1544
1545 assert_let!(
1547 Err(QRCodeGrantLoginError::UnexpectedMessage {
1548 expected: "m.login.protocol",
1549 received,
1550 }) = grant.await,
1551 "Alice should abort the login with expected error variant"
1552 );
1553 assert_matches!(
1554 *received,
1555 QrAuthMessage::LoginSuccess,
1556 "Alice should abort the login with expected error message"
1557 );
1558 updates_task.await.expect("Alice should run through all progress states");
1559 bob_task.await.expect("Bob's task should finish");
1560 }
1561
1562 #[async_test]
1563 async fn test_grant_login_with_generated_qr_code_unsupported_protocol() {
1564 let server = MatrixMockServer::new().await;
1565 let rendezvous_server =
1566 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1567 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1568
1569 let device_authorization_grant = AuthorizationGrant {
1570 verification_uri_complete: Some(VerificationUriComplete::new(
1571 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1572 )),
1573 verification_uri: EndUserVerificationUrl::new(
1574 "https://id.matrix.org/device/abcde".to_owned(),
1575 )
1576 .unwrap(),
1577 };
1578
1579 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1580 server
1581 .mock_upload_cross_signing_keys()
1582 .ok()
1583 .expect(1)
1584 .named("upload_xsigning_keys")
1585 .mount()
1586 .await;
1587 server
1588 .mock_upload_cross_signing_signatures()
1589 .ok()
1590 .expect(1)
1591 .named("upload_xsigning_signatures")
1592 .mount()
1593 .await;
1594
1595 let user_id = owned_user_id!("@alice:example.org");
1597 let device_id = owned_device_id!("ALICE_DEVICE");
1598 let alice = server
1599 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1600 .logged_in_with_oauth()
1601 .build()
1602 .await;
1603 alice
1604 .encryption()
1605 .bootstrap_cross_signing(None)
1606 .await
1607 .expect("Alice should be able to set up cross signing");
1608
1609 let oauth = alice.oauth();
1611 let grant = oauth
1612 .grant_login_with_qr_code()
1613 .device_creation_timeout(Duration::from_secs(2))
1614 .generate();
1615
1616 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1617 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1618
1619 let mut updates = grant.subscribe_to_progress();
1621 let mut state = grant.state.get();
1622 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1623 let updates_task = spawn(async move {
1624 let mut qr_code_tx = Some(qr_code_tx);
1625 let mut checkcode_rx = Some(checkcode_rx);
1626
1627 while let Some(update) = updates.next().await {
1628 match &update {
1629 GrantLoginProgress::Starting => {
1630 assert_matches!(state, GrantLoginProgress::Starting);
1631 }
1632 GrantLoginProgress::EstablishingSecureChannel(
1633 GeneratedQrProgress::QrReady(qr_code_data),
1634 ) => {
1635 assert_matches!(state, GrantLoginProgress::Starting);
1636 qr_code_tx
1637 .take()
1638 .expect("The QR code should only be forwarded once")
1639 .send(qr_code_data.clone())
1640 .expect("Alice should be able to forward the QR code");
1641 }
1642 GrantLoginProgress::EstablishingSecureChannel(
1643 GeneratedQrProgress::QrScanned(checkcode_sender),
1644 ) => {
1645 assert_matches!(
1646 state,
1647 GrantLoginProgress::EstablishingSecureChannel(
1648 GeneratedQrProgress::QrReady(_)
1649 )
1650 );
1651 let checkcode = checkcode_rx
1652 .take()
1653 .expect("The checkcode should only be forwarded once")
1654 .await
1655 .expect("Alice should receive the checkcode");
1656 checkcode_sender
1657 .send(checkcode)
1658 .await
1659 .expect("Alice should be able to forward the checkcode");
1660 }
1661 _ => {
1662 panic!("Alice should abort the process");
1663 }
1664 }
1665 state = update;
1666 }
1667 });
1668
1669 let bob_task = spawn(async move {
1671 request_login_with_scanned_qr_code(
1672 BobBehaviour::UnsupportedProtocol,
1673 qr_code_rx,
1674 checkcode_tx,
1675 None,
1676 &rendezvous_server,
1677 Some(device_authorization_grant),
1678 None,
1679 )
1680 .await;
1681 });
1682
1683 assert_let!(
1685 Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol)) = grant.await,
1686 "Alice should abort the login with expected error variant"
1687 );
1688 assert_eq!(protocol.as_str(), "m.unknown_protocol");
1689 updates_task.await.expect("Alice should run through all progress states");
1690 bob_task.await.expect("Bob's task should finish");
1691 }
1692
1693 #[async_test]
1694 async fn test_grant_login_with_generated_qr_code_device_already_exists() {
1695 let server = MatrixMockServer::new().await;
1696 let rendezvous_server =
1697 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1698 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1699
1700 let device_authorization_grant = AuthorizationGrant {
1701 verification_uri_complete: Some(VerificationUriComplete::new(
1702 "https://id.matrix.org/device/abcde".to_owned(),
1703 )),
1704 verification_uri: EndUserVerificationUrl::new(
1705 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1706 )
1707 .unwrap(),
1708 };
1709
1710 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1711 server
1712 .mock_upload_cross_signing_keys()
1713 .ok()
1714 .expect(1)
1715 .named("upload_xsigning_keys")
1716 .mount()
1717 .await;
1718 server
1719 .mock_upload_cross_signing_signatures()
1720 .ok()
1721 .expect(1)
1722 .named("upload_xsigning_signatures")
1723 .mount()
1724 .await;
1725
1726 let user_id = owned_user_id!("@alice:example.org");
1728 let device_id = owned_device_id!("ALICE_DEVICE");
1729 let alice = server
1730 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1731 .logged_in_with_oauth()
1732 .build()
1733 .await;
1734 alice
1735 .encryption()
1736 .bootstrap_cross_signing(None)
1737 .await
1738 .expect("Alice should be able to set up cross signing");
1739
1740 let oauth = alice.oauth();
1742 let grant = oauth
1743 .grant_login_with_qr_code()
1744 .device_creation_timeout(Duration::from_secs(2))
1745 .generate();
1746 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1747 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1748
1749 let mut updates = grant.subscribe_to_progress();
1751 let mut state = grant.state.get();
1752 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1753 let updates_task = spawn(async move {
1754 let mut qr_code_tx = Some(qr_code_tx);
1755 let mut checkcode_rx = Some(checkcode_rx);
1756
1757 while let Some(update) = updates.next().await {
1758 match &update {
1759 GrantLoginProgress::Starting => {
1760 assert_matches!(state, GrantLoginProgress::Starting);
1761 }
1762 GrantLoginProgress::EstablishingSecureChannel(
1763 GeneratedQrProgress::QrReady(qr_code_data),
1764 ) => {
1765 assert_matches!(state, GrantLoginProgress::Starting);
1766 qr_code_tx
1767 .take()
1768 .expect("The QR code should only be forwarded once")
1769 .send(qr_code_data.clone())
1770 .expect("Alice should be able to forward the QR code");
1771 }
1772 GrantLoginProgress::EstablishingSecureChannel(
1773 GeneratedQrProgress::QrScanned(checkcode_sender),
1774 ) => {
1775 assert_matches!(
1776 state,
1777 GrantLoginProgress::EstablishingSecureChannel(
1778 GeneratedQrProgress::QrReady(_)
1779 )
1780 );
1781 let checkcode = checkcode_rx
1782 .take()
1783 .expect("The checkcode should only be forwarded once")
1784 .await
1785 .expect("Alice should receive the checkcode");
1786 checkcode_sender
1787 .send(checkcode)
1788 .await
1789 .expect("Alice should be able to forward the checkcode");
1790 }
1791 _ => {
1792 panic!("Alice should abort the process");
1793 }
1794 }
1795 state = update;
1796 }
1797 });
1798
1799 let bob_task = spawn(async move {
1801 request_login_with_scanned_qr_code(
1802 BobBehaviour::DeviceAlreadyExists,
1803 qr_code_rx,
1804 checkcode_tx,
1805 Some(server),
1806 &rendezvous_server,
1807 Some(device_authorization_grant),
1808 None,
1809 )
1810 .await;
1811 });
1812
1813 assert_matches!(
1815 grant.await,
1816 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1817 "Alice should abort the login with expected error"
1818 );
1819 updates_task.await.expect("Alice should run through all progress states");
1820 bob_task.await.expect("Bob's task should finish");
1821 }
1822
1823 #[async_test]
1824 async fn test_grant_login_with_scanned_qr_code_device_already_exists() {
1825 let server = MatrixMockServer::new().await;
1826 let rendezvous_server =
1827 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1828 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1829
1830 let device_authorization_grant = AuthorizationGrant {
1831 verification_uri_complete: Some(VerificationUriComplete::new(
1832 "https://id.matrix.org/device/abcde".to_owned(),
1833 )),
1834 verification_uri: EndUserVerificationUrl::new(
1835 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1836 )
1837 .unwrap(),
1838 };
1839
1840 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1841 server
1842 .mock_upload_cross_signing_keys()
1843 .ok()
1844 .expect(1)
1845 .named("upload_xsigning_keys")
1846 .mount()
1847 .await;
1848 server
1849 .mock_upload_cross_signing_signatures()
1850 .ok()
1851 .expect(1)
1852 .named("upload_xsigning_signatures")
1853 .mount()
1854 .await;
1855
1856 let client = HttpClient::new(reqwest::Client::new(), Default::default());
1859 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
1860 .await
1861 .expect("Bob should be able to create a secure channel.");
1862 let qr_code_data = channel.qr_code_data().clone();
1863
1864 let user_id = owned_user_id!("@alice:example.org");
1866 let device_id = owned_device_id!("ALICE_DEVICE");
1867 let alice = server
1868 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1869 .logged_in_with_oauth()
1870 .build()
1871 .await;
1872 alice
1873 .encryption()
1874 .bootstrap_cross_signing(None)
1875 .await
1876 .expect("Alice should be able to set up cross signing");
1877
1878 let oauth = alice.oauth();
1880 let grant = oauth
1881 .grant_login_with_qr_code()
1882 .device_creation_timeout(Duration::from_secs(2))
1883 .scan(&qr_code_data);
1884 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1885
1886 let mut updates = grant.subscribe_to_progress();
1888 let mut state = grant.state.get();
1889 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1890 let updates_task = spawn(async move {
1891 let mut checkcode_tx = Some(checkcode_tx);
1892
1893 while let Some(update) = updates.next().await {
1894 match &update {
1895 GrantLoginProgress::Starting => {
1896 assert_matches!(state, GrantLoginProgress::Starting);
1897 }
1898 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1899 assert_matches!(state, GrantLoginProgress::Starting);
1900 checkcode_tx
1901 .take()
1902 .expect("The checkcode should only be forwarded once")
1903 .send(*check_code)
1904 .expect("Alice should be able to forward the checkcode");
1905 }
1906 _ => {
1907 panic!("Alice should abort the process");
1908 }
1909 }
1910 state = update;
1911 }
1912 });
1913
1914 let bob_task = spawn(async move {
1916 request_login_with_generated_qr_code(
1917 BobBehaviour::DeviceAlreadyExists,
1918 channel,
1919 checkcode_rx,
1920 Some(server),
1921 &rendezvous_server,
1922 alice.homeserver(),
1923 Some(device_authorization_grant),
1924 None,
1925 )
1926 .await;
1927 });
1928
1929 assert_matches!(
1931 grant.await,
1932 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
1933 "Alice should abort the login with expected error"
1934 );
1935 updates_task.await.expect("Alice should run through all progress states");
1936 bob_task.await.expect("Bob's task should finish");
1937 }
1938
1939 #[async_test]
1940 async fn test_grant_login_with_generated_qr_code_device_not_found() {
1941 let server = MatrixMockServer::new().await;
1942 let rendezvous_server =
1943 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
1944 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1945
1946 let device_authorization_grant = AuthorizationGrant {
1947 verification_uri_complete: Some(VerificationUriComplete::new(
1948 "https://id.matrix.org/device/abcde".to_owned(),
1949 )),
1950 verification_uri: EndUserVerificationUrl::new(
1951 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1952 )
1953 .unwrap(),
1954 };
1955
1956 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1957 server
1958 .mock_upload_cross_signing_keys()
1959 .ok()
1960 .expect(1)
1961 .named("upload_xsigning_keys")
1962 .mount()
1963 .await;
1964 server
1965 .mock_upload_cross_signing_signatures()
1966 .ok()
1967 .expect(1)
1968 .named("upload_xsigning_signatures")
1969 .mount()
1970 .await;
1971
1972 let user_id = owned_user_id!("@alice:example.org");
1974 let device_id = owned_device_id!("ALICE_DEVICE");
1975 let alice = server
1976 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1977 .logged_in_with_oauth()
1978 .build()
1979 .await;
1980 alice
1981 .encryption()
1982 .bootstrap_cross_signing(None)
1983 .await
1984 .expect("Alice should be able to set up cross signing");
1985
1986 let oauth = alice.oauth();
1988 let grant = oauth
1989 .grant_login_with_qr_code()
1990 .device_creation_timeout(Duration::from_secs(2))
1991 .generate();
1992 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1993 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1994
1995 let mut updates = grant.subscribe_to_progress();
1997 let mut state = grant.state.get();
1998 let verification_uri_complete =
1999 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2000 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2001 let updates_task = spawn(async move {
2002 let mut qr_code_tx = Some(qr_code_tx);
2003 let mut checkcode_rx = Some(checkcode_rx);
2004
2005 while let Some(update) = updates.next().await {
2006 match &update {
2007 GrantLoginProgress::Starting => {
2008 assert_matches!(state, GrantLoginProgress::Starting);
2009 }
2010 GrantLoginProgress::EstablishingSecureChannel(
2011 GeneratedQrProgress::QrReady(qr_code_data),
2012 ) => {
2013 assert_matches!(state, GrantLoginProgress::Starting);
2014 qr_code_tx
2015 .take()
2016 .expect("The QR code should only be forwarded once")
2017 .send(qr_code_data.clone())
2018 .expect("Alice should be able to forward the QR code");
2019 }
2020 GrantLoginProgress::EstablishingSecureChannel(
2021 GeneratedQrProgress::QrScanned(checkcode_sender),
2022 ) => {
2023 assert_matches!(
2024 state,
2025 GrantLoginProgress::EstablishingSecureChannel(
2026 GeneratedQrProgress::QrReady(_)
2027 )
2028 );
2029 let checkcode = checkcode_rx
2030 .take()
2031 .expect("The checkcode should only be forwarded once")
2032 .await
2033 .expect("Alice should receive the checkcode");
2034 checkcode_sender
2035 .send(checkcode)
2036 .await
2037 .expect("Alice should be able to forward the checkcode");
2038 }
2039 GrantLoginProgress::WaitingForAuth {
2040 verification_uri,
2041 continuation_sender,
2042 } => {
2043 assert_matches!(
2044 state,
2045 GrantLoginProgress::EstablishingSecureChannel(
2046 GeneratedQrProgress::QrScanned(_)
2047 )
2048 );
2049 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2050 continuation_sender.confirm().await.expect("should be able to confirm");
2051 }
2052 _ => {
2053 panic!("Alice should abort the process");
2054 }
2055 }
2056 state = update;
2057 }
2058 });
2059
2060 let bob_task = spawn(async move {
2062 request_login_with_scanned_qr_code(
2063 BobBehaviour::DeviceNotCreated,
2064 qr_code_rx,
2065 checkcode_tx,
2066 Some(server),
2067 &rendezvous_server,
2068 Some(device_authorization_grant),
2069 None,
2070 )
2071 .await;
2072 });
2073
2074 assert_matches!(
2075 grant.await,
2076 Err(QRCodeGrantLoginError::DeviceNotFound),
2077 "Alice should abort the login with expected error"
2078 );
2079 updates_task.await.expect("Alice should run through all progress states");
2080 bob_task.await.expect("Bob's task should finish");
2081 }
2082
2083 #[async_test]
2084 async fn test_grant_login_with_scanned_qr_code_device_not_found() {
2085 let server = MatrixMockServer::new().await;
2086 let rendezvous_server =
2087 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
2088 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2089
2090 let device_authorization_grant = AuthorizationGrant {
2091 verification_uri_complete: Some(VerificationUriComplete::new(
2092 "https://id.matrix.org/device/abcde".to_owned(),
2093 )),
2094 verification_uri: EndUserVerificationUrl::new(
2095 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2096 )
2097 .unwrap(),
2098 };
2099
2100 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2101 server
2102 .mock_upload_cross_signing_keys()
2103 .ok()
2104 .expect(1)
2105 .named("upload_xsigning_keys")
2106 .mount()
2107 .await;
2108 server
2109 .mock_upload_cross_signing_signatures()
2110 .ok()
2111 .expect(1)
2112 .named("upload_xsigning_signatures")
2113 .mount()
2114 .await;
2115
2116 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 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2145
2146 let mut updates = grant.subscribe_to_progress();
2148 let mut state = grant.state.get();
2149 let verification_uri_complete =
2150 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2151 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2152 let updates_task = spawn(async move {
2153 let mut checkcode_tx = Some(checkcode_tx);
2154
2155 while let Some(update) = updates.next().await {
2156 match &update {
2157 GrantLoginProgress::Starting => {
2158 assert_matches!(state, GrantLoginProgress::Starting);
2159 }
2160 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2161 assert_matches!(state, GrantLoginProgress::Starting);
2162 checkcode_tx
2163 .take()
2164 .expect("The checkcode should only be forwarded once")
2165 .send(*check_code)
2166 .expect("Alice should be able to forward the checkcode");
2167 }
2168 GrantLoginProgress::WaitingForAuth {
2169 verification_uri,
2170 continuation_sender,
2171 } => {
2172 assert_matches!(
2173 state,
2174 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2175 );
2176 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2177 continuation_sender.confirm().await.expect("should be able to confirm");
2178 }
2179 _ => {
2180 panic!("Alice should abort the process");
2181 }
2182 }
2183 state = update;
2184 }
2185 });
2186
2187 let bob_task = spawn(async move {
2189 request_login_with_generated_qr_code(
2190 BobBehaviour::DeviceNotCreated,
2191 channel,
2192 checkcode_rx,
2193 None,
2194 &rendezvous_server,
2195 alice.homeserver(),
2196 Some(device_authorization_grant),
2197 None,
2198 )
2199 .await;
2200 });
2201
2202 assert_matches!(
2203 grant.await,
2204 Err(QRCodeGrantLoginError::DeviceNotFound),
2205 "Alice should abort the login with expected error"
2206 );
2207 updates_task.await.expect("Alice should run through all progress states");
2208 bob_task.await.expect("Bob's task should finish");
2209 }
2210
2211 #[async_test]
2212 async fn test_grant_login_with_generated_qr_code_session_expired() {
2213 let server = MatrixMockServer::new().await;
2214 let rendezvous_server =
2215 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
2216 .await;
2217 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2218
2219 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2220 server
2221 .mock_upload_cross_signing_keys()
2222 .ok()
2223 .expect(1)
2224 .named("upload_xsigning_keys")
2225 .mount()
2226 .await;
2227 server
2228 .mock_upload_cross_signing_signatures()
2229 .ok()
2230 .expect(1)
2231 .named("upload_xsigning_signatures")
2232 .mount()
2233 .await;
2234
2235 let user_id = owned_user_id!("@alice:example.org");
2237 let device_id = owned_device_id!("ALICE_DEVICE");
2238 let alice = server
2239 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2240 .logged_in_with_oauth()
2241 .build()
2242 .await;
2243 alice
2244 .encryption()
2245 .bootstrap_cross_signing(None)
2246 .await
2247 .expect("Alice should be able to set up cross signing");
2248
2249 let oauth = alice.oauth();
2251 let grant = oauth
2252 .grant_login_with_qr_code()
2253 .device_creation_timeout(Duration::from_secs(2))
2254 .generate();
2255
2256 let mut updates = grant.subscribe_to_progress();
2258 let mut state = grant.state.get();
2259 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2260 let updates_task = spawn(async move {
2261 while let Some(update) = updates.next().await {
2262 match &update {
2263 GrantLoginProgress::Starting => {
2264 assert_matches!(state, GrantLoginProgress::Starting);
2265 }
2266 GrantLoginProgress::EstablishingSecureChannel(
2267 GeneratedQrProgress::QrReady(_),
2268 ) => {
2269 assert_matches!(state, GrantLoginProgress::Starting);
2270 }
2271 _ => {
2272 panic!("Alice should abort the process");
2273 }
2274 }
2275 state = update;
2276 }
2277 });
2278
2279 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2283 updates_task.await.expect("Alice should run through all progress states");
2284 }
2285
2286 #[async_test]
2287 async fn test_grant_login_with_scanned_qr_code_session_expired() {
2288 let server = MatrixMockServer::new().await;
2289 let rendezvous_server =
2290 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::from_secs(2))
2291 .await;
2292 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2293
2294 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2295 server
2296 .mock_upload_cross_signing_keys()
2297 .ok()
2298 .expect(1)
2299 .named("upload_xsigning_keys")
2300 .mount()
2301 .await;
2302 server
2303 .mock_upload_cross_signing_signatures()
2304 .ok()
2305 .expect(1)
2306 .named("upload_xsigning_signatures")
2307 .mount()
2308 .await;
2309
2310 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2313 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2314 .await
2315 .expect("Bob should be able to create a secure channel.");
2316 let qr_code_data = channel.qr_code_data().clone();
2317
2318 let user_id = owned_user_id!("@alice:example.org");
2320 let device_id = owned_device_id!("ALICE_DEVICE");
2321 let alice = server
2322 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2323 .logged_in_with_oauth()
2324 .build()
2325 .await;
2326 alice
2327 .encryption()
2328 .bootstrap_cross_signing(None)
2329 .await
2330 .expect("Alice should be able to set up cross signing");
2331
2332 let oauth = alice.oauth();
2334 let grant = oauth
2335 .grant_login_with_qr_code()
2336 .device_creation_timeout(Duration::from_secs(2))
2337 .scan(&qr_code_data);
2338
2339 let mut updates = grant.subscribe_to_progress();
2341 let mut state = grant.state.get();
2342 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2343 let updates_task = spawn(async move {
2344 while let Some(update) = updates.next().await {
2345 match &update {
2346 GrantLoginProgress::Starting => {
2347 assert_matches!(state, GrantLoginProgress::Starting);
2348 }
2349 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. }) => {
2350 assert_matches!(state, GrantLoginProgress::Starting);
2351 }
2352 _ => {
2353 panic!("Alice should abort the process");
2354 }
2355 }
2356 state = update;
2357 }
2358 });
2359
2360 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2364 updates_task.await.expect("Alice should run through all progress states");
2365 }
2366
2367 #[async_test]
2368 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_protocol() {
2369 let server = MatrixMockServer::new().await;
2370 let rendezvous_server = Arc::new(
2371 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2372 );
2373 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2374
2375 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2376 server
2377 .mock_upload_cross_signing_keys()
2378 .ok()
2379 .expect(1)
2380 .named("upload_xsigning_keys")
2381 .mount()
2382 .await;
2383 server
2384 .mock_upload_cross_signing_signatures()
2385 .ok()
2386 .expect(1)
2387 .named("upload_xsigning_signatures")
2388 .mount()
2389 .await;
2390
2391 let user_id = owned_user_id!("@alice:example.org");
2393 let device_id = owned_device_id!("ALICE_DEVICE");
2394 let alice = server
2395 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2396 .logged_in_with_oauth()
2397 .build()
2398 .await;
2399 alice
2400 .encryption()
2401 .bootstrap_cross_signing(None)
2402 .await
2403 .expect("Alice should be able to set up cross signing");
2404
2405 let oauth = alice.oauth();
2407 let grant = oauth
2408 .grant_login_with_qr_code()
2409 .device_creation_timeout(Duration::from_secs(2))
2410 .generate();
2411 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2412 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2413
2414 let mut updates = grant.subscribe_to_progress();
2416 let mut state = grant.state.get();
2417 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2418 let updates_task = spawn(async move {
2419 let mut qr_code_tx = Some(qr_code_tx);
2420 let mut checkcode_rx = Some(checkcode_rx);
2421
2422 while let Some(update) = updates.next().await {
2423 match &update {
2424 GrantLoginProgress::Starting => {
2425 assert_matches!(state, GrantLoginProgress::Starting);
2426 }
2427 GrantLoginProgress::EstablishingSecureChannel(
2428 GeneratedQrProgress::QrReady(qr_code_data),
2429 ) => {
2430 assert_matches!(state, GrantLoginProgress::Starting);
2431 qr_code_tx
2432 .take()
2433 .expect("The QR code should only be forwarded once")
2434 .send(qr_code_data.clone())
2435 .expect("Alice should be able to forward the QR code");
2436 }
2437 GrantLoginProgress::EstablishingSecureChannel(
2438 GeneratedQrProgress::QrScanned(checkcode_sender),
2439 ) => {
2440 assert_matches!(
2441 state,
2442 GrantLoginProgress::EstablishingSecureChannel(
2443 GeneratedQrProgress::QrReady(_)
2444 )
2445 );
2446 let checkcode = checkcode_rx
2447 .take()
2448 .expect("The checkcode should only be forwarded once")
2449 .await
2450 .expect("Alice should receive the checkcode");
2451 checkcode_sender
2452 .send(checkcode)
2453 .await
2454 .expect("Alice should be able to forward the checkcode");
2455 break;
2456 }
2457 _ => {
2458 panic!("Alice should abort the process");
2459 }
2460 }
2461 state = update;
2462 }
2463 });
2464
2465 let rendezvous_server_clone = rendezvous_server.clone();
2467 let bob_task = spawn(async move {
2468 request_login_with_scanned_qr_code(
2469 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2470 qr_code_rx,
2471 checkcode_tx,
2472 None,
2473 &rendezvous_server_clone,
2474 None,
2475 None,
2476 )
2477 .await;
2478 });
2479
2480 assert_matches!(
2482 grant.await,
2483 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2484 "Alice should abort the login with expected error"
2485 );
2486 updates_task.await.expect("Alice should run through all progress states");
2487 bob_task.await.expect("Bob's task should finish");
2488 }
2489
2490 #[async_test]
2491 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_protocol() {
2492 let server = MatrixMockServer::new().await;
2493 let rendezvous_server = Arc::new(
2494 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2495 );
2496 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2497
2498 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2499 server
2500 .mock_upload_cross_signing_keys()
2501 .ok()
2502 .expect(1)
2503 .named("upload_xsigning_keys")
2504 .mount()
2505 .await;
2506 server
2507 .mock_upload_cross_signing_signatures()
2508 .ok()
2509 .expect(1)
2510 .named("upload_xsigning_signatures")
2511 .mount()
2512 .await;
2513
2514 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2517 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2518 .await
2519 .expect("Bob should be able to create a secure channel.");
2520 let qr_code_data = channel.qr_code_data().clone();
2521
2522 let user_id = owned_user_id!("@alice:example.org");
2524 let device_id = owned_device_id!("ALICE_DEVICE");
2525 let alice = server
2526 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2527 .logged_in_with_oauth()
2528 .build()
2529 .await;
2530 alice
2531 .encryption()
2532 .bootstrap_cross_signing(None)
2533 .await
2534 .expect("Alice should be able to set up cross signing");
2535
2536 let oauth = alice.oauth();
2538 let grant = oauth
2539 .grant_login_with_qr_code()
2540 .device_creation_timeout(Duration::from_secs(2))
2541 .scan(&qr_code_data);
2542 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2543
2544 let mut updates = grant.subscribe_to_progress();
2546 let mut state = grant.state.get();
2547 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2548 let updates_task = spawn(async move {
2549 let mut checkcode_tx = Some(checkcode_tx);
2550
2551 while let Some(update) = updates.next().await {
2552 match &update {
2553 GrantLoginProgress::Starting => {
2554 assert_matches!(state, GrantLoginProgress::Starting);
2555 }
2556 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2557 assert_matches!(state, GrantLoginProgress::Starting);
2558 checkcode_tx
2559 .take()
2560 .expect("The checkcode should only be forwarded once")
2561 .send(*check_code)
2562 .expect("Alice should be able to forward the checkcode");
2563 break;
2564 }
2565 _ => {
2566 panic!("Alice should abort the process");
2567 }
2568 }
2569 state = update;
2570 }
2571 });
2572
2573 let rendezvous_server_clone = rendezvous_server.clone();
2574 let bob_task = spawn(async move {
2576 request_login_with_generated_qr_code(
2577 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
2578 channel,
2579 checkcode_rx,
2580 None,
2581 &rendezvous_server_clone,
2582 alice.homeserver(),
2583 None,
2584 None,
2585 )
2586 .await;
2587 });
2588
2589 assert_matches!(
2591 grant.await,
2592 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
2593 "Alice should abort the login with expected error"
2594 );
2595 updates_task.await.expect("Alice should run through all progress states");
2596 bob_task.await.expect("Bob's task should finish");
2597 }
2598
2599 #[async_test]
2600 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_success() {
2601 let server = MatrixMockServer::new().await;
2602 let rendezvous_server = Arc::new(
2603 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2604 );
2605 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2606
2607 let device_authorization_grant = AuthorizationGrant {
2608 verification_uri_complete: Some(VerificationUriComplete::new(
2609 "https://id.matrix.org/device/abcde".to_owned(),
2610 )),
2611 verification_uri: EndUserVerificationUrl::new(
2612 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2613 )
2614 .unwrap(),
2615 };
2616
2617 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2618 server
2619 .mock_upload_cross_signing_keys()
2620 .ok()
2621 .expect(1)
2622 .named("upload_xsigning_keys")
2623 .mount()
2624 .await;
2625 server
2626 .mock_upload_cross_signing_signatures()
2627 .ok()
2628 .expect(1)
2629 .named("upload_xsigning_signatures")
2630 .mount()
2631 .await;
2632
2633 let user_id = owned_user_id!("@alice:example.org");
2635 let device_id = owned_device_id!("ALICE_DEVICE");
2636 let alice = server
2637 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2638 .logged_in_with_oauth()
2639 .build()
2640 .await;
2641 alice
2642 .encryption()
2643 .bootstrap_cross_signing(None)
2644 .await
2645 .expect("Alice should be able to set up cross signing");
2646
2647 let oauth = alice.oauth();
2649 let grant = oauth
2650 .grant_login_with_qr_code()
2651 .device_creation_timeout(Duration::from_secs(2))
2652 .generate();
2653 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2654 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2655
2656 let mut updates = grant.subscribe_to_progress();
2658 let mut state = grant.state.get();
2659 let verification_uri_complete =
2660 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2661 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2662 let updates_task = spawn(async move {
2663 let mut qr_code_tx = Some(qr_code_tx);
2664 let mut checkcode_rx = Some(checkcode_rx);
2665
2666 while let Some(update) = updates.next().await {
2667 match &update {
2668 GrantLoginProgress::Starting => {
2669 assert_matches!(state, GrantLoginProgress::Starting);
2670 }
2671 GrantLoginProgress::EstablishingSecureChannel(
2672 GeneratedQrProgress::QrReady(qr_code_data),
2673 ) => {
2674 assert_matches!(state, GrantLoginProgress::Starting);
2675 qr_code_tx
2676 .take()
2677 .expect("The QR code should only be forwarded once")
2678 .send(qr_code_data.clone())
2679 .expect("Alice should be able to forward the QR code");
2680 }
2681 GrantLoginProgress::EstablishingSecureChannel(
2682 GeneratedQrProgress::QrScanned(checkcode_sender),
2683 ) => {
2684 assert_matches!(
2685 state,
2686 GrantLoginProgress::EstablishingSecureChannel(
2687 GeneratedQrProgress::QrReady(_)
2688 )
2689 );
2690 let checkcode = checkcode_rx
2691 .take()
2692 .expect("The checkcode should only be forwarded once")
2693 .await
2694 .expect("Alice should receive the checkcode");
2695 checkcode_sender
2696 .send(checkcode)
2697 .await
2698 .expect("Alice should be able to forward the checkcode");
2699 }
2700 GrantLoginProgress::WaitingForAuth {
2701 verification_uri,
2702 continuation_sender,
2703 } => {
2704 assert_matches!(
2705 state,
2706 GrantLoginProgress::EstablishingSecureChannel(
2707 GeneratedQrProgress::QrScanned(_)
2708 )
2709 );
2710 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2711 continuation_sender.confirm().await.expect("should be able to confirm");
2712 }
2713 _ => {
2714 panic!("Alice should abort the process");
2715 }
2716 }
2717 state = update;
2718 }
2719 });
2720
2721 let rendezvous_server_clone = rendezvous_server.clone();
2722 let bob_task = spawn(async move {
2724 request_login_with_scanned_qr_code(
2725 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2726 qr_code_rx,
2727 checkcode_tx,
2728 None,
2729 &rendezvous_server_clone,
2730 Some(device_authorization_grant),
2731 None,
2732 )
2733 .await;
2734 });
2735
2736 assert_matches!(
2738 grant.await,
2739 Err(QRCodeGrantLoginError::LoginFailure {
2740 reason: LoginFailureReason::AuthorizationExpired
2741 }),
2742 "Alice should abort the login with expected error"
2743 );
2744 updates_task.await.expect("Alice should run through all progress states");
2745 bob_task.await.expect("Bob's task should finish");
2746 }
2747
2748 #[async_test]
2749 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_success() {
2750 let server = MatrixMockServer::new().await;
2751 let rendezvous_server = Arc::new(
2752 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2753 );
2754 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2755
2756 let device_authorization_grant = AuthorizationGrant {
2757 verification_uri_complete: Some(VerificationUriComplete::new(
2758 "https://id.matrix.org/device/abcde".to_owned(),
2759 )),
2760 verification_uri: EndUserVerificationUrl::new(
2761 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2762 )
2763 .unwrap(),
2764 };
2765
2766 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2767 server
2768 .mock_upload_cross_signing_keys()
2769 .ok()
2770 .expect(1)
2771 .named("upload_xsigning_keys")
2772 .mount()
2773 .await;
2774 server
2775 .mock_upload_cross_signing_signatures()
2776 .ok()
2777 .expect(1)
2778 .named("upload_xsigning_signatures")
2779 .mount()
2780 .await;
2781
2782 let client = HttpClient::new(reqwest::Client::new(), Default::default());
2785 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
2786 .await
2787 .expect("Bob should be able to create a secure channel.");
2788 let qr_code_data = channel.qr_code_data().clone();
2789
2790 let user_id = owned_user_id!("@alice:example.org");
2792 let device_id = owned_device_id!("ALICE_DEVICE");
2793 let alice = server
2794 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2795 .logged_in_with_oauth()
2796 .build()
2797 .await;
2798 alice
2799 .encryption()
2800 .bootstrap_cross_signing(None)
2801 .await
2802 .expect("Alice should be able to set up cross signing");
2803
2804 let oauth = alice.oauth();
2806 let grant = oauth
2807 .grant_login_with_qr_code()
2808 .device_creation_timeout(Duration::from_secs(2))
2809 .scan(&qr_code_data);
2810 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2811
2812 let mut updates = grant.subscribe_to_progress();
2814 let mut state = grant.state.get();
2815 let verification_uri_complete =
2816 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2817 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2818 let updates_task = spawn(async move {
2819 let mut checkcode_tx = Some(checkcode_tx);
2820
2821 while let Some(update) = updates.next().await {
2822 match &update {
2823 GrantLoginProgress::Starting => {
2824 assert_matches!(state, GrantLoginProgress::Starting);
2825 }
2826 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2827 assert_matches!(state, GrantLoginProgress::Starting);
2828 checkcode_tx
2829 .take()
2830 .expect("The checkcode should only be forwarded once")
2831 .send(*check_code)
2832 .expect("Alice should be able to forward the checkcode");
2833 }
2834 GrantLoginProgress::WaitingForAuth {
2835 verification_uri,
2836 continuation_sender,
2837 } => {
2838 assert_matches!(
2839 state,
2840 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2841 );
2842 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2843 continuation_sender.confirm().await.expect("should be able to confirm");
2844 }
2845 _ => {
2846 panic!("Alice should abort the process");
2847 }
2848 }
2849 state = update;
2850 }
2851 });
2852
2853 let rendezvous_server_clone = rendezvous_server.clone();
2854 let bob_task = spawn(async move {
2856 request_login_with_generated_qr_code(
2857 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
2858 channel,
2859 checkcode_rx,
2860 None,
2861 &rendezvous_server_clone,
2862 alice.homeserver(),
2863 Some(device_authorization_grant),
2864 None,
2865 )
2866 .await;
2867 });
2868
2869 assert_matches!(
2871 grant.await,
2872 Err(QRCodeGrantLoginError::LoginFailure {
2873 reason: LoginFailureReason::AuthorizationExpired
2874 }),
2875 "Alice should abort the login with expected error"
2876 );
2877 updates_task.await.expect("Alice should run through all progress states");
2878 bob_task.await.expect("Bob's task should finish");
2879 }
2880
2881 #[async_test]
2882 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_success() {
2883 let server = MatrixMockServer::new().await;
2884 let rendezvous_server = Arc::new(
2885 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
2886 );
2887 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2888
2889 let device_authorization_grant = AuthorizationGrant {
2890 verification_uri_complete: Some(VerificationUriComplete::new(
2891 "https://id.matrix.org/device/abcde".to_owned(),
2892 )),
2893 verification_uri: EndUserVerificationUrl::new(
2894 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2895 )
2896 .unwrap(),
2897 };
2898
2899 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2900 server
2901 .mock_upload_cross_signing_keys()
2902 .ok()
2903 .expect(1)
2904 .named("upload_xsigning_keys")
2905 .mount()
2906 .await;
2907 server
2908 .mock_upload_cross_signing_signatures()
2909 .ok()
2910 .expect(1)
2911 .named("upload_xsigning_signatures")
2912 .mount()
2913 .await;
2914
2915 let user_id = owned_user_id!("@alice:example.org");
2917 let device_id = owned_device_id!("ALICE_DEVICE");
2918 let alice = server
2919 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2920 .logged_in_with_oauth()
2921 .build()
2922 .await;
2923 alice
2924 .encryption()
2925 .bootstrap_cross_signing(None)
2926 .await
2927 .expect("Alice should be able to set up cross signing");
2928
2929 let oauth = alice.oauth();
2931 let grant = oauth
2932 .grant_login_with_qr_code()
2933 .device_creation_timeout(Duration::from_secs(2))
2934 .generate();
2935 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2936 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2937
2938 let mut updates = grant.subscribe_to_progress();
2940 let mut state = grant.state.get();
2941 let verification_uri_complete =
2942 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2943 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2944 let updates_task = spawn(async move {
2945 let mut qr_code_tx = Some(qr_code_tx);
2946 let mut checkcode_rx = Some(checkcode_rx);
2947
2948 while let Some(update) = updates.next().await {
2949 match &update {
2950 GrantLoginProgress::Starting => {
2951 assert_matches!(state, GrantLoginProgress::Starting);
2952 }
2953 GrantLoginProgress::EstablishingSecureChannel(
2954 GeneratedQrProgress::QrReady(qr_code_data),
2955 ) => {
2956 assert_matches!(state, GrantLoginProgress::Starting);
2957 qr_code_tx
2958 .take()
2959 .expect("The QR code should only be forwarded once")
2960 .send(qr_code_data.clone())
2961 .expect("Alice should be able to forward the QR code");
2962 }
2963 GrantLoginProgress::EstablishingSecureChannel(
2964 GeneratedQrProgress::QrScanned(checkcode_sender),
2965 ) => {
2966 assert_matches!(
2967 state,
2968 GrantLoginProgress::EstablishingSecureChannel(
2969 GeneratedQrProgress::QrReady(_)
2970 )
2971 );
2972 let checkcode = checkcode_rx
2973 .take()
2974 .expect("The checkcode should only be forwarded once")
2975 .await
2976 .expect("Alice should receive the checkcode");
2977 checkcode_sender
2978 .send(checkcode)
2979 .await
2980 .expect("Alice should be able to forward the checkcode");
2981 }
2982 GrantLoginProgress::WaitingForAuth {
2983 verification_uri,
2984 continuation_sender,
2985 } => {
2986 assert_matches!(
2987 state,
2988 GrantLoginProgress::EstablishingSecureChannel(
2989 GeneratedQrProgress::QrScanned(_)
2990 )
2991 );
2992 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2993 continuation_sender.confirm().await.expect("should be able to confirm");
2994 }
2995 _ => {
2996 panic!("Alice should abort the process");
2997 }
2998 }
2999 state = update;
3000 }
3001 });
3002
3003 let rendezvous_server_clone = rendezvous_server.clone();
3005 let bob_task = spawn(async move {
3006 request_login_with_scanned_qr_code(
3007 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3008 qr_code_rx,
3009 checkcode_tx,
3010 None,
3011 &rendezvous_server_clone,
3012 Some(device_authorization_grant),
3013 None,
3014 )
3015 .await;
3016 });
3017
3018 assert_let!(
3020 Err(QRCodeGrantLoginError::UnexpectedMessage {
3021 expected: "m.login.success",
3022 received,
3023 }) = grant.await,
3024 "Alice should abort the login with expected error variant"
3025 );
3026 assert_matches!(
3027 *received,
3028 QrAuthMessage::LoginProtocolAccepted,
3029 "Alice should abort the login with expected error message"
3030 );
3031 updates_task.await.expect("Alice should run through all progress states");
3032 bob_task.await.expect("Bob's task should finish");
3033 }
3034
3035 #[async_test]
3036 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_success() {
3037 let server = MatrixMockServer::new().await;
3038 let rendezvous_server = Arc::new(
3039 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
3040 );
3041 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3042
3043 let device_authorization_grant = AuthorizationGrant {
3044 verification_uri_complete: Some(VerificationUriComplete::new(
3045 "https://id.matrix.org/device/abcde".to_owned(),
3046 )),
3047 verification_uri: EndUserVerificationUrl::new(
3048 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3049 )
3050 .unwrap(),
3051 };
3052
3053 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3054 server
3055 .mock_upload_cross_signing_keys()
3056 .ok()
3057 .expect(1)
3058 .named("upload_xsigning_keys")
3059 .mount()
3060 .await;
3061 server
3062 .mock_upload_cross_signing_signatures()
3063 .ok()
3064 .expect(1)
3065 .named("upload_xsigning_signatures")
3066 .mount()
3067 .await;
3068
3069 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3072 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3073 .await
3074 .expect("Bob should be able to create a secure channel.");
3075 let qr_code_data = channel.qr_code_data().clone();
3076
3077 let user_id = owned_user_id!("@alice:example.org");
3079 let device_id = owned_device_id!("ALICE_DEVICE");
3080 let alice = server
3081 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3082 .logged_in_with_oauth()
3083 .build()
3084 .await;
3085 alice
3086 .encryption()
3087 .bootstrap_cross_signing(None)
3088 .await
3089 .expect("Alice should be able to set up cross signing");
3090
3091 let oauth = alice.oauth();
3093 let grant = oauth
3094 .grant_login_with_qr_code()
3095 .device_creation_timeout(Duration::from_secs(2))
3096 .scan(&qr_code_data);
3097 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3098
3099 let mut updates = grant.subscribe_to_progress();
3101 let mut state = grant.state.get();
3102 let verification_uri_complete =
3103 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3104 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3105 let updates_task = spawn(async move {
3106 let mut checkcode_tx = Some(checkcode_tx);
3107
3108 while let Some(update) = updates.next().await {
3109 match &update {
3110 GrantLoginProgress::Starting => {
3111 assert_matches!(state, GrantLoginProgress::Starting);
3112 }
3113 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3114 assert_matches!(state, GrantLoginProgress::Starting);
3115 checkcode_tx
3116 .take()
3117 .expect("The checkcode should only be forwarded once")
3118 .send(*check_code)
3119 .expect("Alice should be able to forward the checkcode");
3120 }
3121 GrantLoginProgress::WaitingForAuth {
3122 verification_uri,
3123 continuation_sender,
3124 } => {
3125 assert_matches!(
3126 state,
3127 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3128 );
3129 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3130 continuation_sender.confirm().await.expect("should be able to confirm");
3131 }
3132 _ => {
3133 panic!("Alice should abort the process");
3134 }
3135 }
3136 state = update;
3137 }
3138 });
3139
3140 let rendezvous_server_clone = rendezvous_server.clone();
3141 let bob_task = spawn(async move {
3143 request_login_with_generated_qr_code(
3144 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3145 channel,
3146 checkcode_rx,
3147 None,
3148 &rendezvous_server_clone,
3149 alice.homeserver(),
3150 Some(device_authorization_grant),
3151 None,
3152 )
3153 .await;
3154 });
3155
3156 assert_let!(
3158 Err(QRCodeGrantLoginError::UnexpectedMessage {
3159 expected: "m.login.success",
3160 received,
3161 }) = grant.await,
3162 "Alice should abort the login with expected error variant"
3163 );
3164 assert_matches!(
3165 *received,
3166 QrAuthMessage::LoginProtocolAccepted,
3167 "Alice should abort the login with expected error message"
3168 );
3169 updates_task.await.expect("Alice should run through all progress states");
3170 bob_task.await.expect("Bob's task should finish");
3171 }
3172
3173 #[async_test]
3174 async fn test_grant_login_with_generated_qr_code_secure_channel_error() {
3175 let server = MatrixMockServer::new().await;
3176 let rendezvous_server = Arc::new(
3177 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
3178 );
3179 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3180
3181 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3182 server
3183 .mock_upload_cross_signing_keys()
3184 .ok()
3185 .expect(1)
3186 .named("upload_xsigning_keys")
3187 .mount()
3188 .await;
3189 server
3190 .mock_upload_cross_signing_signatures()
3191 .ok()
3192 .expect(1)
3193 .named("upload_xsigning_signatures")
3194 .mount()
3195 .await;
3196
3197 let user_id = owned_user_id!("@alice:example.org");
3199 let device_id = owned_device_id!("ALICE_DEVICE");
3200 let alice = server
3201 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3202 .logged_in_with_oauth()
3203 .build()
3204 .await;
3205 alice
3206 .encryption()
3207 .bootstrap_cross_signing(None)
3208 .await
3209 .expect("Alice should be able to set up cross signing");
3210
3211 let oauth = alice.oauth();
3213 let grant = oauth
3214 .grant_login_with_qr_code()
3215 .device_creation_timeout(Duration::from_secs(2))
3216 .generate();
3217 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3218 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3219
3220 let mut updates = grant.subscribe_to_progress();
3222 let mut state = grant.state.get();
3223 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3224 let updates_task = spawn(async move {
3225 let mut qr_code_tx = Some(qr_code_tx);
3226 let mut checkcode_rx = Some(checkcode_rx);
3227
3228 while let Some(update) = updates.next().await {
3229 match &update {
3230 GrantLoginProgress::Starting => {
3231 assert_matches!(state, GrantLoginProgress::Starting);
3232 }
3233 GrantLoginProgress::EstablishingSecureChannel(
3234 GeneratedQrProgress::QrReady(qr_code_data),
3235 ) => {
3236 assert_matches!(state, GrantLoginProgress::Starting);
3237 qr_code_tx
3238 .take()
3239 .expect("The QR code should only be forwarded once")
3240 .send(qr_code_data.clone())
3241 .expect("Alice should be able to forward the QR code");
3242 }
3243 GrantLoginProgress::EstablishingSecureChannel(
3244 GeneratedQrProgress::QrScanned(checkcode_sender),
3245 ) => {
3246 assert_matches!(
3247 state,
3248 GrantLoginProgress::EstablishingSecureChannel(
3249 GeneratedQrProgress::QrReady(_)
3250 )
3251 );
3252 let checkcode = checkcode_rx
3253 .take()
3254 .expect("The checkcode should only be forwarded once")
3255 .await
3256 .expect("Alice should receive the checkcode");
3257 checkcode_sender
3258 .send(checkcode)
3259 .await
3260 .expect("Alice should be able to forward the checkcode");
3261 break;
3262 }
3263 _ => {
3264 panic!("Alice should abort the process");
3265 }
3266 }
3267 state = update;
3268 }
3269 });
3270
3271 let rendezvous_server_clone = rendezvous_server.clone();
3273 let bob_task = spawn(async move {
3274 request_login_with_scanned_qr_code(
3275 BobBehaviour::InvalidJsonMessage,
3276 qr_code_rx,
3277 checkcode_tx,
3278 None,
3279 &rendezvous_server_clone,
3280 None,
3281 None,
3282 )
3283 .await;
3284 });
3285
3286 assert_matches!(
3288 grant.await,
3289 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
3290 MessageDecodeError::Json(_)
3291 ))),
3292 "Alice should abort the login with a SecureChannel error"
3293 );
3294 updates_task.await.expect("Alice should run through all progress states");
3295 bob_task.await.expect("Bob's task should finish");
3296 }
3297
3298 #[async_test]
3299 async fn test_grant_login_with_scanned_qr_code_secure_channel_error() {
3300 let server = MatrixMockServer::new().await;
3301 let rendezvous_server = Arc::new(
3302 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await,
3303 );
3304 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3305
3306 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3307 server
3308 .mock_upload_cross_signing_keys()
3309 .ok()
3310 .expect(1)
3311 .named("upload_xsigning_keys")
3312 .mount()
3313 .await;
3314 server
3315 .mock_upload_cross_signing_signatures()
3316 .ok()
3317 .expect(1)
3318 .named("upload_xsigning_signatures")
3319 .mount()
3320 .await;
3321
3322 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3325 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3326 .await
3327 .expect("Bob should be able to create a secure channel.");
3328 let qr_code_data = channel.qr_code_data().clone();
3329
3330 let user_id = owned_user_id!("@alice:example.org");
3332 let device_id = owned_device_id!("ALICE_DEVICE");
3333 let alice = server
3334 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3335 .logged_in_with_oauth()
3336 .build()
3337 .await;
3338 alice
3339 .encryption()
3340 .bootstrap_cross_signing(None)
3341 .await
3342 .expect("Alice should be able to set up cross signing");
3343
3344 let oauth = alice.oauth();
3346 let grant = oauth
3347 .grant_login_with_qr_code()
3348 .device_creation_timeout(Duration::from_secs(2))
3349 .scan(&qr_code_data);
3350 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3351
3352 let mut updates = grant.subscribe_to_progress();
3354 let mut state = grant.state.get();
3355 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3356 let updates_task = spawn(async move {
3357 let mut checkcode_tx = Some(checkcode_tx);
3358
3359 while let Some(update) = updates.next().await {
3360 match &update {
3361 GrantLoginProgress::Starting => {
3362 assert_matches!(state, GrantLoginProgress::Starting);
3363 }
3364 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3365 assert_matches!(state, GrantLoginProgress::Starting);
3366 checkcode_tx
3367 .take()
3368 .expect("The checkcode should only be forwarded once")
3369 .send(*check_code)
3370 .expect("Alice should be able to forward the checkcode");
3371 break;
3372 }
3373 _ => {
3374 panic!("Alice should abort the process");
3375 }
3376 }
3377 state = update;
3378 }
3379 });
3380
3381 let rendezvous_server_clone = rendezvous_server.clone();
3382 let bob_task = spawn(async move {
3384 request_login_with_generated_qr_code(
3385 BobBehaviour::InvalidJsonMessage,
3386 channel,
3387 checkcode_rx,
3388 None,
3389 &rendezvous_server_clone,
3390 alice.homeserver(),
3391 None,
3392 None,
3393 )
3394 .await;
3395 });
3396
3397 assert_matches!(
3399 grant.await,
3400 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
3401 MessageDecodeError::Json(_)
3402 ))),
3403 "Alice should abort the login with a SecureChannel error"
3404 );
3405 updates_task.await.expect("Alice should run through all progress states");
3406 bob_task.await.expect("Bob's task should finish");
3407 }
3408
3409 #[async_test]
3410 async fn test_grant_login_with_generated_qr_code_cancelled_while_waiting_for_auth() {
3411 let server = MatrixMockServer::new().await;
3412 let rendezvous_server =
3413 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
3414 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3415
3416 let device_authorization_grant = AuthorizationGrant {
3417 verification_uri_complete: Some(VerificationUriComplete::new(
3418 "https://id.matrix.org/device/abcde".to_owned(),
3419 )),
3420 verification_uri: EndUserVerificationUrl::new(
3421 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3422 )
3423 .unwrap(),
3424 };
3425
3426 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3427 server
3428 .mock_upload_cross_signing_keys()
3429 .ok()
3430 .expect(1)
3431 .named("upload_xsigning_keys")
3432 .mount()
3433 .await;
3434 server
3435 .mock_upload_cross_signing_signatures()
3436 .ok()
3437 .expect(1)
3438 .named("upload_xsigning_signatures")
3439 .mount()
3440 .await;
3441
3442 let user_id = owned_user_id!("@alice:example.org");
3444 let device_id = owned_device_id!("ALICE_DEVICE");
3445 let alice = server
3446 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3447 .logged_in_with_oauth()
3448 .build()
3449 .await;
3450 alice
3451 .encryption()
3452 .bootstrap_cross_signing(None)
3453 .await
3454 .expect("Alice should be able to set up cross signing");
3455
3456 let oauth = alice.oauth();
3458 let grant = oauth
3459 .grant_login_with_qr_code()
3460 .device_creation_timeout(Duration::from_secs(2))
3461 .generate();
3462 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3463 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3464
3465 let mut updates = grant.subscribe_to_progress();
3467 let mut state = grant.state.get();
3468 let verification_uri_complete =
3469 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3470 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3471 let updates_task = spawn(async move {
3472 let mut qr_code_tx = Some(qr_code_tx);
3473 let mut checkcode_rx = Some(checkcode_rx);
3474
3475 while let Some(update) = updates.next().await {
3476 match &update {
3477 GrantLoginProgress::Starting => {
3478 assert_matches!(state, GrantLoginProgress::Starting);
3479 }
3480 GrantLoginProgress::EstablishingSecureChannel(
3481 GeneratedQrProgress::QrReady(qr_code_data),
3482 ) => {
3483 assert_matches!(state, GrantLoginProgress::Starting);
3484 qr_code_tx
3485 .take()
3486 .expect("The QR code should only be forwarded once")
3487 .send(qr_code_data.clone())
3488 .expect("Alice should be able to forward the QR code");
3489 }
3490 GrantLoginProgress::EstablishingSecureChannel(
3491 GeneratedQrProgress::QrScanned(checkcode_sender),
3492 ) => {
3493 assert_matches!(
3494 state,
3495 GrantLoginProgress::EstablishingSecureChannel(
3496 GeneratedQrProgress::QrReady(_)
3497 )
3498 );
3499 let checkcode = checkcode_rx
3500 .take()
3501 .expect("The checkcode should only be forwarded once")
3502 .await
3503 .expect("Alice should receive the checkcode");
3504 checkcode_sender
3505 .send(checkcode)
3506 .await
3507 .expect("Alice should be able to forward the checkcode");
3508 }
3509 GrantLoginProgress::WaitingForAuth {
3510 verification_uri,
3511 continuation_sender,
3512 } => {
3513 assert_matches!(
3514 state,
3515 GrantLoginProgress::EstablishingSecureChannel(
3516 GeneratedQrProgress::QrScanned(_)
3517 )
3518 );
3519 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3520 continuation_sender.cancel().await.expect("should be able to cancel");
3522 break;
3523 }
3524 _ => {
3525 panic!("Alice should abort the process after being cancelled");
3526 }
3527 }
3528 state = update;
3529 }
3530 });
3531
3532 let bob_task = spawn(async move {
3534 request_login_with_scanned_qr_code(
3535 BobBehaviour::CancelledWhileWaitingForAuth,
3536 qr_code_rx,
3537 checkcode_tx,
3538 Some(server),
3539 &rendezvous_server,
3540 Some(device_authorization_grant),
3541 None,
3542 )
3543 .await;
3544 });
3545
3546 assert_matches!(
3548 grant.await,
3549 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3550 "Alice should abort the login with expected error"
3551 );
3552 updates_task.await.expect("Alice should run through all progress states");
3553 bob_task.await.expect("Bob's task should finish");
3554 }
3555
3556 #[async_test]
3557 async fn test_grant_login_with_scanned_qr_code_cancelled_while_waiting_for_auth() {
3558 let server = MatrixMockServer::new().await;
3559 let rendezvous_server =
3560 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX).await;
3561 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3562
3563 let device_authorization_grant = AuthorizationGrant {
3564 verification_uri_complete: Some(VerificationUriComplete::new(
3565 "https://id.matrix.org/device/abcde".to_owned(),
3566 )),
3567 verification_uri: EndUserVerificationUrl::new(
3568 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3569 )
3570 .unwrap(),
3571 };
3572
3573 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3574 server
3575 .mock_upload_cross_signing_keys()
3576 .ok()
3577 .expect(1)
3578 .named("upload_xsigning_keys")
3579 .mount()
3580 .await;
3581 server
3582 .mock_upload_cross_signing_signatures()
3583 .ok()
3584 .expect(1)
3585 .named("upload_xsigning_signatures")
3586 .mount()
3587 .await;
3588
3589 let client = HttpClient::new(reqwest::Client::new(), Default::default());
3592 let channel = SecureChannel::login(client, &rendezvous_server.homeserver_url)
3593 .await
3594 .expect("Bob should be able to create a secure channel.");
3595 let qr_code_data = channel.qr_code_data().clone();
3596
3597 let user_id = owned_user_id!("@alice:example.org");
3599 let device_id = owned_device_id!("ALICE_DEVICE");
3600 let alice = server
3601 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3602 .logged_in_with_oauth()
3603 .build()
3604 .await;
3605 alice
3606 .encryption()
3607 .bootstrap_cross_signing(None)
3608 .await
3609 .expect("Alice should be able to set up cross signing");
3610
3611 let oauth = alice.oauth();
3613 let grant = oauth
3614 .grant_login_with_qr_code()
3615 .device_creation_timeout(Duration::from_secs(2))
3616 .scan(&qr_code_data);
3617 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3618
3619 let mut updates = grant.subscribe_to_progress();
3621 let mut state = grant.state.get();
3622 let verification_uri_complete =
3623 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3624 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3625 let updates_task = spawn(async move {
3626 let mut checkcode_tx = Some(checkcode_tx);
3627
3628 while let Some(update) = updates.next().await {
3629 match &update {
3630 GrantLoginProgress::Starting => {
3631 assert_matches!(state, GrantLoginProgress::Starting);
3632 }
3633 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3634 assert_matches!(state, GrantLoginProgress::Starting);
3635 checkcode_tx
3636 .take()
3637 .expect("The checkcode should only be forwarded once")
3638 .send(*check_code)
3639 .expect("Alice should be able to forward the checkcode");
3640 }
3641 GrantLoginProgress::WaitingForAuth {
3642 verification_uri,
3643 continuation_sender,
3644 } => {
3645 assert_matches!(
3646 state,
3647 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3648 );
3649 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3650 continuation_sender.cancel().await.expect("should be able to cancel");
3652 break;
3653 }
3654 _ => {
3655 panic!("Alice should abort the process after being cancelled");
3656 }
3657 }
3658 state = update;
3659 }
3660 });
3661
3662 let bob_task = spawn(async move {
3664 request_login_with_generated_qr_code(
3665 BobBehaviour::CancelledWhileWaitingForAuth,
3666 channel,
3667 checkcode_rx,
3668 Some(server),
3669 &rendezvous_server,
3670 alice.homeserver(),
3671 Some(device_authorization_grant),
3672 None,
3673 )
3674 .await;
3675 });
3676
3677 assert_matches!(
3679 grant.await,
3680 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3681 "Alice should abort the login with expected error"
3682 );
3683 updates_task.await.expect("Alice should run through all progress states");
3684 bob_task.await.expect("Bob's task should finish");
3685 }
3686}