| 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 }; | |