From dea26377c860c49e291d187d7ae33a050aa3bf63 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sun, 25 Oct 2026 12:57:08 -1000 Subject: Say when a login fails, and line up the form A wrong password sent the reader back to the same empty form, which looked no different from a crash. The redirect now carries a flag the form reads, the same for an unknown user as for a wrong password, and the form leaves the flag out of the way back it signs. --- tests/extensions/test-auth.lua | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'tests/extensions/test-auth.lua') diff --git a/tests/extensions/test-auth.lua b/tests/extensions/test-auth.lua index 0115716..742eabe 100644 --- a/tests/extensions/test-auth.lua +++ b/tests/extensions/test-auth.lua @@ -278,7 +278,8 @@ out, ret = run_action("no-such-action", {}) h.equals("an unknown action denies rather than raising", ret, 0) out, ret = run_action("body", { url = "/repo/log/?q=x" }) -h.contains("the login form posts to the login url", out, "
") +h.contains("the login form posts to the login url", out, "") +h.equals("a first visit says nothing failed", out:find("login-error", 1, true), nil) local token = out:match("name='redirect' value='([^']*)'") h.equals("the form carries a signed way back", token and validate_value("redirect", token), "/repo/log/?q=x") @@ -286,6 +287,13 @@ out, ret = run_action("body", { url = "//evil.example/x" }) token = out:match("name='redirect' value='([^']*)'") h.equals("an unsafe destination is swapped for the login page", token and validate_value("redirect", token), "/?p=login") +h.equals("and is not taken for a failed login", out:find("login-error", 1, true), nil) + +out, ret = run_action("body", { url = "/repo/log/?q=x&login=failed" }) +h.contains("a failed login says so", out, + "") +token = out:match("name='redirect' value='([^']*)'") +h.equals("and leaves the flag out of the way back", token and validate_value("redirect", token), "/repo/log/?q=x") local way_back = secure_value("redirect", "/repo/", 0) @@ -303,6 +311,7 @@ out, ret = run_action("authenticate-post", { body = "username=Alice&password=wrong&redirect=" .. url_encode(way_back), }) h.contains("a bad password redirects the same way", out, "Status: 302") +h.contains("back to the page with the failure flagged", out, "Location: /repo/?login=failed\n") h.contains("but clears the session cookie", out, "Set-Cookie: " .. session_name .. "=; ") out, ret = run_action("authenticate-post", { @@ -310,6 +319,7 @@ out, ret = run_action("authenticate-post", { body = "username=nobody&password=x&redirect=" .. url_encode(way_back), }) h.contains("an unknown user is told nothing different", out, "Set-Cookie: " .. session_name .. "=; ") +h.contains("and lands on the same flagged page", out, "Location: /repo/?login=failed\n") -- A failed login for a name with no account spends crypt on a configured -- hash, the same work a real check costs, so timing tells nothing. -- cgit 2.9.2