• rate-limiter.js
  • const { RateLimiter } = require("limiter");
    const { log } = require("../src/util");
    
    class KumaRateLimiter {
        /**
         * @param {object} config Rate limiter configuration object
         */
        constructor(config) {
            this.errorMessage = config.errorMessage;
            this.rateLimiter = new RateLimiter(config);
        }
    
        /**
         * Callback for pass
         * @callback passCB
         * @param {object} err Too many requests
         */
    
        /**
         * Should the request be passed through
         * @param {passCB} callback Callback function to call with decision
         * @param {number} num Number of tokens to remove
         * @returns {Promise<boolean>} Should the request be allowed?
         */
        async pass(callback, num = 1) {
            const remainingRequests = await this.removeTokens(num);
            log.info("rate-limit", "remaining requests: " + remainingRequests);
            if (remainingRequests < 0) {
                if (callback) {
                    callback({
                        ok: false,
                        msg: this.errorMessage,
                    });
                }
                return false;
            }
            return true;
        }
    
        /**
         * Remove a given number of tokens
         * @param {number} num Number of tokens to remove
         * @returns {Promise<number>} Number of remaining tokens
         */
        async removeTokens(num = 1) {
            return await this.rateLimiter.removeTokens(num);
        }
    }
    
    const loginRateLimiter = new KumaRateLimiter({
        tokensPerInterval: 20,
        interval: "minute",
        fireImmediately: true,
        errorMessage: "Too frequently, try again later."
    });
    
    const apiRateLimiter = new KumaRateLimiter({
        tokensPerInterval: 60,
        interval: "minute",
        fireImmediately: true,
        errorMessage: "Too frequently, try again later."
    });
    
    const twoFaRateLimiter = new KumaRateLimiter({
        tokensPerInterval: 30,
        interval: "minute",
        fireImmediately: true,
        errorMessage: "Too frequently, try again later."
    });
    
    module.exports = {
        loginRateLimiter,
        apiRateLimiter,
        twoFaRateLimiter,
    };