Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d28ce0b1 | ||
|
|
defface0a5 |
1 changed files with 47 additions and 3 deletions
|
|
@ -378,6 +378,14 @@ fn extract_new_password(bot_message: &str) -> Option<String> {
|
||||||
"reset to:",
|
"reset to:",
|
||||||
"set to: ",
|
"set to: ",
|
||||||
"set to:",
|
"set to:",
|
||||||
|
// Generic "… to: <pw>" form. tuwunel's actual reset-password reply is
|
||||||
|
// "Successfully reset password for @user:server to: <password>" — the
|
||||||
|
// password follows " to: " but no recognised verb sits adjacent to it,
|
||||||
|
// so the markers above miss it. Matrix user ids / server names can't
|
||||||
|
// contain " to: ", so this only ever anchors on the prose delimiter.
|
||||||
|
// Placed after the specific verb markers and before the bare
|
||||||
|
// "password:" last resort.
|
||||||
|
" to: ",
|
||||||
// Bare "new password:" without "is":
|
// Bare "new password:" without "is":
|
||||||
"new password: ",
|
"new password: ",
|
||||||
"new password:",
|
"new password:",
|
||||||
|
|
@ -387,10 +395,15 @@ fn extract_new_password(bot_message: &str) -> Option<String> {
|
||||||
] {
|
] {
|
||||||
if let Some(pos) = lower.find(marker) {
|
if let Some(pos) = lower.find(marker) {
|
||||||
let rest = &bot_message[pos + marker.len()..];
|
let rest = &bot_message[pos + marker.len()..];
|
||||||
let rest = rest.trim_start();
|
// Strip leading whitespace, then a leading code-span backtick:
|
||||||
// Stop at first whitespace or newline; password must be non-empty.
|
// tuwunel renders the password as a code span, so the plain
|
||||||
|
// `body` carries literal backticks ("… to: `<pw>`").
|
||||||
|
let rest = rest.trim_start().trim_start_matches('`');
|
||||||
|
// The password ends at the first whitespace OR the closing
|
||||||
|
// backtick. Generated passwords contain neither, so this never
|
||||||
|
// truncates a real password mid-token.
|
||||||
let end = rest
|
let end = rest
|
||||||
.find(char::is_whitespace)
|
.find(|c: char| c.is_whitespace() || c == '`')
|
||||||
.unwrap_or(rest.len());
|
.unwrap_or(rest.len());
|
||||||
let pw = rest[..end].trim();
|
let pw = rest[..end].trim();
|
||||||
if !pw.is_empty() {
|
if !pw.is_empty() {
|
||||||
|
|
@ -459,6 +472,37 @@ mod extract_new_password_tests {
|
||||||
assert_eq!(extract_new_password(msg).as_deref(), Some("hunter2"));
|
assert_eq!(extract_new_password(msg).as_deref(), Some("hunter2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tuwunel_reset_password_for_to_variant() {
|
||||||
|
// The actual tuwunel admin-room reply observed in production — the
|
||||||
|
// verb ("reset") is not adjacent to "to:", so only the generic
|
||||||
|
// " to: " marker catches it.
|
||||||
|
let msg = "Successfully reset password for @atlas:pr1ma.darkest.space to: N3wP@ssw0rd";
|
||||||
|
assert_eq!(extract_new_password(msg).as_deref(), Some("N3wP@ssw0rd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_marker_not_confused_by_user_id() {
|
||||||
|
// The user id contains no " to: " so the marker only fires on the
|
||||||
|
// real delimiter; the password is the token right after it.
|
||||||
|
let msg = "Successfully reset password for @sock:pr1ma.darkest.space to: abc123XYZ";
|
||||||
|
assert_eq!(extract_new_password(msg).as_deref(), Some("abc123XYZ"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backtick_wrapped_password() {
|
||||||
|
// tuwunel renders the password as a code span; the plain body
|
||||||
|
// carries literal backticks. Strip them, don't capture them.
|
||||||
|
let msg = "Successfully reset password for @atlas:pr1ma.darkest.space to: `N3wP@ssw0rd`";
|
||||||
|
assert_eq!(extract_new_password(msg).as_deref(), Some("N3wP@ssw0rd"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn backtick_wrapped_with_trailing_text() {
|
||||||
|
let msg = "Done. New password is: `hunter2` (store it now)";
|
||||||
|
assert_eq!(extract_new_password(msg).as_deref(), Some("hunter2"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bare_new_password_colon() {
|
fn bare_new_password_colon() {
|
||||||
let msg = "New password: P@ssword1";
|
let msg = "New password: P@ssword1";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue