'use strict'; const RATE_LIMIT_ENDPOINTS_GROUPS = { ANONYMOUS: 'anonymous', STATIC: 'static', STATIC_NAMED: 'static_named', DATAVIEW: 'dataview', DATAVIEW_SEARCH: 'dataview_search', ANALYSIS: 'analysis', ANALYSIS_CATALOG: 'analysis_catalog', 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' }; function rateLimit(userLimitsBackend, endpointGroup = null) { if (!isRateLimitEnabled(endpointGroup)) { return function rateLimitDisabledMiddleware(req, res, next) { next(); }; } return function rateLimitMiddleware(req, res, next) { userLimitsBackend.getRateLimit(res.locals.user, endpointGroup, function (err, userRateLimit) { if (err) { return next(err); } if (!userRateLimit) { return next(); } const [isBlocked, limit, remaining, retry, reset] = userRateLimit; res.set({ 'Carto-Rate-Limit-Limit': limit, 'Carto-Rate-Limit-Remaining': remaining, 'Carto-Rate-Limit-Reset': reset }); if (isBlocked) { // retry is floor rounded in seconds by redis-cell res.set('Retry-After', retry + 1); let rateLimitError = new Error( 'You are over platform\'s limits. Please contact us to know more details' ); rateLimitError.http_status = 429; rateLimitError.type = 'limit'; rateLimitError.subtype = 'rate-limit'; return next(rateLimitError); } return next(); }); }; } function isRateLimitEnabled(endpointGroup) { return global.environment.enabledFeatures.rateLimitsEnabled && endpointGroup && global.environment.enabledFeatures.rateLimitsByEndpoint[endpointGroup]; } module.exports = rateLimit; module.exports.RATE_LIMIT_ENDPOINTS_GROUPS = RATE_LIMIT_ENDPOINTS_GROUPS;