name beim kopieren
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
BadRequestException,
|
||||
ConflictException,
|
||||
Injectable,
|
||||
Optional,
|
||||
UnauthorizedException,
|
||||
} from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
@@ -9,6 +10,7 @@ import { JwtService } from '@nestjs/jwt';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from 'crypto';
|
||||
import { Repository } from 'typeorm';
|
||||
import { AuditLogService } from '../audit/audit-log.service';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import { RefreshTokenDto } from './dto/refresh-token.dto';
|
||||
@@ -39,6 +41,8 @@ export class AuthService {
|
||||
private readonly usersRepository: Repository<UserEntity>,
|
||||
@InjectRepository(RefreshTokenEntity)
|
||||
private readonly refreshTokensRepository: Repository<RefreshTokenEntity>,
|
||||
@Optional()
|
||||
private readonly auditLogService?: AuditLogService,
|
||||
) {}
|
||||
|
||||
async register(
|
||||
@@ -67,6 +71,15 @@ export class AuthService {
|
||||
});
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: savedUser.id,
|
||||
actorEmail: savedUser.email,
|
||||
action: 'user.registered',
|
||||
entityType: 'user',
|
||||
entityId: savedUser.id,
|
||||
metadata: { verified: savedUser.verified },
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(AppEvents.UserRegistered, {
|
||||
email,
|
||||
verificationUrl: this.createVerificationUrl(verificationToken),
|
||||
@@ -98,10 +111,18 @@ export class AuthService {
|
||||
try {
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
|
||||
return {
|
||||
message: 'Email verified successfully.',
|
||||
user: this.toPublicUser(savedUser),
|
||||
};
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: savedUser.id,
|
||||
actorEmail: savedUser.email,
|
||||
action: 'user.email_verified',
|
||||
entityType: 'user',
|
||||
entityId: savedUser.id,
|
||||
});
|
||||
|
||||
return {
|
||||
message: 'Email verified successfully.',
|
||||
user: this.toPublicUser(savedUser),
|
||||
};
|
||||
} catch {
|
||||
throw new BadRequestException('user not saved.')
|
||||
}
|
||||
@@ -122,6 +143,14 @@ export class AuthService {
|
||||
user.verificationToken = this.createToken();
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: savedUser.id,
|
||||
actorEmail: savedUser.email,
|
||||
action: 'user.verification_resent',
|
||||
entityType: 'user',
|
||||
entityId: savedUser.id,
|
||||
});
|
||||
|
||||
this.eventEmitter.emit(AppEvents.UserRegistered, {
|
||||
email: savedUser.email,
|
||||
verificationUrl: this.createVerificationUrl(savedUser.verificationToken!),
|
||||
@@ -136,17 +165,42 @@ export class AuthService {
|
||||
const user = await this.usersRepository.findOne({ where: { email } });
|
||||
|
||||
if (!user || !this.passwordMatches(password, user.passwordHash)) {
|
||||
await this.auditLogService?.record({
|
||||
actorEmail: email,
|
||||
action: 'user.login_failed',
|
||||
entityType: 'user',
|
||||
entityId: user?.id,
|
||||
metadata: { reason: 'invalid_credentials' },
|
||||
});
|
||||
throw new UnauthorizedException('Invalid email or password.');
|
||||
}
|
||||
|
||||
if (!user.verified) {
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: user.id,
|
||||
actorEmail: user.email,
|
||||
action: 'user.login_failed',
|
||||
entityType: 'user',
|
||||
entityId: user.id,
|
||||
metadata: { reason: 'email_not_verified' },
|
||||
});
|
||||
throw new UnauthorizedException('Please verify your email before login.');
|
||||
}
|
||||
|
||||
return {
|
||||
const response = {
|
||||
...(await this.createAuthTokens(user)),
|
||||
user: this.toPublicUser(user),
|
||||
};
|
||||
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: user.id,
|
||||
actorEmail: user.email,
|
||||
action: 'user.login_succeeded',
|
||||
entityType: 'user',
|
||||
entityId: user.id,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async refresh(refreshTokenDto: RefreshTokenDto = {}): Promise<AuthTokenResponse> {
|
||||
@@ -175,10 +229,20 @@ export class AuthService {
|
||||
|
||||
await this.refreshTokensRepository.delete({ jti: payload.jti });
|
||||
|
||||
return {
|
||||
const response = {
|
||||
...(await this.createAuthTokens(user)),
|
||||
user: this.toPublicUser(user),
|
||||
};
|
||||
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: user.id,
|
||||
actorEmail: user.email,
|
||||
action: 'user.token_refreshed',
|
||||
entityType: 'user',
|
||||
entityId: user.id,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async verifyAccessToken(accessToken: string): Promise<JwtTokenPayload> {
|
||||
@@ -243,7 +307,18 @@ export class AuthService {
|
||||
|
||||
user.onboardingCompleted = completed;
|
||||
|
||||
return this.toPublicUser(await this.usersRepository.save(user));
|
||||
const savedUser = await this.usersRepository.save(user);
|
||||
|
||||
await this.auditLogService?.record({
|
||||
actorUserId: savedUser.id,
|
||||
actorEmail: savedUser.email,
|
||||
action: 'user.onboarding_updated',
|
||||
entityType: 'user',
|
||||
entityId: savedUser.id,
|
||||
metadata: { completed },
|
||||
});
|
||||
|
||||
return this.toPublicUser(savedUser);
|
||||
}
|
||||
|
||||
private normalizeEmail(email?: string): string {
|
||||
|
||||
Reference in New Issue
Block a user