From d0d4c586fbcaea6b88cfaaf6ad701bfb888c4cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Tue, 5 Nov 2024 17:35:54 +0100 Subject: [PATCH 1/2] feat(ffi): add room alias format validation --- bindings/matrix-sdk-ffi/src/lib.rs | 1 + bindings/matrix-sdk-ffi/src/room_alias.rs | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 bindings/matrix-sdk-ffi/src/room_alias.rs diff --git a/bindings/matrix-sdk-ffi/src/lib.rs b/bindings/matrix-sdk-ffi/src/lib.rs index 0e404a848ff..a9f1efdb06d 100644 --- a/bindings/matrix-sdk-ffi/src/lib.rs +++ b/bindings/matrix-sdk-ffi/src/lib.rs @@ -30,6 +30,7 @@ mod timeline_event_filter; mod tracing; mod utils; mod widget; +mod room_alias; use async_compat::TOKIO1 as RUNTIME; use matrix_sdk::ruma::events::room::{ diff --git a/bindings/matrix-sdk-ffi/src/room_alias.rs b/bindings/matrix-sdk-ffi/src/room_alias.rs new file mode 100644 index 00000000000..564374b2deb --- /dev/null +++ b/bindings/matrix-sdk-ffi/src/room_alias.rs @@ -0,0 +1,7 @@ +use ruma::RoomAliasId; + +/// Verifies the passed `String` matches the expected room alias format. +#[matrix_sdk_ffi_macros::export] +fn is_room_alias_format_valid(alias: String) -> bool { + RoomAliasId::parse(alias).is_ok() +} \ No newline at end of file From c19a12a118f6493c6e7f6e89fe47c5930a46c11f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Tue, 5 Nov 2024 17:37:10 +0100 Subject: [PATCH 2/2] feat(ffi): add room display name to room alias transformation --- Cargo.lock | 23 +++++----- bindings/matrix-sdk-ffi/src/lib.rs | 2 +- bindings/matrix-sdk-ffi/src/room_alias.rs | 9 +++- crates/matrix-sdk-base/Cargo.toml | 1 + crates/matrix-sdk-base/src/rooms/mod.rs | 54 +++++++++++++++++++++++ 5 files changed, 76 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30db5f2af15..98c2e7b3d74 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -597,7 +597,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", - "regex-automata 0.4.7", + "regex-automata 0.4.8", "serde", ] @@ -2965,6 +2965,7 @@ dependencies = [ "matrix-sdk-store-encryption", "matrix-sdk-test", "once_cell", + "regex", "ruma", "serde", "serde_json", @@ -4143,7 +4144,7 @@ dependencies = [ "rand", "rand_chacha", "rand_xorshift", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", "rusty-fork", "tempfile", "unarray", @@ -4385,14 +4386,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -4406,13 +4407,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -4423,9 +4424,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" diff --git a/bindings/matrix-sdk-ffi/src/lib.rs b/bindings/matrix-sdk-ffi/src/lib.rs index a9f1efdb06d..9ed31580edd 100644 --- a/bindings/matrix-sdk-ffi/src/lib.rs +++ b/bindings/matrix-sdk-ffi/src/lib.rs @@ -16,6 +16,7 @@ mod notification; mod notification_settings; mod platform; mod room; +mod room_alias; mod room_directory_search; mod room_info; mod room_list; @@ -30,7 +31,6 @@ mod timeline_event_filter; mod tracing; mod utils; mod widget; -mod room_alias; use async_compat::TOKIO1 as RUNTIME; use matrix_sdk::ruma::events::room::{ diff --git a/bindings/matrix-sdk-ffi/src/room_alias.rs b/bindings/matrix-sdk-ffi/src/room_alias.rs index 564374b2deb..125cad31512 100644 --- a/bindings/matrix-sdk-ffi/src/room_alias.rs +++ b/bindings/matrix-sdk-ffi/src/room_alias.rs @@ -1,7 +1,14 @@ +use matrix_sdk::DisplayName; use ruma::RoomAliasId; /// Verifies the passed `String` matches the expected room alias format. #[matrix_sdk_ffi_macros::export] fn is_room_alias_format_valid(alias: String) -> bool { RoomAliasId::parse(alias).is_ok() -} \ No newline at end of file +} + +/// Transforms a Room's display name into a valid room alias name. +#[matrix_sdk_ffi_macros::export] +fn room_alias_name_from_room_display_name(room_name: String) -> String { + DisplayName::Named(room_name).to_room_alias_name() +} diff --git a/crates/matrix-sdk-base/Cargo.toml b/crates/matrix-sdk-base/Cargo.toml index 04aac0d4ec3..0c8d575d4b2 100644 --- a/crates/matrix-sdk-base/Cargo.toml +++ b/crates/matrix-sdk-base/Cargo.toml @@ -67,6 +67,7 @@ tokio = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } uniffi = { workspace = true, optional = true } +regex = "1.11.1" [dev-dependencies] assert_matches = { workspace = true } diff --git a/crates/matrix-sdk-base/src/rooms/mod.rs b/crates/matrix-sdk-base/src/rooms/mod.rs index fac5b164f99..9aa9b102750 100644 --- a/crates/matrix-sdk-base/src/rooms/mod.rs +++ b/crates/matrix-sdk-base/src/rooms/mod.rs @@ -15,6 +15,7 @@ pub use normal::{ Room, RoomHero, RoomInfo, RoomInfoNotableUpdate, RoomInfoNotableUpdateReasons, RoomState, RoomStateFilter, }; +use regex::Regex; use ruma::{ assign, events::{ @@ -64,6 +65,38 @@ pub enum DisplayName { Empty, } +const WHITESPACE_REGEX: &str = r"\s+"; +const INVALID_SYMBOLS_REGEX: &str = r"[#,:]+"; + +impl DisplayName { + /// Transforms the current display name into the name part of a + /// `RoomAliasId`. + pub fn to_room_alias_name(&self) -> String { + let room_name = match self { + Self::Named(name) => name, + Self::Aliased(name) => name, + Self::Calculated(name) => name, + Self::EmptyWas(name) => name, + Self::Empty => "", + }; + + let whitespace_regex = + Regex::new(WHITESPACE_REGEX).expect("`WHITESPACE_REGEX` should be valid"); + let symbol_regex = + Regex::new(INVALID_SYMBOLS_REGEX).expect("`INVALID_SYMBOLS_REGEX` should be valid"); + + // Replace whitespaces with `-` + let sanitised = whitespace_regex.replace_all(room_name, "-"); + // Remove non-ASCII characters and ASCII control characters + let sanitised = + String::from_iter(sanitised.chars().filter(|c| c.is_ascii() && !c.is_ascii_control())); + // Remove other problematic ASCII symbols + let sanitised = symbol_regex.replace_all(&sanitised, ""); + // Lowercased + sanitised.to_lowercase() + } +} + impl fmt::Display for DisplayName { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -541,6 +574,7 @@ mod tests { use ruma::events::tag::{TagInfo, TagName, Tags}; use super::{BaseRoomInfo, RoomNotableTags}; + use crate::DisplayName; #[test] fn test_handle_notable_tags_favourite() { @@ -571,4 +605,24 @@ mod tests { base_room_info.handle_notable_tags(&tags); assert!(base_room_info.notable_tags.contains(RoomNotableTags::LOW_PRIORITY).not()); } + + #[test] + fn test_room_alias_from_room_display_name_lowercases() { + assert_eq!("roomalias", DisplayName::Named("RoomAlias".to_owned()).to_room_alias_name()); + } + + #[test] + fn test_room_alias_from_room_display_name_removes_whitespace() { + assert_eq!("room-alias", DisplayName::Named("Room Alias".to_owned()).to_room_alias_name()); + } + + #[test] + fn test_room_alias_from_room_display_name_removes_non_ascii_symbols() { + assert_eq!("roomalias", DisplayName::Named("Room±Alias√".to_owned()).to_room_alias_name()); + } + + #[test] + fn test_room_alias_from_room_display_name_removes_invalid_ascii_symbols() { + assert_eq!("roomalias", DisplayName::Named("#Room,Alias:".to_owned()).to_room_alias_name()); + } }