1use std::future::IntoFuture;
16
17use eyeball::SharedObservable;
18use futures_core::Stream;
19use matrix_sdk_base::{
20 SessionMeta, boxed_into_future,
21 crypto::types::qr_login::{QrCodeData, QrCodeIntent},
22 store::RoomLoadSettings,
23};
24use oauth2::{DeviceCodeErrorResponseType, StandardDeviceAuthorizationResponse};
25use ruma::{
26 OwnedDeviceId,
27 api::client::discovery::get_authorization_server_metadata::v1::AuthorizationServerMetadata,
28};
29use tracing::trace;
30use url::Url;
31use vodozemac::Curve25519PublicKey;
32#[cfg(doc)]
33use vodozemac::ecies::CheckCode;
34
35use super::{
36 DeviceAuthorizationOAuthError, QRCodeLoginError, SecureChannelError,
37 messages::{LoginFailureReason, QrAuthMessage},
38 secure_channel::{EstablishedSecureChannel, SecureChannel},
39};
40use crate::{
41 Client,
42 authentication::oauth::{
43 ClientRegistrationData, OAuth, OAuthError,
44 qrcode::{
45 CheckCodeSender, GeneratedQrProgress, LoginProtocolType, QrProgress,
46 messages::LoginProtocolsMessage, secure_channel::ChannelVariant,
47 },
48 },
49};
50
51async fn send_unexpected_message_error(
52 channel: &mut EstablishedSecureChannel,
53) -> Result<(), SecureChannelError> {
54 channel
55 .send_json(QrAuthMessage::LoginFailure {
56 reason: LoginFailureReason::UnexpectedMessageReceived,
57 homeserver: None,
58 })
59 .await
60}
61
62async fn receive_login_protocols(
67 channel: &mut EstablishedSecureChannel,
68) -> Result<Url, QRCodeLoginError> {
69 let message = channel.receive_json().await?;
71
72 let login_protocols = match channel.channel_variant() {
74 ChannelVariant::Msc4108 => match message {
75 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
76 protocols,
77 homeserver,
78 }) => Ok((protocols, homeserver)),
79 message => Err(message),
80 },
81 #[cfg(feature = "unstable-msc4388")]
82 ChannelVariant::Msc4388 => match message {
83 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
84 protocols,
85 base_url,
86 }) => Ok((protocols, base_url)),
87 message => Err(message),
88 },
89 };
90
91 let (protocols, homeserver) = match login_protocols {
92 Ok(login_protocols) => login_protocols,
93 Err(message) => {
94 send_unexpected_message_error(channel).await?;
95
96 return Err(QRCodeLoginError::UnexpectedMessage {
97 expected: "m.login.protocols",
98 received: Box::new(message),
99 });
100 }
101 };
102
103 if !protocols.contains(&LoginProtocolType::DeviceAuthorizationGrant) {
107 channel
108 .send_json(QrAuthMessage::LoginFailure {
109 reason: LoginFailureReason::UnsupportedProtocol,
110 homeserver: None,
111 })
112 .await?;
113
114 return Err(QRCodeLoginError::LoginFailure {
115 reason: LoginFailureReason::UnsupportedProtocol,
116 homeserver: None,
117 });
118 }
119
120 Ok(homeserver)
121}
122
123async fn finish_login<Q>(
124 client: &Client,
125 mut channel: EstablishedSecureChannel,
126 registration_data: Option<&ClientRegistrationData>,
127 state: SharedObservable<LoginProgress<Q>>,
128) -> Result<(), QRCodeLoginError> {
129 let oauth = client.oauth();
130
131 trace!("Registering the client with the OAuth 2.0 authorization server.");
133 let server_metadata = register_client(&oauth, registration_data).await?;
134
135 let account = vodozemac::olm::Account::new();
138 let public_key = account.identity_keys().curve25519;
139 let device_id = public_key;
140
141 trace!("Requesting device authorization.");
145 let auth_grant_response =
146 request_device_authorization(&oauth, &server_metadata, device_id).await?;
147
148 trace!("Letting the existing device know about the device authorization grant.");
151 let message = QrAuthMessage::authorization_grant_login_protocol(
152 (&auth_grant_response).into(),
153 device_id,
154 channel.channel_variant(),
155 );
156 channel.send_json(&message).await?;
157
158 match channel.receive_json().await? {
160 QrAuthMessage::LoginProtocolAccepted => (),
161 QrAuthMessage::LoginFailure { reason, homeserver } => {
162 return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
163 }
164 message => {
165 send_unexpected_message_error(&mut channel).await?;
166
167 return Err(QRCodeLoginError::UnexpectedMessage {
168 expected: "m.login.protocol_accepted",
169 received: Box::new(message),
170 });
171 }
172 }
173
174 let user_code = auth_grant_response.user_code();
178 state.set(LoginProgress::WaitingForToken { user_code: user_code.secret().to_owned() });
179
180 trace!("Waiting for the OAuth 2.0 authorization server to give us the access token.");
183 if let Err(e) = wait_for_tokens(&oauth, &server_metadata, &auth_grant_response).await {
184 if let Some(e) = e.as_request_token_error() {
187 match e {
188 DeviceCodeErrorResponseType::AccessDenied => {
189 channel.send_json(QrAuthMessage::LoginDeclined).await?;
190 }
191 DeviceCodeErrorResponseType::ExpiredToken => {
192 channel
193 .send_json(QrAuthMessage::LoginFailure {
194 reason: LoginFailureReason::AuthorizationExpired,
195 homeserver: None,
196 })
197 .await?;
198 }
199 _ => (),
200 }
201 }
202
203 return Err(e.into());
204 }
205
206 trace!("Discovering our own user id.");
212 let whoami_response = client.whoami().await.map_err(QRCodeLoginError::UserIdDiscovery)?;
213 client
214 .activate(
215 SessionMeta {
216 user_id: whoami_response.user_id,
217 device_id: OwnedDeviceId::from(device_id.to_base64()),
218 },
219 RoomLoadSettings::default(),
220 Some(account),
221 )
222 .await
223 .map_err(QRCodeLoginError::SessionTokens)?;
224
225 client.oauth().enable_cross_process_lock().await?;
226
227 state.set(LoginProgress::SyncingSecrets);
228
229 trace!("Telling the existing device that we successfully logged in.");
231 let message = QrAuthMessage::LoginSuccess;
232 channel.send_json(&message).await?;
233
234 trace!("Waiting for the secrets bundle.");
237 let bundle = match channel.receive_json().await? {
238 QrAuthMessage::LoginSecrets(bundle) => bundle,
239 QrAuthMessage::LoginFailure { reason, homeserver } => {
240 return Err(QRCodeLoginError::LoginFailure { reason, homeserver });
241 }
242 message => {
243 send_unexpected_message_error(&mut channel).await?;
244
245 return Err(QRCodeLoginError::UnexpectedMessage {
246 expected: "m.login.secrets",
247 received: Box::new(message),
248 });
249 }
250 };
251
252 client.encryption().import_secrets_bundle_impl(&bundle).await?;
255
256 client
259 .encryption()
260 .ensure_device_keys_upload()
261 .await
262 .map_err(QRCodeLoginError::DeviceKeyUpload)?;
263
264 client.encryption().spawn_initialization_task(None).await;
269 client.encryption().wait_for_e2ee_initialization_tasks().await;
270
271 trace!("successfully logged in and enabled E2EE.");
272
273 state.set(LoginProgress::Done);
275
276 Ok(())
278}
279
280async fn register_client(
284 oauth: &OAuth,
285 registration_data: Option<&ClientRegistrationData>,
286) -> Result<AuthorizationServerMetadata, DeviceAuthorizationOAuthError> {
287 let server_metadata = oauth.server_metadata().await.map_err(OAuthError::from)?;
288 oauth.use_registration_data(&server_metadata, registration_data).await?;
289
290 Ok(server_metadata)
291}
292
293async fn request_device_authorization(
294 oauth: &OAuth,
295 server_metadata: &AuthorizationServerMetadata,
296 device_id: Curve25519PublicKey,
297) -> Result<StandardDeviceAuthorizationResponse, DeviceAuthorizationOAuthError> {
298 let response = oauth
299 .request_device_authorization(server_metadata, Some(device_id.to_base64().into()))
300 .await?;
301 Ok(response)
302}
303
304async fn wait_for_tokens(
305 oauth: &OAuth,
306 server_metadata: &AuthorizationServerMetadata,
307 auth_response: &StandardDeviceAuthorizationResponse,
308) -> Result<(), DeviceAuthorizationOAuthError> {
309 oauth.exchange_device_code(server_metadata, auth_response).await?;
310 Ok(())
311}
312
313#[derive(Clone, Debug, Default)]
315pub enum LoginProgress<Q> {
316 #[default]
318 Starting,
319 EstablishingSecureChannel(Q),
322 WaitingForToken {
326 user_code: String,
330 },
331 SyncingSecrets,
333 Done,
335}
336
337#[derive(Debug)]
340pub struct LoginWithQrCode {
341 client: Client,
342 registration_data: Option<ClientRegistrationData>,
343 qr_code_data: QrCodeData,
344 state: SharedObservable<LoginProgress<QrProgress>>,
345}
346
347impl LoginWithQrCode {
348 pub fn subscribe_to_progress(&self) -> impl Stream<Item = LoginProgress<QrProgress>> + use<> {
354 self.state.subscribe()
355 }
356}
357
358impl IntoFuture for LoginWithQrCode {
359 type Output = Result<(), QRCodeLoginError>;
360 boxed_into_future!();
361
362 fn into_future(self) -> Self::IntoFuture {
363 Box::pin(async move {
364 trace!("Trying to establish the secure channel");
376
377 #[cfg_attr(not(feature = "unstable-msc4388"), allow(unused_mut))]
378 let mut channel = self.establish_secure_channel().await?;
379
380 trace!("Established the secure channel.");
381
382 let check_code = channel.check_code().to_owned();
387 self.state.set(LoginProgress::EstablishingSecureChannel(QrProgress { check_code }));
388
389 match channel.channel_variant() {
396 ChannelVariant::Msc4108 => {}
400 #[cfg(feature = "unstable-msc4388")]
405 ChannelVariant::Msc4388 => {
406 let base_url = receive_login_protocols(&mut channel).await?;
407
408 if self.client.homeserver() != base_url {
411 self.client
412 .switch_homeserver_and_re_resolve_well_known(base_url)
413 .await
414 .map_err(QRCodeLoginError::ServerReset)?;
415 }
416 }
417 }
418
419 finish_login(&self.client, channel, self.registration_data.as_ref(), self.state).await
423 })
424 }
425}
426
427impl LoginWithQrCode {
428 pub(crate) fn new(
429 client: &Client,
430 qr_code_data: &QrCodeData,
431 registration_data: Option<&ClientRegistrationData>,
432 ) -> LoginWithQrCode {
433 LoginWithQrCode {
434 client: client.clone(),
435 registration_data: registration_data.cloned(),
436 qr_code_data: qr_code_data.clone(),
437 state: Default::default(),
438 }
439 }
440
441 async fn establish_secure_channel(
442 &self,
443 ) -> Result<EstablishedSecureChannel, SecureChannelError> {
444 let http_client = self.client.inner.http_client.inner.clone();
445
446 let channel = EstablishedSecureChannel::from_qr_code(
447 http_client,
448 &self.qr_code_data,
449 QrCodeIntent::Login,
450 )
451 .await?;
452
453 Ok(channel)
454 }
455}
456
457#[derive(Debug)]
460pub struct LoginWithGeneratedQrCode {
461 client: Client,
462 registration_data: Option<ClientRegistrationData>,
463 state: SharedObservable<LoginProgress<GeneratedQrProgress>>,
464 msc_4388_support: bool,
465}
466
467impl LoginWithGeneratedQrCode {
468 pub fn subscribe_to_progress(
473 &self,
474 ) -> impl Stream<Item = LoginProgress<GeneratedQrProgress>> + use<> {
475 self.state.subscribe()
476 }
477
478 #[cfg(feature = "unstable-msc4388")]
482 pub fn with_msc4388_support(&mut self) -> &mut Self {
483 self.msc_4388_support = true;
484 self
485 }
486}
487
488impl IntoFuture for LoginWithGeneratedQrCode {
489 type Output = Result<(), QRCodeLoginError>;
490 boxed_into_future!();
491
492 fn into_future(self) -> Self::IntoFuture {
493 Box::pin(async move {
494 trace!("Trying to establish the secure channel");
498
499 let mut channel = self.establish_secure_channel().await?;
500
501 trace!("Established the secure channel.");
502
503 let homeserver = receive_login_protocols(&mut channel).await?;
509
510 if self.client.homeserver() != homeserver {
513 self.client
514 .switch_homeserver_and_re_resolve_well_known(homeserver)
515 .await
516 .map_err(QRCodeLoginError::ServerReset)?;
517 }
518
519 finish_login(&self.client, channel, self.registration_data.as_ref(), self.state).await
523 })
524 }
525}
526
527impl LoginWithGeneratedQrCode {
528 pub(crate) fn new(client: &Client, registration_data: Option<&ClientRegistrationData>) -> Self {
529 Self {
530 client: client.clone(),
531 registration_data: registration_data.cloned(),
532 state: Default::default(),
533 msc_4388_support: false,
534 }
535 }
536
537 async fn establish_secure_channel(
538 &self,
539 ) -> Result<EstablishedSecureChannel, SecureChannelError> {
540 let secure_channel = SecureChannel::login(&self.client, self.msc_4388_support).await?;
545
546 let qr_code_data = secure_channel.qr_code_data().clone();
551 trace!("Generated QR code.");
552 self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(
553 qr_code_data,
554 )));
555
556 let channel = secure_channel.connect().await?;
562
563 trace!("Waiting for checkcode.");
569 let (tx, rx) = tokio::sync::oneshot::channel();
570 self.state.set(LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
571 CheckCodeSender::new(tx),
572 )));
573
574 let check_code = rx.await.map_err(|_| SecureChannelError::CannotReceiveCheckCode)?;
579 trace!("Received check code.");
580 channel.confirm(check_code)
581 }
582}
583
584#[cfg(all(test, not(target_family = "wasm")))]
585mod test {
586 use std::{assert_matches, time::Duration};
587
588 use futures_util::StreamExt;
589 use matrix_sdk_base::{
590 CancellableIntoFutureExt,
591 crypto::types::{
592 SecretsBundle,
593 qr_login::{Msc4108IntentData, QrCodeIntentData},
594 },
595 };
596 use matrix_sdk_common::executor::spawn;
597 use matrix_sdk_test::async_test;
598 use serde_json::json;
599 use strass::assert_let;
600 use url::Url;
601
602 use super::*;
603 use crate::{
604 authentication::oauth::qrcode::{
605 messages::{LoginProtocolType, LoginProtocolsMessage},
606 secure_channel::{ChannelVariant, SecureChannel, test::MockedRendezvousServer},
607 },
608 config::RequestConfig,
609 test_utils::{client::oauth::mock_client_metadata, mocks::MatrixMockServer},
610 };
611
612 enum AliceBehaviour {
613 HappyPath,
614 DeclinedProtocol,
615 UnexpectedMessage,
616 UnexpectedMessageInsteadOfSecrets,
617 RefuseSecrets,
618 LetSessionExpire,
619 NoProtocols,
621 }
622
623 #[derive(Clone, Copy)]
624 enum BobBehaviour {
625 HappyPath,
626 CancelWhileWaitingForToken,
627 }
628
629 enum TokenResponse {
631 Ok,
632 AccessDenied,
633 ExpiredToken,
634 }
635
636 fn secrets_bundle() -> SecretsBundle {
637 let json = json!({
638 "cross_signing": {
639 "master_key": "rTtSv67XGS6k/rg6/yTG/m573cyFTPFRqluFhQY+hSw",
640 "self_signing_key": "4jbPt7jh5D2iyM4U+3IDa+WthgJB87IQN1ATdkau+xk",
641 "user_signing_key": "YkFKtkjcsTxF6UAzIIG/l6Nog/G2RigCRfWj3cjNWeM",
642 },
643 });
644
645 serde_json::from_value(json).expect("We should be able to deserialize a secrets bundle")
646 }
647
648 async fn receive_login_outcome(
653 channel: &mut EstablishedSecureChannel,
654 token_response: TokenResponse,
655 ) -> bool {
656 let message: QrAuthMessage = channel
657 .receive_json()
658 .await
659 .expect("Alice should be able to receive the login outcome from Bob");
660
661 match token_response {
662 TokenResponse::Ok => {
663 assert_let!(QrAuthMessage::LoginSuccess = message);
664 true
665 }
666 TokenResponse::AccessDenied => {
667 assert_let!(QrAuthMessage::LoginDeclined = message);
668 false
669 }
670 TokenResponse::ExpiredToken => {
671 assert_matches!(
672 message,
673 QrAuthMessage::LoginFailure {
674 reason: LoginFailureReason::AuthorizationExpired,
675 homeserver: None
676 }
677 );
678 false
679 }
680 }
681 }
682
683 async fn receive_unexpected_message_error(channel: &mut EstablishedSecureChannel) {
685 let message: QrAuthMessage = channel
686 .receive_json()
687 .await
688 .expect("Alice should receive the `m.login.failure` message from Bob");
689 assert_matches!(
690 message,
691 QrAuthMessage::LoginFailure {
692 reason: LoginFailureReason::UnexpectedMessageReceived,
693 homeserver: None
694 }
695 );
696 }
697
698 async fn grant_login(
701 alice: SecureChannel,
702 homeserver: Url,
703 check_code_receiver: tokio::sync::oneshot::Receiver<u8>,
704 behaviour: AliceBehaviour,
705 token_response: TokenResponse,
706 msc_4388: bool,
707 ) {
708 let alice = alice.connect().await.expect("Alice should be able to connect the channel");
709
710 let check_code =
711 check_code_receiver.await.expect("We should receive the check code from bob");
712
713 let mut alice =
714 alice.confirm(check_code).expect("Alice should be able to confirm the secure channel");
715
716 if msc_4388 {
717 let protocols = match behaviour {
721 AliceBehaviour::NoProtocols => vec![],
722 _ => vec![LoginProtocolType::DeviceAuthorizationGrant],
723 };
724 let message = QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
725 protocols,
726 base_url: homeserver,
727 });
728 alice.send_json(message).await.unwrap();
729 }
730
731 if matches!(behaviour, AliceBehaviour::NoProtocols) {
732 let message: QrAuthMessage = alice
735 .receive_json()
736 .await
737 .expect("Alice should receive the `m.login.failure` message from Bob");
738 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
739 assert_eq!(reason, LoginFailureReason::UnsupportedProtocol);
740
741 return;
742 }
743
744 let message = alice
745 .receive_json()
746 .await
747 .expect("Alice should be able to receive the initial message from Bob");
748
749 assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
750 assert_eq!(protocol.protocol(), LoginProtocolType::DeviceAuthorizationGrant);
751
752 let message = match behaviour {
753 AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
754 reason: LoginFailureReason::UnsupportedProtocol,
755 homeserver: None,
756 },
757 AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
758 _ => QrAuthMessage::LoginProtocolAccepted,
759 };
760
761 alice.send_json(message).await.unwrap();
762
763 match behaviour {
764 AliceBehaviour::DeclinedProtocol => return,
766 AliceBehaviour::UnexpectedMessage => {
767 receive_unexpected_message_error(&mut alice).await;
768 return;
769 }
770 _ => (),
771 }
772
773 if !receive_login_outcome(&mut alice, token_response).await {
774 return;
775 }
776
777 let message = match behaviour {
778 AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
779 AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
780 reason: LoginFailureReason::DeviceNotFound,
781 homeserver: None,
782 },
783 _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
784 };
785
786 alice.send_json(message).await.unwrap();
787
788 if matches!(behaviour, AliceBehaviour::UnexpectedMessageInsteadOfSecrets) {
789 receive_unexpected_message_error(&mut alice).await;
790 }
791 }
792
793 async fn test_qr_login(msc_4388: bool) {
794 let server = MatrixMockServer::new().await;
795 let rendezvous_server =
796 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
797 .await;
798 let (sender, receiver) = tokio::sync::oneshot::channel();
799
800 let oauth_server = server.oauth();
801 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
802 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
803 oauth_server
804 .mock_device_authorization()
805 .ok()
806 .expect(1)
807 .named("device_authorization")
808 .mount()
809 .await;
810 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
811
812 server.mock_versions().ok().expect(1..).named("versions").mount().await;
813 server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
814 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
815 server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
816
817 let client = rendezvous_server.unlogged_client().await;
818 let alice = SecureChannel::reciprocate(&client, msc_4388)
819 .await
820 .expect("Alice should be able to create a secure channel.");
821
822 assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
823
824 let server_name = if msc_4388 {
825 assert_let!(
826 QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
827 );
828
829 base_url.to_string()
830 } else {
831 assert_let!(
832 QrCodeIntentData::Msc4108 {
833 data: Msc4108IntentData::Reciprocate { server_name },
834 ..
835 } = &alice.qr_code_data().intent_data()
836 );
837
838 server_name.to_owned()
839 };
840
841 let bob = Client::builder()
842 .server_name_or_homeserver_url(server_name)
843 .request_config(RequestConfig::new().disable_retry())
844 .build()
845 .await
846 .expect("We should be able to build the Client object from the URL in the QR code");
847
848 let qr_code = alice.qr_code_data().clone();
849
850 let oauth = bob.oauth();
851 let registration_data = mock_client_metadata().into();
852 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
853 let mut updates = login_bob.subscribe_to_progress();
854
855 let updates_task = spawn(async move {
856 let mut sender = Some(sender);
857
858 while let Some(update) = updates.next().await {
859 match update {
860 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
861 sender
862 .take()
863 .expect("The establishing secure channel update should be received only once")
864 .send(check_code)
865 .expect("Bob should be able to send the check code to Alice");
866 }
867 LoginProgress::Done => break,
868 _ => (),
869 }
870 }
871 });
872 let alice_homeserver = rendezvous_server.homeserver_url.clone();
873 let alice_task = spawn(async move {
874 grant_login(
875 alice,
876 alice_homeserver,
877 receiver,
878 AliceBehaviour::HappyPath,
879 TokenResponse::Ok,
880 msc_4388,
881 )
882 .await
883 });
884
885 login_bob.await.expect("Bob should be able to login");
887 alice_task.await.expect("Alice should have completed it's task successfully");
888 updates_task.await.unwrap();
889
890 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
891 let own_identity =
892 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
893
894 assert!(own_identity.is_verified());
895 }
896
897 #[async_test]
898 async fn test_qr_login_msc_4108() {
899 test_qr_login(false).await;
900 }
901
902 #[async_test]
903 #[cfg(feature = "unstable-msc4388")]
904 async fn test_qr_login_msc_4388() {
905 test_qr_login(true).await;
906 }
907
908 #[async_test]
912 #[cfg(feature = "unstable-msc4388")]
913 async fn test_qr_login_with_homeserver_swap_msc_4388() {
914 let initial_server = MatrixMockServer::new().await;
915 let rendezvous_server = MockedRendezvousServer::new(
916 initial_server.server(),
917 "abcdEFG12345",
918 Duration::MAX,
919 true,
920 )
921 .await;
922 let (sender, receiver) = tokio::sync::oneshot::channel();
923
924 let login_server = MatrixMockServer::new().await;
925 let oauth_server = login_server.oauth();
926 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
927 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
928 oauth_server
929 .mock_device_authorization()
930 .ok()
931 .expect(1)
932 .named("device_authorization")
933 .mount()
934 .await;
935 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
936
937 initial_server.mock_versions().ok().named("versions initial server").mount().await;
938 initial_server
939 .mock_well_known()
940 .ok()
941 .expect(1)
942 .named("well_known-initial-server")
943 .mount()
944 .await;
945
946 login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
947 login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
948 login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
949 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
950 login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
951
952 let client = rendezvous_server.unlogged_client().await;
954 let alice = SecureChannel::reciprocate(&client, true)
955 .await
956 .expect("Alice should be able to create a secure channel.");
957
958 assert_let!(
959 QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
960 );
961 let initial_server_url: Url = initial_server.server().uri().parse().unwrap();
962 assert_eq!(base_url.as_url(), &initial_server_url);
963
964 let bob = Client::builder()
967 .server_name_or_homeserver_url(base_url.as_str())
968 .request_config(RequestConfig::new().disable_retry())
969 .build()
970 .await
971 .expect("We should be able to build the Client object from the URL in the QR code");
972 assert_eq!(bob.homeserver(), initial_server_url);
973
974 let login_server_url: Url = login_server.server().uri().parse().unwrap();
975 assert_ne!(initial_server_url, login_server_url);
976
977 let qr_code = alice.qr_code_data().clone();
978
979 let oauth = bob.oauth();
980 let registration_data = mock_client_metadata().into();
981 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
982 let mut updates = login_bob.subscribe_to_progress();
983
984 let updates_task = spawn(async move {
985 let mut sender = Some(sender);
986
987 while let Some(update) = updates.next().await {
988 match update {
989 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
990 sender
991 .take()
992 .expect("The establishing secure channel update should be received only once")
993 .send(check_code)
994 .expect("Bob should be able to send the check code to Alice");
995 }
996 LoginProgress::Done => break,
997 _ => (),
998 }
999 }
1000 });
1001
1002 let alice_homeserver = login_server_url.clone();
1005 let alice_task = spawn(async move {
1006 grant_login(
1007 alice,
1008 alice_homeserver,
1009 receiver,
1010 AliceBehaviour::HappyPath,
1011 TokenResponse::Ok,
1012 true,
1013 )
1014 .await
1015 });
1016
1017 login_bob.await.expect("Bob should be able to login");
1019 alice_task.await.expect("Alice should have completed it's task successfully");
1020 updates_task.await.unwrap();
1021
1022 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1023 let own_identity =
1024 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1025
1026 assert!(own_identity.is_verified());
1027
1028 assert_eq!(bob.homeserver(), login_server_url);
1030 }
1031
1032 async fn grant_login_with_generated_qr(
1033 alice: &Client,
1034 qr_receiver: tokio::sync::oneshot::Receiver<QrCodeData>,
1035 cctx_receiver: tokio::sync::oneshot::Receiver<CheckCodeSender>,
1036 behaviour: AliceBehaviour,
1037 token_response: TokenResponse,
1038 ) {
1039 let qr_code_data = qr_receiver.await.expect("Alice should receive the QR code");
1040
1041 let mut channel = EstablishedSecureChannel::from_qr_code(
1042 alice.inner.http_client.inner.clone(),
1043 &qr_code_data,
1044 QrCodeIntent::Reciprocate,
1045 )
1046 .await
1047 .expect("Alice should be able to establish the secure channel");
1048
1049 trace!("Established the secure channel.");
1050
1051 let check_code = channel.check_code();
1054
1055 let check_code_sender =
1056 cctx_receiver.await.expect("Alice should receive the CheckCodeSender");
1057
1058 check_code_sender
1059 .send(check_code)
1060 .await
1061 .expect("Alice should be able to send the check code to Bob");
1062
1063 let protocols = match behaviour {
1065 AliceBehaviour::NoProtocols => vec![],
1066 _ => vec![LoginProtocolType::DeviceAuthorizationGrant],
1067 };
1068 let message = match channel.channel_variant() {
1069 ChannelVariant::Msc4108 => {
1070 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4108 {
1071 protocols,
1072 homeserver: alice.homeserver(),
1073 })
1074 }
1075 #[cfg(feature = "unstable-msc4388")]
1076 ChannelVariant::Msc4388 => {
1077 QrAuthMessage::LoginProtocols(LoginProtocolsMessage::Msc4388 {
1078 protocols,
1079 base_url: alice.homeserver(),
1080 })
1081 }
1082 };
1083
1084 channel
1085 .send_json(message)
1086 .await
1087 .expect("Alice should be able to send the `m.login.protocols` message to Bob");
1088
1089 if matches!(behaviour, AliceBehaviour::NoProtocols) {
1090 let message: QrAuthMessage = channel
1093 .receive_json()
1094 .await
1095 .expect("Alice should receive the `m.login.failure` message from Bob");
1096 assert_let!(QrAuthMessage::LoginFailure { reason, .. } = message);
1097 assert_eq!(reason, LoginFailureReason::UnsupportedProtocol);
1098
1099 return;
1100 }
1101
1102 let message: QrAuthMessage = channel
1104 .receive_json()
1105 .await
1106 .expect("Alice should be able to receive the `m.login.protocol` message from Bob");
1107 assert_let!(QrAuthMessage::LoginProtocol { protocol, .. } = message);
1108 assert_eq!(protocol.protocol(), LoginProtocolType::DeviceAuthorizationGrant);
1109
1110 let message = match behaviour {
1112 AliceBehaviour::DeclinedProtocol => QrAuthMessage::LoginFailure {
1113 reason: LoginFailureReason::UnsupportedProtocol,
1114 homeserver: None,
1115 },
1116 AliceBehaviour::UnexpectedMessage => QrAuthMessage::LoginDeclined,
1117 _ => QrAuthMessage::LoginProtocolAccepted,
1118 };
1119 channel
1120 .send_json(message)
1121 .await
1122 .expect("Alice should be able to send the `m.login.protocol_accepted` message to Bob");
1123
1124 match behaviour {
1125 AliceBehaviour::DeclinedProtocol => return,
1127 AliceBehaviour::UnexpectedMessage => {
1128 receive_unexpected_message_error(&mut channel).await;
1129 return;
1130 }
1131 _ => (),
1132 }
1133
1134 if !receive_login_outcome(&mut channel, token_response).await {
1135 return;
1136 }
1137
1138 let message = match behaviour {
1140 AliceBehaviour::UnexpectedMessageInsteadOfSecrets => QrAuthMessage::LoginDeclined,
1141 AliceBehaviour::RefuseSecrets => QrAuthMessage::LoginFailure {
1142 reason: LoginFailureReason::DeviceNotFound,
1143 homeserver: None,
1144 },
1145 _ => QrAuthMessage::LoginSecrets(secrets_bundle()),
1146 };
1147 channel
1148 .send_json(message)
1149 .await
1150 .expect("Alice should be able to send the `m.login.secrets` message to Bob");
1151
1152 if matches!(behaviour, AliceBehaviour::UnexpectedMessageInsteadOfSecrets) {
1153 receive_unexpected_message_error(&mut channel).await;
1154 }
1155 }
1156
1157 async fn test_generated_qr_login(msc_4388: bool) {
1158 let server = MatrixMockServer::new().await;
1159 let rendezvous_server =
1160 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, msc_4388)
1161 .await;
1162 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1163 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1164
1165 let oauth_server = server.oauth();
1166 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
1167 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1168 oauth_server
1169 .mock_device_authorization()
1170 .ok()
1171 .expect(1)
1172 .named("device_authorization")
1173 .mount()
1174 .await;
1175 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
1176
1177 server.mock_versions().ok().expect(1..).named("versions").mount().await;
1178 server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
1179 server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1180 server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
1181
1182 let homeserver_url = rendezvous_server.homeserver_url.clone();
1183
1184 let alice = server.client_builder().logged_in_with_oauth().build().await;
1187 assert!(alice.session_meta().is_some(), "Alice should be logged in");
1188
1189 let bob = Client::builder()
1191 .server_name_or_homeserver_url(&homeserver_url)
1192 .request_config(RequestConfig::new().disable_retry())
1193 .build()
1194 .await
1195 .expect("Should be able to create a client for Bob");
1196
1197 let secure_channel = SecureChannel::login(&bob, msc_4388)
1198 .await
1199 .expect("Bob should be able to create a secure channel");
1200
1201 assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1202
1203 if msc_4388 {
1204 assert_matches!(
1205 secure_channel.qr_code_data().intent_data(),
1206 QrCodeIntentData::Msc4388 { .. }
1207 );
1208 } else {
1209 assert_matches!(
1210 secure_channel.qr_code_data().intent_data(),
1211 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1212 );
1213 }
1214
1215 let registration_data = mock_client_metadata().into();
1216 let bob_oauth = bob.oauth();
1217 #[allow(unused_mut)]
1218 let mut bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
1219
1220 #[cfg(feature = "unstable-msc4388")]
1221 if msc_4388 {
1222 bob_login.with_msc4388_support();
1223 }
1224
1225 let mut bob_updates = bob_login.subscribe_to_progress();
1226
1227 let updates_task = spawn(async move {
1228 let mut qr_sender = Some(qr_sender);
1229 let mut cctx_sender = Some(cctx_sender);
1230
1231 while let Some(update) = bob_updates.next().await {
1232 match update {
1233 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1234 qr_sender
1235 .take()
1236 .expect("The establishing secure channel update with a qr code should be received only once")
1237 .send(qr)
1238 .expect("Bob should be able to send the qr code code to Alice");
1239 }
1240 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1241 cctx,
1242 )) => {
1243 cctx_sender
1244 .take()
1245 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1246 .send(cctx)
1247 .expect("Bob should be able to send the qr code code to Alice");
1248 }
1249 LoginProgress::Done => break,
1250 _ => (),
1251 }
1252 }
1253 });
1254
1255 let alice_task = spawn(async move {
1256 grant_login_with_generated_qr(
1257 &alice,
1258 qr_receiver,
1259 cctx_receiver,
1260 AliceBehaviour::HappyPath,
1261 TokenResponse::Ok,
1262 )
1263 .await
1264 });
1265
1266 bob_login.await.expect("Bob should be able to login");
1268 alice_task.await.expect("Alice should have completed it's task successfully");
1269 updates_task.await.unwrap();
1270
1271 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1272 let own_identity =
1273 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1274
1275 assert!(own_identity.is_verified());
1276 }
1277
1278 #[async_test]
1279 async fn test_generated_qr_login_msc_4108() {
1280 test_generated_qr_login(false).await;
1281 }
1282
1283 #[async_test]
1284 #[cfg(feature = "unstable-msc4388")]
1285 async fn test_generated_qr_login_msc_4388() {
1286 test_generated_qr_login(true).await;
1287 }
1288
1289 async fn test_generated_qr_login_with_homeserver_swap(msc_4388: bool) {
1290 let initial_server = MatrixMockServer::new().await;
1291 let rendezvous_server = MockedRendezvousServer::new(
1292 initial_server.server(),
1293 "abcdEFG12345",
1294 Duration::MAX,
1295 msc_4388,
1296 )
1297 .await;
1298 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1299 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1300
1301 let login_server = MatrixMockServer::new().await;
1302 let oauth_server = login_server.oauth();
1303 oauth_server.mock_server_metadata().ok().expect(1).named("server_metadata").mount().await;
1304 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
1305 oauth_server
1306 .mock_device_authorization()
1307 .ok()
1308 .expect(1)
1309 .named("device_authorization")
1310 .mount()
1311 .await;
1312 oauth_server.mock_token().ok().expect(1).named("token").mount().await;
1313
1314 initial_server.mock_versions().ok().named("versions initial server").mount().await;
1315 initial_server
1316 .mock_well_known()
1317 .ok()
1318 .expect(1)
1319 .named("well_known-initial-server")
1320 .mount()
1321 .await;
1322
1323 login_server.mock_well_known().ok().expect(1).named("well_known").mount().await;
1324 login_server.mock_versions().ok().expect(1..).named("versions").mount().await;
1325 login_server.mock_who_am_i().ok().expect(1).named("whoami").mount().await;
1326 login_server.mock_upload_keys().ok().expect(1).named("upload_keys").mount().await;
1327 login_server.mock_query_keys().ok().expect(1).named("query_keys").mount().await;
1328
1329 let rendezvous_homeserver_url = rendezvous_server.homeserver_url.clone();
1330
1331 let alice = login_server.client_builder().logged_in_with_oauth().build().await;
1334 assert!(alice.session_meta().is_some(), "Alice should be logged in");
1335
1336 let bob = Client::builder()
1338 .server_name_or_homeserver_url(&rendezvous_homeserver_url)
1339 .request_config(RequestConfig::new().disable_retry())
1340 .build()
1341 .await
1342 .expect("Should be able to create a client for Bob");
1343
1344 let secure_channel = SecureChannel::login(&bob, msc_4388)
1345 .await
1346 .expect("Bob should be able to create a secure channel");
1347
1348 assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1349
1350 if msc_4388 {
1351 assert_matches!(
1352 secure_channel.qr_code_data().intent_data(),
1353 QrCodeIntentData::Msc4388 { .. }
1354 );
1355 } else {
1356 assert_matches!(
1357 secure_channel.qr_code_data().intent_data(),
1358 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1359 );
1360 }
1361
1362 let initial_server_url = initial_server.server().uri().parse().unwrap();
1365 assert_eq!(bob.homeserver(), initial_server_url);
1366 let login_server_url = login_server.server().uri().parse().unwrap();
1367 assert_eq!(alice.homeserver(), login_server_url);
1368 assert_ne!(rendezvous_homeserver_url, login_server_url);
1369
1370 let registration_data = mock_client_metadata().into();
1371 let bob_oauth = bob.oauth();
1372 #[allow(unused_mut)]
1373 let mut bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
1374
1375 #[cfg(feature = "unstable-msc4388")]
1376 if msc_4388 {
1377 bob_login.with_msc4388_support();
1378 }
1379
1380 let mut bob_updates = bob_login.subscribe_to_progress();
1381
1382 let updates_task = spawn(async move {
1383 let mut qr_sender = Some(qr_sender);
1384 let mut cctx_sender = Some(cctx_sender);
1385
1386 while let Some(update) = bob_updates.next().await {
1387 match update {
1388 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1389 qr_sender
1390 .take()
1391 .expect("The establishing secure channel update with a qr code should be received only once")
1392 .send(qr)
1393 .expect("Bob should be able to send the qr code code to Alice");
1394 }
1395 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1396 cctx,
1397 )) => {
1398 cctx_sender
1399 .take()
1400 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1401 .send(cctx)
1402 .expect("Bob should be able to send the qr code code to Alice");
1403 }
1404 LoginProgress::Done => break,
1405 _ => (),
1406 }
1407 }
1408 });
1409
1410 let alice_task = spawn(async move {
1411 grant_login_with_generated_qr(
1412 &alice,
1413 qr_receiver,
1414 cctx_receiver,
1415 AliceBehaviour::HappyPath,
1416 TokenResponse::Ok,
1417 )
1418 .await
1419 });
1420
1421 bob_login.await.expect("Bob should be able to login");
1423 alice_task.await.expect("Alice should have completed it's task successfully");
1424 updates_task.await.unwrap();
1425
1426 assert!(bob.encryption().cross_signing_status().await.unwrap().is_complete());
1427 let own_identity =
1428 bob.encryption().get_user_identity(bob.user_id().unwrap()).await.unwrap().unwrap();
1429
1430 assert!(own_identity.is_verified());
1431
1432 assert_eq!(bob.homeserver(), login_server_url);
1434 }
1435
1436 #[async_test]
1437 async fn test_generated_qr_login_with_homeserver_swap_msc_4108() {
1438 test_generated_qr_login_with_homeserver_swap(false).await;
1439 }
1440
1441 #[async_test]
1442 #[cfg(feature = "unstable-msc4388")]
1443 async fn test_generated_qr_login_with_homeserver_swap_msc_4388() {
1444 test_generated_qr_login_with_homeserver_swap(true).await;
1445 }
1446
1447 async fn test_failure(
1448 token_response: TokenResponse,
1449 alice_behaviour: AliceBehaviour,
1450 bob_behavior: BobBehaviour,
1451 msc_4388: bool,
1452 ) -> Option<Result<(), QRCodeLoginError>> {
1453 let server = MatrixMockServer::new().await;
1454 let expiration = match alice_behaviour {
1455 AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1456 _ => Duration::MAX,
1457 };
1458 let rendezvous_server =
1459 MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration, msc_4388)
1460 .await;
1461 let (sender, receiver) = tokio::sync::oneshot::channel();
1462
1463 let oauth_server = server.oauth();
1464 let expected_calls = match alice_behaviour {
1465 AliceBehaviour::LetSessionExpire | AliceBehaviour::NoProtocols => 0,
1466 _ => 1,
1467 };
1468 oauth_server
1469 .mock_server_metadata()
1470 .ok()
1471 .expect(expected_calls)
1472 .named("server_metadata")
1473 .mount()
1474 .await;
1475 oauth_server
1476 .mock_registration()
1477 .ok()
1478 .expect(expected_calls)
1479 .named("registration")
1480 .mount()
1481 .await;
1482 oauth_server
1483 .mock_device_authorization()
1484 .ok()
1485 .expect(expected_calls)
1486 .named("device_authorization")
1487 .mount()
1488 .await;
1489
1490 let token_mock = oauth_server.mock_token();
1491 let token_mock = match token_response {
1492 TokenResponse::Ok => token_mock.ok(),
1493 TokenResponse::AccessDenied => token_mock.access_denied(),
1494 TokenResponse::ExpiredToken => token_mock.expired_token(),
1495 };
1496 token_mock.named("token").mount().await;
1497
1498 server.mock_versions().ok().named("versions").mount().await;
1499 server.mock_who_am_i().ok().named("whoami").mount().await;
1500
1501 let client = rendezvous_server.unlogged_client().await;
1502 let alice = SecureChannel::reciprocate(&client, msc_4388)
1503 .await
1504 .expect("Alice should be able to create a secure channel.");
1505
1506 assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
1507
1508 let server_name = if msc_4388 {
1509 assert_let!(
1510 QrCodeIntentData::Msc4388 { base_url, .. } = &alice.qr_code_data().intent_data()
1511 );
1512
1513 base_url.to_string()
1514 } else {
1515 assert_let!(
1516 QrCodeIntentData::Msc4108 {
1517 data: Msc4108IntentData::Reciprocate { server_name },
1518 ..
1519 } = &alice.qr_code_data().intent_data()
1520 );
1521
1522 server_name.to_owned()
1523 };
1524
1525 assert_eq!(alice.qr_code_data().intent(), QrCodeIntent::Reciprocate);
1526
1527 let bob = Client::builder()
1528 .server_name_or_homeserver_url(server_name)
1529 .request_config(RequestConfig::new().disable_retry())
1530 .build()
1531 .await
1532 .expect("We should be able to build the Client object from the URL in the QR code");
1533
1534 let qr_code = alice.qr_code_data().clone();
1535
1536 let oauth = bob.oauth();
1537 let registration_data = mock_client_metadata().into();
1538 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
1539 let mut updates = login_bob.subscribe_to_progress();
1540
1541 let login_bob = login_bob.cancellable();
1542 let cancel = login_bob.cancellation_token();
1543
1544 let _updates_task = spawn(async move {
1545 let mut sender = Some(sender);
1546
1547 while let Some(update) = updates.next().await {
1548 match update {
1549 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
1550 sender
1551 .take()
1552 .expect("The establishing secure channel update should be received only once")
1553 .send(check_code)
1554 .expect("Bob should be able to send the check code to Alice");
1555 }
1556 LoginProgress::WaitingForToken { .. } => {
1557 if let BobBehaviour::CancelWhileWaitingForToken = bob_behavior {
1558 cancel.cancel();
1559 }
1560 }
1561 LoginProgress::Done => break,
1562 _ => (),
1563 }
1564 }
1565 });
1566
1567 let alice_homeserver = rendezvous_server.homeserver_url.clone();
1568 let alice_task =
1569 (!matches!(alice_behaviour, AliceBehaviour::LetSessionExpire)).then(|| {
1570 spawn(async move {
1571 grant_login(
1572 alice,
1573 alice_homeserver,
1574 receiver,
1575 alice_behaviour,
1576 token_response,
1577 msc_4388,
1578 )
1579 .await
1580 })
1581 });
1582
1583 let result = login_bob.await;
1584
1585 if let Some(alice_task) = alice_task {
1586 if matches!(bob_behavior, BobBehaviour::CancelWhileWaitingForToken) {
1587 alice_task.abort();
1588 } else {
1589 alice_task.await.expect("Alice should have completed her task successfully");
1590 }
1591 }
1592
1593 result
1594 }
1595
1596 async fn test_generated_failure(
1597 token_response: TokenResponse,
1598 alice_behaviour: AliceBehaviour,
1599 bob_behavior: BobBehaviour,
1600 msc_4388: bool,
1601 ) -> Option<Result<(), QRCodeLoginError>> {
1602 let server = MatrixMockServer::new().await;
1603 let expiration = match alice_behaviour {
1604 AliceBehaviour::LetSessionExpire => Duration::from_secs(2),
1605 _ => Duration::MAX,
1606 };
1607 let rendezvous_server =
1608 MockedRendezvousServer::new(server.server(), "abcdEFG12345", expiration, msc_4388)
1609 .await;
1610
1611 let (qr_sender, qr_receiver) = tokio::sync::oneshot::channel();
1612 let (cctx_sender, cctx_receiver) = tokio::sync::oneshot::channel();
1613
1614 let oauth_server = server.oauth();
1615 let expected_calls = match alice_behaviour {
1616 AliceBehaviour::LetSessionExpire | AliceBehaviour::NoProtocols => 0,
1617 _ => 1,
1618 };
1619 oauth_server
1620 .mock_server_metadata()
1621 .ok()
1622 .expect(expected_calls)
1623 .named("server_metadata")
1624 .mount()
1625 .await;
1626 oauth_server
1627 .mock_registration()
1628 .ok()
1629 .expect(expected_calls)
1630 .named("registration")
1631 .mount()
1632 .await;
1633 oauth_server
1634 .mock_device_authorization()
1635 .ok()
1636 .expect(expected_calls)
1637 .named("device_authorization")
1638 .mount()
1639 .await;
1640
1641 let token_mock = oauth_server.mock_token();
1642 let token_mock = match token_response {
1643 TokenResponse::Ok => token_mock.ok(),
1644 TokenResponse::AccessDenied => token_mock.access_denied(),
1645 TokenResponse::ExpiredToken => token_mock.expired_token(),
1646 };
1647 token_mock.named("token").mount().await;
1648
1649 server.mock_versions().ok().named("versions").mount().await;
1650 server.mock_who_am_i().ok().named("whoami").mount().await;
1651
1652 let homeserver_url = rendezvous_server.homeserver_url.clone();
1653
1654 let alice = server.client_builder().logged_in_with_oauth().build().await;
1657 assert!(alice.session_meta().is_some(), "Alice should be logged in");
1658
1659 let bob = Client::builder()
1661 .server_name_or_homeserver_url(&homeserver_url)
1662 .request_config(RequestConfig::new().disable_retry())
1663 .build()
1664 .await
1665 .expect("Should be able to create a client for Bob");
1666
1667 let secure_channel = SecureChannel::login(&bob, msc_4388)
1668 .await
1669 .expect("Bob should be able to create a secure channel");
1670
1671 assert_eq!(secure_channel.qr_code_data().intent(), QrCodeIntent::Login);
1672
1673 if msc_4388 {
1674 assert_matches!(
1675 secure_channel.qr_code_data().intent_data(),
1676 QrCodeIntentData::Msc4388 { .. }
1677 );
1678 } else {
1679 assert_matches!(
1680 secure_channel.qr_code_data().intent_data(),
1681 QrCodeIntentData::Msc4108 { data: Msc4108IntentData::Login, .. }
1682 );
1683 }
1684
1685 let registration_data = mock_client_metadata().into();
1686 let bob_oauth = bob.oauth();
1687 #[allow(unused_mut)]
1688 let mut bob_login = bob_oauth.login_with_qr_code(Some(®istration_data)).generate();
1689
1690 #[cfg(feature = "unstable-msc4388")]
1691 if msc_4388 {
1692 bob_login.with_msc4388_support();
1693 }
1694
1695 let mut bob_updates = bob_login.subscribe_to_progress();
1696
1697 let bob_login = bob_login.cancellable();
1698 let cancel = bob_login.cancellation_token();
1699
1700 let _updates_task = spawn(async move {
1701 let mut qr_sender = Some(qr_sender);
1702 let mut cctx_sender = Some(cctx_sender);
1703
1704 while let Some(update) = bob_updates.next().await {
1705 match update {
1706 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrReady(qr)) => {
1707 qr_sender
1708 .take()
1709 .expect("The establishing secure channel update with a qr code should be received only once")
1710 .send(qr)
1711 .expect("Bob should be able to send the qr code code to Alice");
1712 }
1713 LoginProgress::EstablishingSecureChannel(GeneratedQrProgress::QrScanned(
1714 cctx,
1715 )) => {
1716 cctx_sender
1717 .take()
1718 .expect("The establishing secure channel update with a CheckCodeSender should be received only once")
1719 .send(cctx)
1720 .expect("Bob should be able to send the qr code code to Alice");
1721 }
1722 LoginProgress::WaitingForToken { .. } => {
1723 if let BobBehaviour::CancelWhileWaitingForToken = bob_behavior {
1724 cancel.cancel();
1725 }
1726 }
1727 LoginProgress::Done => break,
1728 _ => (),
1729 }
1730 }
1731 });
1732
1733 let alice_task =
1734 (!matches!(alice_behaviour, AliceBehaviour::LetSessionExpire)).then(|| {
1735 spawn(async move {
1736 grant_login_with_generated_qr(
1737 &alice,
1738 qr_receiver,
1739 cctx_receiver,
1740 alice_behaviour,
1741 token_response,
1742 )
1743 .await
1744 })
1745 });
1746
1747 let result = bob_login.await;
1748
1749 if let Some(alice_task) = alice_task {
1750 if matches!(bob_behavior, BobBehaviour::CancelWhileWaitingForToken) {
1751 alice_task.abort();
1752 } else {
1753 alice_task.await.expect("Alice should have completed her task successfully");
1754 }
1755 }
1756
1757 result
1758 }
1759
1760 async fn test_qr_login_refused_access_token(msc_4388: bool) {
1761 let result = test_failure(
1762 TokenResponse::AccessDenied,
1763 AliceBehaviour::HappyPath,
1764 BobBehaviour::HappyPath,
1765 msc_4388,
1766 )
1767 .await;
1768
1769 assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1770 assert_eq!(
1771 e.as_request_token_error(),
1772 Some(&DeviceCodeErrorResponseType::AccessDenied),
1773 "The server should have told us that access has been denied."
1774 );
1775 }
1776
1777 #[async_test]
1778 async fn test_qr_login_refused_access_token_msc_4108() {
1779 test_qr_login_refused_access_token(false).await
1780 }
1781
1782 #[async_test]
1783 #[cfg(feature = "unstable-msc4388")]
1784 async fn test_qr_login_refused_access_token_msc_4388() {
1785 test_qr_login_refused_access_token(true).await
1786 }
1787
1788 async fn test_generated_qr_login_refused_access_token(msc_4388: bool) {
1789 let result = test_generated_failure(
1790 TokenResponse::AccessDenied,
1791 AliceBehaviour::HappyPath,
1792 BobBehaviour::HappyPath,
1793 msc_4388,
1794 )
1795 .await;
1796
1797 assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1798 assert_eq!(
1799 e.as_request_token_error(),
1800 Some(&DeviceCodeErrorResponseType::AccessDenied),
1801 "The server should have told us that access has been denied."
1802 );
1803 }
1804
1805 #[async_test]
1806 async fn test_generated_qr_login_refused_access_token_msc_4108() {
1807 test_generated_qr_login_refused_access_token(false).await;
1808 }
1809
1810 #[async_test]
1811 #[cfg(feature = "unstable-msc4388")]
1812 async fn test_generated_qr_login_refused_access_token_msc_4388() {
1813 test_generated_qr_login_refused_access_token(true).await;
1814 }
1815
1816 async fn test_qr_login_expired_token(msc_4388: bool) {
1817 let result = test_failure(
1818 TokenResponse::ExpiredToken,
1819 AliceBehaviour::HappyPath,
1820 BobBehaviour::HappyPath,
1821 msc_4388,
1822 )
1823 .await;
1824
1825 assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1826 assert_eq!(
1827 e.as_request_token_error(),
1828 Some(&DeviceCodeErrorResponseType::ExpiredToken),
1829 "The server should have told us that access has been denied."
1830 );
1831 }
1832
1833 #[async_test]
1834 async fn test_qr_login_expired_token_msc_4108() {
1835 test_qr_login_expired_token(false).await;
1836 }
1837
1838 #[async_test]
1839 #[cfg(feature = "unstable-msc4388")]
1840 async fn test_qr_login_expired_token_msc_4388() {
1841 test_qr_login_expired_token(true).await;
1842 }
1843
1844 async fn test_generated_qr_login_expired_token(msc_4388: bool) {
1845 let result = test_generated_failure(
1846 TokenResponse::ExpiredToken,
1847 AliceBehaviour::HappyPath,
1848 BobBehaviour::HappyPath,
1849 msc_4388,
1850 )
1851 .await;
1852
1853 assert_let!(Some(Err(QRCodeLoginError::OAuth(e))) = result);
1854 assert_eq!(
1855 e.as_request_token_error(),
1856 Some(&DeviceCodeErrorResponseType::ExpiredToken),
1857 "The server should have told us that access has been denied."
1858 );
1859 }
1860
1861 #[async_test]
1862 async fn test_generated_qr_login_expired_token_msc_4108() {
1863 test_generated_qr_login_expired_token(false).await;
1864 }
1865
1866 #[async_test]
1867 #[cfg(feature = "unstable-msc4388")]
1868 async fn test_generated_qr_login_expired_token_msc_4388() {
1869 test_generated_qr_login_expired_token(true).await;
1870 }
1871
1872 async fn test_qr_login_declined_protocol(msc_4388: bool) {
1873 let result = test_failure(
1874 TokenResponse::Ok,
1875 AliceBehaviour::DeclinedProtocol,
1876 BobBehaviour::HappyPath,
1877 msc_4388,
1878 )
1879 .await;
1880
1881 assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
1882 assert_eq!(
1883 reason,
1884 LoginFailureReason::UnsupportedProtocol,
1885 "Alice should have told us that the protocol is unsupported."
1886 );
1887 }
1888
1889 #[async_test]
1890 async fn test_qr_login_declined_protocol_msc_4108() {
1891 test_qr_login_declined_protocol(false).await;
1892 }
1893
1894 #[async_test]
1895 #[cfg(feature = "unstable-msc4388")]
1896 async fn test_qr_login_declined_protocol_msc_4388() {
1897 test_qr_login_declined_protocol(true).await;
1898 }
1899
1900 #[async_test]
1901 #[cfg(feature = "unstable-msc4388")]
1902 async fn test_qr_login_no_protocols_msc_4388() {
1903 let result = test_failure(
1904 TokenResponse::Ok,
1905 AliceBehaviour::NoProtocols,
1906 BobBehaviour::HappyPath,
1907 true,
1908 )
1909 .await;
1910
1911 assert_matches!(
1912 result,
1913 Some(Err(QRCodeLoginError::LoginFailure {
1914 reason: LoginFailureReason::UnsupportedProtocol,
1915 homeserver: None
1916 }))
1917 );
1918 }
1919
1920 async fn test_generated_qr_login_no_protocols(msc_4388: bool) {
1921 let result = test_generated_failure(
1922 TokenResponse::Ok,
1923 AliceBehaviour::NoProtocols,
1924 BobBehaviour::HappyPath,
1925 msc_4388,
1926 )
1927 .await;
1928
1929 assert_matches!(
1930 result,
1931 Some(Err(QRCodeLoginError::LoginFailure {
1932 reason: LoginFailureReason::UnsupportedProtocol,
1933 homeserver: None
1934 }))
1935 );
1936 }
1937
1938 #[async_test]
1939 async fn test_generated_qr_login_no_protocols_msc_4108() {
1940 test_generated_qr_login_no_protocols(false).await;
1941 }
1942
1943 #[async_test]
1944 #[cfg(feature = "unstable-msc4388")]
1945 async fn test_generated_qr_login_no_protocols_msc_4388() {
1946 test_generated_qr_login_no_protocols(true).await;
1947 }
1948
1949 async fn test_generated_qr_login_declined_protocol(msc_4388: bool) {
1950 let result = test_generated_failure(
1951 TokenResponse::Ok,
1952 AliceBehaviour::DeclinedProtocol,
1953 BobBehaviour::HappyPath,
1954 msc_4388,
1955 )
1956 .await;
1957
1958 assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
1959 assert_eq!(
1960 reason,
1961 LoginFailureReason::UnsupportedProtocol,
1962 "Alice should have told us that the protocol is unsupported."
1963 );
1964 }
1965
1966 #[async_test]
1967 async fn test_generated_qr_login_declined_protocol_msc_4108() {
1968 test_generated_qr_login_declined_protocol(false).await;
1969 }
1970
1971 #[async_test]
1972 #[cfg(feature = "unstable-msc4388")]
1973 async fn test_generated_qr_login_declined_protocol_msc_4388() {
1974 test_generated_qr_login_declined_protocol(true).await;
1975 }
1976
1977 async fn test_qr_login_unexpected_message(msc_4388: bool) {
1978 let result = test_failure(
1979 TokenResponse::Ok,
1980 AliceBehaviour::UnexpectedMessage,
1981 BobBehaviour::HappyPath,
1982 msc_4388,
1983 )
1984 .await;
1985
1986 assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
1987 assert_eq!(expected, "m.login.protocol_accepted");
1988 }
1989
1990 #[async_test]
1991 async fn test_qr_login_unexpected_message_msc_4108() {
1992 test_qr_login_unexpected_message(false).await;
1993 }
1994
1995 #[async_test]
1996 #[cfg(feature = "unstable-msc4388")]
1997 async fn test_qr_login_unexpected_message_msc_4388() {
1998 test_qr_login_unexpected_message(true).await;
1999 }
2000
2001 async fn test_generated_qr_login_unexpected_message(msc_4388: bool) {
2002 let result = test_generated_failure(
2003 TokenResponse::Ok,
2004 AliceBehaviour::UnexpectedMessage,
2005 BobBehaviour::HappyPath,
2006 msc_4388,
2007 )
2008 .await;
2009
2010 assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2011 assert_eq!(expected, "m.login.protocol_accepted");
2012 }
2013
2014 #[async_test]
2015 async fn test_generated_qr_login_unexpected_message_msc_4108() {
2016 test_generated_qr_login_unexpected_message(false).await;
2017 }
2018
2019 #[async_test]
2020 #[cfg(feature = "unstable-msc4388")]
2021 async fn test_generated_qr_login_unexpected_message_msc_4388() {
2022 test_generated_qr_login_unexpected_message(true).await;
2023 }
2024
2025 async fn test_qr_login_unexpected_message_instead_of_secrets(msc_4388: bool) {
2026 let result = test_failure(
2027 TokenResponse::Ok,
2028 AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2029 BobBehaviour::HappyPath,
2030 msc_4388,
2031 )
2032 .await;
2033
2034 assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2035 assert_eq!(expected, "m.login.secrets");
2036 }
2037
2038 #[async_test]
2039 async fn test_qr_login_unexpected_message_instead_of_secrets_msc_4108() {
2040 test_qr_login_unexpected_message_instead_of_secrets(false).await;
2041 }
2042
2043 #[async_test]
2044 #[cfg(feature = "unstable-msc4388")]
2045 async fn test_qr_login_unexpected_message_instead_of_secrets_msc_4388() {
2046 test_qr_login_unexpected_message_instead_of_secrets(true).await;
2047 }
2048
2049 async fn test_generated_qr_login_unexpected_message_instead_of_secrets(msc_4388: bool) {
2050 let result = test_generated_failure(
2051 TokenResponse::Ok,
2052 AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2053 BobBehaviour::HappyPath,
2054 msc_4388,
2055 )
2056 .await;
2057
2058 assert_let!(Some(Err(QRCodeLoginError::UnexpectedMessage { expected, .. })) = result);
2059 assert_eq!(expected, "m.login.secrets");
2060 }
2061
2062 #[async_test]
2063 async fn test_generated_qr_login_unexpected_message_instead_of_secrets_msc_4108() {
2064 test_generated_qr_login_unexpected_message_instead_of_secrets(false).await;
2065 }
2066
2067 #[async_test]
2068 #[cfg(feature = "unstable-msc4388")]
2069 async fn test_generated_qr_login_unexpected_message_instead_of_secrets_msc_4388() {
2070 test_generated_qr_login_unexpected_message_instead_of_secrets(true).await;
2071 }
2072
2073 async fn test_qr_login_refuse_secrets(msc_4388: bool) {
2074 let result = test_failure(
2075 TokenResponse::Ok,
2076 AliceBehaviour::RefuseSecrets,
2077 BobBehaviour::HappyPath,
2078 msc_4388,
2079 )
2080 .await;
2081
2082 assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
2083 assert_eq!(reason, LoginFailureReason::DeviceNotFound);
2084 }
2085
2086 #[async_test]
2087 async fn test_qr_login_refuse_secrets_msc_4108() {
2088 test_qr_login_refuse_secrets(false).await
2089 }
2090
2091 #[async_test]
2092 #[cfg(feature = "unstable-msc4388")]
2093 async fn test_qr_login_refuse_secrets_msc_4388() {
2094 test_qr_login_refuse_secrets(true).await
2095 }
2096
2097 async fn test_generated_qr_login_refuse_secrets(msc_4388: bool) {
2098 let result = test_generated_failure(
2099 TokenResponse::Ok,
2100 AliceBehaviour::RefuseSecrets,
2101 BobBehaviour::HappyPath,
2102 msc_4388,
2103 )
2104 .await;
2105
2106 assert_let!(Some(Err(QRCodeLoginError::LoginFailure { reason, .. })) = result);
2107 assert_eq!(reason, LoginFailureReason::DeviceNotFound);
2108 }
2109
2110 #[async_test]
2111 async fn test_generated_qr_login_refuse_secrets_msc_4108() {
2112 test_generated_qr_login_refuse_secrets(false).await;
2113 }
2114
2115 #[async_test]
2116 #[cfg(feature = "unstable-msc4388")]
2117 async fn test_generated_qr_login_refuse_secrets_msc_4388() {
2118 test_generated_qr_login_refuse_secrets(true).await;
2119 }
2120
2121 async fn test_qr_login_session_expired(msc_4388: bool) {
2122 let result = test_failure(
2123 TokenResponse::Ok,
2124 AliceBehaviour::LetSessionExpire,
2125 BobBehaviour::HappyPath,
2126 msc_4388,
2127 )
2128 .await;
2129
2130 assert_matches!(result, Some(Err(QRCodeLoginError::NotFound)));
2131 }
2132
2133 #[async_test]
2134 async fn test_qr_login_session_expired_msc_4108() {
2135 test_qr_login_session_expired(false).await;
2136 }
2137
2138 #[async_test]
2139 #[cfg(feature = "unstable-msc4388")]
2140 async fn test_qr_login_session_expired_msc_4388() {
2141 test_qr_login_session_expired(true).await;
2142 }
2143
2144 async fn test_generated_qr_login_session_expired(msc_4388: bool) {
2145 let result = test_generated_failure(
2146 TokenResponse::Ok,
2147 AliceBehaviour::LetSessionExpire,
2148 BobBehaviour::HappyPath,
2149 msc_4388,
2150 )
2151 .await;
2152
2153 assert_matches!(result, Some(Err(QRCodeLoginError::NotFound)));
2154 }
2155
2156 #[async_test]
2157 async fn test_generated_qr_login_session_expired_msc_4108() {
2158 test_generated_qr_login_session_expired(false).await;
2159 }
2160
2161 #[async_test]
2162 #[cfg(feature = "unstable-msc4388")]
2163 async fn test_generated_qr_login_session_expired_msc_4388() {
2164 test_generated_qr_login_session_expired(true).await;
2165 }
2166
2167 #[async_test]
2168 async fn test_qr_login_cancelled() {
2169 let result = test_failure(
2170 TokenResponse::Ok,
2171 AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2172 BobBehaviour::CancelWhileWaitingForToken,
2173 false,
2174 )
2175 .await;
2176
2177 assert_matches!(result, None);
2178 }
2179
2180 #[async_test]
2181 async fn test_generated_qr_login_cancelled() {
2182 let result = test_generated_failure(
2183 TokenResponse::Ok,
2184 AliceBehaviour::UnexpectedMessageInsteadOfSecrets,
2185 BobBehaviour::CancelWhileWaitingForToken,
2186 false,
2187 )
2188 .await;
2189
2190 assert_matches!(result, None);
2191 }
2192
2193 #[async_test]
2194 async fn test_device_authorization_endpoint_missing() {
2195 let server = MatrixMockServer::new().await;
2196 let rendezvous_server =
2197 MockedRendezvousServer::new(server.server(), "abcdEFG12345", Duration::MAX, false)
2198 .await;
2199 let (sender, receiver) = tokio::sync::oneshot::channel();
2200
2201 let oauth_server = server.oauth();
2202 oauth_server
2203 .mock_server_metadata()
2204 .ok_without_device_authorization()
2205 .expect(1)
2206 .named("server_metadata")
2207 .mount()
2208 .await;
2209 oauth_server.mock_registration().ok().expect(1).named("registration").mount().await;
2210
2211 server.mock_versions().ok().named("versions").mount().await;
2212 server.mock_who_am_i().ok().named("whoami").mount().await;
2213
2214 let client = rendezvous_server.unlogged_client().await;
2215 let alice = SecureChannel::reciprocate(&client, false)
2216 .await
2217 .expect("Alice should be able to create a secure channel.");
2218
2219 assert_let!(
2220 QrCodeIntentData::Msc4108 {
2221 data: Msc4108IntentData::Reciprocate { server_name },
2222 ..
2223 } = &alice.qr_code_data().intent_data()
2224 );
2225
2226 let bob = Client::builder()
2227 .server_name_or_homeserver_url(server_name)
2228 .request_config(RequestConfig::new().disable_retry())
2229 .build()
2230 .await
2231 .expect("We should be able to build the Client object from the URL in the QR code");
2232
2233 let qr_code = alice.qr_code_data().clone();
2234
2235 let oauth = bob.oauth();
2236 let registration_data = mock_client_metadata().into();
2237 let login_bob = oauth.login_with_qr_code(Some(®istration_data)).scan(&qr_code);
2238 let mut updates = login_bob.subscribe_to_progress();
2239
2240 let _updates_task = spawn(async move {
2241 let mut sender = Some(sender);
2242
2243 while let Some(update) = updates.next().await {
2244 match update {
2245 LoginProgress::EstablishingSecureChannel(QrProgress { check_code }) => {
2246 sender
2247 .take()
2248 .expect("The establishing secure channel update should be received only once")
2249 .send(check_code)
2250 .expect("Bob should be able to send the check code to Alice");
2251 }
2252 LoginProgress::Done => break,
2253 _ => (),
2254 }
2255 }
2256 });
2257 let alice_homeserver = rendezvous_server.homeserver_url.clone();
2258 let _alice_task = spawn(async move {
2259 grant_login(
2260 alice,
2261 alice_homeserver,
2262 receiver,
2263 AliceBehaviour::HappyPath,
2264 TokenResponse::Ok,
2265 false,
2266 )
2267 .await
2268 });
2269 let error = login_bob.await.unwrap_err();
2270
2271 assert_matches!(
2272 error,
2273 QRCodeLoginError::OAuth(DeviceAuthorizationOAuthError::NoDeviceAuthorizationEndpoint)
2274 );
2275 }
2276}