ruma_identifiers_validation/
lib.rs1#![doc(html_favicon_url = "https://ruma.dev/favicon.ico")]
2#![doc(html_logo_url = "https://ruma.dev/images/logo.png")]
3
4#[cfg(feature = "unstable-msc4363")]
5pub mod acr;
6pub mod base64_public_key;
7pub mod client_secret;
8pub mod error;
9pub mod event_id;
10pub mod key_id;
11pub mod mxc_uri;
12pub mod oauth_scope;
13pub mod room_alias_id;
14pub mod room_id;
15pub mod room_id_or_alias_id;
16pub mod room_version_id;
17pub mod server_name;
18pub mod server_signing_key_version;
19pub mod space_child_order;
20pub mod user_id;
21pub mod voip_version_id;
22
23pub use error::Error;
24
25pub const ID_MAX_BYTES: usize = 255;
27
28fn validate_id(id: &str, first_byte: u8) -> Result<(), Error> {
30 #[cfg(not(feature = "compat-arbitrary-length-ids"))]
31 if id.len() > ID_MAX_BYTES {
32 return Err(Error::MaximumLengthExceeded);
33 }
34
35 if id.as_bytes().first() != Some(&first_byte) {
36 return Err(Error::MissingLeadingSigil);
37 }
38
39 Ok(())
40}
41
42fn parse_id(id: &str, first_byte: u8) -> Result<usize, Error> {
44 validate_id(id, first_byte)?;
45 let colon_idx = id.find(':').ok_or(Error::MissingColon)?;
46 server_name::validate(&id[colon_idx + 1..])?;
47 Ok(colon_idx)
48}
49
50fn validate_delimited_id(id: &str, first_byte: u8) -> Result<(), Error> {
52 parse_id(id, first_byte)?;
53 Ok(())
54}
55
56pub trait KeyName: AsRef<str> {
58 fn validate(s: &str) -> Result<(), Error>;
60}
61
62pub fn localpart_is_backwards_compatible(localpart: &str) -> Result<(), Error> {
69 let is_invalid = localpart.contains([':', '\0']);
70 if is_invalid { Err(Error::InvalidCharacters) } else { Ok(()) }
71}