diff --git a/packages/backend/server/package.json b/packages/backend/server/package.json index a1cb172f920e7..cd5e562ceaf8a 100644 --- a/packages/backend/server/package.json +++ b/packages/backend/server/package.json @@ -34,7 +34,7 @@ "@nestjs/platform-express": "^10.3.7", "@nestjs/platform-socket.io": "^10.3.7", "@nestjs/schedule": "^4.0.1", - "@nestjs/throttler": "5.2.0", + "@nestjs/throttler": "6.2.1", "@nestjs/websockets": "^10.3.7", "@node-rs/argon2": "^1.8.0", "@node-rs/crc32": "^1.10.0", @@ -76,7 +76,7 @@ "mustache": "^4.2.0", "nanoid": "^5.0.7", "nest-commander": "^3.12.5", - "nestjs-throttler-storage-redis": "^0.4.4", + "nestjs-throttler-storage-redis": "^0.5.0", "nodemailer": "^6.9.13", "on-headers": "^1.0.2", "openai": "^4.33.0", diff --git a/packages/backend/server/src/fundamentals/throttler/index.ts b/packages/backend/server/src/fundamentals/throttler/index.ts index f7a4993a0876b..7040526849ff0 100644 --- a/packages/backend/server/src/fundamentals/throttler/index.ts +++ b/packages/backend/server/src/fundamentals/throttler/index.ts @@ -8,8 +8,8 @@ import { ThrottlerGuard, ThrottlerModule, type ThrottlerModuleOptions, - ThrottlerOptions, ThrottlerOptionsFactory, + ThrottlerRequest, ThrottlerStorageService, } from '@nestjs/throttler'; import type { Request } from 'express'; @@ -74,12 +74,15 @@ export class CloudThrottlerGuard extends ThrottlerGuard { return `${tracker};${throttler}`; } - override async handleRequest( - context: ExecutionContext, - limit: number, - ttl: number, - throttlerOptions: ThrottlerOptions - ) { + override async handleRequest(request: ThrottlerRequest) { + const { + context, + throttler: throttlerOptions, + ttl, + blockDuration, + } = request; + let limit = request.limit; + // give it 'default' if no throttler is specified, // so the unauthenticated users visits will always hit default throttler // authenticated users will directly bypass unprotected APIs in [CloudThrottlerGuard.canActivate] @@ -118,13 +121,11 @@ export class CloudThrottlerGuard extends ThrottlerGuard { tracker, throttlerOptions.name ?? 'default' ); - const { timeToExpire, totalHits } = await this.storageService.increment( - key, - ttl - ); + const { timeToExpire, totalHits, isBlocked, timeToBlockExpire } = + await this.storageService.increment(key, ttl, limit, blockDuration, key); - if (totalHits > limit) { - res.header('Retry-After', timeToExpire.toString()); + if (isBlocked) { + res.header('Retry-After', timeToBlockExpire.toString()); await this.throwThrottlingException(context, { limit, ttl, @@ -132,6 +133,8 @@ export class CloudThrottlerGuard extends ThrottlerGuard { tracker, totalHits, timeToExpire, + isBlocked, + timeToBlockExpire, }); } diff --git a/packages/backend/server/tests/nestjs/throttler.spec.ts b/packages/backend/server/tests/nestjs/throttler.spec.ts index 729ca7852f0c3..552d7b01e8f29 100644 --- a/packages/backend/server/tests/nestjs/throttler.spec.ts +++ b/packages/backend/server/tests/nestjs/throttler.spec.ts @@ -137,6 +137,8 @@ test('should be able to prevent requests if limit is reached', async t => { const stub = Sinon.stub(app.get(ThrottlerStorage), 'increment').resolves({ timeToExpire: 10, totalHits: 21, + isBlocked: true, + timeToBlockExpire: 10, }); const res = await request(app.getHttpServer()) .get('/nonthrottled/strict') diff --git a/yarn.lock b/yarn.lock index 198e590b1ed21..eec76ff419432 100644 --- a/yarn.lock +++ b/yarn.lock @@ -777,7 +777,7 @@ __metadata: "@nestjs/platform-socket.io": "npm:^10.3.7" "@nestjs/schedule": "npm:^4.0.1" "@nestjs/testing": "npm:^10.3.7" - "@nestjs/throttler": "npm:5.2.0" + "@nestjs/throttler": "npm:6.2.1" "@nestjs/websockets": "npm:^10.3.7" "@node-rs/argon2": "npm:^1.8.0" "@node-rs/crc32": "npm:^1.10.0" @@ -836,7 +836,7 @@ __metadata: mustache: "npm:^4.2.0" nanoid: "npm:^5.0.7" nest-commander: "npm:^3.12.5" - nestjs-throttler-storage-redis: "npm:^0.4.4" + nestjs-throttler-storage-redis: "npm:^0.5.0" nodemailer: "npm:^6.9.13" nodemon: "npm:^3.1.0" on-headers: "npm:^1.0.2" @@ -8221,14 +8221,14 @@ __metadata: languageName: node linkType: hard -"@nestjs/throttler@npm:5.2.0": - version: 5.2.0 - resolution: "@nestjs/throttler@npm:5.2.0" +"@nestjs/throttler@npm:6.2.1": + version: 6.2.1 + resolution: "@nestjs/throttler@npm:6.2.1" peerDependencies: "@nestjs/common": ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 "@nestjs/core": ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 reflect-metadata: ^0.1.13 || ^0.2.0 - checksum: 10/ec5805cdba895a61f4cb0f998fb8cd16f3c7a86b41fb699c8eb15a0b74aac9dc7da306e8cd4b95bd6c8d0042bb5a4ee4c479b270a5af9bc6ff781839e9fab5b3 + checksum: 10/4fc05b62f4a115683e3f4072033c1dde5010a9390ee8c6df396a29e90a2599dc18b5c921c2a2958473f7bb66a8336ae014b969c0ff82c2d3b6869b028cb361ee languageName: node linkType: hard @@ -27512,16 +27512,16 @@ __metadata: languageName: node linkType: hard -"nestjs-throttler-storage-redis@npm:^0.4.4": - version: 0.4.4 - resolution: "nestjs-throttler-storage-redis@npm:0.4.4" +"nestjs-throttler-storage-redis@npm:^0.5.0": + version: 0.5.0 + resolution: "nestjs-throttler-storage-redis@npm:0.5.0" peerDependencies: "@nestjs/common": ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 "@nestjs/core": ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 - "@nestjs/throttler": ">=5.0.0" + "@nestjs/throttler": ">=6.0.0" ioredis: ">=5.0.0" reflect-metadata: ^0.2.1 - checksum: 10/210aa46d734c2290637b287d620e6852ad24297dfd3e4b06461a816eec966bc559363554b402d3a92b491286b4802d18c8549d0b94be23f10161d83cc8068aee + checksum: 10/31073270c4fe045bcd37bbf8bf27832724ccffcc42b6d0a46d2f9e0a207c63b29c952250229e0fcb34feef41eea41f095856da1d92a4e6352cc7f04877b57a2c languageName: node linkType: hard