feature/refactor-login #19
|
@ -1,12 +1,16 @@
|
|||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||
import { SessionService } from 'src/modules/session/services/session.service';
|
||||
import { EmailVerificationService } from 'src/modules/verify-module/services/email-verification.service';
|
||||
|
||||
@Injectable()
|
||||
export class ClearExpiredSessionsCron {
|
||||
private readonly logger: Logger = new Logger(ClearExpiredSessionsCron.name);
|
||||
|
||||
public constructor(private readonly sessionService: SessionService) {}
|
||||
public constructor(
|
||||
private readonly sessionService: SessionService,
|
||||
private readonly emailVerificationService: EmailVerificationService
|
||||
) {}
|
||||
|
||||
@Cron(CronExpression.EVERY_12_HOURS, {
|
||||
name: 'Clear-Expired-Sessions',
|
||||
|
@ -17,4 +21,14 @@ export class ClearExpiredSessionsCron {
|
|||
this.sessionService.deleteAllExpiredSessions();
|
||||
this.logger.log('-------------------------------------------');
|
||||
}
|
||||
|
||||
@Cron(CronExpression.EVERY_10_MINUTES, {
|
||||
name: 'Clear-Expired-Tokens',
|
||||
timeZone: 'Europe/Berlin',
|
||||
})
|
||||
public handleClearExpiredTokens(): void {
|
||||
this.logger.log('-Cronjob Executed: Delete-Expired-Tokens-');
|
||||
this.emailVerificationService.deleteAllExpiredTokens();
|
||||
this.logger.log('-------------------------------------------');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { EmailVerification } from 'src/entities';
|
||||
import { Repository } from 'typeorm';
|
||||
import { LessThan, MoreThan, Repository } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class EmailVerifyRepository {
|
||||
|
@ -24,6 +24,23 @@ export class EmailVerifyRepository {
|
|||
});
|
||||
}
|
||||
|
||||
public async findValidVerification(
|
||||
token: string,
|
||||
email: string
|
||||
): Promise<EmailVerification | undefined> {
|
||||
const currentDate = new Date();
|
||||
const tenMinutesAgo = new Date(currentDate.getTime() - 10 * 60 * 1000);
|
||||
|
||||
return await this.repository.findOne({
|
||||
where: {
|
||||
token,
|
||||
email,
|
||||
createdAt: MoreThan(tenMinutesAgo),
|
||||
expiresAt: MoreThan(currentDate),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public async findByTokenAndEmail(
|
||||
token: string,
|
||||
email: string
|
||||
|
@ -49,6 +66,14 @@ export class EmailVerifyRepository {
|
|||
return this.repository.findOne({ where: { email } });
|
||||
}
|
||||
|
||||
public async deleteAllExpiredTokens(): Promise<void> {
|
||||
const currentDate = new Date();
|
||||
|
||||
await this.repository.delete({
|
||||
expiresAt: LessThan(currentDate),
|
||||
});
|
||||
}
|
||||
|
||||
public async deleteEmailVerificationByToken(
|
||||
tokenToDelete: string
|
||||
): Promise<EmailVerification | null> {
|
||||
|
|
|
@ -4,7 +4,10 @@ import { Injectable } from '@nestjs/common';
|
|||
import { EmailVerification } from 'src/entities';
|
||||
import { SessionService } from 'src/modules/session/services/session.service';
|
||||
import { SuccessDto, UriEncoderService } from 'src/shared';
|
||||
import { InternalServerErrorException } from 'src/shared/exceptions';
|
||||
import {
|
||||
InternalServerErrorException,
|
||||
TokenExpiredException,
|
||||
} from 'src/shared/exceptions';
|
||||
|
||||
import { UserDataRepository } from '../../user-module/repositories/user-data.repository';
|
||||
import { EmailVerifyRepository } from '../repositories';
|
||||
|
@ -59,11 +62,11 @@ export class EmailVerificationService {
|
|||
): Promise<string> {
|
||||
try {
|
||||
const verificationToken = await this.createVerificationToken();
|
||||
const expiration = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
||||
const expiresAt = new Date(Date.now() + 10 * 60 * 1000);
|
||||
|
||||
await this.emailVerifyRepository.createEmailVerification(
|
||||
verificationToken,
|
||||
expiration,
|
||||
expiresAt,
|
||||
email,
|
||||
null
|
||||
);
|
||||
|
@ -85,13 +88,23 @@ export class EmailVerificationService {
|
|||
emailToVerify: string
|
||||
): Promise<SuccessDto> {
|
||||
try {
|
||||
const findTokenAndEmail: EmailVerification =
|
||||
await this.emailVerifyRepository.findByTokenAndEmail(
|
||||
const findTokenAndEmail: EmailVerification | null =
|
||||
await this.emailVerifyRepository.findValidVerification(
|
||||
tokenToVerify,
|
||||
emailToVerify
|
||||
);
|
||||
|
||||
if (!findTokenAndEmail) {
|
||||
const expiredToken =
|
||||
await this.emailVerifyRepository.findByTokenAndEmail(
|
||||
tokenToVerify,
|
||||
emailToVerify
|
||||
);
|
||||
|
||||
if (expiredToken) {
|
||||
throw new TokenExpiredException();
|
||||
}
|
||||
|
||||
return { success: false };
|
||||
}
|
||||
|
||||
|
@ -102,6 +115,9 @@ export class EmailVerificationService {
|
|||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
if (error instanceof TokenExpiredException) {
|
||||
throw error;
|
||||
}
|
||||
throw new InternalServerErrorException('EMAIL_VERIFICATION_ERROR', {
|
||||
message: 'An error occurred while verifying the email.',
|
||||
});
|
||||
|
@ -128,6 +144,12 @@ export class EmailVerificationService {
|
|||
}
|
||||
}
|
||||
|
||||
async deleteAllExpiredTokens(): Promise<void> {
|
||||
const currentDate = new Date();
|
||||
|
||||
await this.emailVerifyRepository.deleteAllExpiredTokens();
|
||||
}
|
||||
|
||||
private async createVerificationToken(): Promise<string> {
|
||||
const verifyToken = randomBytes(32).toString('hex');
|
||||
|
||||
|
|
|
@ -2,3 +2,4 @@ export * from './conflict.exception';
|
|||
export * from './forbidden.exception';
|
||||
export * from './internal-server-error.exception';
|
||||
export * from './not-found.exception';
|
||||
export * from './token-expired.exception';
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
import { HttpStatus } from '@nestjs/common';
|
||||
|
||||
import { BaseException } from './base.exception';
|
||||
|
||||
export class TokenExpiredException extends BaseException {
|
||||
public constructor(details?: unknown) {
|
||||
super(
|
||||
'The verification token has expired. Please request a new one.',
|
||||
HttpStatus.BAD_REQUEST,
|
||||
'TOKEN_EXPIRED',
|
||||
details
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue