chore: import DH V2 D5.6.4 production baseline
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { isIP } from 'node:net';
|
||||
import { ConflictException } from '@nestjs/common';
|
||||
import { EntityManager } from 'typeorm';
|
||||
import type {
|
||||
AuthPrincipal,
|
||||
RequestWithContext,
|
||||
} from '../../common/http/request-context';
|
||||
import { AuditSource } from '../../database/entities';
|
||||
|
||||
const REQUIRED_RECOVERY_PERMISSIONS = [
|
||||
'roles.manage',
|
||||
'users.assign_roles',
|
||||
] as const;
|
||||
|
||||
export function administrationAuditContext(
|
||||
principal: AuthPrincipal,
|
||||
request: RequestWithContext,
|
||||
) {
|
||||
const candidateIp = request.ip || request.socket.remoteAddress || '';
|
||||
const rawUserAgent = request.header('user-agent')?.trim();
|
||||
|
||||
return {
|
||||
actorUserId: principal.userId,
|
||||
actorUsername: principal.username,
|
||||
requestId: request.requestId,
|
||||
source: AuditSource.WEB,
|
||||
ip: isIP(candidateIp) ? candidateIp : null,
|
||||
userAgent: rawUserAgent ? rawUserAgent.slice(0, 2048) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function assertAdministrativeRecoveryRemains(
|
||||
manager: EntityManager,
|
||||
): Promise<void> {
|
||||
const [row] = (await manager.query(
|
||||
`
|
||||
SELECT COUNT(*)::integer AS count
|
||||
FROM (
|
||||
SELECT user_account.id
|
||||
FROM users user_account
|
||||
INNER JOIN user_roles user_role
|
||||
ON user_role.user_id = user_account.id
|
||||
INNER JOIN role_permissions role_permission
|
||||
ON role_permission.role_id = user_role.role_id
|
||||
INNER JOIN permissions permission
|
||||
ON permission.id = role_permission.permission_id
|
||||
WHERE user_account.status = 'ACTIVE'
|
||||
AND permission.code = ANY($1::varchar[])
|
||||
GROUP BY user_account.id
|
||||
HAVING COUNT(DISTINCT permission.code) = $2
|
||||
) administrators
|
||||
`,
|
||||
[REQUIRED_RECOVERY_PERMISSIONS, REQUIRED_RECOVERY_PERMISSIONS.length],
|
||||
)) as Array<{ count: number }>;
|
||||
|
||||
if (!row || Number(row.count) < 1) {
|
||||
throw new ConflictException({
|
||||
code: 'LAST_ADMINISTRATOR_PROTECTED',
|
||||
message:
|
||||
'Debe permanecer al menos un usuario activo capaz de administrar roles y asignaciones',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function isUniqueViolation(error: unknown): boolean {
|
||||
return (
|
||||
typeof error === 'object' &&
|
||||
error !== null &&
|
||||
'code' in error &&
|
||||
(error as { code?: unknown }).code === '23505'
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user