feat(server): renew session when "Remember me" is off

This commit is contained in:
Elian Doran 2025-06-07 11:12:36 +03:00
parent f8ded7b171
commit 244a162e42
No known key found for this signature in database
2 changed files with 54 additions and 0 deletions

View File

@ -82,6 +82,24 @@ describe("Login Route test", () => {
expect(expiry).toStrictEqual(new Date(session!.cookie.expires!));
});
it("doesn't renew the session on subsequent requests", async () => {
const { expiry: originalExpiry } = await getSessionFromCookie(setCookieHeader);
// Simulate user waiting half the period before the session expires.
vi.setSystemTime(originalExpiry!.getTime() - (originalExpiry!.getTime() - Date.now()) / 2);
// Make a request to renew the session.
await supertest(app)
.get("/")
.set("Cookie", setCookieHeader)
.expect(200);
// Check the session is still valid and has not been renewed.
const { session, expiry } = await getSessionFromCookie(setCookieHeader);
expect(session).toBeTruthy();
expect(expiry!.getTime()).toStrictEqual(originalExpiry!.getTime());
});
it("cleans up expired sessions", async () => {
let { session, expiry } = await getSessionFromCookie(setCookieHeader);
expect(session).toBeTruthy();
@ -123,6 +141,24 @@ describe("Login Route test", () => {
expect(expiry?.getTime()).toBeLessThanOrEqual(expectedExpirationDate.getTime());
});
it("renews the session on subsequent requests", async () => {
const { expiry: originalExpiry } = await getSessionFromCookie(setCookieHeader);
// Simulate user waiting half the period before the session expires.
vi.setSystemTime(originalExpiry!.getTime() - (originalExpiry!.getTime() - Date.now()) / 2);
// Make a request to renew the session.
await supertest(app)
.get("/")
.set("Cookie", setCookieHeader)
.expect(200);
// Check the session is still valid and has been renewed.
const { session, expiry } = await getSessionFromCookie(setCookieHeader);
expect(session).toBeTruthy();
expect(expiry!.getTime()).toBeGreaterThan(originalExpiry!.getTime());
});
it("cleans up expired sessions", async () => {
let { session, expiry } = await getSessionFromCookie(setCookieHeader);
expect(session).toBeTruthy();

View File

@ -55,6 +55,23 @@ export class SQLiteSessionStore extends Store {
}
}
touch(sid: string, session: session.SessionData, callback?: (err?: any) => void): void {
// For now it's only for session cookies ("Remember me" unchecked).
if (session.cookie?.expires) {
callback?.();
return;
}
try {
const expires = Date.now() + 3600000; // fallback to 1 hour
sql.execute(/*sql*/`UPDATE sessions SET expires = ? WHERE id = ?`, [expires, sid]);
callback?.();
} catch (e) {
log.error(e);
callback?.(e);
}
}
/**
* Given a session ID, returns the expiry date of the session.
*
@ -79,6 +96,7 @@ const sessionParser: express.RequestHandler = session({
secret: sessionSecret,
resave: false, // true forces the session to be saved back to the session store, even if the session was never modified during the request.
saveUninitialized: false, // true forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified.
rolling: true, // forces the session to be saved back to the session store, resetting the expiration date.
cookie: {
path: "/",
httpOnly: true,