dino-express
Version:
DinO enabled REST framework based on express
82 lines • 2.98 kB
JavaScript
;
// 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