feat(tests): add unit and integration test suite (node:test) #2
@@ -392,6 +392,13 @@ export class SqliteInterface implements BackendDbInterface {
|
||||
WHERE "uid" = ${{ uuid: uid }}
|
||||
`);
|
||||
}
|
||||
async deleteSession(token: `as_${string}`): Promise<void> {
|
||||
this.#checkReadonly();
|
||||
this.#db.run(sql`
|
||||
DELETE FROM "sessions"
|
||||
WHERE "token" = ${{ text: token }}
|
||||
`);
|
||||
}
|
||||
|
||||
#getApikeyByToken(token: `at_${string}`): ClientApikey {
|
||||
const apikey = selectClientApikey(
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface BackendDbInterface extends DbInterface {
|
||||
// auth by session
|
||||
getUserBySession(token: `as_${string}`): Promise<ClientUser>;
|
||||
createSession(uid: string): Promise<`as_${string}`>;
|
||||
deleteSession(token: `as_${string}`): Promise<void>;
|
||||
|
||||
// auth by apikey
|
||||
getUserByApikey(token: `at_${string}`): Promise<[ClientUser, ClientApikey]>;
|
||||
@@ -98,6 +99,7 @@ export function isBackendInterface(db: DbInterface): db is BackendDbInterface {
|
||||
"getUserByLogin",
|
||||
"getUserBySession",
|
||||
"createSession",
|
||||
"deleteSession",
|
||||
"getUserByApikey",
|
||||
] as const
|
||||
).every(
|
||||
|
||||
@@ -28,6 +28,8 @@ export function apirouter(db: BackendDbInterface): KoaRouter {
|
||||
});
|
||||
router.post("/auth/logout", authenticate(db), async (ctx) => {
|
||||
if (ctx.session!.source !== "session") throw new InvalidAbodeError();
|
||||
const token = ctx.cookies.get("abode_session");
|
||||
if (token) await db.deleteSession(token as `as_${string}`);
|
||||
ctx.cookies.set("abode_session", "", { expires: new Date("1970-01-01") });
|
||||
ctx.status = 204;
|
||||
});
|
||||
|
||||
@@ -74,7 +74,7 @@ describe("api backend: auth over HTTP", async () => {
|
||||
assert.equal(res.status, 401);
|
||||
});
|
||||
|
||||
it("POST /auth/logout clears the session cookie", async () => {
|
||||
it("POST /auth/logout clears the cookie and invalidates the session server-side", async () => {
|
||||
const login = await fetch(`${server.url}/auth/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
@@ -88,6 +88,11 @@ describe("api backend: auth over HTTP", async () => {
|
||||
});
|
||||
assert.equal(logout.status, 204);
|
||||
assert.equal(getCookie(logout, "abode_session"), "");
|
||||
|
||||
const self = await fetch(`${server.url}/auth/self`, {
|
||||
headers: { Cookie: `abode_session=${cookie}` },
|
||||
});
|
||||
assert.equal(self.status, 401, "session was invalidated server-side, not just the cookie cleared");
|
||||
});
|
||||
|
||||
it("POST /auth/clear-sessions invalidates outstanding session cookies", async () => {
|
||||
|
||||
@@ -71,6 +71,7 @@ function makeMockDb(
|
||||
getUserByLogin: async () => { throw new NotFoundAbodeError(); },
|
||||
getUserBySession: async () => { throw new NotFoundAbodeError(); },
|
||||
createSession: async () => `as_${"0".repeat(32)}`,
|
||||
deleteSession: async () => {},
|
||||
getUserByApikey: async () => { throw new NotFoundAbodeError(); },
|
||||
...overrides,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user