Authored by 姜枫

copy from pc limiter

'use strict';
const limiter = require('../middleware/limiter/index');
module.exports = (req, res, next) => {
return limiter(req, res, next);
};
... ...
'use strict';
const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list');
const userAgent = require('./rules/useragent');
const qpsLimiter = require('./rules/qps-limit');
const fakerLimiter = require('./rules/faker-limit');
const captchaPolicy = require('./policies/captcha');
const reporterPolicy = require('./policies/reporter');
const IP_WHITE_LIST = [
// '106.38.38.146',
// '218.94.75.58'
];
const limiter = (rule, policy, context) => {
return rule(context, policy);
};
module.exports = (req, res, next) => {
let remoteIp = req.get('X-Forwarded-For') || req.connection.remoteAddress;
logger.debug('request remote ip: ', remoteIp);
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
remoteIp = arr[0];
}
const excluded = _.includes(IP_WHITE_LIST, remoteIp);
const enabled = !_.get(req.app.locals, 'wap.sys.noLimiter');
// 判断获取remoteIp成功,并且开关未关闭
if (enabled && remoteIp && !excluded) {
const context = {
req: req,
res: res,
next: next,
remoteIp: remoteIp
};
Promise.all([
limiter(userAgent, captchaPolicy, context),
limiter(ip, captchaPolicy, context),
limiter(qpsLimiter, captchaPolicy, context),
//limiter(fakerLimiter, reporterPolicy, context)
]).then((results) => {
let allPass = true, exclusion = false, policy = null;
logger.debug('limiter result: ' + JSON.stringify(results));
_.forEach(results, (result) => {
if (typeof result === 'object' && !exclusion) {
exclusion = result.exclusion;
}
if (!excluded && typeof result === 'function') {
allPass = false;
}
if (typeof result === 'function') {
policy = result;
}
});
if (exclusion) {
return next();
} else if (!allPass && policy) {
policy(req, res, next);
} else {
return next();
}
}).catch((err) => {
logger.error(err);
return next();
});
} else {
return next();
}
};
... ...
'use strict';
const helpers = global.yoho.helpers;
const _ = require('lodash');
const WHITE_LIST = [
'/3party/check',
'/passport/imagesNode',
'/passport/cert/headerTip'
];
module.exports = (req, res, next) => {
let refer = req.method === 'GET' ? req.get('Referer') : '';
let limitAPI = helpers.urlFormat('/3party/check', {refer: refer});
let limitPage = helpers.urlFormat('/3party/check', {refer: req.protocol + '://' + req.get('host') + req.originalUrl});
if (_.indexOf(WHITE_LIST, req.path) >= 0) {
return next();
}
if (req.xhr) {
return res.json({
code: 400,
data: {refer: limitAPI}
});
}
return res.redirect(limitPage);
};
... ...
'use strict';
module.exports = (req, res, next) => {
return next();
};
... ...
'use strict';
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const ONE_DAY = 60 * 60 * 24;
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const key = `pc:limiter:faker:${limiter.remoteIp}`;
if (req.header('X-Requested-With') === 'XMLHttpRequest') {
cache.decrAsync(key, 1);
}
res.on('render', function() {
cache.incrAsync(key, 1);
});
return cache.getAsync(key).then((result) => {
if (result) {
if (result > 100) {
return Promise.resolve(policy);//policy(req, res, next);
} else {
return Promise.resolve(true);
}
} else {
cache.setAsync(key, 1, ONE_DAY); // 设置key,1m失效
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const cache = global.yoho.cache.master;
const _ = require('lodash');
module.exports = (limiter) => {
const key = `pc:limiter:${limiter.remoteIp}`;
return cache.getAsync(key).then((result) => {
if (result && _.isNumber(result)) {
return Promise.resolve({
exclusion: result === -1
});
} else {
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const config = global.yoho.config;
const ONE_DAY = 60 * 60 * 24;
const MAX_QPS = config.maxQps;
const _ = require('lodash');
const PAGES = {
'/product/\\/pro_([\\d]+)_([\\d]+)\\/(.*)/': 5,
'/product/list/index': 5
};
function urlJoin(a, b) {
if (_.endsWith(a, '/') && _.startsWith(b, '/')) {
return a + b.substring(1, b.length);
} else if (!_.endsWith(a, '/') && !_.startsWith(b, '/')) {
return a + '/' + b;
} else {
return a + b;
}
}
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const key = `pc:limiter:${limiter.remoteIp}`;
res.on('render', function() {
let route = req.route ? req.route.path : '';
let appPath = req.app.mountpath;
if (_.isArray(route) && route.length > 0) {
route = route[0];
}
let pageKey = urlJoin(appPath, route.toString()); // route may be a regexp
let pageIncr = PAGES[pageKey] || 0;
if (/^\/p([\d]+)/.test(req.path)) {
pageIncr = 5;
}
if (pageIncr > 0) {
cache.incrAsync(key, pageIncr);
}
});
return cache.getAsync(key).then((result) => {
logger.debug('qps limiter: ' + key + '@' + result + ' max: ' + MAX_QPS);
if (result && _.isNumber(result)) {
if (result === -1) {
return Promise.resolve(true);
}
if (result > MAX_QPS) { // 判断 qps
cache.touch(key, ONE_DAY);
logger.debug('req limit', key);
return Promise.resolve(policy);
} else {
cache.incrAsync(key, 1); // qps + 1
return Promise.resolve(true);
}
} else {
cache.setAsync(key, 1, 60); // 设置key,1m失效
return Promise.resolve(true);
}
});
};
... ...
'use strict';
const cache = global.yoho.cache.master;
const _ = require('lodash');
const logger = global.yoho.logger;
module.exports = (limiter, policy) => {
const req = limiter.req,
res = limiter.res,
next = limiter.next;
const blackKey = 'pc:limiter:ua:black',
whiteKey = 'pc:limiter:ua:white';
const ua = limiter.req.header('User-Agent');
return Promise.all([
cache.getAsync(blackKey),
cache.getAsync(whiteKey)
]).then((args) => {
const blacklist = args[0] || [], whitelist = args[1] || [];
if (blacklist.length === 0 && whitelist.length === 0) {
return Promise.resolve(true);
}
const test = (list) => {
let result = false;
_.each(list, (item) => {
let regexp;
try {
regexp = new RegExp(item);
} catch (e) {
logger.error(e);
}
if (regexp.test(ua)) {
result = true;
}
});
return result;
};
if (test(blacklist)) {
return Promise.resolve(policy);
} else if (test(whitelist)) {
return Promise.resolve({
exclusion: true
});
} else {
return Promise.resolve(true);
}
});
};
... ...