| const rateLimit = require('express-rate-limit'); |
| const { limiterCache } = require('@librechat/api'); |
| const { ViolationTypes } = require('librechat-data-provider'); |
| const logViolation = require('~/cache/logViolation'); |
|
|
| const getEnvironmentVariables = () => { |
| const FORK_IP_MAX = parseInt(process.env.FORK_IP_MAX) || 30; |
| const FORK_IP_WINDOW = parseInt(process.env.FORK_IP_WINDOW) || 1; |
| const FORK_USER_MAX = parseInt(process.env.FORK_USER_MAX) || 7; |
| const FORK_USER_WINDOW = parseInt(process.env.FORK_USER_WINDOW) || 1; |
| const FORK_VIOLATION_SCORE = process.env.FORK_VIOLATION_SCORE; |
|
|
| const forkIpWindowMs = FORK_IP_WINDOW * 60 * 1000; |
| const forkIpMax = FORK_IP_MAX; |
| const forkIpWindowInMinutes = forkIpWindowMs / 60000; |
|
|
| const forkUserWindowMs = FORK_USER_WINDOW * 60 * 1000; |
| const forkUserMax = FORK_USER_MAX; |
| const forkUserWindowInMinutes = forkUserWindowMs / 60000; |
|
|
| return { |
| forkIpWindowMs, |
| forkIpMax, |
| forkIpWindowInMinutes, |
| forkUserWindowMs, |
| forkUserMax, |
| forkUserWindowInMinutes, |
| forkViolationScore: FORK_VIOLATION_SCORE, |
| }; |
| }; |
|
|
| const createForkHandler = (ip = true) => { |
| const { |
| forkIpMax, |
| forkUserMax, |
| forkViolationScore, |
| forkIpWindowInMinutes, |
| forkUserWindowInMinutes, |
| } = getEnvironmentVariables(); |
|
|
| return async (req, res) => { |
| const type = ViolationTypes.FILE_UPLOAD_LIMIT; |
| const errorMessage = { |
| type, |
| max: ip ? forkIpMax : forkUserMax, |
| limiter: ip ? 'ip' : 'user', |
| windowInMinutes: ip ? forkIpWindowInMinutes : forkUserWindowInMinutes, |
| }; |
|
|
| await logViolation(req, res, type, errorMessage, forkViolationScore); |
| res.status(429).json({ message: 'Too many conversation fork requests. Try again later' }); |
| }; |
| }; |
|
|
| const createForkLimiters = () => { |
| const { forkIpWindowMs, forkIpMax, forkUserWindowMs, forkUserMax } = getEnvironmentVariables(); |
|
|
| const ipLimiterOptions = { |
| windowMs: forkIpWindowMs, |
| max: forkIpMax, |
| handler: createForkHandler(), |
| store: limiterCache('fork_ip_limiter'), |
| }; |
| const userLimiterOptions = { |
| windowMs: forkUserWindowMs, |
| max: forkUserMax, |
| handler: createForkHandler(false), |
| keyGenerator: function (req) { |
| return req.user?.id; |
| }, |
| store: limiterCache('fork_user_limiter'), |
| }; |
|
|
| const forkIpLimiter = rateLimit(ipLimiterOptions); |
| const forkUserLimiter = rateLimit(userLimiterOptions); |
| return { forkIpLimiter, forkUserLimiter }; |
| }; |
|
|
| module.exports = { createForkLimiters }; |
|
|