diff --git a/api/src/auth/auth.controller.ts b/api/src/auth/auth.controller.ts index 7d1b4c4..6239f86 100644 --- a/api/src/auth/auth.controller.ts +++ b/api/src/auth/auth.controller.ts @@ -85,6 +85,16 @@ export class AuthController { return { message: 'API Key Deleted' } } + @UseGuards(AuthGuard, CanModifyApiKey) + @ApiOperation({ summary: 'Revoke Api Key' }) + @ApiBearerAuth() + @HttpCode(HttpStatus.OK) + @Post('/api-keys/:id/revoke') + async revokeApiKey(@Param() params) { + await this.authService.revokeApiKey(params.id) + return { message: 'API Key Revoked' } + } + @ApiOperation({ summary: 'Request Password Reset' }) @HttpCode(HttpStatus.OK) @Post('/request-password-reset') diff --git a/api/src/auth/auth.service.ts b/api/src/auth/auth.service.ts index eb7363a..907a207 100644 --- a/api/src/auth/auth.service.ts +++ b/api/src/auth/auth.service.ts @@ -234,8 +234,23 @@ export class AuthService { HttpStatus.NOT_FOUND, ) } + if (apiKey.usageCount > 0) { + throw new HttpException( + { error: 'Api key cannot be deleted' }, + HttpStatus.BAD_REQUEST, + ) + } - // await this.apiKeyModel.deleteOne({ _id: apiKeyId }) + await this.apiKeyModel.deleteOne({ _id: apiKeyId }) + } + + async revokeApiKey(apiKeyId: string) { + const apiKey = await this.apiKeyModel.findById(apiKeyId) + if (!apiKey) { + throw new HttpException({ error: 'Api key not found' }, HttpStatus.NOT_FOUND) + } + apiKey.revokedAt = new Date() + await apiKey.save() } async trackAccessLog({ request }) { diff --git a/api/src/auth/guards/auth.guard.ts b/api/src/auth/guards/auth.guard.ts index 4563f56..3a35729 100644 --- a/api/src/auth/guards/auth.guard.ts +++ b/api/src/auth/guards/auth.guard.ts @@ -38,6 +38,7 @@ export class AuthGuard implements CanActivate { const regex = new RegExp(`^${apiKeyString.substr(0, 17)}`, 'g') const apiKey = await this.authService.findApiKey({ apiKey: { $regex: regex }, + $or: [{ revokedAt: null }, { revokedAt: { $exists: false } }], }) if (apiKey && bcrypt.compareSync(apiKeyString, apiKey.hashedApiKey)) { diff --git a/api/src/auth/schemas/api-key.schema.ts b/api/src/auth/schemas/api-key.schema.ts index 426aed0..aa2a35a 100644 --- a/api/src/auth/schemas/api-key.schema.ts +++ b/api/src/auth/schemas/api-key.schema.ts @@ -22,6 +22,9 @@ export class ApiKey { @Prop({ type: Date }) lastUsedAt: Date + + @Prop({ type: Date }) + revokedAt?: Date } export const ApiKeySchema = SchemaFactory.createForClass(ApiKey)