Skip to main content

ruma_appservice_api/
lib.rs

1#![doc(html_favicon_url = "https://ruma.dev/favicon.ico")]
2#![doc(html_logo_url = "https://ruma.dev/images/logo.png")]
3//! (De)serializable types for the [Matrix Application Service API][appservice-api].
4//! These types can be shared by application service and server code.
5//!
6//! [appservice-api]: https://spec.matrix.org/v1.19/application-service-api/
7
8// This crate is not useful without either of those features, so export nothing if they are not
9// enabled to avoid errors when running checks wrongly without enabling any of them.
10#![cfg(any(feature = "client", feature = "server"))]
11#![warn(missing_docs)]
12
13use ruma_common::api::auth_scheme::{
14    AuthScheme, ExtractTokenError, add_access_token_as_authorization_header,
15    extract_bearer_or_query_token,
16};
17use serde::{Deserialize, Serialize};
18
19pub mod event;
20#[cfg(feature = "unstable-msc4417")]
21pub mod media;
22pub mod ping;
23pub mod query;
24pub mod thirdparty;
25
26/// A namespace defined by an application service.
27///
28/// Used for [appservice registration](https://spec.matrix.org/v1.19/application-service-api/#registration).
29#[derive(Clone, Debug, Serialize, Deserialize)]
30#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
31pub struct Namespace {
32    /// Whether this application service has exclusive access to events within this namespace.
33    pub exclusive: bool,
34
35    /// A POSIX regular expression defining which values this namespace includes.
36    pub regex: String,
37}
38
39impl Namespace {
40    /// Creates a new `Namespace` with the given exclusivity and regex pattern.
41    pub fn new(exclusive: bool, regex: String) -> Self {
42        Namespace { exclusive, regex }
43    }
44}
45
46/// Namespaces defined by an application service.
47///
48/// Used for [appservice registration](https://spec.matrix.org/v1.19/application-service-api/#registration).
49#[derive(Clone, Debug, Default, Serialize, Deserialize)]
50#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
51pub struct Namespaces {
52    /// Events which are sent from certain users.
53    #[serde(default, skip_serializing_if = "Vec::is_empty")]
54    pub users: Vec<Namespace>,
55
56    /// Events which are sent in rooms with certain room aliases.
57    #[serde(default, skip_serializing_if = "Vec::is_empty")]
58    pub aliases: Vec<Namespace>,
59
60    /// Events which are sent in rooms with certain room IDs.
61    #[serde(default, skip_serializing_if = "Vec::is_empty")]
62    pub rooms: Vec<Namespace>,
63
64    /// URLs that this appservice will be queried about.
65    #[cfg(feature = "unstable-msc4417")]
66    #[serde(default, skip_serializing_if = "Vec::is_empty")]
67    #[serde(rename = "uk.half-shot.msc4417.preview_urls")]
68    pub preview_urls: Vec<Namespace>,
69}
70
71impl Namespaces {
72    /// Creates a new `Namespaces` instance with empty namespaces for `users`,  `aliases` and
73    /// `rooms` (none of them are explicitly required)
74    pub fn new() -> Self {
75        Self::default()
76    }
77}
78
79/// Information required in the registration yaml file that a homeserver needs.
80///
81/// To create an instance of this type, first create a `RegistrationInit` and convert it via
82/// `Registration::from` / `.into()`.
83///
84/// Used for [appservice registration](https://spec.matrix.org/v1.19/application-service-api/#registration).
85#[derive(Clone, Debug, Serialize, Deserialize)]
86#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
87pub struct Registration {
88    /// A unique, user - defined ID of the application service which will never change.
89    pub id: String,
90
91    /// The URL for the application service.
92    ///
93    /// Optionally set to `null` if no traffic is required.
94    #[serde(deserialize_with = "Option::deserialize")]
95    pub url: Option<String>,
96
97    /// A unique token for application services to use to authenticate requests to Homeservers.
98    pub as_token: String,
99
100    /// A unique token for Homeservers to use to authenticate requests to application services.
101    pub hs_token: String,
102
103    /// The localpart of the user associated with the application service.
104    pub sender_localpart: String,
105
106    /// A list of users, aliases and rooms namespaces that the application service controls.
107    pub namespaces: Namespaces,
108
109    /// Whether requests from masqueraded users are rate-limited.
110    ///
111    /// The sender is excluded.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub rate_limited: Option<bool>,
114
115    /// The external protocols which the application service provides (e.g. IRC).
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub protocols: Option<Vec<String>>,
118
119    /// Whether the application service wants to receive ephemeral data.
120    ///
121    /// Defaults to `false`.
122    #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
123    pub receive_ephemeral: bool,
124}
125
126/// Initial set of fields of `Registration`.
127///
128/// This struct will not be updated even if additional fields are added to `Registration` in a new
129/// (non-breaking) release of the Matrix specification.
130///
131/// Used for [appservice registration](https://spec.matrix.org/v1.19/application-service-api/#registration).
132#[derive(Debug)]
133#[allow(clippy::exhaustive_structs)]
134pub struct RegistrationInit {
135    /// A unique, user - defined ID of the application service which will never change.
136    pub id: String,
137
138    /// The URL for the application service.
139    ///
140    /// Optionally set to `null` if no traffic is required.
141    pub url: Option<String>,
142
143    /// A unique token for application services to use to authenticate requests to Homeservers.
144    pub as_token: String,
145
146    /// A unique token for Homeservers to use to authenticate requests to application services.
147    pub hs_token: String,
148
149    /// The localpart of the user associated with the application service.
150    pub sender_localpart: String,
151
152    /// A list of users, aliases and rooms namespaces that the application service controls.
153    pub namespaces: Namespaces,
154
155    /// Whether requests from masqueraded users are rate-limited.
156    ///
157    /// The sender is excluded.
158    pub rate_limited: Option<bool>,
159
160    /// The external protocols which the application service provides (e.g. IRC).
161    pub protocols: Option<Vec<String>>,
162}
163
164impl From<RegistrationInit> for Registration {
165    fn from(init: RegistrationInit) -> Self {
166        let RegistrationInit {
167            id,
168            url,
169            as_token,
170            hs_token,
171            sender_localpart,
172            namespaces,
173            rate_limited,
174            protocols,
175        } = init;
176        Self {
177            id,
178            url,
179            as_token,
180            hs_token,
181            sender_localpart,
182            namespaces,
183            rate_limited,
184            protocols,
185            receive_ephemeral: false,
186        }
187    }
188}
189
190/// Authentication is required, and can only be performed by a homeserver sending a request to an
191/// appservice, by including a homeserver access token in the `Authorization` http header, or an
192/// `access_token` query parameter.
193///
194/// Using the query parameter is deprecated since Matrix 1.4.
195#[derive(Debug, Clone, Copy, Default)]
196#[allow(clippy::exhaustive_structs)]
197pub struct HomeserverToken;
198
199impl AuthScheme for HomeserverToken {
200    type Input<'a> = &'a str;
201    type AddAuthenticationError = http::header::InvalidHeaderValue;
202    /// The homeserver token.
203    type Output = String;
204    type ExtractAuthenticationError = ExtractTokenError;
205
206    fn add_authentication<T: AsRef<[u8]>>(
207        request: &mut http::Request<T>,
208        access_token: Self::Input<'_>,
209    ) -> Result<(), Self::AddAuthenticationError> {
210        add_access_token_as_authorization_header(request.headers_mut(), access_token)
211    }
212
213    fn extract_authentication<T>(
214        request: &http::Request<T>,
215    ) -> Result<Self::Output, Self::ExtractAuthenticationError> {
216        extract_bearer_or_query_token(request)?.ok_or(ExtractTokenError::MissingAccessToken)
217    }
218}