From 8f008c7cc5ebf6c6f5f4f3cb456ca9b97ef21d54 Mon Sep 17 00:00:00 2001 From: Philip Molares Date: Sun, 24 Jan 2021 20:37:04 +0100 Subject: [PATCH] auth: Add cron to clean old tokens Rename AuthToken.identifier to label Signed-off-by: Philip Molares --- docs/content/dev/db-schema.plantuml | 2 +- package.json | 4 +++- src/app.module.ts | 2 ++ src/auth/auth-token.entity.ts | 11 +++-------- src/auth/auth.service.spec.ts | 4 ++-- src/auth/auth.service.ts | 21 ++++++++++++++++----- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/docs/content/dev/db-schema.plantuml b/docs/content/dev/db-schema.plantuml index 84108edb7..ca8d0a3c6 100644 --- a/docs/content/dev/db-schema.plantuml +++ b/docs/content/dev/db-schema.plantuml @@ -30,7 +30,7 @@ entity "auth_token"{ *userId : uuid *keyId: text *accessToken : text - *identifier: text + *label: text *createdAt: date lastUsed: number validUntil: number diff --git a/package.json b/package.json index e7feac7cf..0a90ce822 100644 --- a/package.json +++ b/package.json @@ -30,9 +30,11 @@ "@nestjs/passport": "^7.1.5", "@nestjs/platform-express": "7.6.5", "@nestjs/swagger": "4.7.12", + "@nestjs/schedule": "^0.4.2", "@nestjs/typeorm": "7.1.5", - "@types/passport-http-bearer": "^1.0.36", "@types/bcrypt": "^3.0.0", + "@types/cron": "^1.7.2", + "@types/passport-http-bearer": "^1.0.36", "bcrypt": "^5.0.0", "class-transformer": "0.3.2", "class-validator": "0.13.1", diff --git a/src/app.module.ts b/src/app.module.ts index 0fc3313db..2f09ba425 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -26,6 +26,7 @@ import cspConfig from './config/csp.config'; import databaseConfig from './config/database.config'; import authConfig from './config/auth.config'; import { PrivateApiModule } from './api/private/private-api.module'; +import { ScheduleModule } from '@nestjs/schedule'; @Module({ imports: [ @@ -46,6 +47,7 @@ import { PrivateApiModule } from './api/private/private-api.module'; ], isGlobal: true, }), + ScheduleModule.forRoot(), NotesModule, UsersModule, RevisionsModule, diff --git a/src/auth/auth-token.entity.ts b/src/auth/auth-token.entity.ts index 9d216b40c..59fe5c82f 100644 --- a/src/auth/auth-token.entity.ts +++ b/src/auth/auth-token.entity.ts @@ -25,7 +25,7 @@ export class AuthToken { user: User; @Column() - identifier: string; + label: string; @CreateDateColumn() createdAt: Date; @@ -51,16 +51,11 @@ export class AuthToken { validUntil?: Date, ): Pick< AuthToken, - | 'user' - | 'identifier' - | 'keyId' - | 'accessTokenHash' - | 'createdAt' - | 'validUntil' + 'user' | 'label' | 'keyId' | 'accessTokenHash' | 'createdAt' | 'validUntil' > { const newToken = new AuthToken(); newToken.user = user; - newToken.identifier = identifier; + newToken.label = identifier; newToken.keyId = keyId; newToken.accessTokenHash = accessToken; newToken.createdAt = new Date(); diff --git a/src/auth/auth.service.spec.ts b/src/auth/auth.service.spec.ts index ae57414a3..5b4428b52 100644 --- a/src/auth/auth.service.spec.ts +++ b/src/auth/auth.service.spec.ts @@ -35,7 +35,7 @@ describe('AuthService', () => { accessTokenHash: '', createdAt: new Date(), id: 1, - identifier: 'testIdentifier', + label: 'testIdentifier', keyId: 'abc', lastUsed: null, user: null, @@ -186,7 +186,7 @@ describe('AuthService', () => { const tokenDto = await service.toAuthTokenDto(authToken); expect(tokenDto.keyId).toEqual(authToken.keyId); expect(tokenDto.lastUsed).toBeNull(); - expect(tokenDto.label).toEqual(authToken.identifier); + expect(tokenDto.label).toEqual(authToken.label); expect(tokenDto.validUntil).toBeNull(); expect(tokenDto.createdAt.getTime()).toEqual( authToken.createdAt.getTime(), diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index e37535104..df529ec1e 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -17,6 +17,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ConsoleLoggerService } from '../logger/console-logger.service'; import { TimestampMillis } from '../utils/timestamp'; +import { Cron } from '@nestjs/schedule'; @Injectable() export class AuthService { @@ -32,11 +33,11 @@ export class AuthService { async validateToken(token: string): Promise { const [keyId, secret] = token.split('.'); const accessToken = await this.getAuthTokenAndValidate(keyId, secret); + await this.setLastUsedToken(keyId); const user = await this.usersService.getUserByUsername( accessToken.user.userName, ); if (user) { - await this.setLastUsedToken(keyId); return user; } return null; @@ -125,9 +126,7 @@ export class AuthService { ) { // tokens validUntil Date lies in the past throw new TokenNotValidError( - `AuthToken '${token}' is not valid since ${new Date( - accessToken.validUntil, - )}.`, + `AuthToken '${token}' is not valid since ${accessToken.validUntil}.`, ); } return accessToken; @@ -156,7 +155,7 @@ export class AuthService { const tokenDto: AuthTokenDto = { lastUsed: null, validUntil: null, - label: authToken.identifier, + label: authToken.label, keyId: authToken.keyId, createdAt: authToken.createdAt, }; @@ -182,4 +181,16 @@ export class AuthService { secret: secret, }; } + + // Delete all non valid tokens every sunday on 3:00 AM + @Cron('0 0 3 * * 0') + async handleCron() { + const currentTime = new Date().getTime(); + const tokens: AuthToken[] = await this.authTokenRepository.find(); + for (const token of tokens) { + if (token.validUntil && token.validUntil.getTime() <= currentTime) { + await this.authTokenRepository.remove(token); + } + } + } }