UNPKG

dino-express

Version:

DinO enabled REST framework based on express

82 lines 2.98 kB
"use strict"; // Copyright 2018 Quirino Brizi [quirino.brizi@gmail.com] // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. Object.defineProperty(exports, "__esModule", { value: true }); exports.QuotaPolicy = void 0; const AbstractPolicy_1 = require("./AbstractPolicy"); const dino_core_1 = require("dino-core"); class QuotaPolicy extends AbstractPolicy_1.AbstractPolicy { buckets; configuration; cleanUpJob; constructor() { super(); this.buckets = new Map(); } preDestroy() { clearInterval(this.cleanUpJob); } /** * Apply the quota policy. The quota is calculated based on **window** and **allow** configuration * parameters and based on the IP address of the remote client. * * @param {Any} req the client request * @returns true if the number of requests on the defined window is less than the allow configuration * parameter for the specific client, false otherwise * * @protected * @implements AbstractPolicy#apply(req) */ apply(req) { const now = Date.now(); const key = (req.headers['x-forwarded-for'] ?? req.socket.remoteAddress); let bucket = this.buckets.get(key); if (bucket === undefined) { bucket = { count: 0, expires: now + this.configuration.window }; this.buckets.set(key, bucket); } if (now > bucket.expires) { bucket.count = 0; bucket.expires = now + this.configuration.window; } bucket.count += 1; dino_core_1.Logger.debug('Bucket', bucket); return bucket.count <= this.configuration.allow; } configure(configuration) { this.configuration = configuration; this.cleanUpJob = setInterval(this.removeExpired.bind(this), configuration.resetInterval ?? 30000); } onDeny(res) { res.status(429); res.body = { message: 'Too Many Requests' }; } /** * Remove expired buckets * * @private */ removeExpired() { dino_core_1.Logger.debug('remove expires buckets'); const now = Date.now(); for (const key of this.buckets.keys()) { const bucket = this.buckets.get(key); if (bucket !== undefined && now > bucket.expires) { this.buckets.delete(key); } } } } exports.QuotaPolicy = QuotaPolicy; //# sourceMappingURL=QuotaPolicy.js.map