You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { AuthManager, generatePassphrase } from '../../src/server/auth.js';
|
|
|
|
describe('AuthManager', () => {
|
|
let auth: AuthManager;
|
|
|
|
beforeEach(async () => {
|
|
auth = new AuthManager();
|
|
await auth.setPassword('test-password');
|
|
});
|
|
|
|
describe('password verification', () => {
|
|
it('accepts correct password', async () => {
|
|
expect(await auth.verifyPassword('test-password')).toBe(true);
|
|
});
|
|
|
|
it('rejects wrong password', async () => {
|
|
expect(await auth.verifyPassword('wrong')).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('JWT tokens', () => {
|
|
it('generates and verifies a valid token', () => {
|
|
const token = auth.generateToken();
|
|
expect(auth.verifyToken(token)).toBe(true);
|
|
});
|
|
|
|
it('rejects invalid tokens', () => {
|
|
expect(auth.verifyToken('not-a-real-token')).toBe(false);
|
|
});
|
|
|
|
it('rejects tokens from different instance', async () => {
|
|
const token = auth.generateToken();
|
|
const other = new AuthManager();
|
|
await other.setPassword('x');
|
|
expect(other.verifyToken(token)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('rate limiting', () => {
|
|
it('allows initial attempts', () => {
|
|
expect(auth.isRateLimited('1.2.3.4')).toBe(false);
|
|
});
|
|
|
|
it('blocks after max attempts', () => {
|
|
for (let i = 0; i < 5; i++) {
|
|
auth.recordAttempt('1.2.3.4');
|
|
}
|
|
expect(auth.isRateLimited('1.2.3.4')).toBe(true);
|
|
});
|
|
|
|
it('does not affect other IPs', () => {
|
|
for (let i = 0; i < 5; i++) {
|
|
auth.recordAttempt('1.2.3.4');
|
|
}
|
|
expect(auth.isRateLimited('5.6.7.8')).toBe(false);
|
|
});
|
|
|
|
it('resets after successful auth', () => {
|
|
for (let i = 0; i < 3; i++) {
|
|
auth.recordAttempt('1.2.3.4');
|
|
}
|
|
auth.resetAttempts('1.2.3.4');
|
|
expect(auth.isRateLimited('1.2.3.4')).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('generatePassphrase', () => {
|
|
it('generates a 4-word passphrase', () => {
|
|
const phrase = generatePassphrase();
|
|
const words = phrase.split('-');
|
|
expect(words.length).toBe(4);
|
|
for (const word of words) {
|
|
expect(word.length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('generates different passphrases', () => {
|
|
const a = generatePassphrase();
|
|
const b = generatePassphrase();
|
|
// Extremely unlikely to be equal
|
|
expect(a).not.toBe(b);
|
|
});
|
|
});
|