[grade=B] test: sync auth and version contracts
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
* Covers the BACKLOG.md DC-006 acceptance criteria:
|
||||
* - no code → 400 (ValidationError)
|
||||
* - wrong code → 401 (AuthenticationError)
|
||||
* - valid TOTP → 200 + session cookie + CSRF token
|
||||
* - check-session with valid session → 200 { authenticated: true }
|
||||
* - valid TOTP → 200 + session cookie + CSRF token + SSO handoff token
|
||||
* - check-session with valid session → 200 { success: true, authenticated: true }
|
||||
* - check-session without session → 401 (AuthenticationError)
|
||||
*
|
||||
* Uses real otplib for code generation (so we exercise the actual TOTP math)
|
||||
@@ -79,6 +79,7 @@ function createApp(depsOverride = {}) {
|
||||
sessionStore.delete(ip);
|
||||
}),
|
||||
clearCookie: jest.fn(),
|
||||
createHandoffToken: jest.fn(() => 'mock-sso-handoff-token'),
|
||||
isValid: jest.fn((req) => {
|
||||
const ip = session.getClientIP(req);
|
||||
const entry = sessionStore.get(ip);
|
||||
@@ -303,8 +304,10 @@ describe('TOTP Auth Routes — DC-006 Integration Test', () => {
|
||||
expect(res.body.success).toBe(true);
|
||||
expect(res.body.message).toMatch(/Authenticated successfully/);
|
||||
expect(res.body.csrfToken).toBe('mock-csrf-token');
|
||||
expect(res.body.ssoToken).toBe('mock-sso-handoff-token');
|
||||
expect(deps.session.create).toHaveBeenCalled();
|
||||
expect(deps.session.setCookie).toHaveBeenCalled();
|
||||
expect(deps.session.createHandoffToken).toHaveBeenCalledTimes(1);
|
||||
expect(deps.renewCSRFToken).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -350,7 +353,7 @@ describe('TOTP Auth Routes — DC-006 Integration Test', () => {
|
||||
deps.session._grantSession('127.0.0.1');
|
||||
const res = await request(app).get('/api/totp/check-session').set('X-Forwarded-For', '127.0.0.1');
|
||||
expect(res.status).toBe(200);
|
||||
expect(res.body).toEqual({ authenticated: true });
|
||||
expect(res.body).toEqual({ success: true, authenticated: true });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -450,24 +453,23 @@ describe('TOTP Auth Routes — DC-006 Integration Test', () => {
|
||||
const loginRes = await request(app).post('/api/totp/verify').send({ code: loginCode });
|
||||
expect(loginRes.status).toBe(200);
|
||||
expect(loginRes.body.csrfToken).toBeDefined();
|
||||
expect(loginRes.body.ssoToken).toBe('mock-sso-handoff-token');
|
||||
expect(deps.session.createHandoffToken).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 5. Check-session — should now be authenticated (the BACKLOG "→ endpoint succeeds" step)
|
||||
const checkRes = await request(app).get('/api/totp/check-session');
|
||||
expect(checkRes.status).toBe(200);
|
||||
expect(checkRes.body).toEqual({ authenticated: true });
|
||||
expect(checkRes.body).toEqual({ success: true, authenticated: true });
|
||||
|
||||
// 6. Logout / disable
|
||||
const disableCode = authenticator.generate(secret);
|
||||
const disableRes = await request(app).post('/api/totp/disable').send({ code: disableCode });
|
||||
expect(disableRes.status).toBe(200);
|
||||
|
||||
// 7. After disable, check-session should be 401 (bypass removed for security)
|
||||
// unless the user still holds a valid session, in which case it's 200.
|
||||
// The login step (4) may or may not have granted one depending on test order.
|
||||
// 7. After disable, check-session deterministically rejects before
|
||||
// checking session validity because TOTP protection is disabled.
|
||||
const afterRes = await request(app).get('/api/totp/check-session');
|
||||
// After disable, TOTP is off AND we may or may not have an active session.
|
||||
// The new contract: bypass is gone, but a valid session still authenticates.
|
||||
expect([200, 401]).toContain(afterRes.status);
|
||||
expect(afterRes.status).toBe(401);
|
||||
});
|
||||
|
||||
it('proves otplib is real (not stubbed) by using a totally bogus code', async () => {
|
||||
|
||||
Reference in New Issue
Block a user