Skip to main content

ruma_common/
identifiers.rs

1//! Types for [Matrix](https://matrix.org/) identifiers for devices, events, keys, rooms, servers,
2//! users and URIs.
3
4// FIXME: Remove once lint doesn't trigger on std::convert::TryFrom in identifiers/macros.rs anymore
5#![allow(unused_qualifications)]
6
7#[doc(inline)]
8pub use ruma_identifiers_validation::{
9    ID_MAX_BYTES, KeyName,
10    error::{
11        Error as IdParseError, MatrixIdError, MatrixToError, MatrixUriError, MxcUriError,
12        VoipVersionIdError,
13    },
14};
15use serde::de::{self, Deserializer, Unexpected};
16
17#[doc(inline)]
18pub use self::{
19    base64_public_key::{Base64PublicKey, OwnedBase64PublicKey},
20    base64_public_key_or_device_id::{Base64PublicKeyOrDeviceId, OwnedBase64PublicKeyOrDeviceId},
21    client_secret::{ClientSecret, OwnedClientSecret},
22    crypto_algorithms::{
23        DeviceKeyAlgorithm, EventEncryptionAlgorithm, KeyDerivationAlgorithm, OneTimeKeyAlgorithm,
24        SigningKeyAlgorithm,
25    },
26    device_id::{DeviceId, OwnedDeviceId},
27    direct_user_identifier::{DirectUserIdentifier, OwnedDirectUserIdentifier},
28    event_id::{EventId, OwnedEventId},
29    key_id::{
30        AnyKeyName, CrossSigningKeyId, CrossSigningOrDeviceSigningKeyId, DeviceKeyId,
31        DeviceSigningKeyId, KeyAlgorithm, KeyId, OneTimeKeyId, OwnedCrossSigningKeyId,
32        OwnedCrossSigningOrDeviceSigningKeyId, OwnedDeviceKeyId, OwnedDeviceSigningKeyId,
33        OwnedKeyId, OwnedOneTimeKeyId, OwnedServerSigningKeyId, OwnedSigningKeyId,
34        ServerSigningKeyId, SigningKeyId,
35    },
36    matrix_uri::{MatrixToUri, MatrixUri},
37    mxc_uri::{MxcUri, OwnedMxcUri},
38    one_time_key_name::{OneTimeKeyName, OwnedOneTimeKeyName},
39    room_alias_id::{OwnedRoomAliasId, RoomAliasId},
40    room_id::{OwnedRoomId, RoomId},
41    room_or_alias_id::{OwnedRoomOrAliasId, RoomOrAliasId},
42    room_version_id::RoomVersionId,
43    server_name::{OwnedServerName, ServerName},
44    server_signing_key_version::{OwnedServerSigningKeyVersion, ServerSigningKeyVersion},
45    session_id::{OwnedSessionId, SessionId},
46    signatures::{
47        CrossSigningOrDeviceSignatures, DeviceSignatures, EntitySignatures, ServerSignatures,
48        Signatures,
49    },
50    space_child_order::{OwnedSpaceChildOrder, SpaceChildOrder},
51    transaction_id::{OwnedTransactionId, TransactionId},
52    user_id::{OwnedUserId, UserId},
53    voip_id::{OwnedVoipId, VoipId},
54    voip_version_id::VoipVersionId,
55};
56
57pub mod matrix_uri;
58pub mod user_id;
59
60mod base64_public_key;
61mod base64_public_key_or_device_id;
62mod client_secret;
63mod crypto_algorithms;
64mod device_id;
65mod direct_user_identifier;
66mod event_id;
67mod key_id;
68mod mxc_uri;
69mod one_time_key_name;
70mod room_alias_id;
71mod room_id;
72mod room_or_alias_id;
73mod room_version_id;
74mod server_name;
75mod server_signing_key_version;
76mod session_id;
77mod signatures;
78mod space_child_order;
79mod transaction_id;
80mod voip_id;
81mod voip_version_id;
82
83/// Generates a random identifier localpart.
84#[cfg(feature = "rand")]
85fn generate_localpart(length: usize) -> Box<str> {
86    use rand::RngExt as _;
87    rand::rng()
88        .sample_iter(&rand::distr::Alphanumeric)
89        .map(char::from)
90        .take(length)
91        .collect::<String>()
92        .into_boxed_str()
93}
94
95/// Find the localpart in the given identifier string.
96///
97/// This function expects the string to start with a sigil and the localpart to be the part between
98/// the sigil and the first colon. If there is no colon, the full string after the sigil is assumed
99/// to be the localpart.
100fn find_localpart(s: &str) -> &str {
101    let without_sigil = &s[1..];
102    without_sigil.find(':').map(|idx| &without_sigil[..idx]).unwrap_or(without_sigil)
103}
104
105/// Find the server name in the given identifier string and return it as a `&str`.
106///
107/// This function expects the server name to be the part of the string after the first colon.
108///
109/// Returns `None` if there is no colon in the string.
110fn find_server_name_str(s: &str) -> Option<&str> {
111    s.find(':').map(|idx| &s[idx + 1..])
112}
113
114/// Find the server name from the given identifier string an return it as a `ServerName`.
115///
116/// This function expects the server name to be the part of the string after the first colon, and
117/// that it was already validated.
118///
119/// Returns `None` if there is no colon in the string.
120fn find_server_name_unchecked(s: &str) -> Option<&ServerName> {
121    find_server_name_str(s).map(ServerName::from_borrowed_unchecked)
122}
123
124/// Deserializes any type of id using the provided `TryFrom` implementation.
125///
126/// This is a helper function to reduce the boilerplate of the `Deserialize` implementations.
127fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result<T, D::Error>
128where
129    D: Deserializer<'de>,
130    T: for<'a> TryFrom<&'a str>,
131{
132    crate::serde::deserialize_cow_str(deserializer).and_then(|v| {
133        T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str))
134    })
135}
136
137/// Shorthand for `<&DeviceId>::from`.
138#[macro_export]
139macro_rules! device_id {
140    ($s:expr) => {
141        <&$crate::DeviceId as ::std::convert::From<_>>::from($s)
142    };
143}
144
145/// Shorthand for `OwnedDeviceId::from`.
146#[macro_export]
147macro_rules! owned_device_id {
148    ($s:expr) => {
149        <$crate::OwnedDeviceId as ::std::convert::From<_>>::from($s)
150    };
151}
152
153#[doc(hidden)]
154pub mod __private_macros {
155    pub use ruma_macros::{
156        base64_public_key, event_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
157        server_signing_key_version, user_id,
158    };
159}
160
161/// Compile-time checked [`EventId`] construction.
162#[macro_export]
163macro_rules! event_id {
164    ($s:literal) => {
165        $crate::__private_macros::event_id!($crate, $s)
166    };
167}
168
169/// Compile-time checked [`OwnedEventId`] construction.
170#[macro_export]
171macro_rules! owned_event_id {
172    ($s:literal) => {
173        $crate::event_id!($s).to_owned()
174    };
175}
176
177/// Compile-time checked [`RoomAliasId`] construction.
178#[macro_export]
179macro_rules! room_alias_id {
180    ($s:literal) => {
181        $crate::__private_macros::room_alias_id!($crate, $s)
182    };
183}
184
185/// Compile-time checked [`OwnedRoomAliasId`] construction.
186#[macro_export]
187macro_rules! owned_room_alias_id {
188    ($s:literal) => {
189        $crate::room_alias_id!($s).to_owned()
190    };
191}
192
193/// Compile-time checked [`RoomId`] construction.
194#[macro_export]
195macro_rules! room_id {
196    ($s:literal) => {
197        $crate::__private_macros::room_id!($crate, $s)
198    };
199}
200
201/// Compile-time checked [`OwnedRoomId`] construction.
202#[macro_export]
203macro_rules! owned_room_id {
204    ($s:literal) => {
205        $crate::room_id!($s).to_owned()
206    };
207}
208
209/// Compile-time checked [`RoomVersionId`] construction.
210#[macro_export]
211macro_rules! room_version_id {
212    ($s:literal) => {
213        $crate::__private_macros::room_version_id!($crate, $s)
214    };
215}
216
217/// Compile-time checked [`ServerSigningKeyVersion`] construction.
218#[macro_export]
219macro_rules! server_signing_key_version {
220    ($s:literal) => {
221        $crate::__private_macros::server_signing_key_version!($crate, $s)
222    };
223}
224
225/// Compile-time checked [`OwnedServerSigningKeyVersion`] construction.
226#[macro_export]
227macro_rules! owned_server_signing_key_version {
228    ($s:literal) => {
229        $crate::server_signing_key_version!($s).to_owned()
230    };
231}
232
233/// Compile-time checked [`ServerName`] construction.
234#[macro_export]
235macro_rules! server_name {
236    ($s:literal) => {
237        $crate::__private_macros::server_name!($crate, $s)
238    };
239}
240
241/// Compile-time checked [`OwnedServerName`] construction.
242#[macro_export]
243macro_rules! owned_server_name {
244    ($s:literal) => {
245        $crate::server_name!($s).to_owned()
246    };
247}
248
249/// Compile-time checked [`SessionId`] construction.
250#[macro_export]
251macro_rules! session_id {
252    ($s:literal) => {{
253        const SESSION_ID: &$crate::SessionId = match $crate::SessionId::_priv_const_new($s) {
254            Ok(id) => id,
255            Err(e) => panic!("{}", e),
256        };
257
258        SESSION_ID
259    }};
260}
261
262/// Compile-time checked [`OwnedSessionId`] construction.
263#[macro_export]
264macro_rules! owned_session_id {
265    ($s:literal) => {
266        $crate::session_id!($s).to_owned()
267    };
268}
269
270/// Compile-time checked [`MxcUri`] construction.
271#[macro_export]
272macro_rules! mxc_uri {
273    ($s:literal) => {
274        $crate::__private_macros::mxc_uri!($crate, $s)
275    };
276}
277
278/// Compile-time checked [`OwnedMxcUri`] construction.
279#[macro_export]
280macro_rules! owned_mxc_uri {
281    ($s:literal) => {
282        $crate::mxc_uri!($s).to_owned()
283    };
284}
285
286/// Compile-time checked [`UserId`] construction.
287#[macro_export]
288macro_rules! user_id {
289    ($s:literal) => {
290        $crate::__private_macros::user_id!($crate, $s)
291    };
292}
293
294/// Compile-time checked [`OwnedUserId`] construction.
295#[macro_export]
296macro_rules! owned_user_id {
297    ($s:literal) => {
298        $crate::user_id!($s).to_owned()
299    };
300}
301
302/// Compile-time checked [`Base64PublicKey`] construction.
303#[macro_export]
304macro_rules! base64_public_key {
305    ($s:literal) => {
306        $crate::__private_macros::base64_public_key!($crate, $s)
307    };
308}
309
310/// Compile-time checked [`OwnedBase64PublicKey`] construction.
311#[macro_export]
312macro_rules! owned_base64_public_key {
313    ($s:literal) => {
314        $crate::base64_public_key!($s).to_owned()
315    };
316}