diff --git a/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs b/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs index b7f08ae..6441f5d 100644 --- a/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs +++ b/crates/lanspread-tauri-deno-ts/src-tauri/src/lib.rs @@ -1470,12 +1470,18 @@ fn sanitize_language(language: &str) -> String { } } +/// Characters that `cmd.exe` interprets even when the argument was quoted, +/// because batch scripts expand `%~4` textually into their own command lines. +/// `"` would end the quoted argument and `%` starts variable expansion; the +/// rest are command separators, redirection and the escape character. +const CMD_UNSAFE_USERNAME_CHARS: [char; 7] = ['"', '%', '&', '|', '<', '>', '^']; + #[cfg_attr(not(target_os = "windows"), allow(dead_code))] fn sanitize_username(username: &str) -> String { let cleaned = username .trim() .chars() - .filter(|c| !c.is_control() && *c != '"' && *c != '%') + .filter(|c| !c.is_control() && !CMD_UNSAFE_USERNAME_CHARS.contains(c)) .take(MAX_USERNAME_CHARS) .collect::(); @@ -6173,6 +6179,15 @@ mod tests { username: DEFAULT_USERNAME.to_string(), } ); + // cmd.exe metacharacters are stripped even inside a quoted argument; + // everything else, including spaces and non-ASCII letters, survives. + assert_eq!( + launch_settings("en", "Jörg & Co | x > y < z ^ !"), + LaunchSettings { + language: "en".to_string(), + username: "Jörg Co x y z !".to_string(), + } + ); } #[test]