UNPKG

nest-ratelimiter

Version:

Distributed consistent flexible NestJS rate limiter based on Redis

106 lines 4.66 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.rateLimiterGuardProvider = exports.RateLimiterGuard = void 0; const common_1 = require("@nestjs/common"); const core_1 = require("@nestjs/core"); const asserter_interface_1 = require("./asserter.interface"); const params_1 = require("./params"); const too_many_requests_exception_1 = require("./too-many-requests.exception"); const set_headers_fn_1 = require("./utils/set-headers.fn"); let RateLimiterGuard = class RateLimiterGuard { defaultParams; asserter; reflector; constructor(defaultParams, asserter, reflector) { this.defaultParams = defaultParams; this.asserter = asserter; this.reflector = reflector; } async canActivate(context) { const paramsList = this.reflector.getAllAndOverride(params_1.DECORATOR_PARAMS_TOKEN, [context.getHandler(), context.getClass()]); if (isTurnedOff(paramsList)) return true; const response = context.switchToHttp().getResponse(); // in case of `fastify` get native response via `res` property // https://www.fastify.io/docs/latest/Reply/#introduction // in case of `express` response inherit native response const nativeResponse = response.raw || response; for (const param of paramsList || [{}]) { await this.checkSingleParam(param, context, nativeResponse); } return true; } async checkSingleParam(params, context, response) { const id = await this.getId(params, context); if (!id) return; const { max, duration, createErrorBody } = params; try { const limit = await this.asserter.assert({ id, max, duration, createErrorBody, }); (0, set_headers_fn_1.setHeaders)(response, limit); } catch (error) { /* istanbul ignore else */ if (error instanceof asserter_interface_1.RateLimiterError) { response.setHeader('Retry-After', (error.limiterInfo.reset - Date.now() / 1000) | 0); (0, set_headers_fn_1.setHeaders)(response, error.limiterInfo); throw new too_many_requests_exception_1.TooManyRequestsException(JSON.parse(error.message)); } else throw error; } } async getId(params, context) { let id = undefined; try { if ('id' in params) { id = params.id; } else if ('getId' in params) { id = await params.getId(context); } else if ('id' in this.defaultParams) { id = this.defaultParams.id; } else if ('getId' in this.defaultParams && this.defaultParams.getId) { id = await this.defaultParams.getId(context); } } catch (error) { throw new common_1.InternalServerErrorException('Can not get id for rate limiter', String(error)); } return id; } }; exports.RateLimiterGuard = RateLimiterGuard; exports.RateLimiterGuard = RateLimiterGuard = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(params_1.MODULE_PARAMS_TOKEN)), __param(1, (0, common_1.Inject)(asserter_interface_1.RATE_LIMITER_ASSERTER_TOKEN)), __metadata("design:paramtypes", [Object, Object, core_1.Reflector]) ], RateLimiterGuard); function isTurnedOff(params) { return !!params && params.length === 1 && params[0] === false; } exports.rateLimiterGuardProvider = { provide: core_1.APP_GUARD, useClass: RateLimiterGuard, }; //# sourceMappingURL=guard.js.map