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)
use ruma_api::ruma_api;
use serde::{Deserialize, Serialize};
use ruma_serde::StringEnum;
ruma_api! {
metadata: {
@ -18,7 +18,8 @@ ruma_api! {
response: {
/// The homeserver's supported login types.
pub flows: Vec<LoginType>
#[serde(with = "login_type_list_serde")]
pub flows: Vec<LoginType>,
}
error: crate::Error
@ -39,33 +40,51 @@ impl Response {
}
/// An authentication mechanism.
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[serde(tag = "type")]
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
pub enum LoginType {
/// A password is supplied to authenticate.
#[serde(rename = "m.login.password")]
#[ruma_enum(rename = "m.login.password")]
Password,
/// Token-based login.
#[serde(rename = "m.login.token")]
#[ruma_enum(rename = "m.login.token")]
Token,
/// SSO-based login.
#[serde(rename = "m.login.sso")]
#[ruma_enum(rename = "m.login.sso")]
Sso,
#[doc(hidden)]
_Custom(String),
}
mod login_type_list_serde;
#[cfg(test)]
mod tests {
use matches::assert_matches;
use serde::Deserialize;
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]
fn deserialize_login_type() {
assert_eq!(
from_json_value::<LoginType>(json!({ "type": "m.login.password" })).unwrap(),
LoginType::Password,
assert_matches!(
from_json_value::<Foo>(json!({
"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())
}