Extend authenticated session activity
This commit is contained in:
+32
-1
@@ -1,7 +1,7 @@
|
||||
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { createInitialPlay } from '../src/domain.js';
|
||||
import { buildServer } from './app.js';
|
||||
import { hashPassword } from './security.js';
|
||||
@@ -56,6 +56,37 @@ describe('Fastify Mongo contract', () => {
|
||||
const temporaryRoots = [];
|
||||
afterEach(async () => { await app?.close(); await Promise.all(temporaryRoots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); });
|
||||
|
||||
it('uses a one hour sliding session and never revives an expired session', async () => {
|
||||
vi.useFakeTimers({ toFake: ['Date'] });
|
||||
try {
|
||||
const store = memoryStore(); await seedUser(store, { id: 'clock', email: 'clock@example.com', displayName: 'Clock' });
|
||||
app = await buildServer({ config: testConfig(), db: store, serveStatic: false, secureCookie: false });
|
||||
const start = new Date('2026-01-01T00:00:00.000Z'); vi.setSystemTime(start);
|
||||
const result = await login(app, 'clock@example.com', 'correct horse battery staple');
|
||||
expect(result.response.headers['set-cookie']).toContain('Max-Age=3600');
|
||||
const session = store.sessions.documents[0]; expect(session.expiresAt).toEqual(new Date(start.getTime() + 3_600_000));
|
||||
vi.setSystemTime(new Date(start.getTime() + 50 * 60_000));
|
||||
const renewed = await app.inject({ method: 'GET', url: '/api/teams', headers: { cookie: result.cookie } });
|
||||
expect(renewed.statusCode).toBe(200); expect(session.expiresAt).toEqual(new Date(start.getTime() + 110 * 60_000));
|
||||
vi.setSystemTime(new Date(start.getTime() + 70 * 60_000)); const activity = await app.inject({ method: 'POST', url: '/api/auth/activity', headers: { cookie: result.cookie }, payload: {} }); expect(activity.statusCode).toBe(200); expect(activity.headers['set-cookie']).toContain('Max-Age=3600');
|
||||
vi.setSystemTime(new Date(start.getTime() + 130 * 60_000)); const expired = await app.inject({ method: 'POST', url: '/api/auth/activity', headers: { cookie: result.cookie }, payload: {} }); expect(expired.statusCode).toBe(401); expect(session.expiresAt).toEqual(new Date(start.getTime() + 130 * 60_000));
|
||||
} finally { vi.useRealTimers(); }
|
||||
});
|
||||
|
||||
it('does not renew on health, auth/me, or rejected origins', async () => {
|
||||
const store = memoryStore(); await seedUser(store, { id: 'origin', email: 'origin@example.com', displayName: 'Origin' }); app = await buildServer({ config: testConfig(), db: store, serveStatic: false, secureCookie: false });
|
||||
const result = await login(app, 'origin@example.com', 'correct horse battery staple'); const session = store.sessions.documents[0]; const original = session.expiresAt;
|
||||
expect((await app.inject({ method: 'GET', url: '/api/health', headers: { cookie: result.cookie } })).statusCode).toBe(200); expect(session.expiresAt).toEqual(original);
|
||||
expect((await app.inject({ method: 'GET', url: '/api/auth/me', headers: { cookie: result.cookie } })).statusCode).toBe(200); expect(session.expiresAt).toEqual(original);
|
||||
expect((await app.inject({ method: 'POST', url: '/api/auth/activity', headers: { cookie: result.cookie, origin: 'https://evil.example' }, payload: {} })).statusCode).toBe(403); expect(session.expiresAt).toEqual(original);
|
||||
});
|
||||
|
||||
it('rejects a legacy session that has already been idle for an hour', async () => {
|
||||
const store = memoryStore(); await seedUser(store, { id: 'legacy', email: 'legacy@example.com', displayName: 'Legacy' }); app = await buildServer({ config: testConfig(), db: store, serveStatic: false, secureCookie: false });
|
||||
const result = await login(app, 'legacy@example.com', 'correct horse battery staple'); const session = store.sessions.documents[0]; delete session.lastActivityAt; session.createdAt = new Date(Date.now() - 3_600_000); session.expiresAt = new Date(Date.now() + 86_400_000);
|
||||
expect((await app.inject({ method: 'GET', url: '/api/teams', headers: { cookie: result.cookie } })).statusCode).toBe(401);
|
||||
});
|
||||
|
||||
it('rejects unauthenticated and pending access', async () => {
|
||||
const store = memoryStore(); app = await buildServer({ config: testConfig(), db: store, serveStatic: false, secureCookie: false });
|
||||
expect((await app.inject({ method: 'GET', url: '/api/teams' })).statusCode).toBe(401);
|
||||
|
||||
Reference in New Issue
Block a user