client-api: Support custom login types

This commit is contained in:
Jonas Platte 2021-03-13 20:06:18 +01:00
parent 0c8adbb69e
commit 341869c83c
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
2 changed files with 61 additions and 11 deletions

View File

@ -1,7 +1,7 @@
//! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-login) //! [GET /_matrix/client/r0/login](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-login)
use ruma_api::ruma_api; use ruma_api::ruma_api;
use serde::{Deserialize, Serialize}; use ruma_serde::StringEnum;
ruma_api! { ruma_api! {
metadata: { metadata: {
@ -18,7 +18,8 @@ ruma_api! {
response: { response: {
/// The homeserver's supported login types. /// The homeserver's supported login types.
pub flows: Vec<LoginType> #[serde(with = "login_type_list_serde")]
pub flows: Vec<LoginType>,
} }
error: crate::Error error: crate::Error
@ -39,33 +40,51 @@ impl Response {
} }
/// An authentication mechanism. /// An authentication mechanism.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)] #[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[serde(tag = "type")]
pub enum LoginType { pub enum LoginType {
/// A password is supplied to authenticate. /// A password is supplied to authenticate.
#[serde(rename = "m.login.password")] #[ruma_enum(rename = "m.login.password")]
Password, Password,
/// Token-based login. /// Token-based login.
#[serde(rename = "m.login.token")] #[ruma_enum(rename = "m.login.token")]
Token, Token,
/// SSO-based login. /// SSO-based login.
#[serde(rename = "m.login.sso")] #[ruma_enum(rename = "m.login.sso")]
Sso, Sso,
#[doc(hidden)]
_Custom(String),
} }
mod login_type_list_serde;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use matches::assert_matches;
use serde::Deserialize;
use serde_json::{from_value as from_json_value, json}; use serde_json::{from_value as from_json_value, json};
use super::LoginType; use super::{login_type_list_serde, LoginType};
#[derive(Debug, Deserialize)]
struct Foo {
#[serde(with = "login_type_list_serde")]
pub flows: Vec<LoginType>,
}
#[test] #[test]
fn deserialize_login_type() { fn deserialize_login_type() {
assert_eq!( assert_matches!(
from_json_value::<LoginType>(json!({ "type": "m.login.password" })).unwrap(), from_json_value::<Foo>(json!({
LoginType::Password, "flows": [
{ "type": "m.login.password" }
],
})),
Ok(Foo { flows })
if flows.len() == 1
&& flows[0] == LoginType::Password
); );
} }
} }

View File

@ -0,0 +1,31 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use super::LoginType;
pub fn serialize<S>(login_types: &[LoginType], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct Wrap<'a> {
#[serde(rename = "type")]
inner: &'a LoginType,
}
serializer.collect_seq(login_types.iter().map(|ty| Wrap { inner: ty }))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<LoginType>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct Wrap {
#[serde(rename = "type")]
inner: LoginType,
}
// Could be optimized by using a visitor, but that's a bunch of extra code
let vec = Vec::<Wrap>::deserialize(deserializer)?;
Ok(vec.into_iter().map(|w| w.inner).collect())
}