bliss-cli: detect failed logins instead of caching anon sessions
The server issues a connect.sid cookie on every response, including a rejected login (which re-renders the form as 200). login() treated any returned cookie as success, so bad creds silently cached an anonymous session and the CLI stayed logged out with no warning — and since it only re-authenticates on a 401 (which the server never sends), the stale cookie was never refreshed. Trust the redirect status instead (302 = success, 2xx = rejected) and throw a clear error with the HTTP code on failure. Add a `bliss login` command that forces a fresh login past any stale cookie. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
02cdca748d
commit
e7064a7c6a
2 changed files with 23 additions and 3 deletions
|
|
@ -68,6 +68,14 @@ const commands = {
|
||||||
out(c.BASE);
|
out(c.BASE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// Force a fresh login with BLISS_USER / BLISS_PASS and report the result.
|
||||||
|
// Unlike normal commands (which reuse a cached cookie and only re-auth on a
|
||||||
|
// 401 the server never sends), this always hits /login, so it's the way to
|
||||||
|
// (re)authenticate after changing creds or clearing a stale anonymous cookie.
|
||||||
|
async login() {
|
||||||
|
await c.login(); // throws with a clear message if the server rejects creds
|
||||||
|
out("logged in as '" + (process.env.BLISS_USER || "?") + "' -> " + c.BASE);
|
||||||
|
},
|
||||||
// ---- reads (JSON via /plumbing) ----
|
// ---- reads (JSON via /plumbing) ----
|
||||||
async structures() {
|
async structures() {
|
||||||
out(await c.getJSON("/plumbing/structures"));
|
out(await c.getJSON("/plumbing/structures"));
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,21 @@ async function login() {
|
||||||
headers: { "content-type": "application/x-www-form-urlencoded" },
|
headers: { "content-type": "application/x-www-form-urlencoded" },
|
||||||
body: new URLSearchParams({ username: USER, password: PASS }).toString(),
|
body: new URLSearchParams({ username: USER, password: PASS }).toString(),
|
||||||
});
|
});
|
||||||
|
// The server issues an (anonymous) connect.sid on EVERY response — including a
|
||||||
|
// failed login, which re-renders the form as a 200. So the presence of a
|
||||||
|
// cookie says nothing about success. The real signal is the redirect: a good
|
||||||
|
// login 302s to `next`/"/", a rejected one stays 2xx. Trust the status, not
|
||||||
|
// the cookie, or we'd cache an anonymous session and silently stay logged out.
|
||||||
const cookie = extractCookie(res);
|
const cookie = extractCookie(res);
|
||||||
if (!cookie) {
|
const redirected = res.status >= 300 && res.status < 400;
|
||||||
// A 200 back from /login means the login form re-rendered => bad creds.
|
if (!redirected || !cookie) {
|
||||||
throw new Error("login failed for user '" + USER + "' (check BLISS_PASS)");
|
throw new Error(
|
||||||
|
"login failed for user '" +
|
||||||
|
USER +
|
||||||
|
"' — server rejected the credentials (HTTP " +
|
||||||
|
res.status +
|
||||||
|
"). Check BLISS_USER / BLISS_PASS.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
saveCookie(cookie);
|
saveCookie(cookie);
|
||||||
return cookie;
|
return cookie;
|
||||||
|
|
@ -168,6 +179,7 @@ async function getText(urlPath) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
BASE,
|
BASE,
|
||||||
setTarget,
|
setTarget,
|
||||||
|
login,
|
||||||
request,
|
request,
|
||||||
getJSON,
|
getJSON,
|
||||||
getText,
|
getText,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue