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 LoginProtocolData, 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, messages::LoginProtocolsMessage, secure_channel::ChannelVariant,
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 (protocol, device_id) = match channel.receive_json().await? {
74 QrAuthMessage::LoginProtocol { protocol, device_id } => (protocol, device_id),
75 QrAuthMessage::LoginFailure { reason, .. } => {
76 return Err(QRCodeGrantLoginError::LoginFailure { reason });
77 }
78 message => {
79 return Err(QRCodeGrantLoginError::UnexpectedMessage {
80 expected: "m.login.protocol",
81 received: Box::new(message),
82 });
83 }
84 };
85
86 let device_authorization_grant = match channel.channel_variant() {
91 ChannelVariant::Msc4108 => match protocol {
92 LoginProtocolData::Msc4108DeviceAuthorizationGrant(device_authorization_grant) => {
93 Ok(device_authorization_grant)
94 }
95 protocol => Err(protocol),
96 },
97 #[cfg(feature = "unstable-msc4388")]
98 ChannelVariant::Msc4388 => match protocol {
99 LoginProtocolData::Msc4388DeviceAuthorizationGrant(device_authorization_grant) => {
100 Ok(device_authorization_grant)
101 }
102 protocol => Err(protocol),
103 },
104 };
105
106 let device_authorization_grant = match device_authorization_grant {
107 Ok(device_authorization_grant) => device_authorization_grant,
108 Err(
111 protocol @ (LoginProtocolData::Msc4108DeviceAuthorizationGrant(_)
112 | LoginProtocolData::Msc4388DeviceAuthorizationGrant(_)),
113 ) => {
114 channel
115 .send_json(QrAuthMessage::LoginFailure {
116 reason: LoginFailureReason::UnexpectedMessageReceived,
117 homeserver: None,
118 })
119 .await?;
120 return Err(QRCodeGrantLoginError::UnexpectedMessage {
121 expected: "m.login.protocol",
122 received: Box::new(QrAuthMessage::LoginProtocol { protocol, device_id }),
123 });
124 }
125 Err(protocol) => {
126 channel
127 .send_json(QrAuthMessage::LoginFailure {
128 reason: LoginFailureReason::UnsupportedProtocol,
129 homeserver: None,
130 })
131 .await?;
132 return Err(QRCodeGrantLoginError::UnsupportedProtocol(protocol.protocol()));
133 }
134 };
135
136 if !matches!(client.device_exists(device_id.clone().into()).await, Ok(false)) {
140 channel
141 .send_json(QrAuthMessage::LoginFailure {
142 reason: LoginFailureReason::DeviceAlreadyExists,
143 homeserver: None,
144 })
145 .await?;
146 return Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse);
147 }
148
149 let verification_uri = Url::parse(
154 device_authorization_grant
155 .verification_uri_complete
156 .map(VerificationUriComplete::into_secret)
157 .unwrap_or(device_authorization_grant.verification_uri.to_string())
158 .as_str(),
159 )
160 .map_err(|e| QRCodeGrantLoginError::Unknown(e.to_string()))?;
161
162 let message = QrAuthMessage::LoginProtocolAccepted;
167 channel.send_json(&message).await?;
168
169 let (sender, receiver) = tokio::sync::oneshot::channel();
170 state.set(GrantLoginProgress::WaitingForAuth {
171 verification_uri,
172 continuation_sender: ContinuationMessageSender(CloneableSender::new(sender)),
173 });
174
175 match receiver.await {
178 Ok(ContinuationMessage::Confirm) => {}
179 Ok(ContinuationMessage::Cancel) | Err(_) => {
180 channel
181 .send_json(QrAuthMessage::LoginFailure {
182 reason: LoginFailureReason::UserCancelled,
183 homeserver: None,
184 })
185 .await?;
186 return Err(QRCodeGrantLoginError::LoginFailure {
187 reason: LoginFailureReason::UserCancelled,
188 });
189 }
190 }
191
192 match channel.receive_json().await? {
202 QrAuthMessage::LoginSuccess => (),
203 QrAuthMessage::LoginFailure { reason, .. } => {
204 return Err(QRCodeGrantLoginError::LoginFailure { reason });
205 }
206 message => {
207 return Err(QRCodeGrantLoginError::UnexpectedMessage {
208 expected: "m.login.success",
209 received: Box::new(message),
210 });
211 }
212 }
213
214 let deadline = Instant::now() + device_creation_timeout;
219
220 loop {
221 if matches!(client.device_exists(device_id.clone().into()).await, Ok(true)) {
222 break;
223 } else {
224 if Instant::now() < deadline {
227 matrix_sdk_common::sleep::sleep(Duration::from_millis(500)).await;
228 continue;
229 } else {
230 channel
232 .send_json(QrAuthMessage::LoginFailure {
233 reason: LoginFailureReason::DeviceNotFound,
234 homeserver: None,
235 })
236 .await?;
237 return Err(QRCodeGrantLoginError::DeviceNotFound);
238 }
239 }
240 }
241
242 state.set(GrantLoginProgress::SyncingSecrets);
246 let message = QrAuthMessage::LoginSecrets(secrets_bundle.clone());
247 channel.send_json(&message).await?;
248
249 state.set(GrantLoginProgress::Done);
251
252 Ok(())
253}
254
255#[derive(Clone, Debug, Default)]
257pub enum GrantLoginProgress<Q> {
258 #[default]
260 Starting,
261 EstablishingSecureChannel(Q),
264 WaitingForAuth {
267 verification_uri: Url,
269 continuation_sender: ContinuationMessageSender,
277 },
278 SyncingSecrets,
281 Done,
283}
284
285#[derive(Debug)]
288pub struct GrantLoginWithScannedQrCode {
289 client: Client,
290 qr_code_data: QrCodeData,
291 device_creation_timeout: Duration,
292 state: SharedObservable<GrantLoginProgress<QrProgress>>,
293}
294
295impl GrantLoginWithScannedQrCode {
296 pub(crate) fn new(
297 client: &Client,
298 qr_code_data: &QrCodeData,
299 device_creation_timeout: Duration,
300 ) -> GrantLoginWithScannedQrCode {
301 GrantLoginWithScannedQrCode {
302 client: client.clone(),
303 qr_code_data: qr_code_data.clone(),
304 device_creation_timeout,
305 state: Default::default(),
306 }
307 }
308}
309
310impl GrantLoginWithScannedQrCode {
311 pub fn subscribe_to_progress(
317 &self,
318 ) -> impl Stream<Item = GrantLoginProgress<QrProgress>> + use<> {
319 self.state.subscribe()
320 }
321}
322
323impl IntoFuture for GrantLoginWithScannedQrCode {
324 type Output = Result<(), QRCodeGrantLoginError>;
325 boxed_into_future!();
326
327 fn into_future(self) -> Self::IntoFuture {
328 Box::pin(async move {
329 let secrets_bundle = export_secrets_bundle(&self.client).await?;
341
342 let mut channel = EstablishedSecureChannel::from_qr_code(
343 self.client.inner.http_client.inner.clone(),
344 &self.qr_code_data,
345 QrCodeIntent::Reciprocate,
346 )
347 .await?;
348
349 let check_code = channel.check_code().to_owned();
354 self.state
355 .set(GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
356
357 let message = match channel.channel_variant() {
368 ChannelVariant::Msc4108 => {
369 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
370 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
371 homeserver: self.client.homeserver(),
372 })
373 }
374 #[cfg(feature = "unstable-msc4388")]
375 ChannelVariant::Msc4388 => {
376 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
377 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
378 base_url: self.client.homeserver(),
379 })
380 }
381 };
382 channel.send_json(message).await?;
383
384 finish_login_grant(
388 &self.client,
389 &mut channel,
390 self.device_creation_timeout,
391 &secrets_bundle,
392 &self.state,
393 )
394 .await
395 })
396 }
397}
398
399#[derive(Debug)]
402pub struct GrantLoginWithGeneratedQrCode {
403 client: Client,
404 device_creation_timeout: Duration,
405 state: SharedObservable<GrantLoginProgress<GeneratedQrProgress>>,
406 msc_4388_support: bool,
407}
408
409impl GrantLoginWithGeneratedQrCode {
410 pub(crate) fn new(
411 client: &Client,
412 device_creation_timeout: Duration,
413 ) -> GrantLoginWithGeneratedQrCode {
414 GrantLoginWithGeneratedQrCode {
415 client: client.clone(),
416 device_creation_timeout,
417 state: Default::default(),
418 msc_4388_support: false,
419 }
420 }
421}
422
423impl GrantLoginWithGeneratedQrCode {
424 pub fn subscribe_to_progress(
431 &self,
432 ) -> impl Stream<Item = GrantLoginProgress<GeneratedQrProgress>> + use<> {
433 self.state.subscribe()
434 }
435
436 #[cfg(feature = "unstable-msc4388")]
440 pub fn with_msc4388_support(&mut self) -> &mut Self {
441 self.msc_4388_support = true;
442 self
443 }
444}
445
446impl IntoFuture for GrantLoginWithGeneratedQrCode {
447 type Output = Result<(), QRCodeGrantLoginError>;
448 boxed_into_future!();
449
450 fn into_future(self) -> Self::IntoFuture {
451 Box::pin(async move {
452 let secrets_bundle = export_secrets_bundle(&self.client).await?;
457 let channel = SecureChannel::reciprocate(&self.client, self.msc_4388_support).await?;
458
459 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
464 GeneratedQrProgress::QrReady(channel.qr_code_data().clone()),
465 ));
466
467 let channel = channel.connect().await?;
473
474 let (tx, rx) = tokio::sync::oneshot::channel();
481 self.state.set(GrantLoginProgress::EstablishingSecureChannel(
482 GeneratedQrProgress::QrScanned(CheckCodeSender::new(tx)),
483 ));
484 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
485
486 let mut channel = channel.confirm(check_code)?;
491
492 match channel.channel_variant() {
501 ChannelVariant::Msc4108 => {}
502 #[cfg(feature = "unstable-msc4388")]
503 ChannelVariant::Msc4388 => {
504 let message = QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
505 protocols: vec![LoginProtocolType::DeviceAuthorizationGrant],
506 base_url: self.client.homeserver(),
507 });
508 channel.send_json(message).await?;
509 }
510 }
511
512 finish_login_grant(
516 &self.client,
517 &mut channel,
518 self.device_creation_timeout,
519 &secrets_bundle,
520 &self.state,
521 )
522 .await
523 })
524 }
525}
526
527#[cfg(all(test, not(target_family = "wasm")))]
528mod test {
529 use std::{assert_matches, sync::Arc};
530
531 use futures_util::StreamExt;
532 use matrix_sdk_base::{
533 CancellableIntoFutureExt,
534 crypto::types::{SecretsBundle, qr_login::QrCodeIntentData},
535 };
536 use matrix_sdk_common::executor::spawn;
537 use matrix_sdk_test::async_test;
538 use oauth2::{EndUserVerificationUrl, VerificationUriComplete};
539 use ruma::{owned_device_id, owned_user_id};
540 use strass::assert_let;
541 use tokio::sync::oneshot;
542 use tracing::debug;
543
544 use super::*;
545 use crate::{
546 authentication::oauth::qrcode::{
547 LoginFailureReason, MessageDecodeError, QrAuthMessage,
548 messages::AuthorizationGrant,
549 secure_channel::{EstablishedSecureChannel, test::MockedRendezvousServer},
550 },
551 test_utils::mocks::MatrixMockServer,
552 };
553
554 enum BobBehaviour {
555 HappyPath,
556 UnexpectedMessageInsteadOfLoginProtocol,
557 LoginFailureInsteadOfLoginProtocol,
558 UnexpectedMessageInsteadOfLoginSuccess,
559 LoginFailureInsteadOfLoginSuccess,
560 DeviceAlreadyExists,
561 DeviceNotCreated,
562 InvalidJsonMessage,
563 CancelledWhileWaitingForAuth(oneshot::Sender<()>),
566 UnsupportedProtocol,
567 UnsupportedProtocolWithDeviceAuthorizationGrant,
568 MissingDeviceAuthorizationGrant,
569 MismatchedDeviceAuthorizationGrantLayout,
570 }
571
572 #[allow(clippy::too_many_arguments)]
573 async fn request_login_with_scanned_qr_code(
574 behaviour: BobBehaviour,
575 qr_code_rx: oneshot::Receiver<QrCodeData>,
576 check_code_tx: oneshot::Sender<u8>,
577 server: Option<MatrixMockServer>,
578 _rendezvous_server: &MockedRendezvousServer,
582 device_authorization_grant: Option<AuthorizationGrant>,
583 secrets_bundle: Option<SecretsBundle>,
584 ) {
585 let qr_code_data = qr_code_rx.await.expect("Bob should receive the QR code");
587
588 let mut bob = EstablishedSecureChannel::from_qr_code(
591 reqwest::Client::new(),
592 &qr_code_data,
593 QrCodeIntent::Login,
594 )
595 .await
596 .expect("Bob should be able to connect the secure channel");
597
598 check_code_tx.send(bob.check_code()).expect("Bob should be able to send the checkcode");
600
601 if let QrCodeIntentData::Msc4388 { base_url: qr_base_url, .. } = qr_code_data.intent_data()
604 {
605 let message = bob
606 .receive_json()
607 .await
608 .expect("Bob should receive the LoginProtocols message from Alice");
609
610 assert_let!(
611 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
612 protocols,
613 base_url,
614 }) = message
615 );
616
617 assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
618 assert_eq!(&base_url, qr_base_url.as_url());
619 }
620
621 match behaviour {
622 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
623 let message = QrAuthMessage::LoginSuccess;
625 bob.send_json(message).await.unwrap();
626 return;
627 }
628 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
629 let message = QrAuthMessage::LoginFailure {
631 reason: LoginFailureReason::UserCancelled,
632 homeserver: None,
633 };
634 bob.send_json(message).await.unwrap();
635 return;
636 }
637 BobBehaviour::InvalidJsonMessage => {
638 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
641 return;
642 }
643 BobBehaviour::DeviceAlreadyExists => {
644 server
647 .as_ref()
648 .expect("Bob needs the server for DeviceAlreadyExists")
649 .mock_get_device()
650 .ok()
651 .expect(1..)
652 .named("get_device")
653 .mount()
654 .await;
655
656 let message = QrAuthMessage::LoginProtocol {
658 protocol: LoginProtocolData::device_authorization_grant(
659 device_authorization_grant
660 .expect("Bob needs the device authorization grant"),
661 bob.channel_variant(),
662 ),
663 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
664 };
665 bob.send_json(message).await.unwrap();
666
667 let message = bob
669 .receive_json()
670 .await
671 .expect("Bob should receive the LoginFailure message from Alice");
672 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
673 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
674
675 return; }
677 BobBehaviour::UnsupportedProtocol => {
678 bob.send_json(serde_json::json!({
680 "type": "m.login.protocol",
681 "protocol": "m.unknown_protocol",
682 "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
683 }))
684 .await
685 .unwrap();
686
687 let message = bob
689 .receive_json()
690 .await
691 .expect("Bob should receive the LoginFailure message from Alice");
692 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
693 assert_matches!(reason, LoginFailureReason::UnsupportedProtocol);
694
695 return; }
697 BobBehaviour::UnsupportedProtocolWithDeviceAuthorizationGrant => {
698 bob.send_json(serde_json::json!({
701 "type": "m.login.protocol",
702 "protocol": "m.unknown_protocol",
703 "device_authorization_grant": device_authorization_grant
704 .expect("Bob needs the device authorization grant"),
705 "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
706 }))
707 .await
708 .unwrap();
709
710 let message = bob
713 .receive_json()
714 .await
715 .expect("Bob should receive the LoginFailure message from Alice");
716 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
717 assert_matches!(reason, LoginFailureReason::UnsupportedProtocol);
718
719 return; }
721 BobBehaviour::MissingDeviceAuthorizationGrant => {
722 bob.send_json(serde_json::json!({
725 "type": "m.login.protocol",
726 "protocol": "device_authorization_grant",
727 "device_id": "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4",
728 }))
729 .await
730 .unwrap();
731
732 return;
733 }
734 BobBehaviour::MismatchedDeviceAuthorizationGrantLayout => {
735 let device_authorization_grant =
738 device_authorization_grant.expect("Bob needs the device authorization grant");
739 let protocol = match bob.channel_variant() {
740 ChannelVariant::Msc4108 => LoginProtocolData::Msc4388DeviceAuthorizationGrant(
741 device_authorization_grant,
742 ),
743 #[cfg(feature = "unstable-msc4388")]
744 ChannelVariant::Msc4388 => LoginProtocolData::Msc4108DeviceAuthorizationGrant(
745 device_authorization_grant,
746 ),
747 };
748 let message = QrAuthMessage::LoginProtocol {
749 protocol,
750 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
751 };
752 bob.send_json(message).await.unwrap();
753
754 let message = bob
756 .receive_json()
757 .await
758 .expect("Bob should receive the LoginFailure message from Alice");
759 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
760 assert_matches!(reason, LoginFailureReason::UnexpectedMessageReceived);
761
762 return; }
764 BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx) => {
765 let message = QrAuthMessage::LoginProtocol {
767 protocol: LoginProtocolData::device_authorization_grant(
768 device_authorization_grant
769 .expect("Bob needs the device authorization grant"),
770 bob.channel_variant(),
771 ),
772 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
773 };
774 bob.send_json(message).await.unwrap();
775
776 let message = bob
778 .receive_json()
779 .await
780 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
781 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
782
783 protocol_accepted_tx
785 .send(())
786 .expect("Bob should be able to signal that the protocol was accepted");
787
788 let message = bob
791 .receive_json()
792 .await
793 .expect("Bob should receive the LoginFailure message from Alice");
794 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
795 assert_matches!(reason, LoginFailureReason::UserCancelled);
796
797 return; }
799 _ => {
800 let message = QrAuthMessage::LoginProtocol {
802 protocol: LoginProtocolData::device_authorization_grant(
803 device_authorization_grant
804 .expect("Bob needs the device authorization grant"),
805 bob.channel_variant(),
806 ),
807 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
808 };
809 bob.send_json(message).await.unwrap();
810 }
811 }
812
813 let message = bob
815 .receive_json()
816 .await
817 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
818 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
819
820 match behaviour {
821 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
822 let message = QrAuthMessage::LoginProtocolAccepted;
824 bob.send_json(message).await.unwrap();
825 return;
826 }
827 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
828 let message = QrAuthMessage::LoginFailure {
830 reason: LoginFailureReason::AuthorizationExpired,
831 homeserver: None,
832 };
833 bob.send_json(message).await.unwrap();
834 return;
835 }
836 BobBehaviour::DeviceNotCreated => {
837 let message = QrAuthMessage::LoginSuccess;
843 bob.send_json(message).await.unwrap();
844
845 let message = bob
848 .receive_json()
849 .await
850 .expect("Bob should receive the LoginFailure message from Alice");
851 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
852 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
853
854 return; }
856 _ => {
857 server
860 .as_ref()
861 .expect("Bob needs the server for HappyPath")
862 .mock_get_device()
863 .ok()
864 .expect(1..)
865 .named("get_device")
866 .mount()
867 .await;
868
869 let message = QrAuthMessage::LoginSuccess;
871 bob.send_json(message).await.unwrap();
872 }
873 }
874
875 let message = bob
877 .receive_json()
878 .await
879 .expect("Bob should receive the LoginSecrets message from Alice");
880 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
881
882 assert_eq!(
884 serde_json::to_value(&secrets_bundle).unwrap(),
885 serde_json::to_value(&bundle).unwrap()
886 );
887 }
888
889 #[allow(clippy::too_many_arguments)]
890 async fn request_login_with_generated_qr_code(
891 behaviour: BobBehaviour,
892 channel: SecureChannel,
893 check_code_rx: oneshot::Receiver<u8>,
894 server: Option<MatrixMockServer>,
895 _rendezvous_server: &MockedRendezvousServer,
899 homeserver: Url,
900 device_authorization_grant: Option<AuthorizationGrant>,
901 secrets_bundle: Option<SecretsBundle>,
902 ) {
903 let is_using_msc_4388 = match channel.qr_code_data().intent_data() {
904 QrCodeIntentData::Msc4108 { .. } => false,
905 QrCodeIntentData::Msc4388 { .. } => true,
906 };
907
908 let channel =
910 channel.connect().await.expect("Bob should be able to connect the secure channel");
911
912 let check_code = check_code_rx.await.expect("Bob should receive the checkcode");
915 let mut bob = channel
916 .confirm(check_code)
917 .expect("Bob should be able to confirm the channel is secure");
918
919 let message = bob
921 .receive_json()
922 .await
923 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
924
925 let (protocols, alice_homeserver) = if is_using_msc_4388 {
926 assert_let!(
927 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
928 protocols,
929 base_url,
930 }) = message
931 );
932
933 (protocols, base_url)
934 } else {
935 assert_let!(
936 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
937 protocols,
938 homeserver,
939 }) = message
940 );
941
942 (protocols, homeserver)
943 };
944
945 assert_eq!(protocols, vec![LoginProtocolType::DeviceAuthorizationGrant]);
946 assert_eq!(alice_homeserver, homeserver);
947
948 match behaviour {
949 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol => {
950 let message = QrAuthMessage::LoginSuccess;
952 bob.send_json(message).await.unwrap();
953 return;
954 }
955 BobBehaviour::LoginFailureInsteadOfLoginProtocol => {
956 let message = QrAuthMessage::LoginFailure {
958 reason: LoginFailureReason::UserCancelled,
959 homeserver: None,
960 };
961 bob.send_json(message).await.unwrap();
962 return;
963 }
964 BobBehaviour::InvalidJsonMessage => {
965 bob.send_json(serde_json::json!({"type": "m.login.bogus"})).await.unwrap();
968 return;
969 }
970 BobBehaviour::DeviceAlreadyExists => {
971 server
974 .as_ref()
975 .expect("Bob needs the MatrixMockServer")
976 .mock_get_device()
977 .ok()
978 .expect(1..)
979 .named("get_device")
980 .mount()
981 .await;
982
983 let message = QrAuthMessage::LoginProtocol {
985 protocol: LoginProtocolData::device_authorization_grant(
986 device_authorization_grant
987 .expect("Bob needs the device authorization grant"),
988 bob.channel_variant(),
989 ),
990 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
991 };
992 bob.send_json(message).await.unwrap();
993
994 let message = bob
996 .receive_json()
997 .await
998 .expect("Bob should receive the LoginFailure message from Alice");
999 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1000 assert_matches!(reason, LoginFailureReason::DeviceAlreadyExists);
1001
1002 return; }
1004 BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx) => {
1005 let message = QrAuthMessage::LoginProtocol {
1007 protocol: LoginProtocolData::device_authorization_grant(
1008 device_authorization_grant
1009 .expect("Bob needs the device authorization grant"),
1010 bob.channel_variant(),
1011 ),
1012 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
1013 };
1014 bob.send_json(message).await.unwrap();
1015
1016 let message = bob
1018 .receive_json()
1019 .await
1020 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
1021 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
1022
1023 protocol_accepted_tx
1025 .send(())
1026 .expect("Bob should be able to signal that the protocol was accepted");
1027
1028 let message = bob
1031 .receive_json()
1032 .await
1033 .expect("Bob should receive the LoginFailure message from Alice");
1034 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1035 assert_matches!(reason, LoginFailureReason::UserCancelled);
1036
1037 return; }
1039 _ => {
1040 let message = QrAuthMessage::LoginProtocol {
1042 protocol: LoginProtocolData::device_authorization_grant(
1043 device_authorization_grant
1044 .expect("Bob needs the device authorization grant"),
1045 bob.channel_variant(),
1046 ),
1047 device_id: "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4".to_owned(),
1048 };
1049 bob.send_json(message).await.unwrap();
1050 }
1051 }
1052
1053 let message = bob
1055 .receive_json()
1056 .await
1057 .expect("Bob should receive the LoginProtocolAccepted message from Alice");
1058 assert_let!(QrAuthMessage::LoginProtocolAccepted = message);
1059
1060 match behaviour {
1061 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess => {
1062 let message = QrAuthMessage::LoginProtocolAccepted;
1064 bob.send_json(message).await.unwrap();
1065 return;
1066 }
1067 BobBehaviour::LoginFailureInsteadOfLoginSuccess => {
1068 let message = QrAuthMessage::LoginFailure {
1070 reason: LoginFailureReason::AuthorizationExpired,
1071 homeserver: None,
1072 };
1073 bob.send_json(message).await.unwrap();
1074 return;
1075 }
1076 BobBehaviour::DeviceNotCreated => {
1077 let message = QrAuthMessage::LoginSuccess;
1083 bob.send_json(message).await.unwrap();
1084
1085 let message = bob
1088 .receive_json()
1089 .await
1090 .expect("Bob should receive the LoginFailure message from Alice");
1091 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1092 assert_matches!(reason, LoginFailureReason::DeviceNotFound);
1093
1094 return; }
1096 _ => {
1097 server
1100 .as_ref()
1101 .expect("Bob needs the MatrixMockServer")
1102 .mock_get_device()
1103 .ok()
1104 .expect(1..)
1105 .named("get_device")
1106 .mount()
1107 .await;
1108
1109 let message = QrAuthMessage::LoginSuccess;
1111 bob.send_json(message).await.unwrap();
1112 }
1113 }
1114
1115 let message = bob
1117 .receive_json()
1118 .await
1119 .expect("Bob should receive the LoginSecrets message from Alice");
1120 assert_let!(QrAuthMessage::LoginSecrets(bundle) = message);
1121
1122 assert_eq!(
1124 serde_json::to_value(&secrets_bundle).unwrap(),
1125 serde_json::to_value(&bundle).unwrap()
1126 );
1127 }
1128
1129 async fn test_grant_login_with_generated_qr_code(msc_4388: bool) {
1130 let server = MatrixMockServer::new().await;
1131 let rendezvous_server =
1132 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1133 .await;
1134 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1135
1136 let device_authorization_grant = AuthorizationGrant {
1137 verification_uri_complete: Some(VerificationUriComplete::new(
1138 "https://id.matrix.org/device/abcde".to_owned(),
1139 )),
1140 verification_uri: EndUserVerificationUrl::new(
1141 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1142 )
1143 .unwrap(),
1144 };
1145
1146 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1147 server
1148 .mock_upload_cross_signing_keys()
1149 .ok()
1150 .expect(1)
1151 .named("upload_xsigning_keys")
1152 .mount()
1153 .await;
1154 server
1155 .mock_upload_cross_signing_signatures()
1156 .ok()
1157 .expect(1)
1158 .named("upload_xsigning_signatures")
1159 .mount()
1160 .await;
1161
1162 let user_id = owned_user_id!("@alice:example.org");
1164 let device_id = owned_device_id!("ALICE_DEVICE");
1165 let alice = server
1166 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1167 .logged_in_with_oauth()
1168 .build()
1169 .await;
1170 alice
1171 .encryption()
1172 .bootstrap_cross_signing(None)
1173 .await
1174 .expect("Alice should be able to set up cross signing");
1175
1176 let oauth = alice.oauth();
1178 #[allow(unused_mut)]
1179 let mut grant = oauth
1180 .grant_login_with_qr_code()
1181 .device_creation_timeout(Duration::from_secs(2))
1182 .generate();
1183
1184 #[cfg(feature = "unstable-msc4388")]
1185 if msc_4388 {
1186 grant.with_msc4388_support();
1187 }
1188
1189 let secrets_bundle = export_secrets_bundle(&alice)
1190 .await
1191 .expect("Alice should be able to export the secrets bundle");
1192 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1193 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1194
1195 let mut updates = grant.subscribe_to_progress();
1197 let mut state = grant.state.get();
1198 let verification_uri_complete =
1199 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1200 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1201 let updates_task = spawn(async move {
1202 let mut qr_code_tx = Some(qr_code_tx);
1203 let mut checkcode_rx = Some(checkcode_rx);
1204
1205 while let Some(update) = updates.next().await {
1206 match &update {
1207 GrantLoginProgress::Starting => {
1208 assert_matches!(state, GrantLoginProgress::Starting);
1209 }
1210 GrantLoginProgress::EstablishingSecureChannel(
1211 GeneratedQrProgress::QrReady(qr_code_data),
1212 ) => {
1213 assert_matches!(state, GrantLoginProgress::Starting);
1214 qr_code_tx
1215 .take()
1216 .expect("The QR code should only be forwarded once")
1217 .send(qr_code_data.clone())
1218 .expect("Alice should be able to forward the QR code");
1219 }
1220 GrantLoginProgress::EstablishingSecureChannel(
1221 GeneratedQrProgress::QrScanned(checkcode_sender),
1222 ) => {
1223 assert_matches!(
1224 state,
1225 GrantLoginProgress::EstablishingSecureChannel(
1226 GeneratedQrProgress::QrReady(_)
1227 )
1228 );
1229 let checkcode = checkcode_rx
1230 .take()
1231 .expect("The checkcode should only be forwarded once")
1232 .await
1233 .expect("Alice should receive the checkcode");
1234 checkcode_sender
1235 .send(checkcode)
1236 .await
1237 .expect("Alice should be able to forward the checkcode");
1238 }
1239 GrantLoginProgress::WaitingForAuth {
1240 verification_uri,
1241 continuation_sender,
1242 } => {
1243 assert_matches!(
1244 state,
1245 GrantLoginProgress::EstablishingSecureChannel(
1246 GeneratedQrProgress::QrScanned(_)
1247 )
1248 );
1249 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1250 continuation_sender.confirm().await.expect("should be able to confirm");
1251 }
1252 GrantLoginProgress::SyncingSecrets => {
1253 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1254 }
1255 GrantLoginProgress::Done => {
1256 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1257 break;
1258 }
1259 }
1260 state = update;
1261 }
1262 });
1263
1264 let bob_task = spawn(async move {
1266 request_login_with_scanned_qr_code(
1267 BobBehaviour::HappyPath,
1268 qr_code_rx,
1269 checkcode_tx,
1270 Some(server),
1271 &rendezvous_server,
1272 Some(device_authorization_grant),
1273 Some(secrets_bundle),
1274 )
1275 .await;
1276 });
1277
1278 grant.await.expect("Alice should be able to grant the login");
1280 updates_task.await.expect("Alice should run through all progress states");
1281 bob_task.await.expect("Bob's task should finish");
1282 }
1283
1284 #[async_test]
1285 async fn test_grant_login_with_generated_qr_code_msc_4108() {
1286 test_grant_login_with_generated_qr_code(false).await;
1287 }
1288
1289 #[async_test]
1290 #[cfg(feature = "unstable-msc4388")]
1291 async fn test_grant_login_with_generated_qr_code_msc_4388() {
1292 test_grant_login_with_generated_qr_code(true).await;
1293 }
1294
1295 async fn test_grant_login_with_scanned_qr_code(msc_4388: bool) {
1296 let server = MatrixMockServer::new().await;
1297 let rendezvous_server =
1298 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1299 .await;
1300 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1301
1302 let device_authorization_grant = AuthorizationGrant {
1303 verification_uri_complete: Some(VerificationUriComplete::new(
1304 "https://id.matrix.org/device/abcde".to_owned(),
1305 )),
1306 verification_uri: EndUserVerificationUrl::new(
1307 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1308 )
1309 .unwrap(),
1310 };
1311
1312 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1313 server
1314 .mock_upload_cross_signing_keys()
1315 .ok()
1316 .expect(1)
1317 .named("upload_xsigning_keys")
1318 .mount()
1319 .await;
1320 server
1321 .mock_upload_cross_signing_signatures()
1322 .ok()
1323 .expect(1)
1324 .named("upload_xsigning_signatures")
1325 .mount()
1326 .await;
1327
1328 let client = rendezvous_server.unlogged_client().await;
1331 let channel = SecureChannel::login(&client, msc_4388)
1332 .await
1333 .expect("Bob should be able to create a secure channel.");
1334 let qr_code_data = channel.qr_code_data().clone();
1335
1336 let user_id = owned_user_id!("@alice:example.org");
1338 let device_id = owned_device_id!("ALICE_DEVICE");
1339 let alice = server
1340 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1341 .logged_in_with_oauth()
1342 .build()
1343 .await;
1344 alice
1345 .encryption()
1346 .bootstrap_cross_signing(None)
1347 .await
1348 .expect("Alice should be able to set up cross signing");
1349
1350 let oauth = alice.oauth();
1352 let grant = oauth
1353 .grant_login_with_qr_code()
1354 .device_creation_timeout(Duration::from_secs(2))
1355 .scan(&qr_code_data);
1356 let secrets_bundle = export_secrets_bundle(&alice)
1357 .await
1358 .expect("Alice should be able to export the secrets bundle");
1359 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1360
1361 let mut updates = grant.subscribe_to_progress();
1363 let mut state = grant.state.get();
1364 let verification_uri_complete =
1365 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1366 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1367 let updates_task = spawn(async move {
1368 let mut checkcode_tx = Some(checkcode_tx);
1369
1370 while let Some(update) = updates.next().await {
1371 match &update {
1372 GrantLoginProgress::Starting => {
1373 assert_matches!(state, GrantLoginProgress::Starting);
1374 }
1375 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1376 assert_matches!(state, GrantLoginProgress::Starting);
1377 checkcode_tx
1378 .take()
1379 .expect("The checkcode should only be forwarded once")
1380 .send(*check_code)
1381 .expect("Alice should be able to forward the checkcode");
1382 }
1383 GrantLoginProgress::WaitingForAuth {
1384 verification_uri,
1385 continuation_sender,
1386 } => {
1387 assert_matches!(
1388 state,
1389 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1390 );
1391 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1392 continuation_sender.confirm().await.expect("should be able to confirm");
1393 }
1394 GrantLoginProgress::SyncingSecrets => {
1395 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1396 }
1397 GrantLoginProgress::Done => {
1398 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1399 break;
1400 }
1401 }
1402 state = update;
1403 }
1404 });
1405
1406 let bob_task = spawn(async move {
1408 request_login_with_generated_qr_code(
1409 BobBehaviour::HappyPath,
1410 channel,
1411 checkcode_rx,
1412 Some(server),
1413 &rendezvous_server,
1414 alice.homeserver(),
1415 Some(device_authorization_grant),
1416 Some(secrets_bundle),
1417 )
1418 .await;
1419 });
1420
1421 grant.await.expect("Alice should be able to grant the login");
1423 updates_task.await.expect("Alice should run through all progress states");
1424 bob_task.await.expect("Bob's task should finish");
1425 }
1426
1427 #[async_test]
1428 async fn test_grant_login_with_scanned_qr_code_msc_4108() {
1429 test_grant_login_with_scanned_qr_code(false).await;
1430 }
1431
1432 #[async_test]
1433 #[cfg(feature = "unstable-msc4388")]
1434 async fn test_grant_login_with_scanned_qr_code_msc_4388() {
1435 test_grant_login_with_scanned_qr_code(true).await;
1436 }
1437
1438 #[async_test]
1439 async fn test_grant_login_with_scanned_qr_code_with_homeserver_swap() {
1440 let server = MatrixMockServer::new().await;
1441 let rendezvous_server =
1442 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1443 .await;
1444 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1445
1446 let device_authorization_grant = AuthorizationGrant {
1447 verification_uri_complete: Some(VerificationUriComplete::new(
1448 "https://id.matrix.org/device/abcde".to_owned(),
1449 )),
1450 verification_uri: EndUserVerificationUrl::new(
1451 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
1452 )
1453 .unwrap(),
1454 };
1455
1456 let login_server = MatrixMockServer::new().await;
1457
1458 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1459 login_server
1460 .mock_upload_cross_signing_keys()
1461 .ok()
1462 .expect(1)
1463 .named("upload_xsigning_keys")
1464 .mount()
1465 .await;
1466 login_server
1467 .mock_upload_cross_signing_signatures()
1468 .ok()
1469 .expect(1)
1470 .named("upload_xsigning_signatures")
1471 .mount()
1472 .await;
1473
1474 let client = rendezvous_server.unlogged_client().await;
1477 let channel = SecureChannel::login(&client, false)
1478 .await
1479 .expect("Bob should be able to create a secure channel.");
1480 let qr_code_data = channel.qr_code_data().clone();
1481
1482 let user_id = owned_user_id!("@alice:example.org");
1484 let device_id = owned_device_id!("ALICE_DEVICE");
1485 let alice = login_server
1486 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1487 .logged_in_with_oauth()
1488 .build()
1489 .await;
1490 alice
1491 .encryption()
1492 .bootstrap_cross_signing(None)
1493 .await
1494 .expect("Alice should be able to set up cross signing");
1495
1496 let oauth = alice.oauth();
1498 let grant = oauth
1499 .grant_login_with_qr_code()
1500 .device_creation_timeout(Duration::from_secs(2))
1501 .scan(&qr_code_data);
1502 let secrets_bundle = export_secrets_bundle(&alice)
1503 .await
1504 .expect("Alice should be able to export the secrets bundle");
1505 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1506
1507 let mut updates = grant.subscribe_to_progress();
1509 let mut state = grant.state.get();
1510 let verification_uri_complete =
1511 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
1512 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1513 let updates_task = spawn(async move {
1514 let mut checkcode_tx = Some(checkcode_tx);
1515
1516 while let Some(update) = updates.next().await {
1517 match &update {
1518 GrantLoginProgress::Starting => {
1519 assert_matches!(state, GrantLoginProgress::Starting);
1520 }
1521 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1522 assert_matches!(state, GrantLoginProgress::Starting);
1523 checkcode_tx
1524 .take()
1525 .expect("The checkcode should only be forwarded once")
1526 .send(*check_code)
1527 .expect("Alice should be able to forward the checkcode");
1528 }
1529 GrantLoginProgress::WaitingForAuth {
1530 verification_uri,
1531 continuation_sender,
1532 } => {
1533 assert_matches!(
1534 state,
1535 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
1536 );
1537 assert_eq!(verification_uri.as_str(), verification_uri_complete);
1538 continuation_sender.confirm().await.expect("should be able to confirm");
1539 }
1540 GrantLoginProgress::SyncingSecrets => {
1541 assert_matches!(state, GrantLoginProgress::WaitingForAuth { .. });
1542 }
1543 GrantLoginProgress::Done => {
1544 assert_matches!(state, GrantLoginProgress::SyncingSecrets);
1545 break;
1546 }
1547 }
1548 state = update;
1549 }
1550 });
1551
1552 let bob_task = spawn(async move {
1554 request_login_with_generated_qr_code(
1555 BobBehaviour::HappyPath,
1556 channel,
1557 checkcode_rx,
1558 Some(login_server),
1559 &rendezvous_server,
1560 alice.homeserver(),
1561 Some(device_authorization_grant),
1562 Some(secrets_bundle),
1563 )
1564 .await;
1565 });
1566
1567 grant.await.expect("Alice should be able to grant the login");
1569 updates_task.await.expect("Alice should run through all progress states");
1570 bob_task.await.expect("Bob's task should finish");
1571 }
1572
1573 #[async_test]
1574 async fn test_grant_login_with_generated_qr_code_grant_cancelled() {
1575 let server = MatrixMockServer::new().await;
1576 let rendezvous_server = Arc::new(
1577 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1578 .await,
1579 );
1580 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1581
1582 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1583 server
1584 .mock_upload_cross_signing_keys()
1585 .ok()
1586 .expect(1)
1587 .named("upload_xsigning_keys")
1588 .mount()
1589 .await;
1590 server
1591 .mock_upload_cross_signing_signatures()
1592 .ok()
1593 .expect(1)
1594 .named("upload_xsigning_signatures")
1595 .mount()
1596 .await;
1597
1598 let user_id = owned_user_id!("@alice:example.org");
1600 let device_id = owned_device_id!("ALICE_DEVICE");
1601 let alice = server
1602 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1603 .logged_in_with_oauth()
1604 .build()
1605 .await;
1606 alice
1607 .encryption()
1608 .bootstrap_cross_signing(None)
1609 .await
1610 .expect("Alice should be able to set up cross signing");
1611
1612 let oauth = alice.oauth();
1614
1615 let grant = oauth
1616 .grant_login_with_qr_code()
1617 .device_creation_timeout(Duration::from_secs(2))
1618 .generate();
1619 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1620 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1621
1622 let mut updates = grant.subscribe_to_progress();
1624 let mut state = grant.state.get();
1625 let grant = grant.cancellable();
1626 let cancel = grant.cancellation_token();
1627 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1628 let updates_task = spawn(async move {
1629 let mut qr_code_tx = Some(qr_code_tx);
1630 let mut checkcode_rx = Some(checkcode_rx);
1631
1632 while let Some(update) = updates.next().await {
1633 match &update {
1634 GrantLoginProgress::Starting => {
1635 assert_matches!(state, GrantLoginProgress::Starting);
1636 }
1637 GrantLoginProgress::EstablishingSecureChannel(
1638 GeneratedQrProgress::QrReady(qr_code_data),
1639 ) => {
1640 assert_matches!(state, GrantLoginProgress::Starting);
1641 qr_code_tx
1642 .take()
1643 .expect("The QR code should only be forwarded once")
1644 .send(qr_code_data.clone())
1645 .expect("Alice should be able to forward the QR code");
1646 }
1647 GrantLoginProgress::EstablishingSecureChannel(
1648 GeneratedQrProgress::QrScanned(checkcode_sender),
1649 ) => {
1650 assert_matches!(
1651 state,
1652 GrantLoginProgress::EstablishingSecureChannel(
1653 GeneratedQrProgress::QrReady(_)
1654 )
1655 );
1656 let checkcode = checkcode_rx
1657 .take()
1658 .expect("The checkcode should only be forwarded once")
1659 .await
1660 .expect("Alice should receive the checkcode");
1661 checkcode_sender
1662 .send(checkcode)
1663 .await
1664 .expect("Alice should be able to forward the checkcode");
1665 cancel.cancel();
1666 break;
1667 }
1668 _ => {
1669 panic!("Alice should abort the process");
1670 }
1671 }
1672 state = update;
1673 }
1674 });
1675
1676 let rendezvous_server_clone = rendezvous_server.clone();
1678 let bob_task = spawn(async move {
1679 request_login_with_scanned_qr_code(
1680 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1681 qr_code_rx,
1682 checkcode_tx,
1683 None,
1684 &rendezvous_server_clone,
1685 None,
1686 None,
1687 )
1688 .await;
1689 });
1690
1691 assert_matches!(grant.await, None, "Alice should abort the login by cancelling it");
1693 updates_task.await.expect("Alice should run through all progress states");
1694 bob_task.await.expect("Bob's task should finish");
1695 }
1696
1697 #[async_test]
1698 async fn test_grant_login_with_scanned_qr_code_grant_cancelled() {
1699 let server = MatrixMockServer::new().await;
1700 let rendezvous_server = Arc::new(
1701 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1702 .await,
1703 );
1704 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1705
1706 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1707 server
1708 .mock_upload_cross_signing_keys()
1709 .ok()
1710 .expect(1)
1711 .named("upload_xsigning_keys")
1712 .mount()
1713 .await;
1714 server
1715 .mock_upload_cross_signing_signatures()
1716 .ok()
1717 .expect(1)
1718 .named("upload_xsigning_signatures")
1719 .mount()
1720 .await;
1721
1722 let client = rendezvous_server.unlogged_client().await;
1725 let channel = SecureChannel::login(&client, false)
1726 .await
1727 .expect("Bob should be able to create a secure channel.");
1728 let qr_code_data = channel.qr_code_data().clone();
1729
1730 let user_id = owned_user_id!("@alice:example.org");
1732 let device_id = owned_device_id!("ALICE_DEVICE");
1733 let alice = server
1734 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1735 .logged_in_with_oauth()
1736 .build()
1737 .await;
1738 alice
1739 .encryption()
1740 .bootstrap_cross_signing(None)
1741 .await
1742 .expect("Alice should be able to set up cross signing");
1743
1744 let oauth = alice.oauth();
1746 let grant = oauth
1747 .grant_login_with_qr_code()
1748 .device_creation_timeout(Duration::from_secs(2))
1749 .scan(&qr_code_data);
1750 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1751
1752 let mut updates = grant.subscribe_to_progress();
1754 let mut state = grant.state.get();
1755 let grant = grant.cancellable();
1756 let cancel = grant.cancellation_token();
1757 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1758 let updates_task = spawn(async move {
1759 let mut checkcode_tx = Some(checkcode_tx);
1760
1761 while let Some(update) = updates.next().await {
1762 match &update {
1763 GrantLoginProgress::Starting => {
1764 assert_matches!(state, GrantLoginProgress::Starting);
1765 }
1766 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1767 assert_matches!(state, GrantLoginProgress::Starting);
1768 checkcode_tx
1769 .take()
1770 .expect("The checkcode should only be forwarded once")
1771 .send(*check_code)
1772 .expect("Alice should be able to forward the checkcode");
1773 cancel.cancel();
1774 break;
1775 }
1776 _ => {
1777 panic!("Alice should abort the process");
1778 }
1779 }
1780 state = update;
1781 }
1782 });
1783
1784 let rendezvous_server_clone = rendezvous_server.clone();
1785 let bob_task = spawn(async move {
1787 request_login_with_generated_qr_code(
1788 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1789 channel,
1790 checkcode_rx,
1791 None,
1792 &rendezvous_server_clone,
1793 alice.homeserver(),
1794 None,
1795 None,
1796 )
1797 .await;
1798 });
1799
1800 assert_matches!(grant.await, None, "Alice should abort the login by cancelling it");
1802 updates_task.await.expect("Alice should run through all progress states");
1803 bob_task.await.expect("Bob's task should finish");
1804 }
1805
1806 #[async_test]
1807 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_protocol()
1808 {
1809 let server = MatrixMockServer::new().await;
1810 let rendezvous_server = Arc::new(
1811 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1812 .await,
1813 );
1814 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1815
1816 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1817 server
1818 .mock_upload_cross_signing_keys()
1819 .ok()
1820 .expect(1)
1821 .named("upload_xsigning_keys")
1822 .mount()
1823 .await;
1824 server
1825 .mock_upload_cross_signing_signatures()
1826 .ok()
1827 .expect(1)
1828 .named("upload_xsigning_signatures")
1829 .mount()
1830 .await;
1831
1832 let user_id = owned_user_id!("@alice:example.org");
1834 let device_id = owned_device_id!("ALICE_DEVICE");
1835 let alice = server
1836 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1837 .logged_in_with_oauth()
1838 .build()
1839 .await;
1840 alice
1841 .encryption()
1842 .bootstrap_cross_signing(None)
1843 .await
1844 .expect("Alice should be able to set up cross signing");
1845
1846 let oauth = alice.oauth();
1848 let grant = oauth
1849 .grant_login_with_qr_code()
1850 .device_creation_timeout(Duration::from_secs(2))
1851 .generate();
1852 let (qr_code_tx, qr_code_rx) = oneshot::channel();
1853 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1854
1855 let mut updates = grant.subscribe_to_progress();
1857 let mut state = grant.state.get();
1858 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1859 let updates_task = spawn(async move {
1860 let mut qr_code_tx = Some(qr_code_tx);
1861 let mut checkcode_rx = Some(checkcode_rx);
1862
1863 while let Some(update) = updates.next().await {
1864 match &update {
1865 GrantLoginProgress::Starting => {
1866 assert_matches!(state, GrantLoginProgress::Starting);
1867 }
1868 GrantLoginProgress::EstablishingSecureChannel(
1869 GeneratedQrProgress::QrReady(qr_code_data),
1870 ) => {
1871 assert_matches!(state, GrantLoginProgress::Starting);
1872 qr_code_tx
1873 .take()
1874 .expect("The QR code should only be forwarded once")
1875 .send(qr_code_data.clone())
1876 .expect("Alice should be able to forward the QR code");
1877 }
1878 GrantLoginProgress::EstablishingSecureChannel(
1879 GeneratedQrProgress::QrScanned(checkcode_sender),
1880 ) => {
1881 assert_matches!(
1882 state,
1883 GrantLoginProgress::EstablishingSecureChannel(
1884 GeneratedQrProgress::QrReady(_)
1885 )
1886 );
1887 let checkcode = checkcode_rx
1888 .take()
1889 .expect("The checkcode should only be forwarded once")
1890 .await
1891 .expect("Alice should receive the checkcode");
1892 checkcode_sender
1893 .send(checkcode)
1894 .await
1895 .expect("Alice should be able to forward the checkcode");
1896 break;
1897 }
1898 _ => {
1899 panic!("Alice should abort the process");
1900 }
1901 }
1902 state = update;
1903 }
1904 });
1905
1906 let rendezvous_server_clone = rendezvous_server.clone();
1908 let bob_task = spawn(async move {
1909 request_login_with_scanned_qr_code(
1910 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
1911 qr_code_rx,
1912 checkcode_tx,
1913 None,
1914 &rendezvous_server_clone,
1915 None,
1916 None,
1917 )
1918 .await;
1919 });
1920
1921 assert_let!(
1923 Err(QRCodeGrantLoginError::UnexpectedMessage {
1924 expected: "m.login.protocol",
1925 received,
1926 }) = grant.await,
1927 "Alice should abort the login with expected error variant"
1928 );
1929 assert_matches!(
1930 *received,
1931 QrAuthMessage::LoginSuccess,
1932 "Alice should abort the login with expected error message"
1933 );
1934 updates_task.await.expect("Alice should run through all progress states");
1935 bob_task.await.expect("Bob's task should finish");
1936 }
1937
1938 #[async_test]
1939 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_protocol() {
1940 let server = MatrixMockServer::new().await;
1941 let rendezvous_server = Arc::new(
1942 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
1943 .await,
1944 );
1945 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
1946
1947 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1948 server
1949 .mock_upload_cross_signing_keys()
1950 .ok()
1951 .expect(1)
1952 .named("upload_xsigning_keys")
1953 .mount()
1954 .await;
1955 server
1956 .mock_upload_cross_signing_signatures()
1957 .ok()
1958 .expect(1)
1959 .named("upload_xsigning_signatures")
1960 .mount()
1961 .await;
1962
1963 let client = rendezvous_server.unlogged_client().await;
1966 let channel = SecureChannel::login(&client, false)
1967 .await
1968 .expect("Bob should be able to create a secure channel.");
1969 let qr_code_data = channel.qr_code_data().clone();
1970
1971 let user_id = owned_user_id!("@alice:example.org");
1973 let device_id = owned_device_id!("ALICE_DEVICE");
1974 let alice = server
1975 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
1976 .logged_in_with_oauth()
1977 .build()
1978 .await;
1979 alice
1980 .encryption()
1981 .bootstrap_cross_signing(None)
1982 .await
1983 .expect("Alice should be able to set up cross signing");
1984
1985 let oauth = alice.oauth();
1987 let grant = oauth
1988 .grant_login_with_qr_code()
1989 .device_creation_timeout(Duration::from_secs(2))
1990 .scan(&qr_code_data);
1991 let (checkcode_tx, checkcode_rx) = oneshot::channel();
1992
1993 let mut updates = grant.subscribe_to_progress();
1995 let mut state = grant.state.get();
1996 assert_matches!(state.clone(), GrantLoginProgress::Starting);
1997 let updates_task = spawn(async move {
1998 let mut checkcode_tx = Some(checkcode_tx);
1999
2000 while let Some(update) = updates.next().await {
2001 match &update {
2002 GrantLoginProgress::Starting => {
2003 assert_matches!(state, GrantLoginProgress::Starting);
2004 }
2005 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2006 assert_matches!(state, GrantLoginProgress::Starting);
2007 checkcode_tx
2008 .take()
2009 .expect("The checkcode should only be forwarded once")
2010 .send(*check_code)
2011 .expect("Alice should be able to forward the checkcode");
2012 break;
2013 }
2014 _ => {
2015 panic!("Alice should abort the process");
2016 }
2017 }
2018 state = update;
2019 }
2020 });
2021
2022 let rendezvous_server_clone = rendezvous_server.clone();
2023 let bob_task = spawn(async move {
2025 request_login_with_generated_qr_code(
2026 BobBehaviour::UnexpectedMessageInsteadOfLoginProtocol,
2027 channel,
2028 checkcode_rx,
2029 None,
2030 &rendezvous_server_clone,
2031 alice.homeserver(),
2032 None,
2033 None,
2034 )
2035 .await;
2036 });
2037
2038 assert_let!(
2040 Err(QRCodeGrantLoginError::UnexpectedMessage {
2041 expected: "m.login.protocol",
2042 received,
2043 }) = grant.await,
2044 "Alice should abort the login with expected error variant"
2045 );
2046 assert_matches!(
2047 *received,
2048 QrAuthMessage::LoginSuccess,
2049 "Alice should abort the login with expected error message"
2050 );
2051 updates_task.await.expect("Alice should run through all progress states");
2052 bob_task.await.expect("Bob's task should finish");
2053 }
2054
2055 async fn grant_login_with_generated_qr_code_rejected_protocol(
2058 behaviour: BobBehaviour,
2059 msc_4388: bool,
2060 ) -> QRCodeGrantLoginError {
2061 let server = MatrixMockServer::new().await;
2062 let rendezvous_server = Arc::new(
2065 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
2066 .await,
2067 );
2068 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2069
2070 let device_authorization_grant = AuthorizationGrant {
2071 verification_uri_complete: Some(VerificationUriComplete::new(
2072 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2073 )),
2074 verification_uri: EndUserVerificationUrl::new(
2075 "https://id.matrix.org/device/abcde".to_owned(),
2076 )
2077 .unwrap(),
2078 };
2079
2080 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2081 server
2082 .mock_upload_cross_signing_keys()
2083 .ok()
2084 .expect(1)
2085 .named("upload_xsigning_keys")
2086 .mount()
2087 .await;
2088 server
2089 .mock_upload_cross_signing_signatures()
2090 .ok()
2091 .expect(1)
2092 .named("upload_xsigning_signatures")
2093 .mount()
2094 .await;
2095
2096 let user_id = owned_user_id!("@alice:example.org");
2098 let device_id = owned_device_id!("ALICE_DEVICE");
2099 let alice = server
2100 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2101 .logged_in_with_oauth()
2102 .build()
2103 .await;
2104 alice
2105 .encryption()
2106 .bootstrap_cross_signing(None)
2107 .await
2108 .expect("Alice should be able to set up cross signing");
2109
2110 let oauth = alice.oauth();
2112 #[allow(unused_mut)]
2113 let mut grant = oauth
2114 .grant_login_with_qr_code()
2115 .device_creation_timeout(Duration::from_secs(2))
2116 .generate();
2117
2118 #[cfg(feature = "unstable-msc4388")]
2119 if msc_4388 {
2120 grant.with_msc4388_support();
2121 }
2122
2123 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2124 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2125
2126 let mut updates = grant.subscribe_to_progress();
2128 let mut state = grant.state.get();
2129 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2130 let updates_task = spawn(async move {
2131 let mut qr_code_tx = Some(qr_code_tx);
2132 let mut checkcode_rx = Some(checkcode_rx);
2133
2134 while let Some(update) = updates.next().await {
2135 match &update {
2136 GrantLoginProgress::Starting => {
2137 assert_matches!(state, GrantLoginProgress::Starting);
2138 }
2139 GrantLoginProgress::EstablishingSecureChannel(
2140 GeneratedQrProgress::QrReady(qr_code_data),
2141 ) => {
2142 assert_matches!(state, GrantLoginProgress::Starting);
2143 qr_code_tx
2144 .take()
2145 .expect("The QR code should only be forwarded once")
2146 .send(qr_code_data.clone())
2147 .expect("Alice should be able to forward the QR code");
2148 }
2149 GrantLoginProgress::EstablishingSecureChannel(
2150 GeneratedQrProgress::QrScanned(checkcode_sender),
2151 ) => {
2152 assert_matches!(
2153 state,
2154 GrantLoginProgress::EstablishingSecureChannel(
2155 GeneratedQrProgress::QrReady(_)
2156 )
2157 );
2158 let checkcode = checkcode_rx
2159 .take()
2160 .expect("The checkcode should only be forwarded once")
2161 .await
2162 .expect("Alice should receive the checkcode");
2163 checkcode_sender
2164 .send(checkcode)
2165 .await
2166 .expect("Alice should be able to forward the checkcode");
2167 }
2168 _ => {
2169 panic!("Alice should abort the process");
2170 }
2171 }
2172 state = update;
2173 }
2174 });
2175
2176 let rendezvous_server_clone = rendezvous_server.clone();
2179 let bob_task = spawn(async move {
2180 request_login_with_scanned_qr_code(
2181 behaviour,
2182 qr_code_rx,
2183 checkcode_tx,
2184 None,
2185 &rendezvous_server_clone,
2186 Some(device_authorization_grant),
2187 None,
2188 )
2189 .await;
2190 });
2191
2192 let error = grant.await.expect_err("Alice should abort the login");
2194 updates_task.await.expect("Alice should run through all progress states");
2195 bob_task.await.expect("Bob's task should finish");
2196
2197 error
2198 }
2199
2200 async fn test_grant_login_with_generated_qr_code_unsupported_protocol(msc_4388: bool) {
2201 let error = grant_login_with_generated_qr_code_rejected_protocol(
2202 BobBehaviour::UnsupportedProtocol,
2203 msc_4388,
2204 )
2205 .await;
2206 assert_let!(
2207 QRCodeGrantLoginError::UnsupportedProtocol(protocol) = error,
2208 "Alice should abort the login with expected error variant"
2209 );
2210 assert_eq!(protocol.as_str(), "m.unknown_protocol");
2211 }
2212
2213 #[async_test]
2214 async fn test_grant_login_with_generated_qr_code_unsupported_protocol_msc_4108() {
2215 test_grant_login_with_generated_qr_code_unsupported_protocol(false).await;
2216 }
2217
2218 #[async_test]
2219 #[cfg(feature = "unstable-msc4388")]
2220 async fn test_grant_login_with_generated_qr_code_unsupported_protocol_msc_4388() {
2221 test_grant_login_with_generated_qr_code_unsupported_protocol(true).await;
2222 }
2223
2224 async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(
2225 msc_4388: bool,
2226 ) {
2227 let error = grant_login_with_generated_qr_code_rejected_protocol(
2228 BobBehaviour::UnsupportedProtocolWithDeviceAuthorizationGrant,
2229 msc_4388,
2230 )
2231 .await;
2232 assert_let!(
2233 QRCodeGrantLoginError::UnsupportedProtocol(protocol) = error,
2234 "Alice should abort the login with expected error variant"
2235 );
2236 assert_eq!(protocol.as_str(), "m.unknown_protocol");
2237 }
2238
2239 #[async_test]
2240 async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant_msc_4108() {
2241 test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(false).await;
2242 }
2243
2244 #[async_test]
2245 #[cfg(feature = "unstable-msc4388")]
2246 async fn test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant_msc_4388() {
2247 test_grant_login_with_generated_qr_code_unsupported_protocol_with_grant(true).await;
2248 }
2249
2250 async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant(
2251 msc_4388: bool,
2252 ) {
2253 let error = grant_login_with_generated_qr_code_rejected_protocol(
2254 BobBehaviour::MissingDeviceAuthorizationGrant,
2255 msc_4388,
2256 )
2257 .await;
2258 assert_matches!(
2259 error,
2260 QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
2261 MessageDecodeError::Json(_)
2262 )),
2263 "Alice should abort the login with expected error variant"
2264 );
2265 }
2266
2267 #[async_test]
2268 async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant_msc_4108() {
2269 test_grant_login_with_generated_qr_code_missing_device_authorization_grant(false).await;
2270 }
2271
2272 #[async_test]
2273 #[cfg(feature = "unstable-msc4388")]
2274 async fn test_grant_login_with_generated_qr_code_missing_device_authorization_grant_msc_4388() {
2275 test_grant_login_with_generated_qr_code_missing_device_authorization_grant(true).await;
2276 }
2277
2278 async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(
2279 msc_4388: bool,
2280 ) {
2281 let error = grant_login_with_generated_qr_code_rejected_protocol(
2282 BobBehaviour::MismatchedDeviceAuthorizationGrantLayout,
2283 msc_4388,
2284 )
2285 .await;
2286 assert_let!(
2287 QRCodeGrantLoginError::UnexpectedMessage { expected, received } = error,
2288 "Alice should abort the login with expected error variant"
2289 );
2290 assert_eq!(expected, "m.login.protocol");
2291 assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = *received);
2292 if msc_4388 {
2294 assert_matches!(protocol, LoginProtocolData::Msc4108DeviceAuthorizationGrant(_));
2295 } else {
2296 assert_matches!(protocol, LoginProtocolData::Msc4388DeviceAuthorizationGrant(_));
2297 }
2298 }
2299
2300 #[async_test]
2301 async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout_msc_4108()
2302 {
2303 test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(false)
2304 .await;
2305 }
2306
2307 #[async_test]
2308 #[cfg(feature = "unstable-msc4388")]
2309 async fn test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout_msc_4388()
2310 {
2311 test_grant_login_with_generated_qr_code_mismatched_device_authorization_grant_layout(true)
2312 .await;
2313 }
2314
2315 #[async_test]
2316 async fn test_grant_login_with_generated_qr_code_device_already_exists() {
2317 let server = MatrixMockServer::new().await;
2318 let rendezvous_server =
2319 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2320 .await;
2321 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2322
2323 let device_authorization_grant = AuthorizationGrant {
2324 verification_uri_complete: Some(VerificationUriComplete::new(
2325 "https://id.matrix.org/device/abcde".to_owned(),
2326 )),
2327 verification_uri: EndUserVerificationUrl::new(
2328 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2329 )
2330 .unwrap(),
2331 };
2332
2333 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2334 server
2335 .mock_upload_cross_signing_keys()
2336 .ok()
2337 .expect(1)
2338 .named("upload_xsigning_keys")
2339 .mount()
2340 .await;
2341 server
2342 .mock_upload_cross_signing_signatures()
2343 .ok()
2344 .expect(1)
2345 .named("upload_xsigning_signatures")
2346 .mount()
2347 .await;
2348
2349 let user_id = owned_user_id!("@alice:example.org");
2351 let device_id = owned_device_id!("ALICE_DEVICE");
2352 let alice = server
2353 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2354 .logged_in_with_oauth()
2355 .build()
2356 .await;
2357 alice
2358 .encryption()
2359 .bootstrap_cross_signing(None)
2360 .await
2361 .expect("Alice should be able to set up cross signing");
2362
2363 let oauth = alice.oauth();
2365 let grant = oauth
2366 .grant_login_with_qr_code()
2367 .device_creation_timeout(Duration::from_secs(2))
2368 .generate();
2369 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2370 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2371
2372 let mut updates = grant.subscribe_to_progress();
2374 let mut state = grant.state.get();
2375 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2376 let updates_task = spawn(async move {
2377 let mut qr_code_tx = Some(qr_code_tx);
2378 let mut checkcode_rx = Some(checkcode_rx);
2379
2380 while let Some(update) = updates.next().await {
2381 match &update {
2382 GrantLoginProgress::Starting => {
2383 assert_matches!(state, GrantLoginProgress::Starting);
2384 }
2385 GrantLoginProgress::EstablishingSecureChannel(
2386 GeneratedQrProgress::QrReady(qr_code_data),
2387 ) => {
2388 assert_matches!(state, GrantLoginProgress::Starting);
2389 qr_code_tx
2390 .take()
2391 .expect("The QR code should only be forwarded once")
2392 .send(qr_code_data.clone())
2393 .expect("Alice should be able to forward the QR code");
2394 }
2395 GrantLoginProgress::EstablishingSecureChannel(
2396 GeneratedQrProgress::QrScanned(checkcode_sender),
2397 ) => {
2398 assert_matches!(
2399 state,
2400 GrantLoginProgress::EstablishingSecureChannel(
2401 GeneratedQrProgress::QrReady(_)
2402 )
2403 );
2404 let checkcode = checkcode_rx
2405 .take()
2406 .expect("The checkcode should only be forwarded once")
2407 .await
2408 .expect("Alice should receive the checkcode");
2409 checkcode_sender
2410 .send(checkcode)
2411 .await
2412 .expect("Alice should be able to forward the checkcode");
2413 }
2414 _ => {
2415 panic!("Alice should abort the process");
2416 }
2417 }
2418 state = update;
2419 }
2420 });
2421
2422 let bob_task = spawn(async move {
2424 request_login_with_scanned_qr_code(
2425 BobBehaviour::DeviceAlreadyExists,
2426 qr_code_rx,
2427 checkcode_tx,
2428 Some(server),
2429 &rendezvous_server,
2430 Some(device_authorization_grant),
2431 None,
2432 )
2433 .await;
2434 });
2435
2436 assert_matches!(
2438 grant.await,
2439 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
2440 "Alice should abort the login with expected error"
2441 );
2442 updates_task.await.expect("Alice should run through all progress states");
2443 bob_task.await.expect("Bob's task should finish");
2444 }
2445
2446 #[async_test]
2447 async fn test_grant_login_with_scanned_qr_code_device_already_exists() {
2448 let server = MatrixMockServer::new().await;
2449 let rendezvous_server =
2450 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2451 .await;
2452 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2453
2454 let device_authorization_grant = AuthorizationGrant {
2455 verification_uri_complete: Some(VerificationUriComplete::new(
2456 "https://id.matrix.org/device/abcde".to_owned(),
2457 )),
2458 verification_uri: EndUserVerificationUrl::new(
2459 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2460 )
2461 .unwrap(),
2462 };
2463
2464 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2465 server
2466 .mock_upload_cross_signing_keys()
2467 .ok()
2468 .expect(1)
2469 .named("upload_xsigning_keys")
2470 .mount()
2471 .await;
2472 server
2473 .mock_upload_cross_signing_signatures()
2474 .ok()
2475 .expect(1)
2476 .named("upload_xsigning_signatures")
2477 .mount()
2478 .await;
2479
2480 let client = rendezvous_server.unlogged_client().await;
2483 let channel = SecureChannel::login(&client, false)
2484 .await
2485 .expect("Bob should be able to create a secure channel.");
2486 let qr_code_data = channel.qr_code_data().clone();
2487
2488 let user_id = owned_user_id!("@alice:example.org");
2490 let device_id = owned_device_id!("ALICE_DEVICE");
2491 let alice = server
2492 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2493 .logged_in_with_oauth()
2494 .build()
2495 .await;
2496 alice
2497 .encryption()
2498 .bootstrap_cross_signing(None)
2499 .await
2500 .expect("Alice should be able to set up cross signing");
2501
2502 let oauth = alice.oauth();
2504 let grant = oauth
2505 .grant_login_with_qr_code()
2506 .device_creation_timeout(Duration::from_secs(2))
2507 .scan(&qr_code_data);
2508 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2509
2510 let mut updates = grant.subscribe_to_progress();
2512 let mut state = grant.state.get();
2513 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2514 let updates_task = spawn(async move {
2515 let mut checkcode_tx = Some(checkcode_tx);
2516
2517 while let Some(update) = updates.next().await {
2518 match &update {
2519 GrantLoginProgress::Starting => {
2520 assert_matches!(state, GrantLoginProgress::Starting);
2521 }
2522 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2523 assert_matches!(state, GrantLoginProgress::Starting);
2524 checkcode_tx
2525 .take()
2526 .expect("The checkcode should only be forwarded once")
2527 .send(*check_code)
2528 .expect("Alice should be able to forward the checkcode");
2529 }
2530 _ => {
2531 panic!("Alice should abort the process");
2532 }
2533 }
2534 state = update;
2535 }
2536 });
2537
2538 let bob_task = spawn(async move {
2540 request_login_with_generated_qr_code(
2541 BobBehaviour::DeviceAlreadyExists,
2542 channel,
2543 checkcode_rx,
2544 Some(server),
2545 &rendezvous_server,
2546 alice.homeserver(),
2547 Some(device_authorization_grant),
2548 None,
2549 )
2550 .await;
2551 });
2552
2553 assert_matches!(
2555 grant.await,
2556 Err(QRCodeGrantLoginError::DeviceIDAlreadyInUse),
2557 "Alice should abort the login with expected error"
2558 );
2559 updates_task.await.expect("Alice should run through all progress states");
2560 bob_task.await.expect("Bob's task should finish");
2561 }
2562
2563 #[async_test]
2564 async fn test_grant_login_with_generated_qr_code_device_not_found() {
2565 let server = MatrixMockServer::new().await;
2566 let rendezvous_server =
2567 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2568 .await;
2569 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2570
2571 let device_authorization_grant = AuthorizationGrant {
2572 verification_uri_complete: Some(VerificationUriComplete::new(
2573 "https://id.matrix.org/device/abcde".to_owned(),
2574 )),
2575 verification_uri: EndUserVerificationUrl::new(
2576 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2577 )
2578 .unwrap(),
2579 };
2580
2581 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2582 server
2583 .mock_upload_cross_signing_keys()
2584 .ok()
2585 .expect(1)
2586 .named("upload_xsigning_keys")
2587 .mount()
2588 .await;
2589 server
2590 .mock_upload_cross_signing_signatures()
2591 .ok()
2592 .expect(1)
2593 .named("upload_xsigning_signatures")
2594 .mount()
2595 .await;
2596
2597 let user_id = owned_user_id!("@alice:example.org");
2599 let device_id = owned_device_id!("ALICE_DEVICE");
2600 let alice = server
2601 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2602 .logged_in_with_oauth()
2603 .build()
2604 .await;
2605 alice
2606 .encryption()
2607 .bootstrap_cross_signing(None)
2608 .await
2609 .expect("Alice should be able to set up cross signing");
2610
2611 let oauth = alice.oauth();
2613 let grant = oauth
2614 .grant_login_with_qr_code()
2615 .device_creation_timeout(Duration::from_secs(2))
2616 .generate();
2617 let (qr_code_tx, qr_code_rx) = oneshot::channel();
2618 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2619
2620 let mut updates = grant.subscribe_to_progress();
2622 let mut state = grant.state.get();
2623 let verification_uri_complete =
2624 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2625 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2626 let updates_task = spawn(async move {
2627 let mut qr_code_tx = Some(qr_code_tx);
2628 let mut checkcode_rx = Some(checkcode_rx);
2629
2630 while let Some(update) = updates.next().await {
2631 match &update {
2632 GrantLoginProgress::Starting => {
2633 assert_matches!(state, GrantLoginProgress::Starting);
2634 }
2635 GrantLoginProgress::EstablishingSecureChannel(
2636 GeneratedQrProgress::QrReady(qr_code_data),
2637 ) => {
2638 assert_matches!(state, GrantLoginProgress::Starting);
2639 qr_code_tx
2640 .take()
2641 .expect("The QR code should only be forwarded once")
2642 .send(qr_code_data.clone())
2643 .expect("Alice should be able to forward the QR code");
2644 }
2645 GrantLoginProgress::EstablishingSecureChannel(
2646 GeneratedQrProgress::QrScanned(checkcode_sender),
2647 ) => {
2648 assert_matches!(
2649 state,
2650 GrantLoginProgress::EstablishingSecureChannel(
2651 GeneratedQrProgress::QrReady(_)
2652 )
2653 );
2654 let checkcode = checkcode_rx
2655 .take()
2656 .expect("The checkcode should only be forwarded once")
2657 .await
2658 .expect("Alice should receive the checkcode");
2659 checkcode_sender
2660 .send(checkcode)
2661 .await
2662 .expect("Alice should be able to forward the checkcode");
2663 }
2664 GrantLoginProgress::WaitingForAuth {
2665 verification_uri,
2666 continuation_sender,
2667 } => {
2668 assert_matches!(
2669 state,
2670 GrantLoginProgress::EstablishingSecureChannel(
2671 GeneratedQrProgress::QrScanned(_)
2672 )
2673 );
2674 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2675 continuation_sender.confirm().await.expect("should be able to confirm");
2676 }
2677 _ => {
2678 panic!("Alice should abort the process");
2679 }
2680 }
2681 state = update;
2682 }
2683 });
2684
2685 let bob_task = spawn(async move {
2687 request_login_with_scanned_qr_code(
2688 BobBehaviour::DeviceNotCreated,
2689 qr_code_rx,
2690 checkcode_tx,
2691 Some(server),
2692 &rendezvous_server,
2693 Some(device_authorization_grant),
2694 None,
2695 )
2696 .await;
2697 });
2698
2699 assert_matches!(
2700 grant.await,
2701 Err(QRCodeGrantLoginError::DeviceNotFound),
2702 "Alice should abort the login with expected error"
2703 );
2704 updates_task.await.expect("Alice should run through all progress states");
2705 bob_task.await.expect("Bob's task should finish");
2706 }
2707
2708 #[async_test]
2709 async fn test_grant_login_with_scanned_qr_code_device_not_found() {
2710 let server = MatrixMockServer::new().await;
2711 let rendezvous_server =
2712 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2713 .await;
2714 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2715
2716 let device_authorization_grant = AuthorizationGrant {
2717 verification_uri_complete: Some(VerificationUriComplete::new(
2718 "https://id.matrix.org/device/abcde".to_owned(),
2719 )),
2720 verification_uri: EndUserVerificationUrl::new(
2721 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
2722 )
2723 .unwrap(),
2724 };
2725
2726 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2727 server
2728 .mock_upload_cross_signing_keys()
2729 .ok()
2730 .expect(1)
2731 .named("upload_xsigning_keys")
2732 .mount()
2733 .await;
2734 server
2735 .mock_upload_cross_signing_signatures()
2736 .ok()
2737 .expect(1)
2738 .named("upload_xsigning_signatures")
2739 .mount()
2740 .await;
2741
2742 let client = rendezvous_server.unlogged_client().await;
2745 let channel = SecureChannel::login(&client, false)
2746 .await
2747 .expect("Bob should be able to create a secure channel.");
2748 let qr_code_data = channel.qr_code_data().clone();
2749
2750 let user_id = owned_user_id!("@alice:example.org");
2752 let device_id = owned_device_id!("ALICE_DEVICE");
2753 let alice = server
2754 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2755 .logged_in_with_oauth()
2756 .build()
2757 .await;
2758 alice
2759 .encryption()
2760 .bootstrap_cross_signing(None)
2761 .await
2762 .expect("Alice should be able to set up cross signing");
2763
2764 let oauth = alice.oauth();
2766 let grant = oauth
2767 .grant_login_with_qr_code()
2768 .device_creation_timeout(Duration::from_secs(2))
2769 .scan(&qr_code_data);
2770 let (checkcode_tx, checkcode_rx) = oneshot::channel();
2771
2772 let mut updates = grant.subscribe_to_progress();
2774 let mut state = grant.state.get();
2775 let verification_uri_complete =
2776 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
2777 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2778 let updates_task = spawn(async move {
2779 let mut checkcode_tx = Some(checkcode_tx);
2780
2781 while let Some(update) = updates.next().await {
2782 match &update {
2783 GrantLoginProgress::Starting => {
2784 assert_matches!(state, GrantLoginProgress::Starting);
2785 }
2786 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2787 assert_matches!(state, GrantLoginProgress::Starting);
2788 checkcode_tx
2789 .take()
2790 .expect("The checkcode should only be forwarded once")
2791 .send(*check_code)
2792 .expect("Alice should be able to forward the checkcode");
2793 }
2794 GrantLoginProgress::WaitingForAuth {
2795 verification_uri,
2796 continuation_sender,
2797 } => {
2798 assert_matches!(
2799 state,
2800 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
2801 );
2802 assert_eq!(verification_uri.as_str(), verification_uri_complete);
2803 continuation_sender.confirm().await.expect("should be able to confirm");
2804 }
2805 _ => {
2806 panic!("Alice should abort the process");
2807 }
2808 }
2809 state = update;
2810 }
2811 });
2812
2813 let bob_task = spawn(async move {
2815 request_login_with_generated_qr_code(
2816 BobBehaviour::DeviceNotCreated,
2817 channel,
2818 checkcode_rx,
2819 None,
2820 &rendezvous_server,
2821 alice.homeserver(),
2822 Some(device_authorization_grant),
2823 None,
2824 )
2825 .await;
2826 });
2827
2828 assert_matches!(
2829 grant.await,
2830 Err(QRCodeGrantLoginError::DeviceNotFound),
2831 "Alice should abort the login with expected error"
2832 );
2833 updates_task.await.expect("Alice should run through all progress states");
2834 bob_task.await.expect("Bob's task should finish");
2835 }
2836
2837 #[async_test]
2838 async fn test_grant_login_with_generated_qr_code_session_expired() {
2839 let server = MatrixMockServer::new().await;
2840 let rendezvous_server = MockedRendezvousServer::new(
2841 server.server(),
2842 "abcdEFG12345",
2843 Duration::from_secs(2),
2844 false,
2845 )
2846 .await;
2847 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2848
2849 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2850 server
2851 .mock_upload_cross_signing_keys()
2852 .ok()
2853 .expect(1)
2854 .named("upload_xsigning_keys")
2855 .mount()
2856 .await;
2857 server
2858 .mock_upload_cross_signing_signatures()
2859 .ok()
2860 .expect(1)
2861 .named("upload_xsigning_signatures")
2862 .mount()
2863 .await;
2864
2865 let user_id = owned_user_id!("@alice:example.org");
2867 let device_id = owned_device_id!("ALICE_DEVICE");
2868 let alice = server
2869 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2870 .logged_in_with_oauth()
2871 .build()
2872 .await;
2873 alice
2874 .encryption()
2875 .bootstrap_cross_signing(None)
2876 .await
2877 .expect("Alice should be able to set up cross signing");
2878
2879 let oauth = alice.oauth();
2881 let grant = oauth
2882 .grant_login_with_qr_code()
2883 .device_creation_timeout(Duration::from_secs(2))
2884 .generate();
2885
2886 let mut updates = grant.subscribe_to_progress();
2888 let mut state = grant.state.get();
2889 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2890 let updates_task = spawn(async move {
2891 while let Some(update) = updates.next().await {
2892 match &update {
2893 GrantLoginProgress::Starting => {
2894 assert_matches!(state, GrantLoginProgress::Starting);
2895 }
2896 GrantLoginProgress::EstablishingSecureChannel(
2897 GeneratedQrProgress::QrReady(_),
2898 ) => {
2899 assert_matches!(state, GrantLoginProgress::Starting);
2900 }
2901 _ => {
2902 panic!("Alice should abort the process");
2903 }
2904 }
2905 state = update;
2906 }
2907 });
2908
2909 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2913 updates_task.await.expect("Alice should run through all progress states");
2914 }
2915
2916 #[async_test]
2917 async fn test_grant_login_with_scanned_qr_code_session_expired() {
2918 let server = MatrixMockServer::new().await;
2919 let rendezvous_server = MockedRendezvousServer::new(
2920 server.server(),
2921 "abcdEFG12345",
2922 Duration::from_secs(2),
2923 false,
2924 )
2925 .await;
2926 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
2927
2928 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
2929 server
2930 .mock_upload_cross_signing_keys()
2931 .ok()
2932 .expect(1)
2933 .named("upload_xsigning_keys")
2934 .mount()
2935 .await;
2936 server
2937 .mock_upload_cross_signing_signatures()
2938 .ok()
2939 .expect(1)
2940 .named("upload_xsigning_signatures")
2941 .mount()
2942 .await;
2943
2944 let client = rendezvous_server.unlogged_client().await;
2947 let channel = SecureChannel::login(&client, false)
2948 .await
2949 .expect("Bob should be able to create a secure channel.");
2950 let qr_code_data = channel.qr_code_data().clone();
2951
2952 let user_id = owned_user_id!("@alice:example.org");
2954 let device_id = owned_device_id!("ALICE_DEVICE");
2955 let alice = server
2956 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
2957 .logged_in_with_oauth()
2958 .build()
2959 .await;
2960 alice
2961 .encryption()
2962 .bootstrap_cross_signing(None)
2963 .await
2964 .expect("Alice should be able to set up cross signing");
2965
2966 let oauth = alice.oauth();
2968 let grant = oauth
2969 .grant_login_with_qr_code()
2970 .device_creation_timeout(Duration::from_secs(2))
2971 .scan(&qr_code_data);
2972
2973 let mut updates = grant.subscribe_to_progress();
2975 let mut state = grant.state.get();
2976 assert_matches!(state.clone(), GrantLoginProgress::Starting);
2977 let updates_task = spawn(async move {
2978 while let Some(update) = updates.next().await {
2979 match &update {
2980 GrantLoginProgress::Starting => {
2981 assert_matches!(state, GrantLoginProgress::Starting);
2982 }
2983 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. }) => {
2984 assert_matches!(state, GrantLoginProgress::Starting);
2985 }
2986 _ => {
2987 panic!("Alice should abort the process");
2988 }
2989 }
2990 state = update;
2991 }
2992 });
2993
2994 assert_matches!(grant.await, Err(QRCodeGrantLoginError::NotFound));
2998 updates_task.await.expect("Alice should run through all progress states");
2999 }
3000
3001 #[async_test]
3002 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_protocol() {
3003 let server = MatrixMockServer::new().await;
3004 let rendezvous_server = Arc::new(
3005 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3006 .await,
3007 );
3008 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3009
3010 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3011 server
3012 .mock_upload_cross_signing_keys()
3013 .ok()
3014 .expect(1)
3015 .named("upload_xsigning_keys")
3016 .mount()
3017 .await;
3018 server
3019 .mock_upload_cross_signing_signatures()
3020 .ok()
3021 .expect(1)
3022 .named("upload_xsigning_signatures")
3023 .mount()
3024 .await;
3025
3026 let user_id = owned_user_id!("@alice:example.org");
3028 let device_id = owned_device_id!("ALICE_DEVICE");
3029 let alice = server
3030 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3031 .logged_in_with_oauth()
3032 .build()
3033 .await;
3034 alice
3035 .encryption()
3036 .bootstrap_cross_signing(None)
3037 .await
3038 .expect("Alice should be able to set up cross signing");
3039
3040 let oauth = alice.oauth();
3042 let grant = oauth
3043 .grant_login_with_qr_code()
3044 .device_creation_timeout(Duration::from_secs(2))
3045 .generate();
3046 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3047 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3048
3049 let mut updates = grant.subscribe_to_progress();
3051 let mut state = grant.state.get();
3052 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3053 let updates_task = spawn(async move {
3054 let mut qr_code_tx = Some(qr_code_tx);
3055 let mut checkcode_rx = Some(checkcode_rx);
3056
3057 while let Some(update) = updates.next().await {
3058 match &update {
3059 GrantLoginProgress::Starting => {
3060 assert_matches!(state, GrantLoginProgress::Starting);
3061 }
3062 GrantLoginProgress::EstablishingSecureChannel(
3063 GeneratedQrProgress::QrReady(qr_code_data),
3064 ) => {
3065 assert_matches!(state, GrantLoginProgress::Starting);
3066 qr_code_tx
3067 .take()
3068 .expect("The QR code should only be forwarded once")
3069 .send(qr_code_data.clone())
3070 .expect("Alice should be able to forward the QR code");
3071 }
3072 GrantLoginProgress::EstablishingSecureChannel(
3073 GeneratedQrProgress::QrScanned(checkcode_sender),
3074 ) => {
3075 assert_matches!(
3076 state,
3077 GrantLoginProgress::EstablishingSecureChannel(
3078 GeneratedQrProgress::QrReady(_)
3079 )
3080 );
3081 let checkcode = checkcode_rx
3082 .take()
3083 .expect("The checkcode should only be forwarded once")
3084 .await
3085 .expect("Alice should receive the checkcode");
3086 checkcode_sender
3087 .send(checkcode)
3088 .await
3089 .expect("Alice should be able to forward the checkcode");
3090 break;
3091 }
3092 _ => {
3093 panic!("Alice should abort the process");
3094 }
3095 }
3096 state = update;
3097 }
3098 });
3099
3100 let rendezvous_server_clone = rendezvous_server.clone();
3102 let bob_task = spawn(async move {
3103 request_login_with_scanned_qr_code(
3104 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
3105 qr_code_rx,
3106 checkcode_tx,
3107 None,
3108 &rendezvous_server_clone,
3109 None,
3110 None,
3111 )
3112 .await;
3113 });
3114
3115 assert_matches!(
3117 grant.await,
3118 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3119 "Alice should abort the login with expected error"
3120 );
3121 updates_task.await.expect("Alice should run through all progress states");
3122 bob_task.await.expect("Bob's task should finish");
3123 }
3124
3125 #[async_test]
3126 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_protocol() {
3127 let server = MatrixMockServer::new().await;
3128 let rendezvous_server = Arc::new(
3129 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3130 .await,
3131 );
3132 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3133
3134 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3135 server
3136 .mock_upload_cross_signing_keys()
3137 .ok()
3138 .expect(1)
3139 .named("upload_xsigning_keys")
3140 .mount()
3141 .await;
3142 server
3143 .mock_upload_cross_signing_signatures()
3144 .ok()
3145 .expect(1)
3146 .named("upload_xsigning_signatures")
3147 .mount()
3148 .await;
3149
3150 let client = rendezvous_server.unlogged_client().await;
3153 let channel = SecureChannel::login(&client, false)
3154 .await
3155 .expect("Bob should be able to create a secure channel.");
3156 let qr_code_data = channel.qr_code_data().clone();
3157
3158 let user_id = owned_user_id!("@alice:example.org");
3160 let device_id = owned_device_id!("ALICE_DEVICE");
3161 let alice = server
3162 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3163 .logged_in_with_oauth()
3164 .build()
3165 .await;
3166 alice
3167 .encryption()
3168 .bootstrap_cross_signing(None)
3169 .await
3170 .expect("Alice should be able to set up cross signing");
3171
3172 let oauth = alice.oauth();
3174 let grant = oauth
3175 .grant_login_with_qr_code()
3176 .device_creation_timeout(Duration::from_secs(2))
3177 .scan(&qr_code_data);
3178 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3179
3180 let mut updates = grant.subscribe_to_progress();
3182 let mut state = grant.state.get();
3183 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3184 let updates_task = spawn(async move {
3185 let mut checkcode_tx = Some(checkcode_tx);
3186
3187 while let Some(update) = updates.next().await {
3188 match &update {
3189 GrantLoginProgress::Starting => {
3190 assert_matches!(state, GrantLoginProgress::Starting);
3191 }
3192 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3193 assert_matches!(state, GrantLoginProgress::Starting);
3194 checkcode_tx
3195 .take()
3196 .expect("The checkcode should only be forwarded once")
3197 .send(*check_code)
3198 .expect("Alice should be able to forward the checkcode");
3199 break;
3200 }
3201 _ => {
3202 panic!("Alice should abort the process");
3203 }
3204 }
3205 state = update;
3206 }
3207 });
3208
3209 let rendezvous_server_clone = rendezvous_server.clone();
3210 let bob_task = spawn(async move {
3212 request_login_with_generated_qr_code(
3213 BobBehaviour::LoginFailureInsteadOfLoginProtocol,
3214 channel,
3215 checkcode_rx,
3216 None,
3217 &rendezvous_server_clone,
3218 alice.homeserver(),
3219 None,
3220 None,
3221 )
3222 .await;
3223 });
3224
3225 assert_matches!(
3227 grant.await,
3228 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
3229 "Alice should abort the login with expected error"
3230 );
3231 updates_task.await.expect("Alice should run through all progress states");
3232 bob_task.await.expect("Bob's task should finish");
3233 }
3234
3235 #[async_test]
3236 async fn test_grant_login_with_scanned_qr_code_login_failure_instead_of_login_success() {
3237 let server = MatrixMockServer::new().await;
3238 let rendezvous_server = Arc::new(
3239 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3240 .await,
3241 );
3242 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3243
3244 let device_authorization_grant = AuthorizationGrant {
3245 verification_uri_complete: Some(VerificationUriComplete::new(
3246 "https://id.matrix.org/device/abcde".to_owned(),
3247 )),
3248 verification_uri: EndUserVerificationUrl::new(
3249 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3250 )
3251 .unwrap(),
3252 };
3253
3254 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3255 server
3256 .mock_upload_cross_signing_keys()
3257 .ok()
3258 .expect(1)
3259 .named("upload_xsigning_keys")
3260 .mount()
3261 .await;
3262 server
3263 .mock_upload_cross_signing_signatures()
3264 .ok()
3265 .expect(1)
3266 .named("upload_xsigning_signatures")
3267 .mount()
3268 .await;
3269
3270 let user_id = owned_user_id!("@alice:example.org");
3272 let device_id = owned_device_id!("ALICE_DEVICE");
3273 let alice = server
3274 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3275 .logged_in_with_oauth()
3276 .build()
3277 .await;
3278 alice
3279 .encryption()
3280 .bootstrap_cross_signing(None)
3281 .await
3282 .expect("Alice should be able to set up cross signing");
3283
3284 let oauth = alice.oauth();
3286 let grant = oauth
3287 .grant_login_with_qr_code()
3288 .device_creation_timeout(Duration::from_secs(2))
3289 .generate();
3290 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3291 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3292
3293 let mut updates = grant.subscribe_to_progress();
3295 let mut state = grant.state.get();
3296 let verification_uri_complete =
3297 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3298 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3299 let updates_task = spawn(async move {
3300 let mut qr_code_tx = Some(qr_code_tx);
3301 let mut checkcode_rx = Some(checkcode_rx);
3302
3303 while let Some(update) = updates.next().await {
3304 match &update {
3305 GrantLoginProgress::Starting => {
3306 assert_matches!(state, GrantLoginProgress::Starting);
3307 }
3308 GrantLoginProgress::EstablishingSecureChannel(
3309 GeneratedQrProgress::QrReady(qr_code_data),
3310 ) => {
3311 assert_matches!(state, GrantLoginProgress::Starting);
3312 qr_code_tx
3313 .take()
3314 .expect("The QR code should only be forwarded once")
3315 .send(qr_code_data.clone())
3316 .expect("Alice should be able to forward the QR code");
3317 }
3318 GrantLoginProgress::EstablishingSecureChannel(
3319 GeneratedQrProgress::QrScanned(checkcode_sender),
3320 ) => {
3321 assert_matches!(
3322 state,
3323 GrantLoginProgress::EstablishingSecureChannel(
3324 GeneratedQrProgress::QrReady(_)
3325 )
3326 );
3327 let checkcode = checkcode_rx
3328 .take()
3329 .expect("The checkcode should only be forwarded once")
3330 .await
3331 .expect("Alice should receive the checkcode");
3332 checkcode_sender
3333 .send(checkcode)
3334 .await
3335 .expect("Alice should be able to forward the checkcode");
3336 }
3337 GrantLoginProgress::WaitingForAuth {
3338 verification_uri,
3339 continuation_sender,
3340 } => {
3341 assert_matches!(
3342 state,
3343 GrantLoginProgress::EstablishingSecureChannel(
3344 GeneratedQrProgress::QrScanned(_)
3345 )
3346 );
3347 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3348 continuation_sender.confirm().await.expect("should be able to confirm");
3349 }
3350 _ => {
3351 panic!("Alice should abort the process");
3352 }
3353 }
3354 state = update;
3355 }
3356 });
3357
3358 let rendezvous_server_clone = rendezvous_server.clone();
3359 let bob_task = spawn(async move {
3361 request_login_with_scanned_qr_code(
3362 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
3363 qr_code_rx,
3364 checkcode_tx,
3365 None,
3366 &rendezvous_server_clone,
3367 Some(device_authorization_grant),
3368 None,
3369 )
3370 .await;
3371 });
3372
3373 assert_matches!(
3375 grant.await,
3376 Err(QRCodeGrantLoginError::LoginFailure {
3377 reason: LoginFailureReason::AuthorizationExpired
3378 }),
3379 "Alice should abort the login with expected error"
3380 );
3381 updates_task.await.expect("Alice should run through all progress states");
3382 bob_task.await.expect("Bob's task should finish");
3383 }
3384
3385 #[async_test]
3386 async fn test_grant_login_with_generated_qr_code_login_failure_instead_of_login_success() {
3387 let server = MatrixMockServer::new().await;
3388 let rendezvous_server = Arc::new(
3389 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3390 .await,
3391 );
3392 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3393
3394 let device_authorization_grant = AuthorizationGrant {
3395 verification_uri_complete: Some(VerificationUriComplete::new(
3396 "https://id.matrix.org/device/abcde".to_owned(),
3397 )),
3398 verification_uri: EndUserVerificationUrl::new(
3399 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3400 )
3401 .unwrap(),
3402 };
3403
3404 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3405 server
3406 .mock_upload_cross_signing_keys()
3407 .ok()
3408 .expect(1)
3409 .named("upload_xsigning_keys")
3410 .mount()
3411 .await;
3412 server
3413 .mock_upload_cross_signing_signatures()
3414 .ok()
3415 .expect(1)
3416 .named("upload_xsigning_signatures")
3417 .mount()
3418 .await;
3419
3420 let client = rendezvous_server.unlogged_client().await;
3423 let channel = SecureChannel::login(&client, false)
3424 .await
3425 .expect("Bob should be able to create a secure channel.");
3426 let qr_code_data = channel.qr_code_data().clone();
3427
3428 let user_id = owned_user_id!("@alice:example.org");
3430 let device_id = owned_device_id!("ALICE_DEVICE");
3431 let alice = server
3432 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3433 .logged_in_with_oauth()
3434 .build()
3435 .await;
3436 alice
3437 .encryption()
3438 .bootstrap_cross_signing(None)
3439 .await
3440 .expect("Alice should be able to set up cross signing");
3441
3442 let oauth = alice.oauth();
3444 let grant = oauth
3445 .grant_login_with_qr_code()
3446 .device_creation_timeout(Duration::from_secs(2))
3447 .scan(&qr_code_data);
3448 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3449
3450 let mut updates = grant.subscribe_to_progress();
3452 let mut state = grant.state.get();
3453 let verification_uri_complete =
3454 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3455 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3456 let updates_task = spawn(async move {
3457 let mut checkcode_tx = Some(checkcode_tx);
3458
3459 while let Some(update) = updates.next().await {
3460 match &update {
3461 GrantLoginProgress::Starting => {
3462 assert_matches!(state, GrantLoginProgress::Starting);
3463 }
3464 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3465 assert_matches!(state, GrantLoginProgress::Starting);
3466 checkcode_tx
3467 .take()
3468 .expect("The checkcode should only be forwarded once")
3469 .send(*check_code)
3470 .expect("Alice should be able to forward the checkcode");
3471 }
3472 GrantLoginProgress::WaitingForAuth {
3473 verification_uri,
3474 continuation_sender,
3475 } => {
3476 assert_matches!(
3477 state,
3478 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3479 );
3480 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3481 continuation_sender.confirm().await.expect("should be able to confirm");
3482 }
3483 _ => {
3484 panic!("Alice should abort the process");
3485 }
3486 }
3487 state = update;
3488 }
3489 });
3490
3491 let rendezvous_server_clone = rendezvous_server.clone();
3492 let bob_task = spawn(async move {
3494 request_login_with_generated_qr_code(
3495 BobBehaviour::LoginFailureInsteadOfLoginSuccess,
3496 channel,
3497 checkcode_rx,
3498 None,
3499 &rendezvous_server_clone,
3500 alice.homeserver(),
3501 Some(device_authorization_grant),
3502 None,
3503 )
3504 .await;
3505 });
3506
3507 assert_matches!(
3509 grant.await,
3510 Err(QRCodeGrantLoginError::LoginFailure {
3511 reason: LoginFailureReason::AuthorizationExpired
3512 }),
3513 "Alice should abort the login with expected error"
3514 );
3515 updates_task.await.expect("Alice should run through all progress states");
3516 bob_task.await.expect("Bob's task should finish");
3517 }
3518
3519 #[async_test]
3520 async fn test_grant_login_with_generated_qr_code_unexpected_message_instead_of_login_success() {
3521 let server = MatrixMockServer::new().await;
3522 let rendezvous_server = Arc::new(
3523 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3524 .await,
3525 );
3526 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3527
3528 let device_authorization_grant = AuthorizationGrant {
3529 verification_uri_complete: Some(VerificationUriComplete::new(
3530 "https://id.matrix.org/device/abcde".to_owned(),
3531 )),
3532 verification_uri: EndUserVerificationUrl::new(
3533 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3534 )
3535 .unwrap(),
3536 };
3537
3538 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3539 server
3540 .mock_upload_cross_signing_keys()
3541 .ok()
3542 .expect(1)
3543 .named("upload_xsigning_keys")
3544 .mount()
3545 .await;
3546 server
3547 .mock_upload_cross_signing_signatures()
3548 .ok()
3549 .expect(1)
3550 .named("upload_xsigning_signatures")
3551 .mount()
3552 .await;
3553
3554 let user_id = owned_user_id!("@alice:example.org");
3556 let device_id = owned_device_id!("ALICE_DEVICE");
3557 let alice = server
3558 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3559 .logged_in_with_oauth()
3560 .build()
3561 .await;
3562 alice
3563 .encryption()
3564 .bootstrap_cross_signing(None)
3565 .await
3566 .expect("Alice should be able to set up cross signing");
3567
3568 let oauth = alice.oauth();
3570 let grant = oauth
3571 .grant_login_with_qr_code()
3572 .device_creation_timeout(Duration::from_secs(2))
3573 .generate();
3574 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3575 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3576
3577 let mut updates = grant.subscribe_to_progress();
3579 let mut state = grant.state.get();
3580 let verification_uri_complete =
3581 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3582 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3583 let updates_task = spawn(async move {
3584 let mut qr_code_tx = Some(qr_code_tx);
3585 let mut checkcode_rx = Some(checkcode_rx);
3586
3587 while let Some(update) = updates.next().await {
3588 match &update {
3589 GrantLoginProgress::Starting => {
3590 assert_matches!(state, GrantLoginProgress::Starting);
3591 }
3592 GrantLoginProgress::EstablishingSecureChannel(
3593 GeneratedQrProgress::QrReady(qr_code_data),
3594 ) => {
3595 assert_matches!(state, GrantLoginProgress::Starting);
3596 qr_code_tx
3597 .take()
3598 .expect("The QR code should only be forwarded once")
3599 .send(qr_code_data.clone())
3600 .expect("Alice should be able to forward the QR code");
3601 }
3602 GrantLoginProgress::EstablishingSecureChannel(
3603 GeneratedQrProgress::QrScanned(checkcode_sender),
3604 ) => {
3605 assert_matches!(
3606 state,
3607 GrantLoginProgress::EstablishingSecureChannel(
3608 GeneratedQrProgress::QrReady(_)
3609 )
3610 );
3611 let checkcode = checkcode_rx
3612 .take()
3613 .expect("The checkcode should only be forwarded once")
3614 .await
3615 .expect("Alice should receive the checkcode");
3616 checkcode_sender
3617 .send(checkcode)
3618 .await
3619 .expect("Alice should be able to forward the checkcode");
3620 }
3621 GrantLoginProgress::WaitingForAuth {
3622 verification_uri,
3623 continuation_sender,
3624 } => {
3625 assert_matches!(
3626 state,
3627 GrantLoginProgress::EstablishingSecureChannel(
3628 GeneratedQrProgress::QrScanned(_)
3629 )
3630 );
3631 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3632 continuation_sender.confirm().await.expect("should be able to confirm");
3633 }
3634 _ => {
3635 panic!("Alice should abort the process");
3636 }
3637 }
3638 state = update;
3639 }
3640 });
3641
3642 let rendezvous_server_clone = rendezvous_server.clone();
3644 let bob_task = spawn(async move {
3645 request_login_with_scanned_qr_code(
3646 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3647 qr_code_rx,
3648 checkcode_tx,
3649 None,
3650 &rendezvous_server_clone,
3651 Some(device_authorization_grant),
3652 None,
3653 )
3654 .await;
3655 });
3656
3657 assert_let!(
3659 Err(QRCodeGrantLoginError::UnexpectedMessage {
3660 expected: "m.login.success",
3661 received,
3662 }) = grant.await,
3663 "Alice should abort the login with expected error variant"
3664 );
3665 assert_matches!(
3666 *received,
3667 QrAuthMessage::LoginProtocolAccepted,
3668 "Alice should abort the login with expected error message"
3669 );
3670 updates_task.await.expect("Alice should run through all progress states");
3671 bob_task.await.expect("Bob's task should finish");
3672 }
3673
3674 #[async_test]
3675 async fn test_grant_login_with_scanned_qr_code_unexpected_message_instead_of_login_success() {
3676 let server = MatrixMockServer::new().await;
3677 let rendezvous_server = Arc::new(
3678 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3679 .await,
3680 );
3681 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3682
3683 let device_authorization_grant = AuthorizationGrant {
3684 verification_uri_complete: Some(VerificationUriComplete::new(
3685 "https://id.matrix.org/device/abcde".to_owned(),
3686 )),
3687 verification_uri: EndUserVerificationUrl::new(
3688 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
3689 )
3690 .unwrap(),
3691 };
3692
3693 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3694 server
3695 .mock_upload_cross_signing_keys()
3696 .ok()
3697 .expect(1)
3698 .named("upload_xsigning_keys")
3699 .mount()
3700 .await;
3701 server
3702 .mock_upload_cross_signing_signatures()
3703 .ok()
3704 .expect(1)
3705 .named("upload_xsigning_signatures")
3706 .mount()
3707 .await;
3708
3709 let client = rendezvous_server.unlogged_client().await;
3712 let channel = SecureChannel::login(&client, false)
3713 .await
3714 .expect("Bob should be able to create a secure channel.");
3715 let qr_code_data = channel.qr_code_data().clone();
3716
3717 let user_id = owned_user_id!("@alice:example.org");
3719 let device_id = owned_device_id!("ALICE_DEVICE");
3720 let alice = server
3721 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3722 .logged_in_with_oauth()
3723 .build()
3724 .await;
3725 alice
3726 .encryption()
3727 .bootstrap_cross_signing(None)
3728 .await
3729 .expect("Alice should be able to set up cross signing");
3730
3731 let oauth = alice.oauth();
3733 let grant = oauth
3734 .grant_login_with_qr_code()
3735 .device_creation_timeout(Duration::from_secs(2))
3736 .scan(&qr_code_data);
3737 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3738
3739 let mut updates = grant.subscribe_to_progress();
3741 let mut state = grant.state.get();
3742 let verification_uri_complete =
3743 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
3744 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3745 let updates_task = spawn(async move {
3746 let mut checkcode_tx = Some(checkcode_tx);
3747
3748 while let Some(update) = updates.next().await {
3749 match &update {
3750 GrantLoginProgress::Starting => {
3751 assert_matches!(state, GrantLoginProgress::Starting);
3752 }
3753 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
3754 assert_matches!(state, GrantLoginProgress::Starting);
3755 checkcode_tx
3756 .take()
3757 .expect("The checkcode should only be forwarded once")
3758 .send(*check_code)
3759 .expect("Alice should be able to forward the checkcode");
3760 }
3761 GrantLoginProgress::WaitingForAuth {
3762 verification_uri,
3763 continuation_sender,
3764 } => {
3765 assert_matches!(
3766 state,
3767 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
3768 );
3769 assert_eq!(verification_uri.as_str(), verification_uri_complete);
3770 continuation_sender.confirm().await.expect("should be able to confirm");
3771 }
3772 _ => {
3773 panic!("Alice should abort the process");
3774 }
3775 }
3776 state = update;
3777 }
3778 });
3779
3780 let rendezvous_server_clone = rendezvous_server.clone();
3781 let bob_task = spawn(async move {
3783 request_login_with_generated_qr_code(
3784 BobBehaviour::UnexpectedMessageInsteadOfLoginSuccess,
3785 channel,
3786 checkcode_rx,
3787 None,
3788 &rendezvous_server_clone,
3789 alice.homeserver(),
3790 Some(device_authorization_grant),
3791 None,
3792 )
3793 .await;
3794 });
3795
3796 assert_let!(
3798 Err(QRCodeGrantLoginError::UnexpectedMessage {
3799 expected: "m.login.success",
3800 received,
3801 }) = grant.await,
3802 "Alice should abort the login with expected error variant"
3803 );
3804 assert_matches!(
3805 *received,
3806 QrAuthMessage::LoginProtocolAccepted,
3807 "Alice should abort the login with expected error message"
3808 );
3809 updates_task.await.expect("Alice should run through all progress states");
3810 bob_task.await.expect("Bob's task should finish");
3811 }
3812
3813 #[async_test]
3814 async fn test_grant_login_with_generated_qr_code_secure_channel_error() {
3815 let server = MatrixMockServer::new().await;
3816 let rendezvous_server = Arc::new(
3817 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3818 .await,
3819 );
3820 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3821
3822 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3823 server
3824 .mock_upload_cross_signing_keys()
3825 .ok()
3826 .expect(1)
3827 .named("upload_xsigning_keys")
3828 .mount()
3829 .await;
3830 server
3831 .mock_upload_cross_signing_signatures()
3832 .ok()
3833 .expect(1)
3834 .named("upload_xsigning_signatures")
3835 .mount()
3836 .await;
3837
3838 let user_id = owned_user_id!("@alice:example.org");
3840 let device_id = owned_device_id!("ALICE_DEVICE");
3841 let alice = server
3842 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3843 .logged_in_with_oauth()
3844 .build()
3845 .await;
3846 alice
3847 .encryption()
3848 .bootstrap_cross_signing(None)
3849 .await
3850 .expect("Alice should be able to set up cross signing");
3851
3852 let oauth = alice.oauth();
3854 let grant = oauth
3855 .grant_login_with_qr_code()
3856 .device_creation_timeout(Duration::from_secs(2))
3857 .generate();
3858 let (qr_code_tx, qr_code_rx) = oneshot::channel();
3859 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3860
3861 let mut updates = grant.subscribe_to_progress();
3863 let mut state = grant.state.get();
3864 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3865 let updates_task = spawn(async move {
3866 let mut qr_code_tx = Some(qr_code_tx);
3867 let mut checkcode_rx = Some(checkcode_rx);
3868
3869 while let Some(update) = updates.next().await {
3870 match &update {
3871 GrantLoginProgress::Starting => {
3872 assert_matches!(state, GrantLoginProgress::Starting);
3873 }
3874 GrantLoginProgress::EstablishingSecureChannel(
3875 GeneratedQrProgress::QrReady(qr_code_data),
3876 ) => {
3877 assert_matches!(state, GrantLoginProgress::Starting);
3878 qr_code_tx
3879 .take()
3880 .expect("The QR code should only be forwarded once")
3881 .send(qr_code_data.clone())
3882 .expect("Alice should be able to forward the QR code");
3883 }
3884 GrantLoginProgress::EstablishingSecureChannel(
3885 GeneratedQrProgress::QrScanned(checkcode_sender),
3886 ) => {
3887 assert_matches!(
3888 state,
3889 GrantLoginProgress::EstablishingSecureChannel(
3890 GeneratedQrProgress::QrReady(_)
3891 )
3892 );
3893 let checkcode = checkcode_rx
3894 .take()
3895 .expect("The checkcode should only be forwarded once")
3896 .await
3897 .expect("Alice should receive the checkcode");
3898 checkcode_sender
3899 .send(checkcode)
3900 .await
3901 .expect("Alice should be able to forward the checkcode");
3902 break;
3903 }
3904 _ => {
3905 panic!("Alice should abort the process");
3906 }
3907 }
3908 state = update;
3909 }
3910 });
3911
3912 let rendezvous_server_clone = rendezvous_server.clone();
3914 let bob_task = spawn(async move {
3915 request_login_with_scanned_qr_code(
3916 BobBehaviour::InvalidJsonMessage,
3917 qr_code_rx,
3918 checkcode_tx,
3919 None,
3920 &rendezvous_server_clone,
3921 None,
3922 None,
3923 )
3924 .await;
3925 });
3926
3927 assert_matches!(
3929 grant.await,
3930 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
3931 MessageDecodeError::Json(_)
3932 ))),
3933 "Alice should abort the login with a SecureChannel error"
3934 );
3935 updates_task.await.expect("Alice should run through all progress states");
3936 bob_task.await.expect("Bob's task should finish");
3937 }
3938
3939 #[async_test]
3940 async fn test_grant_login_with_scanned_qr_code_secure_channel_error() {
3941 let server = MatrixMockServer::new().await;
3942 let rendezvous_server = Arc::new(
3943 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
3944 .await,
3945 );
3946 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
3947
3948 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
3949 server
3950 .mock_upload_cross_signing_keys()
3951 .ok()
3952 .expect(1)
3953 .named("upload_xsigning_keys")
3954 .mount()
3955 .await;
3956 server
3957 .mock_upload_cross_signing_signatures()
3958 .ok()
3959 .expect(1)
3960 .named("upload_xsigning_signatures")
3961 .mount()
3962 .await;
3963
3964 let client = rendezvous_server.unlogged_client().await;
3967 let channel = SecureChannel::login(&client, false)
3968 .await
3969 .expect("Bob should be able to create a secure channel.");
3970 let qr_code_data = channel.qr_code_data().clone();
3971
3972 let user_id = owned_user_id!("@alice:example.org");
3974 let device_id = owned_device_id!("ALICE_DEVICE");
3975 let alice = server
3976 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
3977 .logged_in_with_oauth()
3978 .build()
3979 .await;
3980 alice
3981 .encryption()
3982 .bootstrap_cross_signing(None)
3983 .await
3984 .expect("Alice should be able to set up cross signing");
3985
3986 let oauth = alice.oauth();
3988 let grant = oauth
3989 .grant_login_with_qr_code()
3990 .device_creation_timeout(Duration::from_secs(2))
3991 .scan(&qr_code_data);
3992 let (checkcode_tx, checkcode_rx) = oneshot::channel();
3993
3994 let mut updates = grant.subscribe_to_progress();
3996 let mut state = grant.state.get();
3997 assert_matches!(state.clone(), GrantLoginProgress::Starting);
3998 let updates_task = spawn(async move {
3999 let mut checkcode_tx = Some(checkcode_tx);
4000
4001 while let Some(update) = updates.next().await {
4002 match &update {
4003 GrantLoginProgress::Starting => {
4004 assert_matches!(state, GrantLoginProgress::Starting);
4005 }
4006 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
4007 assert_matches!(state, GrantLoginProgress::Starting);
4008 checkcode_tx
4009 .take()
4010 .expect("The checkcode should only be forwarded once")
4011 .send(*check_code)
4012 .expect("Alice should be able to forward the checkcode");
4013 break;
4014 }
4015 _ => {
4016 panic!("Alice should abort the process");
4017 }
4018 }
4019 state = update;
4020 }
4021 });
4022
4023 let rendezvous_server_clone = rendezvous_server.clone();
4024 let bob_task = spawn(async move {
4026 request_login_with_generated_qr_code(
4027 BobBehaviour::InvalidJsonMessage,
4028 channel,
4029 checkcode_rx,
4030 None,
4031 &rendezvous_server_clone,
4032 alice.homeserver(),
4033 None,
4034 None,
4035 )
4036 .await;
4037 });
4038
4039 assert_matches!(
4041 grant.await,
4042 Err(QRCodeGrantLoginError::SecureChannel(SecureChannelError::MessageDecode(
4043 MessageDecodeError::Json(_)
4044 ))),
4045 "Alice should abort the login with a SecureChannel error"
4046 );
4047 updates_task.await.expect("Alice should run through all progress states");
4048 bob_task.await.expect("Bob's task should finish");
4049 }
4050
4051 #[async_test]
4052 async fn test_grant_login_with_generated_qr_code_cancelled_while_waiting_for_auth() {
4053 let (protocol_accepted_tx, protocol_accepted_rx) = oneshot::channel();
4054 let server = MatrixMockServer::new().await;
4055 let rendezvous_server =
4056 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
4057 .await;
4058 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
4059
4060 let device_authorization_grant = AuthorizationGrant {
4061 verification_uri_complete: Some(VerificationUriComplete::new(
4062 "https://id.matrix.org/device/abcde".to_owned(),
4063 )),
4064 verification_uri: EndUserVerificationUrl::new(
4065 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
4066 )
4067 .unwrap(),
4068 };
4069
4070 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
4071 server
4072 .mock_upload_cross_signing_keys()
4073 .ok()
4074 .expect(1)
4075 .named("upload_xsigning_keys")
4076 .mount()
4077 .await;
4078 server
4079 .mock_upload_cross_signing_signatures()
4080 .ok()
4081 .expect(1)
4082 .named("upload_xsigning_signatures")
4083 .mount()
4084 .await;
4085
4086 let user_id = owned_user_id!("@alice:example.org");
4088 let device_id = owned_device_id!("ALICE_DEVICE");
4089 let alice = server
4090 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
4091 .logged_in_with_oauth()
4092 .build()
4093 .await;
4094 alice
4095 .encryption()
4096 .bootstrap_cross_signing(None)
4097 .await
4098 .expect("Alice should be able to set up cross signing");
4099
4100 let oauth = alice.oauth();
4102 let grant = oauth
4103 .grant_login_with_qr_code()
4104 .device_creation_timeout(Duration::from_secs(2))
4105 .generate();
4106 let (qr_code_tx, qr_code_rx) = oneshot::channel();
4107 let (checkcode_tx, checkcode_rx) = oneshot::channel();
4108
4109 let mut updates = grant.subscribe_to_progress();
4111 let mut state = grant.state.get();
4112 let verification_uri_complete =
4113 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
4114 assert_matches!(state.clone(), GrantLoginProgress::Starting);
4115 let updates_task = spawn(async move {
4116 let mut qr_code_tx = Some(qr_code_tx);
4117 let mut checkcode_rx = Some(checkcode_rx);
4118
4119 while let Some(update) = updates.next().await {
4120 match &update {
4121 GrantLoginProgress::Starting => {
4122 assert_matches!(state, GrantLoginProgress::Starting);
4123 }
4124 GrantLoginProgress::EstablishingSecureChannel(
4125 GeneratedQrProgress::QrReady(qr_code_data),
4126 ) => {
4127 assert_matches!(state, GrantLoginProgress::Starting);
4128 qr_code_tx
4129 .take()
4130 .expect("The QR code should only be forwarded once")
4131 .send(qr_code_data.clone())
4132 .expect("Alice should be able to forward the QR code");
4133 }
4134 GrantLoginProgress::EstablishingSecureChannel(
4135 GeneratedQrProgress::QrScanned(checkcode_sender),
4136 ) => {
4137 assert_matches!(
4138 state,
4139 GrantLoginProgress::EstablishingSecureChannel(
4140 GeneratedQrProgress::QrReady(_)
4141 )
4142 );
4143 let checkcode = checkcode_rx
4144 .take()
4145 .expect("The checkcode should only be forwarded once")
4146 .await
4147 .expect("Alice should receive the checkcode");
4148 checkcode_sender
4149 .send(checkcode)
4150 .await
4151 .expect("Alice should be able to forward the checkcode");
4152 }
4153 GrantLoginProgress::WaitingForAuth {
4154 verification_uri,
4155 continuation_sender,
4156 } => {
4157 assert_matches!(
4158 state,
4159 GrantLoginProgress::EstablishingSecureChannel(
4160 GeneratedQrProgress::QrScanned(_)
4161 )
4162 );
4163 assert_eq!(verification_uri.as_str(), verification_uri_complete);
4164 protocol_accepted_rx
4166 .await
4167 .expect("Bob should signal that the protocol was accepted");
4168 continuation_sender.cancel().await.expect("should be able to cancel");
4170 break;
4171 }
4172 _ => {
4173 panic!("Alice should abort the process after being cancelled");
4174 }
4175 }
4176 state = update;
4177 }
4178 });
4179
4180 let bob_task = spawn(async move {
4182 request_login_with_scanned_qr_code(
4183 BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx),
4184 qr_code_rx,
4185 checkcode_tx,
4186 Some(server),
4187 &rendezvous_server,
4188 Some(device_authorization_grant),
4189 None,
4190 )
4191 .await;
4192 });
4193
4194 assert_matches!(
4196 grant.await,
4197 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
4198 "Alice should abort the login with expected error"
4199 );
4200 updates_task.await.expect("Alice should run through all progress states");
4201 bob_task.await.expect("Bob's task should finish");
4202 }
4203
4204 #[async_test]
4205 async fn test_grant_login_with_scanned_qr_code_cancelled_while_waiting_for_auth() {
4206 let (protocol_accepted_tx, protocol_accepted_rx) = oneshot::channel();
4207 let server = MatrixMockServer::new().await;
4208 let rendezvous_server =
4209 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
4210 .await;
4211 debug!("Set up rendezvous server mock at {}", rendezvous_server.rendezvous_url);
4212
4213 let device_authorization_grant = AuthorizationGrant {
4214 verification_uri_complete: Some(VerificationUriComplete::new(
4215 "https://id.matrix.org/device/abcde".to_owned(),
4216 )),
4217 verification_uri: EndUserVerificationUrl::new(
4218 "https://id.matrix.org/device/abcde?code=ABCDE".to_owned(),
4219 )
4220 .unwrap(),
4221 };
4222
4223 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
4224 server
4225 .mock_upload_cross_signing_keys()
4226 .ok()
4227 .expect(1)
4228 .named("upload_xsigning_keys")
4229 .mount()
4230 .await;
4231 server
4232 .mock_upload_cross_signing_signatures()
4233 .ok()
4234 .expect(1)
4235 .named("upload_xsigning_signatures")
4236 .mount()
4237 .await;
4238
4239 let client = rendezvous_server.unlogged_client().await;
4242 let channel = SecureChannel::login(&client, false)
4243 .await
4244 .expect("Bob should be able to create a secure channel.");
4245 let qr_code_data = channel.qr_code_data().clone();
4246
4247 let user_id = owned_user_id!("@alice:example.org");
4249 let device_id = owned_device_id!("ALICE_DEVICE");
4250 let alice = server
4251 .client_builder_for_crypto_end_to_end(&user_id, &device_id)
4252 .logged_in_with_oauth()
4253 .build()
4254 .await;
4255 alice
4256 .encryption()
4257 .bootstrap_cross_signing(None)
4258 .await
4259 .expect("Alice should be able to set up cross signing");
4260
4261 let oauth = alice.oauth();
4263 let grant = oauth
4264 .grant_login_with_qr_code()
4265 .device_creation_timeout(Duration::from_secs(2))
4266 .scan(&qr_code_data);
4267 let (checkcode_tx, checkcode_rx) = oneshot::channel();
4268
4269 let mut updates = grant.subscribe_to_progress();
4271 let mut state = grant.state.get();
4272 let verification_uri_complete =
4273 device_authorization_grant.clone().verification_uri_complete.unwrap().into_secret();
4274 assert_matches!(state.clone(), GrantLoginProgress::Starting);
4275 let updates_task = spawn(async move {
4276 let mut checkcode_tx = Some(checkcode_tx);
4277
4278 while let Some(update) = updates.next().await {
4279 match &update {
4280 GrantLoginProgress::Starting => {
4281 assert_matches!(state, GrantLoginProgress::Starting);
4282 }
4283 GrantLoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
4284 assert_matches!(state, GrantLoginProgress::Starting);
4285 checkcode_tx
4286 .take()
4287 .expect("The checkcode should only be forwarded once")
4288 .send(*check_code)
4289 .expect("Alice should be able to forward the checkcode");
4290 }
4291 GrantLoginProgress::WaitingForAuth {
4292 verification_uri,
4293 continuation_sender,
4294 } => {
4295 assert_matches!(
4296 state,
4297 GrantLoginProgress::EstablishingSecureChannel(QrProgress { .. })
4298 );
4299 assert_eq!(verification_uri.as_str(), verification_uri_complete);
4300 protocol_accepted_rx
4302 .await
4303 .expect("Bob should signal that the protocol was accepted");
4304 continuation_sender.cancel().await.expect("should be able to cancel");
4306 break;
4307 }
4308 _ => {
4309 panic!("Alice should abort the process after being cancelled");
4310 }
4311 }
4312 state = update;
4313 }
4314 });
4315
4316 let bob_task = spawn(async move {
4318 request_login_with_generated_qr_code(
4319 BobBehaviour::CancelledWhileWaitingForAuth(protocol_accepted_tx),
4320 channel,
4321 checkcode_rx,
4322 Some(server),
4323 &rendezvous_server,
4324 alice.homeserver(),
4325 Some(device_authorization_grant),
4326 None,
4327 )
4328 .await;
4329 });
4330
4331 assert_matches!(
4333 grant.await,
4334 Err(QRCodeGrantLoginError::LoginFailure { reason: LoginFailureReason::UserCancelled }),
4335 "Alice should abort the login with expected error"
4336 );
4337 updates_task.await.expect("Alice should run through all progress states");
4338 bob_task.await.expect("Bob's task should finish");
4339 }
4340}