fix(auth): trim the username before authenticating
The login form guarded on `username.trim()` but sent the raw value, so a trailing space from a soft keyboard reached the server verbatim. Jellyfin reports that as an unknown user, which surfaces as a 401 indistinguishable from a wrong password — the user is certain of their credentials and the app insists otherwise. Normalising in AuthManager rather than the form keeps it on the path every caller uses, alongside normalize_url. Only surrounding whitespace is stripped; interior spaces are legal in Jellyfin usernames.
This commit is contained in:
@@ -129,6 +129,18 @@ impl AuthManager {
|
|||||||
Ok(normalized)
|
Ok(normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize a username before it goes to the server.
|
||||||
|
///
|
||||||
|
/// Only surrounding whitespace is stripped — interior spaces are legal in
|
||||||
|
/// Jellyfin usernames. Without this, a trailing space from a soft keyboard's
|
||||||
|
/// autocorrect makes the server report an unknown user, which surfaces as a
|
||||||
|
/// 401 that looks exactly like a wrong password.
|
||||||
|
///
|
||||||
|
/// TRACES: UR-042 | DR-054
|
||||||
|
pub fn normalize_username(username: &str) -> String {
|
||||||
|
username.trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// Connect to server and get server info
|
/// Connect to server and get server info
|
||||||
pub async fn connect_to_server(&self, server_url: &str) -> Result<ServerInfo, String> {
|
pub async fn connect_to_server(&self, server_url: &str) -> Result<ServerInfo, String> {
|
||||||
let normalized_url = Self::normalize_url(server_url)?;
|
let normalized_url = Self::normalize_url(server_url)?;
|
||||||
@@ -185,6 +197,7 @@ impl AuthManager {
|
|||||||
) -> Result<AuthResult, String> {
|
) -> Result<AuthResult, String> {
|
||||||
let url = Self::normalize_url(server_url)?;
|
let url = Self::normalize_url(server_url)?;
|
||||||
let endpoint = format!("{}/Users/AuthenticateByName", url);
|
let endpoint = format!("{}/Users/AuthenticateByName", url);
|
||||||
|
let username = Self::normalize_username(username);
|
||||||
|
|
||||||
log::info!("[AuthManager] Authenticating user: {}", username);
|
log::info!("[AuthManager] Authenticating user: {}", username);
|
||||||
|
|
||||||
@@ -443,6 +456,26 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Usernames must be trimmed before they reach the server: the Android soft
|
||||||
|
/// keyboard appends a trailing space after autocorrect, and Jellyfin then
|
||||||
|
/// reports an unknown user — a 401 indistinguishable from a wrong password.
|
||||||
|
#[test]
|
||||||
|
fn test_normalize_username_trims_whitespace() {
|
||||||
|
assert_eq!(AuthManager::normalize_username("duncan "), "duncan");
|
||||||
|
assert_eq!(AuthManager::normalize_username(" duncan"), "duncan");
|
||||||
|
assert_eq!(AuthManager::normalize_username(" duncan "), "duncan");
|
||||||
|
assert_eq!(AuthManager::normalize_username("duncan\n"), "duncan");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Interior spaces are legal in Jellyfin usernames and must survive.
|
||||||
|
#[test]
|
||||||
|
fn test_normalize_username_preserves_interior_spaces() {
|
||||||
|
assert_eq!(
|
||||||
|
AuthManager::normalize_username(" duncan tourolle "),
|
||||||
|
"duncan tourolle"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Test URL normalization - real world case
|
/// Test URL normalization - real world case
|
||||||
#[test]
|
#[test]
|
||||||
fn test_normalize_url_real_world_case() {
|
fn test_normalize_url_real_world_case() {
|
||||||
|
|||||||
Reference in New Issue
Block a user