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