nest-ratelimiter
Version:
Distributed consistent flexible NestJS rate limiter based on Redis
106 lines • 4.66 kB
JavaScript
;
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