appservice-api: Add types for appservice registration YAML

This commit is contained in:
Akshay 2021-02-24 17:02:56 +05:30 committed by GitHub
parent 6b0bf53601
commit ed559c63f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 203 additions and 0 deletions

View File

@ -22,3 +22,7 @@ serde_json = "1.0.61"
[features] [features]
unstable-exhaustive-types = [] unstable-exhaustive-types = []
[dev-dependencies]
matches = "0.1.8"
serde_yaml = "0.8.17"

View File

@ -4,6 +4,140 @@
#![warn(missing_debug_implementations, missing_docs)] #![warn(missing_debug_implementations, missing_docs)]
use serde::{Deserialize, Serialize};
pub mod event; pub mod event;
pub mod query; pub mod query;
pub mod thirdparty; pub mod thirdparty;
/// A namespace defined by an application service.
///
/// Used for [appservice registration](https://matrix.org/docs/spec/application_service/r0.1.2#registration).
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Namespace {
/// Whether this application service has exclusive access to events within this namespace.
pub exclusive: bool,
/// A regular expression defining which values this namespace includes.
pub regex: String,
}
impl Namespace {
/// Creates a new `Namespace` with the given exclusivity and regex pattern.
pub fn new(exclusive: bool, regex: String) -> Self {
Namespace { exclusive, regex }
}
}
/// Namespaces defined by an application service.
///
/// Used for [appservice registration](https://matrix.org/docs/spec/application_service/r0.1.2#registration).
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Namespaces {
/// Events which are sent from certain users.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub users: Vec<Namespace>,
/// Events which are sent in rooms with certain room aliases.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub aliases: Vec<Namespace>,
/// Events which are sent in rooms with certain room IDs.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub rooms: Vec<Namespace>,
}
impl Namespaces {
/// Creates a new `Namespaces` instance with empty namespaces for `users`, `aliases` and
/// `rooms` (none of them are explicitly required)
pub fn new() -> Self {
Self::default()
}
}
/// Information required in the registration yaml file that a homeserver needs.
///
/// To create an instance of this type, first create a `RegistrationInit` and convert it via
/// `Registration::from` / `.into()`.
///
/// Used for [appservice registration](https://matrix.org/docs/spec/application_service/r0.1.2#registration).
#[derive(Clone, Debug, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Registration {
/// A unique, user - defined ID of the application service which will never change.
pub id: String,
/// The URL for the application service.
pub url: String,
/// A unique token for application services to use to authenticate requests to Homeservers.
pub as_token: String,
/// A unique token for Homeservers to use to authenticate requests to application services.
pub hs_token: String,
/// The localpart of the user associated with the application service.
pub sender_localpart: String,
/// A list of users, aliases and rooms namespaces that the application service controls.
pub namespaces: Namespaces,
/// Whether requests from masqueraded users are rate-limited. The sender is excluded.
#[serde(skip_serializing_if = "Option::is_none")]
pub rate_limited: Option<bool>,
/// The external protocols which the application service provides (e.g. IRC).
#[serde(skip_serializing_if = "Option::is_none")]
pub protocols: Option<Vec<String>>,
}
/// Initial set of fields of `Registration`.
///
/// This struct will not be updated even if additional fields are added to `Registration` in a new
/// (non-breaking) release of the Matrix specification.
///
/// Used for [appservice registration](https://matrix.org/docs/spec/application_service/r0.1.2#registration).
#[derive(Debug)]
pub struct RegistrationInit {
/// A unique, user - defined ID of the application service which will never change.
pub id: String,
/// The URL for the application service.
pub url: String,
/// A unique token for application services to use to authenticate requests to Homeservers.
pub as_token: String,
/// A unique token for Homeservers to use to authenticate requests to application services.
pub hs_token: String,
/// The localpart of the user associated with the application service.
pub sender_localpart: String,
/// A list of users, aliases and rooms namespaces that the application service controls.
pub namespaces: Namespaces,
/// Whether requests from masqueraded users are rate-limited. The sender is excluded.
pub rate_limited: Option<bool>,
/// The external protocols which the application service provides (e.g. IRC).
pub protocols: Option<Vec<String>>,
}
impl From<RegistrationInit> for Registration {
fn from(init: RegistrationInit) -> Self {
let RegistrationInit {
id,
url,
as_token,
hs_token,
sender_localpart,
namespaces,
rate_limited,
protocols,
} = init;
Self { id, url, as_token, hs_token, sender_localpart, namespaces, rate_limited, protocols }
}
}

View File

@ -0,0 +1,65 @@
use matches::assert_matches;
use ruma_appservice_api::{Namespace, Namespaces, Registration};
#[test]
fn registration_deserialization() {
let registration_config = r##"
id: "IRC Bridge"
url: "http://127.0.0.1:1234"
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
sender_localpart: "_irc_bot"
namespaces:
users:
- exclusive: true
regex: "@_irc_bridge_.*"
aliases:
- exclusive: false
regex: "#_irc_bridge_.*"
rooms: []
"##;
let observed = serde_yaml::from_str(&registration_config).unwrap();
assert_matches!(
observed,
Registration {
id,
url,
as_token,
hs_token,
sender_localpart,
rate_limited,
protocols,
namespaces: Namespaces { users, aliases, rooms, .. },
..
}
if id == "IRC Bridge"
&& url == "http://127.0.0.1:1234"
&& as_token == "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
&& hs_token == "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
&& sender_localpart == "_irc_bot"
&& rate_limited == None
&& protocols == None
&& users[0] == Namespace::new(true, "@_irc_bridge_.*".into())
&& aliases[0] == Namespace::new(false, "#_irc_bridge_.*".into())
&& rooms.is_empty()
);
}
#[test]
fn config_with_optional_url() {
let registration_config = r#"
id: "IRC Bridge"
url: null
as_token: "30c05ae90a248a4188e620216fa72e349803310ec83e2a77b34fe90be6081f46"
hs_token: "312df522183efd404ec1cd22d2ffa4bbc76a8c1ccf541dd692eef281356bb74e"
sender_localpart: "_irc_bot"
namespaces:
users: []
aliases: []
rooms: []
"#;
assert_matches!(
serde_yaml::from_str(&registration_config).unwrap(),
Registration { url, .. } if url == "null"
);
}