chore: import DH V2 D5.6.4 production baseline

This commit is contained in:
DH V2
2026-09-05 10:12:35 -03:00
commit 82213e72f5
757 changed files with 84218 additions and 0 deletions
@@ -0,0 +1,21 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PHASE_A_ENTITIES } from '../database/entities';
import { AuditEventsRepository } from './repositories/audit-events.repository';
import { AuthSessionsRepository } from './repositories/auth-sessions.repository';
import { RolesRepository } from './repositories/roles.repository';
import { UsersRepository } from './repositories/users.repository';
const repositories = [
UsersRepository,
RolesRepository,
AuthSessionsRepository,
AuditEventsRepository,
];
@Module({
imports: [TypeOrmModule.forFeature(PHASE_A_ENTITIES)],
providers: repositories,
exports: repositories,
})
export class PhaseADataModule {}
@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeepPartial, Repository } from 'typeorm';
import { AuditEvent } from '../../database/entities';
@Injectable()
export class AuditEventsRepository {
constructor(
@InjectRepository(AuditEvent)
private readonly repository: Repository<AuditEvent>,
) {}
create(input: DeepPartial<AuditEvent>): AuditEvent {
return this.repository.create(input);
}
save(event: AuditEvent): Promise<AuditEvent> {
return this.repository.save(event);
}
}
@@ -0,0 +1,110 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
DeepPartial,
EntityManager,
IsNull,
MoreThan,
Repository,
} from 'typeorm';
import { AuthSession } from '../../database/entities';
@Injectable()
export class AuthSessionsRepository {
constructor(
@InjectRepository(AuthSession)
private readonly repository: Repository<AuthSession>,
) {}
create(input: DeepPartial<AuthSession>): AuthSession {
return this.repository.create(input);
}
save(session: AuthSession): Promise<AuthSession> {
return this.repository.save(session);
}
findActiveById(id: string, now = new Date()): Promise<AuthSession | null> {
return this.repository.findOne({
where: {
id,
revokedAt: IsNull(),
expiresAt: MoreThan(now),
},
});
}
findByIdWithRefreshTokenHash(id: string): Promise<AuthSession | null> {
return this.repository
.createQueryBuilder('session')
.addSelect('session.refreshTokenHash')
.where('session.id = :id', { id })
.getOne();
}
async revokeUserSessions(
userId: string,
exceptSessionId?: string,
manager?: EntityManager,
): Promise<void> {
const parameters: unknown[] = [userId];
let exception = '';
if (exceptSessionId) {
parameters.push(exceptSessionId);
exception = 'AND id <> $2';
}
await (manager ?? this.repository.manager).query(
`
UPDATE auth_sessions
SET revoked_at = COALESCE(revoked_at, CURRENT_TIMESTAMP)
WHERE user_id = $1
AND revoked_at IS NULL
${exception}
`,
parameters,
);
}
async revokeSessionFamily(
sessionId: string,
manager?: EntityManager,
): Promise<void> {
await (manager ?? this.repository.manager).query(
`
WITH RECURSIVE family AS (
SELECT id, replaced_by_session_id
FROM auth_sessions
WHERE id = $1
UNION
SELECT session.id, session.replaced_by_session_id
FROM auth_sessions session
INNER JOIN family member
ON session.id = member.replaced_by_session_id
OR session.replaced_by_session_id = member.id
)
UPDATE auth_sessions
SET revoked_at = COALESCE(revoked_at, CURRENT_TIMESTAMP)
WHERE id IN (SELECT id FROM family)
`,
[sessionId],
);
}
async revokeSession(
sessionId: string,
userId: string,
manager?: EntityManager,
): Promise<void> {
await (manager ?? this.repository.manager).query(
`
UPDATE auth_sessions
SET
revoked_at = COALESCE(revoked_at, CURRENT_TIMESTAMP),
last_used_at = CURRENT_TIMESTAMP
WHERE id = $1 AND user_id = $2
`,
[sessionId, userId],
);
}
}
@@ -0,0 +1,57 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Repository } from 'typeorm';
import { Role } from '../../database/entities';
interface PermissionCodeRow {
code: string;
}
interface RoleCodeRow {
code: string;
}
@Injectable()
export class RolesRepository {
constructor(
@InjectRepository(Role)
private readonly repository: Repository<Role>,
) {}
findByCodes(codes: string[]): Promise<Role[]> {
if (codes.length === 0) return Promise.resolve([]);
return this.repository.find({ where: { code: In(codes) } });
}
async findRoleCodesForUser(userId: string): Promise<string[]> {
const rows = (await this.repository.query(
`
SELECT role.code
FROM roles role
INNER JOIN user_roles user_role ON user_role.role_id = role.id
WHERE user_role.user_id = $1
ORDER BY role.code ASC
`,
[userId],
)) as RoleCodeRow[];
return rows.map((row) => row.code);
}
async findPermissionCodesForUser(userId: string): Promise<string[]> {
const rows = (await this.repository.query(
`
SELECT DISTINCT permission.code
FROM permissions permission
INNER JOIN role_permissions role_permission
ON role_permission.permission_id = permission.id
INNER JOIN user_roles user_role
ON user_role.role_id = role_permission.role_id
WHERE user_role.user_id = $1
ORDER BY permission.code ASC
`,
[userId],
)) as PermissionCodeRow[];
return rows.map((row) => row.code);
}
}
@@ -0,0 +1,69 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DeepPartial, Repository } from 'typeorm';
import { User } from '../../database/entities';
@Injectable()
export class UsersRepository {
constructor(
@InjectRepository(User)
private readonly repository: Repository<User>,
) {}
create(input: DeepPartial<User>): User {
return this.repository.create(input);
}
save(user: User): Promise<User> {
return this.repository.save(user);
}
findById(id: string): Promise<User | null> {
return this.repository.findOne({ where: { id } });
}
findForAuthentication(identifier: string): Promise<User | null> {
const normalizedIdentifier = identifier.trim().toLowerCase();
return this.repository
.createQueryBuilder('user')
.addSelect('user.passwordHash')
.where('LOWER(user.username) = :identifier', {
identifier: normalizedIdentifier,
})
.orWhere('LOWER(user.email) = :identifier', {
identifier: normalizedIdentifier,
})
.getOne();
}
findByIdForPasswordVerification(id: string): Promise<User | null> {
return this.repository
.createQueryBuilder('user')
.addSelect('user.passwordHash')
.where('user.id = :id', { id })
.getOne();
}
async registerFailedLogin(
userId: string,
maxAttempts: number,
lockoutSeconds: number,
): Promise<void> {
await this.repository.query(
`
UPDATE users
SET
failed_login_attempts = failed_login_attempts + 1,
locked_until = CASE
WHEN failed_login_attempts + 1 >= $2
THEN CURRENT_TIMESTAMP + ($3 * INTERVAL '1 second')
ELSE locked_until
END,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
`,
[userId, maxAttempts, lockoutSeconds],
);
}
}