nestjs-cluster-throttle
Version:
Enterprise-grade rate limiting module for NestJS with Redis support, multiple strategies, and cluster mode
97 lines • 4.82 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.RateLimitGuard = void 0;
const common_1 = require("@nestjs/common");
const core_1 = require("@nestjs/core");
const rate_limit_service_1 = require("../rate-limit.service");
const geo_service_1 = require("../geo/geo.service");
const rate_limit_decorator_1 = require("../decorators/rate-limit.decorator");
const skip_rate_limit_decorator_1 = require("../decorators/skip-rate-limit.decorator");
let RateLimitGuard = class RateLimitGuard {
constructor(reflector, rateLimitService, geoService) {
this.reflector = reflector;
this.rateLimitService = rateLimitService;
this.geoService = geoService;
}
async canActivate(context) {
const request = context.switchToHttp().getRequest();
const response = context.switchToHttp().getResponse();
const skipRateLimit = this.reflector.getAllAndOverride(skip_rate_limit_decorator_1.SKIP_RATE_LIMIT_METADATA, [
context.getHandler(),
context.getClass(),
]);
if (skipRateLimit) {
return true;
}
const options = this.reflector.getAllAndOverride(rate_limit_decorator_1.RATE_LIMIT_METADATA, [
context.getHandler(),
context.getClass(),
]);
if (this.geoService && options?.geoLocation) {
const ip = this.getClientIp(request);
try {
const geoCheck = await this.geoService.isCountryAllowed(ip, options.geoLocation.allowedCountries, options.geoLocation.blockedCountries);
if (!geoCheck.allowed) {
if (options.geoLocation.onGeoBlock) {
options.geoLocation.onGeoBlock(ip, geoCheck.countryCode || 'Unknown', request);
}
throw new common_1.HttpException(options.geoLocation.message ||
`Access denied for country: ${geoCheck.country || geoCheck.countryCode}`, options.geoLocation.statusCode || common_1.HttpStatus.FORBIDDEN);
}
}
catch (error) {
if (error instanceof common_1.HttpException) {
throw error;
}
console.error('Geo-location check failed:', error);
}
}
try {
const result = await this.rateLimitService.checkRateLimit(request, options);
if (!result.allowed) {
response.setHeader('X-RateLimit-Limit', result.limit);
response.setHeader('X-RateLimit-Remaining', result.remaining);
response.setHeader('X-RateLimit-Reset', Math.ceil(result.resetTime.getTime() / 1000));
throw new common_1.HttpException(options?.message || 'Too Many Requests', options?.statusCode || common_1.HttpStatus.TOO_MANY_REQUESTS);
}
response.setHeader('X-RateLimit-Limit', result.limit);
response.setHeader('X-RateLimit-Remaining', result.remaining);
response.setHeader('X-RateLimit-Reset', Math.ceil(result.resetTime.getTime() / 1000));
return true;
}
catch (error) {
if (error instanceof common_1.HttpException) {
throw error;
}
return true;
}
}
getClientIp(request) {
return (request.ip ||
request.connection?.remoteAddress ||
request.socket?.remoteAddress ||
request.info?.remoteAddress ||
'unknown');
}
};
exports.RateLimitGuard = RateLimitGuard;
exports.RateLimitGuard = RateLimitGuard = __decorate([
(0, common_1.Injectable)(),
__param(2, (0, common_1.Optional)()),
__metadata("design:paramtypes", [core_1.Reflector,
rate_limit_service_1.RateLimitService,
geo_service_1.GeoService])
], RateLimitGuard);
//# sourceMappingURL=rate-limit.guard.js.map