index.js 2.32 KB
'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, 'pc.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();
    }
};