init commit

This commit is contained in:
2025-11-07 22:24:40 +01:00
parent a5373286bf
commit 15b8f36d4d
217 changed files with 168229 additions and 0 deletions

View File

@@ -0,0 +1,91 @@
import myError from '../api/myError'
import * as rateLimiteFlexible from 'rate-limiter-flexible'
import * as redis from 'redis'
export const globalRedisClient = redis.createClient({
port: process.env.REDIS_PORT,
host: process.env.REDIS_HOST,
enable_offline_queue: false
})
globalRedisClient.on('connect', function (err) {
console.log('Redis-server is connected')
})
globalRedisClient.on('error', function (err) {
console.log('Error ' + err)
})
const RateLimiterRedis = rateLimiteFlexible.RateLimiterRedis
const maxWrongAttemptsByIPperDay = 100
const maxConsecutiveFailsByUsernameAndIP = 5
const rateLimiterRedis = new RateLimiterRedis({
storeClient: globalRedisClient,
points: maxWrongAttemptsByIPperDay, // Number of points
duration: 1000, // Per second,
blockDuration: 60 * 60 // Per second
})
export const rateLimiterMiddleware = (req, res, next) => {
rateLimiterRedis.consume(req.ip)
.then(() => {
next()
})
.catch(err => {
err.statusCode = 429
err.clientCode = 11
err.clientMessage = 'درخواست بیش از حد انجام داده اید! بعد از یک ساعت دیگر دوباره اقدام بفرمایید!'
err.messageEnglish = 'Too Many Requests'
next(err)
})
}
const limiterSlowBruteByIP = new RateLimiterRedis({
storeClient: globalRedisClient,
keyPrefix: 'login_fail_ip_per_day',
points: maxWrongAttemptsByIPperDay,
duration: 60 * 60 * 24,
blockDuration: 60 * 60 * 24 // Block for 1 day, if 100 wrong attempts per day
})
const limiterConsecutiveFailsByUsernameAndIP = new RateLimiterRedis({
storeClient: globalRedisClient,
keyPrefix: 'login_fail_consecutive_username_and_ip',
points: maxConsecutiveFailsByUsernameAndIP,
duration: 60 * 60, // Store number for 90 days since first fail
blockDuration: 60 * 60 // Block for 1 hour
})
const getUsernameIPkey = (username, ip) => `${username}_${ip}`
export async function preventBruteForce (req, res, next) {
const ipAddr = req.ip
const usernameIPkey = getUsernameIPkey(req.body.email, ipAddr)
const [resUsernameAndIP, resSlowByIP] = await Promise.all([
limiterConsecutiveFailsByUsernameAndIP.get(usernameIPkey),
limiterSlowBruteByIP.get(ipAddr)
])
let retrySecs = 0
// Check if IP or Username + IP is already blocked
if (resSlowByIP !== null && resSlowByIP.consumedPoints > maxWrongAttemptsByIPperDay) {
retrySecs = Math.round(resSlowByIP.msBeforeNext / 1000) || 1
} else if (resUsernameAndIP !== null && resUsernameAndIP.consumedPoints > maxConsecutiveFailsByUsernameAndIP) {
retrySecs = Math.round(resUsernameAndIP.msBeforeNext / 1000) || 1
}
if (retrySecs > 0) {
const error = new myError(`Too many requests for user ${req.body.email} with ip ${ipAddr}`, 1, 429, 'درخواست بیش از حد انجام داده اید! بعد از یک ساعت دیگر دوباره اقدام بفرمایید!', 'خطا رخ داد')
next(error)
} else {
limiterConsecutiveFailsByUsernameAndIP.consume(usernameIPkey)
limiterSlowBruteByIP.consume(ipAddr)
next()
}
}