LibreChat/api/server/services/twoFactorService.spec.js
Paco Cartones bf1e13b806
🥁 fix: Compare TOTP Codes in Constant Time (#15157)
Co-authored-by: pacocartones <pacocartones@users.noreply.github.com>
2026-08-24 09:10:03 -04:00

42 lines
1.3 KiB
JavaScript

const crypto = require('node:crypto');
jest.mock('node:crypto', () => {
const actual = jest.requireActual('node:crypto');
return {
...actual,
timingSafeEqual: jest.fn((a, b) => actual.timingSafeEqual(a, b)),
};
});
jest.mock('@librechat/data-schemas', () => ({
hashBackupCode: jest.fn(),
decryptV3: jest.fn(),
decryptV2: jest.fn(),
}));
jest.mock('~/models', () => ({ updateUser: jest.fn() }));
const { generateTOTP, verifyTOTP, generateTOTPSecret } = require('./twoFactorService');
describe('verifyTOTP', () => {
it('accepts a valid current TOTP code', async () => {
const secret = generateTOTPSecret();
const code = await generateTOTP(secret);
await expect(verifyTOTP(secret, code)).resolves.toBe(true);
});
it('rejects an invalid code of the same length', async () => {
const secret = generateTOTPSecret();
const code = await generateTOTP(secret);
const wrong = code === '000000' ? '111111' : '000000';
await expect(verifyTOTP(secret, wrong)).resolves.toBe(false);
});
it('compares codes in constant time via crypto.timingSafeEqual', async () => {
const secret = generateTOTPSecret();
const code = await generateTOTP(secret);
crypto.timingSafeEqual.mockClear();
await verifyTOTP(secret, code);
expect(crypto.timingSafeEqual).toHaveBeenCalled();
});
});