fix: harden tenant auth and quality gates
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { UnauthorizedException } from '@nestjs/common';
|
||||
import { AuthService } from './auth.service';
|
||||
import { hashPassword } from '../users/users.service';
|
||||
import { legacyHashPassword } from './password-hasher';
|
||||
|
||||
function createUsersMock(roleCode: string, overrides: Record<string, unknown> = {}) {
|
||||
const user = {
|
||||
@@ -10,7 +10,7 @@ function createUsersMock(roleCode: string, overrides: Record<string, unknown> =
|
||||
email: 'user@example.com',
|
||||
phone: '13800000000',
|
||||
displayName: '用户',
|
||||
passwordHash: hashPassword('secret1'),
|
||||
passwordHash: legacyHashPassword('secret1'),
|
||||
status: 'active',
|
||||
deletedAt: null,
|
||||
lockedUntil: null,
|
||||
@@ -20,24 +20,32 @@ function createUsersMock(roleCode: string, overrides: Record<string, unknown> =
|
||||
};
|
||||
return {
|
||||
findByLogin: jest.fn().mockResolvedValue(user),
|
||||
verifyLoginPassword: jest.fn(async (_id: string, password: string) => password === 'secret1'),
|
||||
recordLoginSuccess: jest.fn(),
|
||||
recordLoginFailure: jest.fn(),
|
||||
};
|
||||
}
|
||||
|
||||
function createSessionsMock() {
|
||||
const captchas = new Map<string, string>();
|
||||
const failures = new Map<string, number>();
|
||||
const record = {
|
||||
userId: 'user-1', portal: 'admin', sessionVersion: 0, createdAt: 1, lastActivityAt: 1,
|
||||
lastAuthenticatedAt: 1, absoluteExpiresAt: Date.now() + 1000,
|
||||
};
|
||||
return {
|
||||
storeCaptcha: jest.fn(async (id: string, answer: string) => { captchas.set(id, answer); }),
|
||||
consumeCaptcha: jest.fn(async (id: string) => { const answer = captchas.get(id) ?? null; captchas.delete(id); return answer; }),
|
||||
isAnonymousLoginLocked: jest.fn(async (login: string) => (failures.get(login) ?? 0) >= 5),
|
||||
recordAnonymousLoginFailure: jest.fn(async (login: string) => { const count = (failures.get(login) ?? 0) + 1; failures.set(login, count); return count; }),
|
||||
clearAnonymousLoginFailures: jest.fn(async (login: string) => { failures.delete(login); }),
|
||||
create: jest.fn().mockResolvedValue({ token: 'opaque-session-token', record }),
|
||||
publicSession: jest.fn().mockReturnValue({ idleTimeoutSeconds: 3600, absoluteExpiresAt: new Date(record.absoluteExpiresAt).toISOString() }),
|
||||
};
|
||||
}
|
||||
|
||||
async function loginWithCaptcha(service: AuthService, portal: 'admin' | 'client', password = 'secret1') {
|
||||
const captcha = service.createCaptcha();
|
||||
const captcha = await service.createCaptcha();
|
||||
const answer = captcha.challenge.split('=')[0].split('+').map((part) => Number(part.trim())).reduce((sum, value) => sum + value, 0);
|
||||
return service.login({
|
||||
login: 'user@example.com',
|
||||
|
||||
Reference in New Issue
Block a user