From 03c2919b696c9a8e424e21399c3ead846488f96a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 15:36:58 +0900 Subject: [PATCH 01/12] fix rate limit check never ends --- packages/backend/src/server/api/RateLimiterService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index cae106c273..52d73baa0a 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -57,7 +57,7 @@ export class RateLimiterService { return reject({ code: 'BRIEF_REQUEST_INTERVAL', info }); } else { if (hasLongTermLimit) { - return max; + return max.then(ok, reject); } else { return ok(); } From 28c8d318e11484dca1c6b2b67d0c5d14fa78fbf6 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:18:33 +0900 Subject: [PATCH 02/12] =?UTF-8?q?fix:=20long=20term=20/=20short=20term=20l?= =?UTF-8?q?imit=E3=81=8C=E3=81=AA=E3=81=84=E3=81=A8=E3=81=8D=E3=81=A7?= =?UTF-8?q?=E3=82=82=E3=81=9D=E3=82=8C=E3=81=9E=E3=82=8C=E7=94=A8=E3=81=AE?= =?UTF-8?q?new=20Limiter=E3=81=A8limiter.get=E3=81=8C=E5=91=BC=E3=81=B0?= =?UTF-8?q?=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/server/api/RateLimiterService.ts | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 52d73baa0a..c212c0fa45 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -32,13 +32,13 @@ export class RateLimiterService { @bindThis public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { - { - if (this.disabled) { - return Promise.resolve(); - } + if (this.disabled) { + return Promise.resolve(); + } - // Short-term limit - const min = new Promise((ok, reject) => { + // Short-term limit + const min = () => { + return new Promise((ok, reject) => { const minIntervalLimiter = new Limiter({ id: `${actor}:${limitation.key}:min`, duration: limitation.minInterval! * factor, @@ -57,16 +57,18 @@ export class RateLimiterService { return reject({ code: 'BRIEF_REQUEST_INTERVAL', info }); } else { if (hasLongTermLimit) { - return max.then(ok, reject); + return max().then(ok, reject); } else { return ok(); } } }); }); + }; - // Long term limit - const max = new Promise((ok, reject) => { + // Long term limit + const max = () => { + return new Promise((ok, reject) => { const limiter = new Limiter({ id: `${actor}:${limitation.key}`, duration: limitation.duration! * factor, @@ -88,20 +90,20 @@ export class RateLimiterService { } }); }); + }; - const hasShortTermLimit = typeof limitation.minInterval === 'number'; + const hasShortTermLimit = typeof limitation.minInterval === 'number'; - const hasLongTermLimit = - typeof limitation.duration === 'number' && - typeof limitation.max === 'number'; + const hasLongTermLimit = + typeof limitation.duration === 'number' && + typeof limitation.max === 'number'; - if (hasShortTermLimit) { - return min; - } else if (hasLongTermLimit) { - return max; - } else { - return Promise.resolve(); - } + if (hasShortTermLimit) { + return min(); + } else if (hasLongTermLimit) { + return max(); + } else { + return Promise.resolve(); } } } From d8844aed6f9ab1dd733792efc6e3025d67494bcf Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:29:09 +0900 Subject: [PATCH 03/12] refactor: wrap ratelimiter with promise --- .../src/server/api/RateLimiterService.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index c212c0fa45..b6e9485d54 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -30,6 +30,18 @@ export class RateLimiterService { } } + @bindThis + private checkLimiter(options: Limiter.LimiterOption): Promise { + return new Promise((resolve, reject) => { + new Limiter(options).get((err, info) => { + if (err) { + return reject({ code: 'ERR', info }); + } + resolve(info); + }); + }); + } + @bindThis public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { if (this.disabled) { @@ -39,18 +51,12 @@ export class RateLimiterService { // Short-term limit const min = () => { return new Promise((ok, reject) => { - const minIntervalLimiter = new Limiter({ + this.checkLimiter({ id: `${actor}:${limitation.key}:min`, duration: limitation.minInterval! * factor, max: 1, db: this.redisClient, - }); - - minIntervalLimiter.get((err, info) => { - if (err) { - return reject({ code: 'ERR', info }); - } - + }).then((info) => { this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); if (info.remaining === 0) { @@ -69,18 +75,12 @@ export class RateLimiterService { // Long term limit const max = () => { return new Promise((ok, reject) => { - const limiter = new Limiter({ + this.checkLimiter({ id: `${actor}:${limitation.key}`, duration: limitation.duration! * factor, max: limitation.max! / factor, db: this.redisClient, - }); - - limiter.get((err, info) => { - if (err) { - return reject({ code: 'ERR', info }); - } - + }).then((info) => { this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); if (info.remaining === 0) { From 1d6d90d62d06407e8c6eecd2d0c287c0f347585a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:33:09 +0900 Subject: [PATCH 04/12] refactor: reimplement max/min with async --- .../src/server/api/RateLimiterService.ts | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index b6e9485d54..5c967b4551 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -49,47 +49,45 @@ export class RateLimiterService { } // Short-term limit - const min = () => { - return new Promise((ok, reject) => { - this.checkLimiter({ - id: `${actor}:${limitation.key}:min`, - duration: limitation.minInterval! * factor, - max: 1, - db: this.redisClient, - }).then((info) => { - this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); - - if (info.remaining === 0) { - return reject({ code: 'BRIEF_REQUEST_INTERVAL', info }); - } else { - if (hasLongTermLimit) { - return max().then(ok, reject); - } else { - return ok(); - } - } - }); + const min = async () => { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}:min`, + duration: limitation.minInterval! * factor, + max: 1, + db: this.redisClient, }); + + this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); + + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'BRIEF_REQUEST_INTERVAL', info }; + } else { + if (hasLongTermLimit) { + await max(); + } else { + return; + } + } }; // Long term limit - const max = () => { - return new Promise((ok, reject) => { - this.checkLimiter({ - id: `${actor}:${limitation.key}`, - duration: limitation.duration! * factor, - max: limitation.max! / factor, - db: this.redisClient, - }).then((info) => { - this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); - - if (info.remaining === 0) { - return reject({ code: 'RATE_LIMIT_EXCEEDED', info }); - } else { - return ok(); - } - }); + const max = async () => { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}`, + duration: limitation.duration! * factor, + max: limitation.max! / factor, + db: this.redisClient, }); + + this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); + + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'RATE_LIMIT_EXCEEDED', info }; + } else { + return; + } }; const hasShortTermLimit = typeof limitation.minInterval === 'number'; From b3561ce425fd7274e20f1b62740bda0c57d6dad8 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:34:01 +0900 Subject: [PATCH 05/12] refactor: reimplement limit with async --- packages/backend/src/server/api/RateLimiterService.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 5c967b4551..31c3809f5f 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -43,9 +43,9 @@ export class RateLimiterService { } @bindThis - public limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { + public async limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { if (this.disabled) { - return Promise.resolve(); + return; } // Short-term limit @@ -97,11 +97,11 @@ export class RateLimiterService { typeof limitation.max === 'number'; if (hasShortTermLimit) { - return min(); + await min(); } else if (hasLongTermLimit) { - return max(); + await max(); } else { - return Promise.resolve(); + return; } } } From f72c76840710ba491b9d635390067b793b84b4bc Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:36:44 +0900 Subject: [PATCH 06/12] refactor: do not check long term limit inside min --- packages/backend/src/server/api/RateLimiterService.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 31c3809f5f..9c125dc0df 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -63,11 +63,7 @@ export class RateLimiterService { // eslint-disable-next-line no-throw-literal throw { code: 'BRIEF_REQUEST_INTERVAL', info }; } else { - if (hasLongTermLimit) { - await max(); - } else { - return; - } + return; } }; @@ -98,10 +94,9 @@ export class RateLimiterService { if (hasShortTermLimit) { await min(); - } else if (hasLongTermLimit) { + } + if (hasLongTermLimit) { await max(); - } else { - return; } } } From 3eb187580459e296afc77a477844d4f0f83c76aa Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:41:39 +0900 Subject: [PATCH 07/12] refactor: check if there is rate limit inside min/max function --- .../src/server/api/RateLimiterService.ts | 70 ++++++++----------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 9c125dc0df..7d782795f9 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -50,53 +50,43 @@ export class RateLimiterService { // Short-term limit const min = async () => { - const info = await this.checkLimiter({ - id: `${actor}:${limitation.key}:min`, - duration: limitation.minInterval! * factor, - max: 1, - db: this.redisClient, - }); - - this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); - - if (info.remaining === 0) { - // eslint-disable-next-line no-throw-literal - throw { code: 'BRIEF_REQUEST_INTERVAL', info }; - } else { - return; + if (limitation.minInterval != null) { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}:min`, + duration: limitation.minInterval * factor, + max: 1, + db: this.redisClient, + }); + this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'BRIEF_REQUEST_INTERVAL', info }; + } else { + return; + } } }; // Long term limit const max = async () => { - const info = await this.checkLimiter({ - id: `${actor}:${limitation.key}`, - duration: limitation.duration! * factor, - max: limitation.max! / factor, - db: this.redisClient, - }); - - this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); - - if (info.remaining === 0) { - // eslint-disable-next-line no-throw-literal - throw { code: 'RATE_LIMIT_EXCEEDED', info }; - } else { - return; + if (limitation.duration != null && limitation.max != null) { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}`, + duration: limitation.duration * factor, + max: limitation.max / factor, + db: this.redisClient, + }); + this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'RATE_LIMIT_EXCEEDED', info }; + } else { + return; + } } }; - const hasShortTermLimit = typeof limitation.minInterval === 'number'; - - const hasLongTermLimit = - typeof limitation.duration === 'number' && - typeof limitation.max === 'number'; - - if (hasShortTermLimit) { - await min(); - } - if (hasLongTermLimit) { - await max(); - } + await min(); + await max(); } } From 4af9c90d12ab3aef89c66caa97e6b6208516476b Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:42:06 +0900 Subject: [PATCH 08/12] refactor: remove unnecessary return in min/max function --- packages/backend/src/server/api/RateLimiterService.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 7d782795f9..8230c98c1d 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -61,8 +61,6 @@ export class RateLimiterService { if (info.remaining === 0) { // eslint-disable-next-line no-throw-literal throw { code: 'BRIEF_REQUEST_INTERVAL', info }; - } else { - return; } } }; @@ -80,8 +78,6 @@ export class RateLimiterService { if (info.remaining === 0) { // eslint-disable-next-line no-throw-literal throw { code: 'RATE_LIMIT_EXCEEDED', info }; - } else { - return; } } }; From 0ef7f14fa9a43e38a2339a1e36d817edf2fb67b0 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 14 Jun 2024 17:48:05 +0900 Subject: [PATCH 09/12] refactor: remove unnecessary max/min function --- .../src/server/api/RateLimiterService.ts | 59 +++++++++---------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 8230c98c1d..f78b380d9e 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -49,40 +49,37 @@ export class RateLimiterService { } // Short-term limit - const min = async () => { - if (limitation.minInterval != null) { - const info = await this.checkLimiter({ - id: `${actor}:${limitation.key}:min`, - duration: limitation.minInterval * factor, - max: 1, - db: this.redisClient, - }); - this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); - if (info.remaining === 0) { - // eslint-disable-next-line no-throw-literal - throw { code: 'BRIEF_REQUEST_INTERVAL', info }; - } + if (limitation.minInterval != null) { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}:min`, + duration: limitation.minInterval * factor, + max: 1, + db: this.redisClient, + }); + + this.logger.debug(`${actor} ${limitation.key} min remaining: ${info.remaining}`); + + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'BRIEF_REQUEST_INTERVAL', info }; } - }; + } // Long term limit - const max = async () => { - if (limitation.duration != null && limitation.max != null) { - const info = await this.checkLimiter({ - id: `${actor}:${limitation.key}`, - duration: limitation.duration * factor, - max: limitation.max / factor, - db: this.redisClient, - }); - this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); - if (info.remaining === 0) { - // eslint-disable-next-line no-throw-literal - throw { code: 'RATE_LIMIT_EXCEEDED', info }; - } - } - }; + if (limitation.duration != null && limitation.max != null) { + const info = await this.checkLimiter({ + id: `${actor}:${limitation.key}`, + duration: limitation.duration * factor, + max: limitation.max / factor, + db: this.redisClient, + }); - await min(); - await max(); + this.logger.debug(`${actor} ${limitation.key} max remaining: ${info.remaining}`); + + if (info.remaining === 0) { + // eslint-disable-next-line no-throw-literal + throw { code: 'RATE_LIMIT_EXCEEDED', info }; + } + } } } From f9dd3aca785dc9cec5c4f2a7abc746987b534e1a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sat, 22 Jun 2024 13:34:52 +0900 Subject: [PATCH 10/12] refactor: return rate limit instead of throwing an object --- .../backend/src/server/api/ApiCallService.ts | 22 ++++++++----------- .../src/server/api/RateLimiterService.ts | 20 ++++++++++++----- .../src/server/api/SigninApiService.ts | 5 ++--- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index 47f64f6609..02a1df12b8 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -317,19 +317,15 @@ export class ApiCallService implements OnApplicationShutdown { if (factor > 0) { // Rate limit - await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable }, limitActor, factor).catch(err => { - if ('info' in err) { - // errはLimiter.LimiterInfoであることが期待される - throw new ApiError({ - message: 'Rate limit exceeded. Please try again later.', - code: 'RATE_LIMIT_EXCEEDED', - id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', - httpStatusCode: 429, - }, err.info); - } else { - throw new TypeError('information must be a rate-limiter information.'); - } - }); + const rateLimit = await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable }, limitActor, factor); + if (rateLimit != null) { + throw new ApiError({ + message: 'Rate limit exceeded. Please try again later.', + code: 'RATE_LIMIT_EXCEEDED', + id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef', + httpStatusCode: 429, + }, rateLimit.info); + } } } diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index f78b380d9e..9b1cef8155 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -12,6 +12,14 @@ import { LoggerService } from '@/core/LoggerService.js'; import { bindThis } from '@/decorators.js'; import type { IEndpointMeta } from './endpoints.js'; +type RateLimitInfo = { + code: 'BRIEF_REQUEST_INTERVAL', + info: Limiter.LimiterInfo, +} | { + code: 'RATE_LIMIT_EXCEEDED', + info: Limiter.LimiterInfo, +} + @Injectable() export class RateLimiterService { private logger: Logger; @@ -35,7 +43,7 @@ export class RateLimiterService { return new Promise((resolve, reject) => { new Limiter(options).get((err, info) => { if (err) { - return reject({ code: 'ERR', info }); + return reject(err); } resolve(info); }); @@ -43,9 +51,9 @@ export class RateLimiterService { } @bindThis - public async limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1) { + public async limit(limitation: IEndpointMeta['limit'] & { key: NonNullable }, actor: string, factor = 1): Promise { if (this.disabled) { - return; + return null; } // Short-term limit @@ -61,7 +69,7 @@ export class RateLimiterService { if (info.remaining === 0) { // eslint-disable-next-line no-throw-literal - throw { code: 'BRIEF_REQUEST_INTERVAL', info }; + return { code: 'BRIEF_REQUEST_INTERVAL', info }; } } @@ -78,8 +86,10 @@ export class RateLimiterService { if (info.remaining === 0) { // eslint-disable-next-line no-throw-literal - throw { code: 'RATE_LIMIT_EXCEEDED', info }; + return { code: 'RATE_LIMIT_EXCEEDED', info }; } } + + return null } } diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts index edac9b3beb..d8e96006ec 100644 --- a/packages/backend/src/server/api/SigninApiService.ts +++ b/packages/backend/src/server/api/SigninApiService.ts @@ -73,10 +73,9 @@ export class SigninApiService { return { error }; } - try { // not more than 1 attempt per second and not more than 10 attempts per hour - await this.rateLimiterService.limit({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(request.ip)); - } catch (err) { + const rateLimit = await this.rateLimiterService.limit({ key: 'signin', duration: 60 * 60 * 1000, max: 10, minInterval: 1000 }, getIpHash(request.ip)); + if (rateLimit != null) { reply.code(429); return { error: { From d8941558c33b62dc99f23f19588269cb4eb7c61d Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sat, 22 Jun 2024 13:40:23 +0900 Subject: [PATCH 11/12] =?UTF-8?q?fix:=20=E3=83=AC=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=83=9F=E3=83=83=E3=83=88=E3=81=AEfactor=E3=81=8C?= =?UTF-8?q?=E4=BA=8C=E5=9B=9E=E9=81=A9=E7=94=A8=E3=81=95=E3=82=8C=E3=81=A6?= =?UTF-8?q?=E4=BA=8C=E4=B9=97=E3=81=AE=E5=8A=B9=E6=9E=9C=E3=81=8C=E3=81=82?= =?UTF-8?q?=E3=82=8B=E5=95=8F=E9=A1=8C=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + packages/backend/src/server/api/RateLimiterService.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab9f5f8000..8c0a82eea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Fix: アンテナ・クリップ・リスト・ウェブフックがロールポリシーの上限より一つ多く作れてしまうのを修正 (#14036) - Fix: notRespondingSinceが実装される前に不通になったインスタンスが自動的に配信停止にならない (#14059) - Fix: FTT有効時、タイムライン用エンドポイントで`sinceId`にキャッシュ内最古のものより古いものを指定した場合に正しく結果が返ってこない問題を修正 +- Fix: レートリミットのfactorが二回適用されて二乗の効果がある問題を修正 (#13997) ## 2024.5.0 diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 9b1cef8155..54fc8b3b66 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -77,7 +77,7 @@ export class RateLimiterService { if (limitation.duration != null && limitation.max != null) { const info = await this.checkLimiter({ id: `${actor}:${limitation.key}`, - duration: limitation.duration * factor, + duration: limitation.duration, max: limitation.max / factor, db: this.redisClient, }); From 31daf10f87b44ebaf6ad5a8548f8b8cee6a0cfea Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Sat, 22 Jun 2024 14:32:39 +0900 Subject: [PATCH 12/12] fix lint error --- packages/backend/src/server/api/RateLimiterService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/server/api/RateLimiterService.ts b/packages/backend/src/server/api/RateLimiterService.ts index 54fc8b3b66..58fd6c7d8b 100644 --- a/packages/backend/src/server/api/RateLimiterService.ts +++ b/packages/backend/src/server/api/RateLimiterService.ts @@ -90,6 +90,6 @@ export class RateLimiterService { } } - return null + return null; } }