feat: establish auth listing and image vertical slices

Includes MFA-capable authentication, session and CSRF security, password recovery, listing lifecycle and ownership rules, inventory image metadata, local ImageStorage, migrations, tests, and implementation status documentation. Verification: npm test (62 passing) and integration suite (14 passing).
This commit is contained in:
2026-09-08 17:32:03 -04:00
commit c728016dec
128 changed files with 9788 additions and 0 deletions
@@ -0,0 +1,126 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { createSecretProtector } from '../../src/modules/auth/domain/secret-protection.js';
import { createMfaService } from '../../src/modules/auth/services/mfa-service.js';
function createService({ method, isCodeValid = true } = {}) {
const createdMethods = [];
const auditEvents = [];
const repository = {
async create(input) {
const createdMethod = { id: 'method-id', isEnabled: false, ...input };
createdMethods.push(createdMethod);
return createdMethod;
},
async findActiveByIdAndUserId() {
return method ?? createdMethods[0] ?? null;
},
async enable(id) {
return { id, name: 'Authenticator', type: 'TOTP', isEnabled: true };
},
async disable(id) {
return { id, isEnabled: false };
},
};
const service = createMfaService({
mfaMethodRepository: repository,
now: () => new Date('2026-09-07T00:00:00.000Z'),
secretProtector: {
encrypt(secret) { return `encrypted:${secret}`; },
decrypt(ciphertext) { return ciphertext.replace('encrypted:', ''); },
},
securityAuditRepository: { async record(event) { auditEvents.push(event); } },
totpEnrollment: () => ({ secret: 'TOTPSECRET', provisioningUri: 'otpauth://test' }),
totpVerifier: () => isCodeValid,
});
return { auditEvents, createdMethods, service };
}
test('encrypts the TOTP secret and returns the provisioning URI only during enrollment', async () => {
const { createdMethods, service } = createService();
const enrollment = await service.enroll({ userId: 'user-id', name: 'Authenticator' });
assert.deepEqual(enrollment, { id: 'method-id', provisioningUri: 'otpauth://test' });
assert.equal(createdMethods[0].secretCiphertext, 'encrypted:TOTPSECRET');
assert.equal(createdMethods[0].isEnabled, false);
assert.equal('secret' in enrollment, false);
});
test('encrypts MFA secrets with authenticated encryption', () => {
const protector = createSecretProtector(Buffer.alloc(32, 7).toString('base64'));
const ciphertext = protector.encrypt('TOTPSECRET');
assert.notEqual(ciphertext, 'TOTPSECRET');
assert.equal(protector.decrypt(ciphertext), 'TOTPSECRET');
});
test('enables an owned MFA method only after a valid code and records enrollment', async () => {
const { auditEvents, service } = createService({
method: {
id: 'method-id',
userId: 'user-id',
type: 'TOTP',
name: 'Authenticator',
secretCiphertext: 'encrypted:TOTPSECRET',
isEnabled: false,
},
});
const method = await service.verifyEnrollment({
userId: 'user-id',
methodId: 'method-id',
code: '123456',
});
assert.deepEqual(method, { id: 'method-id', name: 'Authenticator', type: 'TOTP' });
assert.deepEqual(auditEvents, [{ userId: 'user-id', event: 'MFA_ENROLLED' }]);
});
test('rejects invalid MFA codes without enabling or disabling a method', async () => {
const { auditEvents, service } = createService({
isCodeValid: false,
method: {
id: 'method-id',
userId: 'user-id',
type: 'TOTP',
name: 'Authenticator',
secretCiphertext: 'encrypted:TOTPSECRET',
isEnabled: true,
},
});
await assert.rejects(
() => service.disable({ userId: 'user-id', methodId: 'method-id', code: '000000' }),
(error) => error.code === 'MFA_CODE_INVALID',
);
assert.deepEqual(auditEvents, [{ userId: 'user-id', event: 'MFA_FAILURE' }]);
});
test('requires a valid TOTP code when an enabled MFA method exists at login', async () => {
let markedMethod;
const repository = {
async listEnabledByUserId(userId) {
assert.equal(userId, 'user-id');
return [{ id: 'method-id', secretCiphertext: 'encrypted:TOTPSECRET' }];
},
async markUsed(id) {
markedMethod = id;
},
};
const service = createMfaService({
mfaMethodRepository: repository,
secretProtector: { decrypt() { return 'TOTPSECRET'; } },
totpVerifier: ({ code }) => code === '123456',
});
await assert.rejects(
() => service.verifyLogin({ userId: 'user-id', code: undefined }),
(error) => error.code === 'MFA_CODE_INVALID',
);
await service.verifyLogin({ userId: 'user-id', code: '123456' });
assert.equal(markedMethod, 'method-id');
});