Password Policy/App rename/PM Scheduling Improvements
This commit is contained in:
80
server/services/passwordPolicy.test.js
Normal file
80
server/services/passwordPolicy.test.js
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Tests for the password-policy validation and lockout helpers. These exercise the pure logic
|
||||
* (complexity checks, identifier detection, lockout math) against an explicit policy object so
|
||||
* they do not depend on the database-backed settings store.
|
||||
*/
|
||||
|
||||
const { checkPassword, describe: describePolicy, DEFAULT_POLICY, isLocked, minAgeRemainingMinutes, passwordExpired } = require('./passwordPolicy');
|
||||
|
||||
const strictPolicy = {
|
||||
...DEFAULT_POLICY,
|
||||
min_length: 12,
|
||||
require_upper: true,
|
||||
require_lower: true,
|
||||
require_number: true,
|
||||
require_symbol: true,
|
||||
disallow_identifiers: true,
|
||||
history_count: 0 // disable DB-backed history for these pure tests
|
||||
};
|
||||
|
||||
describe('password policy', () => {
|
||||
test('a compliant password passes every rule', () => {
|
||||
expect(checkPassword('Str0ng!Passphrase', null, strictPolicy)).toEqual([]);
|
||||
});
|
||||
|
||||
test('each missing character class is reported', () => {
|
||||
expect(checkPassword('short', null, strictPolicy).length).toBeGreaterThan(0);
|
||||
expect(checkPassword('alllowercase1!', null, strictPolicy)).toContain('Add an uppercase letter');
|
||||
expect(checkPassword('ALLUPPERCASE1!', null, strictPolicy)).toContain('Add a lowercase letter');
|
||||
expect(checkPassword('NoNumbersHere!', null, strictPolicy)).toContain('Add a number');
|
||||
expect(checkPassword('NoSymbolsHere1', null, strictPolicy)).toContain('Add a symbol');
|
||||
});
|
||||
|
||||
test('minimum length is enforced', () => {
|
||||
expect(checkPassword('Ab1!', null, strictPolicy)).toContain('Use at least 12 characters');
|
||||
});
|
||||
|
||||
test('the user name or email cannot appear in the password', () => {
|
||||
const user = { name: 'Jordan Banks', email: 'jbanks@example.com' };
|
||||
expect(checkPassword('Jordan!Secret99', user, strictPolicy)).toContain('Must not contain your name or email');
|
||||
expect(checkPassword('jbanks!Secret99', user, strictPolicy)).toContain('Must not contain your name or email');
|
||||
// A password without the identifiers is fine.
|
||||
expect(checkPassword('Unrelated!Secret99', user, strictPolicy)).toEqual([]);
|
||||
});
|
||||
|
||||
test('identifier check is skipped when the policy disables it', () => {
|
||||
const policy = { ...strictPolicy, disallow_identifiers: false };
|
||||
const user = { name: 'Jordan Banks', email: 'jbanks@example.com' };
|
||||
expect(checkPassword('Jordan!Secret99', user, policy)).toEqual([]);
|
||||
});
|
||||
|
||||
test('describe lists the active rules', () => {
|
||||
const rules = describePolicy(strictPolicy);
|
||||
expect(rules.some((r) => /12 characters/.test(r))).toBe(true);
|
||||
expect(rules.some((r) => /uppercase/.test(r))).toBe(true);
|
||||
});
|
||||
|
||||
test('isLocked reflects the locked_until timestamp', () => {
|
||||
expect(isLocked({ locked_until: new Date(Date.now() + 60000).toISOString() })).toBe(true);
|
||||
expect(isLocked({ locked_until: new Date(Date.now() - 60000).toISOString() })).toBe(false);
|
||||
expect(isLocked({ locked_until: null })).toBe(false);
|
||||
});
|
||||
|
||||
test('passwordExpired compares age against expiry_days', () => {
|
||||
const policy = { ...DEFAULT_POLICY, expiry_days: 30 };
|
||||
const old = new Date(Date.now() - 40 * 86400000).toISOString();
|
||||
const recent = new Date(Date.now() - 5 * 86400000).toISOString();
|
||||
expect(passwordExpired({ password_changed_at: old }, policy)).toBe(true);
|
||||
expect(passwordExpired({ password_changed_at: recent }, policy)).toBe(false);
|
||||
// expiry_days 0 means passwords never expire.
|
||||
expect(passwordExpired({ password_changed_at: old }, { ...policy, expiry_days: 0 })).toBe(false);
|
||||
});
|
||||
|
||||
test('minAgeRemainingMinutes blocks changes that are too soon', () => {
|
||||
const policy = { ...DEFAULT_POLICY, min_age_hours: 24 };
|
||||
const justChanged = new Date(Date.now() - 60000).toISOString();
|
||||
const longAgo = new Date(Date.now() - 48 * 3600000).toISOString();
|
||||
expect(minAgeRemainingMinutes({ password_changed_at: justChanged }, policy)).toBeGreaterThan(0);
|
||||
expect(minAgeRemainingMinutes({ password_changed_at: longAgo }, policy)).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user