This commit is contained in:
Bastian Wagner
2026-07-17 10:50:10 +02:00
parent 8c6ad294b2
commit 201c4e03f8
22 changed files with 1275 additions and 21 deletions

View File

@@ -3,11 +3,16 @@ import { ConfigService } from '@nestjs/config';
import { InjectRepository } from '@nestjs/typeorm';
import { IsNull, Repository } from 'typeorm';
import { AuditService } from '../audit/audit.service';
import { ApplicationErrorCategory, ApplicationErrorCode } from '../application-error-log/application-error-codes';
import { ApplicationErrorLoggerService } from '../application-error-log/application-error-logger.service';
import { markErrorAsLogged } from '../application-error-log/logged-error-marker';
import { assertPasswordPolicy } from '../common/password-policy';
import { RequestContextService } from '../common/request-context.service';
import { hashToken, randomToken } from '../common/token.util';
import { LdapAuthService } from '../lldap/ldap-auth.service';
import { LldapService } from '../lldap/lldap.service';
import { PortalMailService } from '../mail/portal-mail.service';
import { maskEmail } from '../application-error-log/application-error-sanitizer';
import { PasswordResetToken } from './password-reset-token.entity';
@Injectable()
@@ -20,6 +25,8 @@ export class PasswordService {
private readonly lldap: LldapService,
private readonly mail: PortalMailService,
private readonly audit: AuditService,
private readonly applicationErrorLogger: ApplicationErrorLoggerService,
private readonly requestContext: RequestContextService,
) {}
async changePassword(
@@ -73,6 +80,24 @@ export class PasswordService {
await this.mail.sendPasswordResetMail(user.email, token);
} catch (error) {
await this.resetTokens.delete({ id: resetToken.id }).catch(() => undefined);
const currentRequestContext = this.requestContext.get();
await this.applicationErrorLogger.log({
error,
category: ApplicationErrorCategory.EMAIL,
code: ApplicationErrorCode.PASSWORD_RESET_EMAIL_SEND_FAILED,
module: 'PasswordModule',
service: PasswordService.name,
operation: 'sendPasswordResetEmail',
requestContext: {
...currentRequestContext,
userId: user.id,
},
context: {
maskedRecipient: maskEmail(user.email),
mailProvider: this.config.get<string>('SMTP_HOST') ?? 'smtp',
},
handled: true,
});
await this.audit
.record({
type: 'password.reset_mail_failed',
@@ -82,9 +107,11 @@ export class PasswordService {
metadata: { error: this.errorMessage(error) },
})
.catch(() => undefined);
throw new ServiceUnavailableException(
const exception = new ServiceUnavailableException(
'Der Reset-Link konnte nicht versendet werden. Bitte versuche es spaeter erneut.',
);
markErrorAsLogged(exception);
throw exception;
}
await this.audit.record({