auth: Add cron to clean old tokens

Rename AuthToken.identifier to label

Signed-off-by: Philip Molares <philip.molares@udo.edu>
This commit is contained in:
Philip Molares 2021-01-24 20:37:04 +01:00
parent cc2fcac532
commit 0a3247492a
6 changed files with 27 additions and 17 deletions

View file

@ -30,7 +30,7 @@ entity "auth_token"{
*userId : uuid *userId : uuid
*keyId: text *keyId: text
*accessToken : text *accessToken : text
*identifier: text *label: text
*createdAt: date *createdAt: date
lastUsed: number lastUsed: number
validUntil: number validUntil: number

View file

@ -30,9 +30,11 @@
"@nestjs/passport": "^7.1.5", "@nestjs/passport": "^7.1.5",
"@nestjs/platform-express": "7.6.5", "@nestjs/platform-express": "7.6.5",
"@nestjs/swagger": "4.7.12", "@nestjs/swagger": "4.7.12",
"@nestjs/schedule": "^0.4.2",
"@nestjs/typeorm": "7.1.5", "@nestjs/typeorm": "7.1.5",
"@types/passport-http-bearer": "^1.0.36",
"@types/bcrypt": "^3.0.0", "@types/bcrypt": "^3.0.0",
"@types/cron": "^1.7.2",
"@types/passport-http-bearer": "^1.0.36",
"bcrypt": "^5.0.0", "bcrypt": "^5.0.0",
"class-transformer": "0.3.2", "class-transformer": "0.3.2",
"class-validator": "0.13.1", "class-validator": "0.13.1",

View file

@ -26,6 +26,7 @@ import cspConfig from './config/csp.config';
import databaseConfig from './config/database.config'; import databaseConfig from './config/database.config';
import authConfig from './config/auth.config'; import authConfig from './config/auth.config';
import { PrivateApiModule } from './api/private/private-api.module'; import { PrivateApiModule } from './api/private/private-api.module';
import { ScheduleModule } from '@nestjs/schedule';
@Module({ @Module({
imports: [ imports: [
@ -46,6 +47,7 @@ import { PrivateApiModule } from './api/private/private-api.module';
], ],
isGlobal: true, isGlobal: true,
}), }),
ScheduleModule.forRoot(),
NotesModule, NotesModule,
UsersModule, UsersModule,
RevisionsModule, RevisionsModule,

View file

@ -25,7 +25,7 @@ export class AuthToken {
user: User; user: User;
@Column() @Column()
identifier: string; label: string;
@CreateDateColumn() @CreateDateColumn()
createdAt: Date; createdAt: Date;
@ -51,16 +51,11 @@ export class AuthToken {
validUntil?: Date, validUntil?: Date,
): Pick< ): Pick<
AuthToken, AuthToken,
| 'user' 'user' | 'label' | 'keyId' | 'accessTokenHash' | 'createdAt' | 'validUntil'
| 'identifier'
| 'keyId'
| 'accessTokenHash'
| 'createdAt'
| 'validUntil'
> { > {
const newToken = new AuthToken(); const newToken = new AuthToken();
newToken.user = user; newToken.user = user;
newToken.identifier = identifier; newToken.label = identifier;
newToken.keyId = keyId; newToken.keyId = keyId;
newToken.accessTokenHash = accessToken; newToken.accessTokenHash = accessToken;
newToken.createdAt = new Date(); newToken.createdAt = new Date();

View file

@ -35,7 +35,7 @@ describe('AuthService', () => {
accessTokenHash: '', accessTokenHash: '',
createdAt: new Date(), createdAt: new Date(),
id: 1, id: 1,
identifier: 'testIdentifier', label: 'testIdentifier',
keyId: 'abc', keyId: 'abc',
lastUsed: null, lastUsed: null,
user: null, user: null,
@ -186,7 +186,7 @@ describe('AuthService', () => {
const tokenDto = await service.toAuthTokenDto(authToken); const tokenDto = await service.toAuthTokenDto(authToken);
expect(tokenDto.keyId).toEqual(authToken.keyId); expect(tokenDto.keyId).toEqual(authToken.keyId);
expect(tokenDto.lastUsed).toBeNull(); expect(tokenDto.lastUsed).toBeNull();
expect(tokenDto.label).toEqual(authToken.identifier); expect(tokenDto.label).toEqual(authToken.label);
expect(tokenDto.validUntil).toBeNull(); expect(tokenDto.validUntil).toBeNull();
expect(tokenDto.createdAt.getTime()).toEqual( expect(tokenDto.createdAt.getTime()).toEqual(
authToken.createdAt.getTime(), authToken.createdAt.getTime(),

View file

@ -17,6 +17,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { ConsoleLoggerService } from '../logger/console-logger.service'; import { ConsoleLoggerService } from '../logger/console-logger.service';
import { TimestampMillis } from '../utils/timestamp'; import { TimestampMillis } from '../utils/timestamp';
import { Cron } from '@nestjs/schedule';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
@ -32,11 +33,11 @@ export class AuthService {
async validateToken(token: string): Promise<User> { async validateToken(token: string): Promise<User> {
const [keyId, secret] = token.split('.'); const [keyId, secret] = token.split('.');
const accessToken = await this.getAuthTokenAndValidate(keyId, secret); const accessToken = await this.getAuthTokenAndValidate(keyId, secret);
await this.setLastUsedToken(keyId);
const user = await this.usersService.getUserByUsername( const user = await this.usersService.getUserByUsername(
accessToken.user.userName, accessToken.user.userName,
); );
if (user) { if (user) {
await this.setLastUsedToken(keyId);
return user; return user;
} }
return null; return null;
@ -125,9 +126,7 @@ export class AuthService {
) { ) {
// tokens validUntil Date lies in the past // tokens validUntil Date lies in the past
throw new TokenNotValidError( throw new TokenNotValidError(
`AuthToken '${token}' is not valid since ${new Date( `AuthToken '${token}' is not valid since ${accessToken.validUntil}.`,
accessToken.validUntil,
)}.`,
); );
} }
return accessToken; return accessToken;
@ -156,7 +155,7 @@ export class AuthService {
const tokenDto: AuthTokenDto = { const tokenDto: AuthTokenDto = {
lastUsed: null, lastUsed: null,
validUntil: null, validUntil: null,
label: authToken.identifier, label: authToken.label,
keyId: authToken.keyId, keyId: authToken.keyId,
createdAt: authToken.createdAt, createdAt: authToken.createdAt,
}; };
@ -182,4 +181,16 @@ export class AuthService {
secret: secret, 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);
}
}
}
} }