From d99de49c0063829b9a67e2366f87ab1b35d73d8d Mon Sep 17 00:00:00 2001 From: Anand Chowdhary Date: Tue, 27 Oct 2020 19:45:37 +0530 Subject: [PATCH] :sparkles: Add scheduler to delete sessions --- src/app.module.ts | 4 ++++ src/config/configuration.ts | 1 + src/modules/auth/auth.service.ts | 11 +++++------ src/modules/email/email.service.ts | 5 +++-- src/modules/tasks/tasks.module.ts | 11 +++++++++++ src/modules/tasks/tasks.service.ts | 27 +++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 src/modules/tasks/tasks.module.ts create mode 100644 src/modules/tasks/tasks.service.ts diff --git a/src/app.module.ts b/src/app.module.ts index 3ba0c6e95..f2810aa52 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -1,6 +1,7 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core'; +import { ScheduleModule } from '@nestjs/schedule'; import { RateLimiterInterceptor, RateLimiterModule } from 'nestjs-rate-limiter'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @@ -14,6 +15,7 @@ import { EmailsModule } from './modules/emails/emails.module'; import { GroupsModule } from './modules/groups/groups.module'; import { PrismaModule } from './modules/prisma/prisma.module'; import { SessionsModule } from './modules/sessions/sessions.module'; +import { TasksModule } from './modules/tasks/tasks.module'; import { UsersModule } from './modules/user/user.module'; @Module({ @@ -21,7 +23,9 @@ import { UsersModule } from './modules/user/user.module'; ConfigModule.forRoot({ load: [configuration], }), + ScheduleModule.forRoot(), PrismaModule, + TasksModule, UsersModule, AuthModule, RateLimiterModule.register({ diff --git a/src/config/configuration.ts b/src/config/configuration.ts index ccef6b4d2..5d04f437f 100644 --- a/src/config/configuration.ts +++ b/src/config/configuration.ts @@ -5,6 +5,7 @@ export default () => ({ jwtSecret: process.env.JWT_SECRET ?? 'staart', accessTokenExpiry: process.env.ACCESS_TOKEN_EXPIRY ?? '1h', passwordPwnedCheck: !!process.env.PASSWORD_PWNED_CHECK, + unusedRefreshTokenExpiryDays: process.env.DELETE_EXPIRED_SESSIONS ?? 30, }, email: { name: process.env.EMAIL_NAME ?? 'Staart', diff --git a/src/modules/auth/auth.service.ts b/src/modules/auth/auth.service.ts index b1488dd09..2f935da77 100644 --- a/src/modules/auth/auth.service.ts +++ b/src/modules/auth/auth.service.ts @@ -5,19 +5,18 @@ import { UnauthorizedException, UnprocessableEntityException, } from '@nestjs/common'; +import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util'; import { ConfigService } from '@nestjs/config'; +import { JwtService } from '@nestjs/jwt'; import { users } from '@prisma/client'; +import { compare, hash } from 'bcrypt'; +import { safeEmail } from 'src/helpers/safe-email'; import { EmailService } from '../email/email.service'; import { Expose } from '../prisma/prisma.interface'; import { PrismaService } from '../prisma/prisma.service'; -import { UsersService } from '../user/user.service'; +import { PwnedService } from '../pwned/pwned.service'; import { RegisterDto } from './auth.dto'; -import { compare, hash } from 'bcrypt'; -import { JwtService } from '@nestjs/jwt'; -import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util'; import { AccessTokenClaims } from './auth.interface'; -import { PwnedService } from '../pwned/pwned.service'; -import { safeEmail } from 'src/helpers/safe-email'; @Injectable() export class AuthService { diff --git a/src/modules/email/email.service.ts b/src/modules/email/email.service.ts index 91f13d5be..7868d5363 100644 --- a/src/modules/email/email.service.ts +++ b/src/modules/email/email.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { EmailConfig, EmailOptions } from './email.interface'; import PQueue from 'p-queue'; @@ -12,6 +12,7 @@ import { render } from '@staart/mustache-markdown'; @Injectable() export class EmailService { + private readonly logger = new Logger(EmailService.name); private transport: Mail; private config: EmailConfig; private queue = new PQueue({ concurrency: 1 }); @@ -35,7 +36,7 @@ export class EmailService { { retries: 3, onFailedAttempt: error => { - console.log( + this.logger.error( `Email to ${options.to} failed, retrying (${error.retriesLeft} attempts left)`, error.name, ); diff --git a/src/modules/tasks/tasks.module.ts b/src/modules/tasks/tasks.module.ts new file mode 100644 index 000000000..f7f732e31 --- /dev/null +++ b/src/modules/tasks/tasks.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { PrismaModule } from '../prisma/prisma.module'; +import { TasksService } from './tasks.service'; + +@Module({ + imports: [ConfigModule, PrismaModule], + providers: [TasksService], + exports: [TasksService], +}) +export class TasksModule {} diff --git a/src/modules/tasks/tasks.service.ts b/src/modules/tasks/tasks.service.ts new file mode 100644 index 000000000..2dd8df8ed --- /dev/null +++ b/src/modules/tasks/tasks.service.ts @@ -0,0 +1,27 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { Cron, CronExpression } from '@nestjs/schedule'; +import { PrismaService } from '../prisma/prisma.service'; + +@Injectable() +export class TasksService { + constructor( + private prisma: PrismaService, + private configService: ConfigService, + ) {} + private readonly logger = new Logger(TasksService.name); + + @Cron(CronExpression.EVERY_DAY_AT_1PM) + async deleteOldSessions() { + const now = new Date(); + now.setDate( + now.getDate() - + this.configService.get('security.unusedRefreshTokenExpiryDays'), + ); + const deleted = await this.prisma.sessions.deleteMany({ + where: { updatedAt: { lte: now } }, + }); + if (deleted.count) + this.logger.debug(`Deleted ${deleted.count} expired sessions`); + } +}