Move user ID localpart classification into a public function
This commit is contained in:
parent
76a5a487d2
commit
93f75353a7
@ -27,6 +27,9 @@ Improvements:
|
|||||||
* Add support for historical uppercase MXIDs
|
* Add support for historical uppercase MXIDs
|
||||||
* Made all dependencies optional
|
* Made all dependencies optional
|
||||||
* `serde` is the only one that is enabled by default
|
* `serde` is the only one that is enabled by default
|
||||||
|
* The `user_id` module is now public and contains `fn localpart_is_fully_conforming`
|
||||||
|
* This function can be used to determine whether a user name (the localpart of a user ID) is valid
|
||||||
|
without actually constructing a full user ID first
|
||||||
|
|
||||||
# 0.14.1
|
# 0.14.1
|
||||||
|
|
||||||
|
@ -20,10 +20,9 @@ use std::num::NonZeroU8;
|
|||||||
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
|
use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::device_id::DeviceId;
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
error::Error, event_id::EventId, room_alias_id::RoomAliasId, room_id::RoomId,
|
device_id::DeviceId, error::Error, event_id::EventId, room_alias_id::RoomAliasId,
|
||||||
room_id_or_room_alias_id::RoomIdOrAliasId, room_version_id::RoomVersionId,
|
room_id::RoomId, room_id_or_room_alias_id::RoomIdOrAliasId, room_version_id::RoomVersionId,
|
||||||
server_name::is_valid_server_name, user_id::UserId,
|
server_name::is_valid_server_name, user_id::UserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ mod room_id;
|
|||||||
mod room_id_or_room_alias_id;
|
mod room_id_or_room_alias_id;
|
||||||
mod room_version_id;
|
mod room_version_id;
|
||||||
mod server_name;
|
mod server_name;
|
||||||
mod user_id;
|
pub mod user_id;
|
||||||
|
|
||||||
/// All identifiers must be 255 bytes or less.
|
/// All identifiers must be 255 bytes or less.
|
||||||
const MAX_BYTES: usize = 255;
|
const MAX_BYTES: usize = 255;
|
||||||
|
@ -84,29 +84,43 @@ impl TryFrom<Cow<'_, str>> for UserId {
|
|||||||
let colon_idx = parse_id(&user_id, &['@'])?;
|
let colon_idx = parse_id(&user_id, &['@'])?;
|
||||||
let localpart = &user_id[1..colon_idx.get() as usize];
|
let localpart = &user_id[1..colon_idx.get() as usize];
|
||||||
|
|
||||||
// See https://matrix.org/docs/spec/appendices#user-identifiers
|
let is_historical = localpart_is_fully_comforming(localpart)?;
|
||||||
let is_fully_conforming = localpart.bytes().all(|b| match b {
|
|
||||||
b'0'..=b'9' | b'a'..=b'z' | b'-' | b'.' | b'=' | b'_' | b'/' => true,
|
|
||||||
_ => false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If it's not fully conforming, check if it contains characters that are also disallowed
|
|
||||||
// for historical user IDs. If there are, return an error.
|
|
||||||
// See https://matrix.org/docs/spec/appendices#historical-user-ids
|
|
||||||
if !is_fully_conforming && localpart.bytes().any(|b| b < 0x21 || b == b':' || b > 0x7E) {
|
|
||||||
return Err(Error::InvalidCharacters);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
full_id: user_id.into_owned(),
|
full_id: user_id.into_owned(),
|
||||||
colon_idx,
|
colon_idx,
|
||||||
is_historical: !is_fully_conforming,
|
is_historical: !is_historical,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
common_impls!(UserId, "a Matrix user ID");
|
common_impls!(UserId, "a Matrix user ID");
|
||||||
|
|
||||||
|
/// Check whether the given user id localpart is valid and fully conforming
|
||||||
|
///
|
||||||
|
/// Returns an `Err` for invalid user ID localparts, `Ok(false)` for historical user ID localparts
|
||||||
|
/// and `Ok(true)` for fully conforming user ID localparts.
|
||||||
|
pub fn localpart_is_fully_comforming(localpart: &str) -> Result<bool, Error> {
|
||||||
|
if localpart.is_empty() {
|
||||||
|
return Err(Error::InvalidLocalPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://matrix.org/docs/spec/appendices#user-identifiers
|
||||||
|
let is_fully_conforming = localpart.bytes().all(|b| match b {
|
||||||
|
b'0'..=b'9' | b'a'..=b'z' | b'-' | b'.' | b'=' | b'_' | b'/' => true,
|
||||||
|
_ => false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// If it's not fully conforming, check if it contains characters that are also disallowed
|
||||||
|
// for historical user IDs. If there are, return an error.
|
||||||
|
// See https://matrix.org/docs/spec/appendices#historical-user-ids
|
||||||
|
if !is_fully_conforming && localpart.bytes().any(|b| b < 0x21 || b == b':' || b > 0x7E) {
|
||||||
|
Err(Error::InvalidCharacters)
|
||||||
|
} else {
|
||||||
|
Ok(is_fully_conforming)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user