2018-02-13 00:19:08 +08:00
|
|
|
'use strict';
|
|
|
|
|
2018-02-20 00:01:41 +08:00
|
|
|
const RATE_LIMIT_ENDPOINTS_GROUPS = {
|
2018-02-28 00:57:25 +08:00
|
|
|
ANONYMOUS: 'anonymous',
|
|
|
|
STATIC: 'static',
|
|
|
|
STATIC_NAMED: 'static_named',
|
|
|
|
DATAVIEW: 'dataview',
|
|
|
|
DATAVIEW_SEARCH: 'dataview_search',
|
|
|
|
ANALYSIS: 'analysis',
|
2018-03-15 00:46:19 +08:00
|
|
|
ANALYSIS_CATALOG: 'analysis_catalog',
|
2018-02-28 00:57:25 +08:00
|
|
|
TILE: 'tile',
|
|
|
|
ATTRIBUTES: 'attributes',
|
|
|
|
NAMED_LIST: 'named_list',
|
|
|
|
NAMED_CREATE: 'named_create',
|
|
|
|
NAMED_GET: 'named_get',
|
|
|
|
NAMED: 'named',
|
|
|
|
NAMED_UPDATE: 'named_update',
|
|
|
|
NAMED_DELETE: 'named_delete',
|
|
|
|
NAMED_TILES: 'named_tiles'
|
2018-02-13 00:19:08 +08:00
|
|
|
};
|
|
|
|
|
2018-04-10 16:16:07 +08:00
|
|
|
function rateLimit(userLimitsBackend, endpointGroup = null) {
|
2018-03-02 22:48:31 +08:00
|
|
|
if (!isRateLimitEnabled(endpointGroup)) {
|
2018-03-02 22:33:50 +08:00
|
|
|
return function rateLimitDisabledMiddleware(req, res, next) { next(); };
|
|
|
|
}
|
2018-02-26 18:20:31 +08:00
|
|
|
|
2018-03-02 22:33:50 +08:00
|
|
|
return function rateLimitMiddleware(req, res, next) {
|
2018-04-10 16:16:07 +08:00
|
|
|
userLimitsBackend.getRateLimit(res.locals.user, endpointGroup, function (err, userRateLimit) {
|
2018-02-13 00:19:08 +08:00
|
|
|
if (err) {
|
|
|
|
return next(err);
|
|
|
|
}
|
2018-03-02 22:33:50 +08:00
|
|
|
|
2018-03-02 22:35:38 +08:00
|
|
|
if (!userRateLimit) {
|
2018-02-15 01:39:57 +08:00
|
|
|
return next();
|
|
|
|
}
|
2018-03-02 22:33:50 +08:00
|
|
|
|
2018-03-02 22:35:38 +08:00
|
|
|
const [isBlocked, limit, remaining, retry, reset] = userRateLimit;
|
2018-03-02 22:33:50 +08:00
|
|
|
|
2018-02-13 00:19:08 +08:00
|
|
|
res.set({
|
2018-03-14 19:09:20 +08:00
|
|
|
'Carto-Rate-Limit-Limit': limit,
|
|
|
|
'Carto-Rate-Limit-Remaining': remaining,
|
|
|
|
'Carto-Rate-Limit-Reset': reset
|
2018-02-13 00:19:08 +08:00
|
|
|
});
|
2018-03-02 22:33:50 +08:00
|
|
|
|
2018-02-28 00:36:03 +08:00
|
|
|
if (isBlocked) {
|
2018-03-23 17:23:57 +08:00
|
|
|
// retry is floor rounded in seconds by redis-cell
|
|
|
|
res.set('Retry-After', retry + 1);
|
|
|
|
|
2018-03-23 18:42:53 +08:00
|
|
|
let rateLimitError = new Error(
|
|
|
|
'You are over platform\'s limits. Please contact us to know more details'
|
|
|
|
);
|
2018-03-01 22:50:20 +08:00
|
|
|
rateLimitError.http_status = 429;
|
2018-03-15 00:27:59 +08:00
|
|
|
rateLimitError.type = 'limit';
|
|
|
|
rateLimitError.subtype = 'rate-limit';
|
2018-03-01 22:50:20 +08:00
|
|
|
return next(rateLimitError);
|
2018-02-13 00:19:08 +08:00
|
|
|
}
|
2018-03-02 22:33:50 +08:00
|
|
|
|
2018-02-15 01:39:57 +08:00
|
|
|
return next();
|
2018-02-13 00:19:08 +08:00
|
|
|
});
|
|
|
|
};
|
2018-02-20 00:08:26 +08:00
|
|
|
}
|
2018-02-13 00:19:08 +08:00
|
|
|
|
|
|
|
|
2018-03-02 22:33:50 +08:00
|
|
|
function isRateLimitEnabled(endpointGroup) {
|
|
|
|
return global.environment.enabledFeatures.rateLimitsEnabled &&
|
|
|
|
endpointGroup &&
|
|
|
|
global.environment.enabledFeatures.rateLimitsByEndpoint[endpointGroup];
|
2018-02-21 01:18:15 +08:00
|
|
|
}
|
|
|
|
|
2018-03-02 22:35:38 +08:00
|
|
|
module.exports = rateLimit;
|
2018-02-20 00:01:41 +08:00
|
|
|
module.exports.RATE_LIMIT_ENDPOINTS_GROUPS = RATE_LIMIT_ENDPOINTS_GROUPS;
|