index2.js 2.13 KB
'use strict';

const _ = require('lodash');
const logger = global.yoho.logger;
const ip = require('./rules/ip-list2');
const userAgent = require('./rules/useragent2');
const pathWhiteList = require('./rules/path-white-list');

// const asynchronous = require('./rules/asynchronous');
// const fakerLimiter = require('./rules/faker-limit');
const captchaPolicy = require('./policies/captcha');

// const reporterPolicy = require('./policies/reporter');

const _excluded = (req) => {
    return Boolean(
        _.includes(pathWhiteList(), req.path)
    );
};

const limiter = (rule, policy, context) => {
    return rule(context, policy);
};

module.exports = (req, res, next) => {
    const remoteIp = req.yoho.clientIp || '';
    const enabled = !_.get(req.app.locals, 'pc.sys.noLimiter');
    let excluded = _excluded(req);

    // 开关为关或者未获取到remoteIp,放行
    if (!enabled || !remoteIp || excluded) {
        logger.debug(`request remote ip: ${remoteIp}; enabled: ${enabled}`);
        return next();
    }

    (async function() {
        const context = {
            req: req,
            res: res,
            next: next,
            remoteIp: remoteIp
        };

        let results = await Promise.all([
            limiter(userAgent, captchaPolicy, context),
            limiter(ip, captchaPolicy, context),

            // limiter(asynchronous, captchaPolicy, context)
            // limiter(fakerLimiter, reporterPolicy, context)
        ]);

        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 (typeof result === 'function') {
                allPass = false;
                policy = result;
            }
        });

        if (exclusion) {
            return next();
        } else if (!allPass && policy) {
            policy(req, res, next);
        } else {
            return next();
        }
    }()).catch((err) => {
        logger.error(err);
        return next();
    });
};