feat: complete account and dashboard sprint
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
Some checks failed
CI / build-and-test (pull_request) Has been cancelled
This commit is contained in:
@@ -64,6 +64,12 @@ async function createUser(email: string, password: string, verified: boolean) {
|
||||
return inserted.rows[0].id;
|
||||
}
|
||||
|
||||
async function loginAgent(email: string, password: string) {
|
||||
const agent = request.agent(app);
|
||||
const login = await agent.post("/api/auth/login").send({ email, password }).expect(200);
|
||||
return { agent, csrfToken: login.body.csrfToken as string };
|
||||
}
|
||||
|
||||
async function countByTokenHash(table: "sessions" | "email_verification_tokens" | "password_reset_tokens", tokenHash: string) {
|
||||
const { rows } = await pool.query<{ count: string }>(
|
||||
`SELECT COUNT(*)::text AS count FROM ${table} WHERE token_hash = $1`,
|
||||
@@ -183,6 +189,76 @@ test("login uses generic response for missing user and wrong password", async ()
|
||||
assert.deepEqual(missingUser.body, wrongPassword.body);
|
||||
});
|
||||
|
||||
test("account session endpoints list and revoke only the current user's sessions", async () => {
|
||||
userCounter += 1;
|
||||
const email = `sessions${userCounter}@example.com`;
|
||||
const password = "correct horse battery staple";
|
||||
await createVerifiedUser(email, password);
|
||||
const first = await loginAgent(email, password);
|
||||
const second = await loginAgent(email, password);
|
||||
|
||||
const listed = await first.agent.get("/api/auth/sessions").expect(200);
|
||||
assert.equal(listed.body.sessions.length, 2);
|
||||
assert.ok(listed.body.sessions.every((session: { tokenHash?: unknown }) => session.tokenHash === undefined));
|
||||
const other = listed.body.sessions.find((session: { current: boolean }) => !session.current);
|
||||
assert.ok(other);
|
||||
|
||||
const outsider = await authAgent();
|
||||
const foreign = (await outsider.agent.get("/api/auth/sessions").expect(200)).body.sessions[0];
|
||||
await first.agent
|
||||
.delete(`/api/auth/sessions/${foreign.id}`)
|
||||
.set("X-CSRF-Token", first.csrfToken)
|
||||
.expect(404);
|
||||
|
||||
await first.agent
|
||||
.delete(`/api/auth/sessions/${other.id}`)
|
||||
.set("X-CSRF-Token", first.csrfToken)
|
||||
.expect(204);
|
||||
await second.agent.get("/api/auth/me").expect(401);
|
||||
await first.agent.get("/api/auth/sessions").expect(200).then((res) => assert.equal(res.body.sessions.length, 1));
|
||||
});
|
||||
|
||||
test("password change checks the current password and revokes other sessions", async () => {
|
||||
userCounter += 1;
|
||||
const email = `password${userCounter}@example.com`;
|
||||
const password = "correct horse battery staple";
|
||||
const nextPassword = "another correct horse battery staple";
|
||||
await createVerifiedUser(email, password);
|
||||
const first = await loginAgent(email, password);
|
||||
const second = await loginAgent(email, password);
|
||||
|
||||
await first.agent
|
||||
.post("/api/auth/password")
|
||||
.set("X-CSRF-Token", first.csrfToken)
|
||||
.send({ currentPassword: "wrong password", newPassword: nextPassword })
|
||||
.expect(400);
|
||||
await first.agent
|
||||
.post("/api/auth/password")
|
||||
.set("X-CSRF-Token", first.csrfToken)
|
||||
.send({ currentPassword: password, newPassword: nextPassword })
|
||||
.expect(200);
|
||||
|
||||
await second.agent.get("/api/auth/me").expect(401);
|
||||
await request(app).post("/api/auth/login").send({ email, password }).expect(401);
|
||||
await request(app).post("/api/auth/login").send({ email, password: nextPassword }).expect(200);
|
||||
});
|
||||
|
||||
test("revoke other sessions retains the current session", async () => {
|
||||
userCounter += 1;
|
||||
const email = `revoke-others${userCounter}@example.com`;
|
||||
const password = "correct horse battery staple";
|
||||
await createVerifiedUser(email, password);
|
||||
const first = await loginAgent(email, password);
|
||||
const second = await loginAgent(email, password);
|
||||
|
||||
await first.agent
|
||||
.post("/api/auth/sessions/revoke-others")
|
||||
.set("X-CSRF-Token", first.csrfToken)
|
||||
.expect(200);
|
||||
await first.agent.get("/api/auth/me").expect(200);
|
||||
await second.agent.get("/api/auth/me").expect(401);
|
||||
});
|
||||
|
||||
test("GET /api/races/:id returns not_found for another user's race", async () => {
|
||||
const first = await authAgent();
|
||||
const created = await first.agent
|
||||
|
||||
Reference in New Issue
Block a user