From d5154577a0d79800abf2d7de6cbceb6cc571c7c8 Mon Sep 17 00:00:00 2001 From: boxdot Date: Thu, 23 Feb 2023 08:16:04 +0100 Subject: [PATCH] feat(sdk): Add custom login method The `Client::login_custom` allows to login by using a custom login method. In particular, it is possible to login to Synapse which supports JWT authentication. Signed-off-by: boxdot --- crates/matrix-sdk/src/client/login_builder.rs | 20 +++++++- crates/matrix-sdk/src/client/mod.rs | 50 ++++++++++++++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/crates/matrix-sdk/src/client/login_builder.rs b/crates/matrix-sdk/src/client/login_builder.rs index efc4c602a..b589c372e 100644 --- a/crates/matrix-sdk/src/client/login_builder.rs +++ b/crates/matrix-sdk/src/client/login_builder.rs @@ -22,6 +22,7 @@ use std::{ use ruma::{ api::client::{session::login, uiaa::UserIdentifier}, assign, + serde::JsonObject, }; use tracing::{info, instrument}; @@ -35,16 +36,20 @@ use crate::{config::RequestConfig, Result}; /// [the spec]: https://spec.matrix.org/v1.3/client-server-api/#post_matrixclientv3login enum LoginMethod { /// Login type `m.login.password` - UserPassword { id: UserIdentifier, password: String }, + UserPassword { + id: UserIdentifier, + password: String, + }, /// Login type `m.token` Token(String), + Custom(login::v3::LoginInfo), } impl LoginMethod { fn id(&self) -> Option<&UserIdentifier> { match self { LoginMethod::UserPassword { id, .. } => Some(id), - LoginMethod::Token(_) => None, + LoginMethod::Token(_) | LoginMethod::Custom(_) => None, } } @@ -52,6 +57,7 @@ impl LoginMethod { match self { LoginMethod::UserPassword { .. } => "identifier and password", LoginMethod::Token(_) => "token", + LoginMethod::Custom(_) => "custom", } } @@ -61,6 +67,7 @@ impl LoginMethod { login::v3::LoginInfo::Password(login::v3::Password::new(id, password)) } LoginMethod::Token(token) => login::v3::LoginInfo::Token(login::v3::Token::new(token)), + LoginMethod::Custom(login_info) => login_info, } } } @@ -98,6 +105,15 @@ impl LoginBuilder { Self::new(client, LoginMethod::Token(token)) } + pub(super) fn new_custom( + client: Client, + login_type: &str, + data: JsonObject, + ) -> serde_json::Result { + let login_info = login::v3::LoginInfo::new(login_type, data)?; + Ok(Self::new(client, LoginMethod::Custom(login_info))) + } + /// Set the device ID. /// /// The device ID is a unique ID that will be associated with this session. diff --git a/crates/matrix-sdk/src/client/mod.rs b/crates/matrix-sdk/src/client/mod.rs index 33108a66e..2f4b758e9 100644 --- a/crates/matrix-sdk/src/client/mod.rs +++ b/crates/matrix-sdk/src/client/mod.rs @@ -61,8 +61,10 @@ use ruma::{ error::FromHttpResponseError, MatrixVersion, OutgoingRequest, SendAccessToken, }, - assign, DeviceId, OwnedDeviceId, OwnedRoomId, OwnedServerName, RoomAliasId, RoomId, - RoomOrAliasId, ServerName, UInt, UserId, + assign, + serde::JsonObject, + DeviceId, OwnedDeviceId, OwnedRoomId, OwnedServerName, RoomAliasId, RoomId, RoomOrAliasId, + ServerName, UInt, UserId, }; use serde::de::DeserializeOwned; #[cfg(not(target_arch = "wasm32"))] @@ -1017,6 +1019,50 @@ impl Client { LoginBuilder::new_password(self.clone(), id, password.to_owned()) } + /// Login to the server with a custom login type + /// + /// # Arguments + /// + /// * `login_type` - Identifier of the custom login type, e.g. + /// `org.matrix.login.jwt` + /// + /// * `data` - The additional data which should be attached to the login + /// request. + /// + /// ```no_run + /// # use futures::executor::block_on; + /// # use url::Url; + /// # let homeserver = Url::parse("http://example.com").unwrap(); + /// # block_on(async { + /// use matrix_sdk::Client; + /// + /// let client = Client::new(homeserver).await?; + /// let user = "example"; + /// + /// let response = client + /// .login_custom( + /// "org.matrix.login.jwt", + /// [("token".to_owned(), "jwt_token_content".into())] + /// .into_iter() + /// .collect(), + /// )? + /// .initial_device_display_name("My bot") + /// .await?; + /// + /// println!( + /// "Logged in as {user}, got device_id {} and access_token {}", + /// response.device_id, response.access_token, + /// ); + /// # anyhow::Ok(()) }); + /// ``` + pub fn login_custom( + &self, + login_type: &str, + data: JsonObject, + ) -> serde_json::Result { + LoginBuilder::new_custom(self.clone(), login_type, data) + } + /// Login to the server with a token. /// /// This token is usually received in the SSO flow after following the URL