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