AdamPflug / express-brute

Brute-force protection middleware for express routes by rate limiting incoming requests
MIT License
564 stars 91 forks source link

Not working with >=redis@4.1.0 redis #97

Open Code-Crash opened 2 years ago

Code-Crash commented 2 years ago

Express-Brute: 1.0.1 Node: 16.13.1 Redis: 4.3.0

With new Redis, there is no support for the callback anymore, please see the redis npm

I will also create the issue in express-brute-redis

Code-Crash commented 2 years ago

For Fix, we can use this code for a Redis store:

Please customize it as per your need.

const AbstractClientStore = require('express-brute/lib/AbstractClientStore');
const Redis = require('redis');
const _ = require('underscore');
const { logger } = require('../config/logger');

const defaults = {
    prefix: '',
    port: 6379,
    host: '127.0.0.1'
};

class RedisStore {
    constructor(options) {
        AbstractClientStore.apply(this, arguments);
        this.options = _.extend({}, defaults, options);
        this.redisOptions = _(this.options).clone();
        this.Redis = Redis;
        delete this.redisOptions.prefix;
        delete this.redisOptions.client;
        delete this.redisOptions.port;
        delete this.redisOptions.host;

        if (this.options.client) {
            this.client = this.options.client;
        } else {
            this.client = RedisStore.Redis.createClient(
                this.options.port,
                this.options.host,
                this.options.redisOptions
            );
            this.client.connect();
        }
    }

    async set(key, value, lifetime, callback) {
        try {
            lifetime = parseInt(lifetime, 10) || 0;
            const redisKey = this.options.prefix + key;
            const multi = await this.client.multi();
            multi.set(redisKey, JSON.stringify(value));
            if (lifetime > 0) {
                multi.expire(redisKey, lifetime);
            }
            const data = multi.exec();
            typeof callback == 'function' && callback(null, data);
        } catch (error) {
            logger.error(error);
            typeof callback == 'function' && callback(error, null);
        };
    }

    async get(key, callback) {
        console.log('Called: key:', key, 'callback:', callback);
        try {
            let data = await this.client.get(this.options.prefix + key)
            if (data) {
                data = JSON.parse(data);
                data.lastRequest = new Date(data.lastRequest);
                data.firstRequest = new Date(data.firstRequest);
            }
            typeof callback == 'function' && callback(null, data);
        } catch (error) {
            logger.error(error);
            typeof callback == 'function' && callback(error, null);
        }
    }

    async reset(key, callback) {
        try {
            let data = await this.client.del(this.options.prefix + key);
            typeof callback == 'function' && callback(null, data);
        } catch (error) {
            logger.error(error);
            typeof callback == 'function' && callback(error, null);
        }
    };
}

module.exports = RedisStore;