From e567d1706270b2ff34065952d7badfd34199d073 Mon Sep 17 00:00:00 2001 From: Xre0uS Date: Thu, 21 May 2026 11:23:59 +0800 Subject: [PATCH] fix: percent-decode user_id route params for users with spaces in ID (#585) --- Cargo.lock | 1 + app/Cargo.toml | 1 + app/src/components/app.rs | 24 ++++++++++++++++++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e989f4..f8a462e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2743,6 +2743,7 @@ dependencies = [ "lldap_auth", "lldap_frontend_options", "lldap_validation", + "percent-encoding", "rand 0.8.6", "serde", "serde_json", diff --git a/app/Cargo.toml b/app/Cargo.toml index f99dc6f..cb1d572 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -24,6 +24,7 @@ rand = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } strum = { workspace = true } +percent-encoding = "2" url-escape = "0.1.1" validator = "0.14" validator_derive = "0.14" diff --git a/app/src/components/app.rs b/app/src/components/app.rs index 564f361..89b5527 100644 --- a/app/src/components/app.rs +++ b/app/src/components/app.rs @@ -183,6 +183,16 @@ impl App { } } + /// Percent-decode a URL path segment into a user ID string. + /// Returns `None` if the decoded bytes are not valid UTF-8, so the caller + /// can redirect to a safe page rather than silently mangling the ID. + fn decode_user_id(raw: &str) -> Option { + percent_encoding::percent_decode_str(raw) + .decode_utf8() + .ok() + .map(|s| s.into_owned()) + } + fn dispatch_route( switch: &AppRoute, link: &Scope, @@ -248,11 +258,17 @@ impl App { AppRoute::GroupDetails { group_id } => html! { }, - AppRoute::UserDetails { user_id } => html! { - + AppRoute::UserDetails { user_id } => match Self::decode_user_id(user_id) { + Some(decoded_id) => html! { + + }, + None => html! { }, }, - AppRoute::ChangePassword { user_id } => html! { - + AppRoute::ChangePassword { user_id } => match Self::decode_user_id(user_id) { + Some(decoded_id) => html! { + + }, + None => html! { }, }, AppRoute::StartResetPassword => match password_reset_enabled { Some(true) => html! { },