Software: Apache/2.4.41 (Ubuntu). PHP/8.0.30 uname -a: Linux apirnd 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 uid=33(www-data) gid=33(www-data) groups=33(www-data) Safe-mode: OFF (not secure) /var/www/html/wincloud_gateway/node_modules/koa2-ratelimit/src/ drwxr-xr-x | |
| Viewing file: Select action/file-type: const Store = require('./Store.js');
const MemoryStore = require('./MemoryStore.js');
/* eslint-disable no-var */
var defaultOptions = {
// window, delay, and max apply per-key unless global is set to true
interval: { min: 1 }, // milliseconds - how long to keep records of requests in memory
delayAfter: 0, // how many requests to allow through before starting to delay responses
timeWait: { sec: 1 }, // milliseconds - base delay applied to the response - multiplied by number of recent hits for the same key.
max: 5, // max number of recent connections during `window` milliseconds before sending a 429 response
message: 'Too many requests, please try again later.',
statusCode: 429, // 429 status = Too Many Requests (RFC 6585)
headers: true, // Send custom rate limit header with limit and remaining
skipFailedRequests: false, // Do not count failed requests (status >= 400)
prefixKey: 'global', // the prefixKey to get to remove all key
store: new MemoryStore(),
// redefin fonction
keyGenerator: undefined,
skip: undefined,
getUserId: undefined,
handler: undefined,
onLimitReached: undefined,
weight: undefined,
whitelist: []
};
const TimeKeys = ['ms', 'sec', 'min', 'hour', 'day', 'week', 'month', 'year'];
const Times = {
ms: 1,
sec: 1000,
min: 60000,
hour: 3600000,
day: 86400000,
week: 604800000,
month: 2628000000,
year: 12 * 2628000000,
};
const toFinds = ['id', 'userId', 'user_id', 'idUser', 'id_user'];
class RateLimit {
constructor(options) {
this.options = Object.assign({}, defaultOptions, options);
this.options.interval = RateLimit.timeToMs(this.options.interval);
this.options.timeWait = RateLimit.timeToMs(this.options.timeWait);
// store to use for persisting rate limit data
this.store = this.options.store;
// ensure that the store extends Store class
if (!(this.store instanceof Store)) {
throw new Error('The store is not valid.');
}
}
static timeToMs(time) {
if (typeof time === 'object') {
let timeMs = 0;
for (const key in time) {
if (key) {
if (!TimeKeys.includes(key)) {
throw new Error(`Invalide key ${key}, allow keys: ${TimeKeys.toString()}`);
}
if (time[key] > 0) {
timeMs += time[key] * Times[key];
}
}
}
return timeMs;
}
return time;
}
async keyGenerator(ctx) {
if (this.options.keyGenerator) {
return this.options.keyGenerator(ctx);
}
const userId = await this.getUserId(ctx);
if (userId) {
return `${this.options.prefixKey}|${userId}`;
}
return `${this.options.prefixKey}|${ctx.request.ip}`;
}
async weight(ctx) {
if (this.options.weight) {
return this.options.weight(ctx);
}
return 1;
}
async skip(ctx) { // eslint-disable-line
if (this.options.skip) {
return this.options.skip(ctx);
}
return false;
}
async getUserId(ctx) {
if (this.options.getUserId) {
return this.options.getUserId(ctx);
}
const whereFinds = [ctx.state.user, ctx.user, ctx.state.User, ctx.User, ctx.state, ctx];
for (const whereFind of whereFinds) {
if (whereFind) {
for (const toFind of toFinds) {
if (whereFind[toFind]) {
return whereFind[toFind];
}
}
}
}
return null;
}
async handler(ctx/* , next */) {
if (this.options.handler) {
this.options.handler(ctx);
} else {
ctx.status = this.options.statusCode;
ctx.body = { message: this.options.message };
if (this.options.headers) {
ctx.set('Retry-After', Math.ceil(this.options.interval / 1000));
}
}
}
async onLimitReached(ctx) {
if (this.options.onLimitReached) {
this.options.onLimitReached(ctx);
} else {
this.store.saveAbuse(Object.assign({}, this.options, {
key: await this.keyGenerator(ctx),
ip: ctx.request.ip,
user_id: await this.getUserId(ctx),
}));
}
}
get middleware() {
return this._rateLimit.bind(this);
}
async _rateLimit(ctx, next) {
const skip = await this.skip(ctx);
if (skip) {
return next();
}
const key = await this.keyGenerator(ctx);
if (this._isWhitelisted(key)) {
return next();
}
const weight = await this.weight(ctx);
const { counter, dateEnd } = await this.store.incr(key, this.options, weight);
const reset = new Date(dateEnd).getTime();
ctx.state.rateLimit = {
limit: this.options.max,
current: counter,
remaining: Math.max(this.options.max - counter, 0),
reset: Math.ceil(reset / 1000),
};
if (this.options.headers) {
ctx.set('X-RateLimit-Limit', this.options.max);
ctx.set('X-RateLimit-Remaining', ctx.state.rateLimit.remaining);
ctx.set('X-RateLimit-Reset', ctx.state.rateLimit.reset);
}
if (this.options.max && counter > this.options.max) {
await this.onLimitReached(ctx);
return this.handler(ctx, next);
}
if (this.options.skipFailedRequests) {
ctx.res.on('finish', () => {
if (ctx.status >= 400) {
this.store.decrement(key, this.options, weight);
}
});
}
if (this.options.delayAfter && this.options.timeWait && counter > this.options.delayAfter) {
const delay = (counter - this.options.delayAfter) * this.options.timeWait;
await this.wait(delay);
return next();
}
return next();
}
_isWhitelisted(key) {
const arr = key.split('::');
if (arr.length > 0) {
const ip = arr[1];
const { whitelist } = this.options;
return whitelist.includes(ip);
}
return false;
}
async wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
module.exports = {
RateLimit,
middleware(options = {}) {
return new RateLimit(options).middleware;
},
defaultOptions(options = {}) {
defaultOptions = Object.assign(defaultOptions, options);
},
};
|
:: Command execute :: | |
--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0046 ]-- |