mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-21 21:50:49 +02:00
⚖️ feat: Add Violation Scores (#8304)
- Introduced new violation scores for TTS, STT, Fork, Import, and File Upload actions in the .env.example file. - Updated logViolation function to accept a score parameter, allowing for dynamic severity levels based on the action type. - Modified limiters for Fork, Import, Message, STT, TTS, Tool Call, and File Upload to utilize the new violation scores when logging violations.
This commit is contained in:
parent
916cd46221
commit
550610dba9
11 changed files with 61 additions and 14 deletions
|
@ -349,6 +349,11 @@ REGISTRATION_VIOLATION_SCORE=1
|
||||||
CONCURRENT_VIOLATION_SCORE=1
|
CONCURRENT_VIOLATION_SCORE=1
|
||||||
MESSAGE_VIOLATION_SCORE=1
|
MESSAGE_VIOLATION_SCORE=1
|
||||||
NON_BROWSER_VIOLATION_SCORE=20
|
NON_BROWSER_VIOLATION_SCORE=20
|
||||||
|
TTS_VIOLATION_SCORE=0
|
||||||
|
STT_VIOLATION_SCORE=0
|
||||||
|
FORK_VIOLATION_SCORE=0
|
||||||
|
IMPORT_VIOLATION_SCORE=0
|
||||||
|
FILE_UPLOAD_VIOLATION_SCORE=0
|
||||||
|
|
||||||
LOGIN_MAX=7
|
LOGIN_MAX=7
|
||||||
LOGIN_WINDOW=5
|
LOGIN_WINDOW=5
|
||||||
|
|
2
api/cache/logViolation.js
vendored
2
api/cache/logViolation.js
vendored
|
@ -9,7 +9,7 @@ const banViolation = require('./banViolation');
|
||||||
* @param {Object} res - Express response object.
|
* @param {Object} res - Express response object.
|
||||||
* @param {string} type - The type of violation.
|
* @param {string} type - The type of violation.
|
||||||
* @param {Object} errorMessage - The error message to log.
|
* @param {Object} errorMessage - The error message to log.
|
||||||
* @param {number} [score=1] - The severity of the violation. Defaults to 1
|
* @param {number | string} [score=1] - The severity of the violation. Defaults to 1
|
||||||
*/
|
*/
|
||||||
const logViolation = async (req, res, type, errorMessage, score = 1) => {
|
const logViolation = async (req, res, type, errorMessage, score = 1) => {
|
||||||
const userId = req.user?.id ?? req.user?._id;
|
const userId = req.user?.id ?? req.user?._id;
|
||||||
|
|
|
@ -11,6 +11,7 @@ const getEnvironmentVariables = () => {
|
||||||
const FORK_IP_WINDOW = parseInt(process.env.FORK_IP_WINDOW) || 1;
|
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_MAX = parseInt(process.env.FORK_USER_MAX) || 7;
|
||||||
const FORK_USER_WINDOW = parseInt(process.env.FORK_USER_WINDOW) || 1;
|
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 forkIpWindowMs = FORK_IP_WINDOW * 60 * 1000;
|
||||||
const forkIpMax = FORK_IP_MAX;
|
const forkIpMax = FORK_IP_MAX;
|
||||||
|
@ -27,12 +28,18 @@ const getEnvironmentVariables = () => {
|
||||||
forkUserWindowMs,
|
forkUserWindowMs,
|
||||||
forkUserMax,
|
forkUserMax,
|
||||||
forkUserWindowInMinutes,
|
forkUserWindowInMinutes,
|
||||||
|
forkViolationScore: FORK_VIOLATION_SCORE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createForkHandler = (ip = true) => {
|
const createForkHandler = (ip = true) => {
|
||||||
const { forkIpMax, forkIpWindowInMinutes, forkUserMax, forkUserWindowInMinutes } =
|
const {
|
||||||
getEnvironmentVariables();
|
forkIpMax,
|
||||||
|
forkUserMax,
|
||||||
|
forkViolationScore,
|
||||||
|
forkIpWindowInMinutes,
|
||||||
|
forkUserWindowInMinutes,
|
||||||
|
} = getEnvironmentVariables();
|
||||||
|
|
||||||
return async (req, res) => {
|
return async (req, res) => {
|
||||||
const type = ViolationTypes.FILE_UPLOAD_LIMIT;
|
const type = ViolationTypes.FILE_UPLOAD_LIMIT;
|
||||||
|
@ -43,7 +50,7 @@ const createForkHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? forkIpWindowInMinutes : forkUserWindowInMinutes,
|
windowInMinutes: ip ? forkIpWindowInMinutes : forkUserWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, forkViolationScore);
|
||||||
res.status(429).json({ message: 'Too many conversation fork requests. Try again later' });
|
res.status(429).json({ message: 'Too many conversation fork requests. Try again later' });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ const getEnvironmentVariables = () => {
|
||||||
const IMPORT_IP_WINDOW = parseInt(process.env.IMPORT_IP_WINDOW) || 15;
|
const IMPORT_IP_WINDOW = parseInt(process.env.IMPORT_IP_WINDOW) || 15;
|
||||||
const IMPORT_USER_MAX = parseInt(process.env.IMPORT_USER_MAX) || 50;
|
const IMPORT_USER_MAX = parseInt(process.env.IMPORT_USER_MAX) || 50;
|
||||||
const IMPORT_USER_WINDOW = parseInt(process.env.IMPORT_USER_WINDOW) || 15;
|
const IMPORT_USER_WINDOW = parseInt(process.env.IMPORT_USER_WINDOW) || 15;
|
||||||
|
const IMPORT_VIOLATION_SCORE = process.env.IMPORT_VIOLATION_SCORE;
|
||||||
|
|
||||||
const importIpWindowMs = IMPORT_IP_WINDOW * 60 * 1000;
|
const importIpWindowMs = IMPORT_IP_WINDOW * 60 * 1000;
|
||||||
const importIpMax = IMPORT_IP_MAX;
|
const importIpMax = IMPORT_IP_MAX;
|
||||||
|
@ -27,12 +28,18 @@ const getEnvironmentVariables = () => {
|
||||||
importUserWindowMs,
|
importUserWindowMs,
|
||||||
importUserMax,
|
importUserMax,
|
||||||
importUserWindowInMinutes,
|
importUserWindowInMinutes,
|
||||||
|
importViolationScore: IMPORT_VIOLATION_SCORE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createImportHandler = (ip = true) => {
|
const createImportHandler = (ip = true) => {
|
||||||
const { importIpMax, importIpWindowInMinutes, importUserMax, importUserWindowInMinutes } =
|
const {
|
||||||
getEnvironmentVariables();
|
importIpMax,
|
||||||
|
importUserMax,
|
||||||
|
importViolationScore,
|
||||||
|
importIpWindowInMinutes,
|
||||||
|
importUserWindowInMinutes,
|
||||||
|
} = getEnvironmentVariables();
|
||||||
|
|
||||||
return async (req, res) => {
|
return async (req, res) => {
|
||||||
const type = ViolationTypes.FILE_UPLOAD_LIMIT;
|
const type = ViolationTypes.FILE_UPLOAD_LIMIT;
|
||||||
|
@ -43,7 +50,7 @@ const createImportHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? importIpWindowInMinutes : importUserWindowInMinutes,
|
windowInMinutes: ip ? importIpWindowInMinutes : importUserWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, importViolationScore);
|
||||||
res.status(429).json({ message: 'Too many conversation import requests. Try again later' });
|
res.status(429).json({ message: 'Too many conversation import requests. Try again later' });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ const {
|
||||||
MESSAGE_IP_WINDOW = 1,
|
MESSAGE_IP_WINDOW = 1,
|
||||||
MESSAGE_USER_MAX = 40,
|
MESSAGE_USER_MAX = 40,
|
||||||
MESSAGE_USER_WINDOW = 1,
|
MESSAGE_USER_WINDOW = 1,
|
||||||
|
MESSAGE_VIOLATION_SCORE: score,
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
const ipWindowMs = MESSAGE_IP_WINDOW * 60 * 1000;
|
const ipWindowMs = MESSAGE_IP_WINDOW * 60 * 1000;
|
||||||
|
@ -39,7 +40,7 @@ const createHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? ipWindowInMinutes : userWindowInMinutes,
|
windowInMinutes: ip ? ipWindowInMinutes : userWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, score);
|
||||||
return await denyRequest(req, res, errorMessage);
|
return await denyRequest(req, res, errorMessage);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ const getEnvironmentVariables = () => {
|
||||||
const STT_IP_WINDOW = parseInt(process.env.STT_IP_WINDOW) || 1;
|
const STT_IP_WINDOW = parseInt(process.env.STT_IP_WINDOW) || 1;
|
||||||
const STT_USER_MAX = parseInt(process.env.STT_USER_MAX) || 50;
|
const STT_USER_MAX = parseInt(process.env.STT_USER_MAX) || 50;
|
||||||
const STT_USER_WINDOW = parseInt(process.env.STT_USER_WINDOW) || 1;
|
const STT_USER_WINDOW = parseInt(process.env.STT_USER_WINDOW) || 1;
|
||||||
|
const STT_VIOLATION_SCORE = process.env.STT_VIOLATION_SCORE;
|
||||||
|
|
||||||
const sttIpWindowMs = STT_IP_WINDOW * 60 * 1000;
|
const sttIpWindowMs = STT_IP_WINDOW * 60 * 1000;
|
||||||
const sttIpMax = STT_IP_MAX;
|
const sttIpMax = STT_IP_MAX;
|
||||||
|
@ -27,11 +28,12 @@ const getEnvironmentVariables = () => {
|
||||||
sttUserWindowMs,
|
sttUserWindowMs,
|
||||||
sttUserMax,
|
sttUserMax,
|
||||||
sttUserWindowInMinutes,
|
sttUserWindowInMinutes,
|
||||||
|
sttViolationScore: STT_VIOLATION_SCORE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSTTHandler = (ip = true) => {
|
const createSTTHandler = (ip = true) => {
|
||||||
const { sttIpMax, sttIpWindowInMinutes, sttUserMax, sttUserWindowInMinutes } =
|
const { sttIpMax, sttIpWindowInMinutes, sttUserMax, sttUserWindowInMinutes, sttViolationScore } =
|
||||||
getEnvironmentVariables();
|
getEnvironmentVariables();
|
||||||
|
|
||||||
return async (req, res) => {
|
return async (req, res) => {
|
||||||
|
@ -43,7 +45,7 @@ const createSTTHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? sttIpWindowInMinutes : sttUserWindowInMinutes,
|
windowInMinutes: ip ? sttIpWindowInMinutes : sttUserWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, sttViolationScore);
|
||||||
res.status(429).json({ message: 'Too many STT requests. Try again later' });
|
res.status(429).json({ message: 'Too many STT requests. Try again later' });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,8 @@ const logViolation = require('~/cache/logViolation');
|
||||||
const { isEnabled } = require('~/server/utils');
|
const { isEnabled } = require('~/server/utils');
|
||||||
const { logger } = require('~/config');
|
const { logger } = require('~/config');
|
||||||
|
|
||||||
|
const { TOOL_CALL_VIOLATION_SCORE: score } = process.env;
|
||||||
|
|
||||||
const handler = async (req, res) => {
|
const handler = async (req, res) => {
|
||||||
const type = ViolationTypes.TOOL_CALL_LIMIT;
|
const type = ViolationTypes.TOOL_CALL_LIMIT;
|
||||||
const errorMessage = {
|
const errorMessage = {
|
||||||
|
@ -15,7 +17,7 @@ const handler = async (req, res) => {
|
||||||
windowInMinutes: 1,
|
windowInMinutes: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage, 0);
|
await logViolation(req, res, type, errorMessage, score);
|
||||||
res.status(429).json({ message: 'Too many tool call requests. Try again later' });
|
res.status(429).json({ message: 'Too many tool call requests. Try again later' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ const getEnvironmentVariables = () => {
|
||||||
const TTS_IP_WINDOW = parseInt(process.env.TTS_IP_WINDOW) || 1;
|
const TTS_IP_WINDOW = parseInt(process.env.TTS_IP_WINDOW) || 1;
|
||||||
const TTS_USER_MAX = parseInt(process.env.TTS_USER_MAX) || 50;
|
const TTS_USER_MAX = parseInt(process.env.TTS_USER_MAX) || 50;
|
||||||
const TTS_USER_WINDOW = parseInt(process.env.TTS_USER_WINDOW) || 1;
|
const TTS_USER_WINDOW = parseInt(process.env.TTS_USER_WINDOW) || 1;
|
||||||
|
const TTS_VIOLATION_SCORE = process.env.TTS_VIOLATION_SCORE;
|
||||||
|
|
||||||
const ttsIpWindowMs = TTS_IP_WINDOW * 60 * 1000;
|
const ttsIpWindowMs = TTS_IP_WINDOW * 60 * 1000;
|
||||||
const ttsIpMax = TTS_IP_MAX;
|
const ttsIpMax = TTS_IP_MAX;
|
||||||
|
@ -27,11 +28,12 @@ const getEnvironmentVariables = () => {
|
||||||
ttsUserWindowMs,
|
ttsUserWindowMs,
|
||||||
ttsUserMax,
|
ttsUserMax,
|
||||||
ttsUserWindowInMinutes,
|
ttsUserWindowInMinutes,
|
||||||
|
ttsViolationScore: TTS_VIOLATION_SCORE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const createTTSHandler = (ip = true) => {
|
const createTTSHandler = (ip = true) => {
|
||||||
const { ttsIpMax, ttsIpWindowInMinutes, ttsUserMax, ttsUserWindowInMinutes } =
|
const { ttsIpMax, ttsIpWindowInMinutes, ttsUserMax, ttsUserWindowInMinutes, ttsViolationScore } =
|
||||||
getEnvironmentVariables();
|
getEnvironmentVariables();
|
||||||
|
|
||||||
return async (req, res) => {
|
return async (req, res) => {
|
||||||
|
@ -43,7 +45,7 @@ const createTTSHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? ttsIpWindowInMinutes : ttsUserWindowInMinutes,
|
windowInMinutes: ip ? ttsIpWindowInMinutes : ttsUserWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, ttsViolationScore);
|
||||||
res.status(429).json({ message: 'Too many TTS requests. Try again later' });
|
res.status(429).json({ message: 'Too many TTS requests. Try again later' });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,7 @@ const getEnvironmentVariables = () => {
|
||||||
const FILE_UPLOAD_IP_WINDOW = parseInt(process.env.FILE_UPLOAD_IP_WINDOW) || 15;
|
const FILE_UPLOAD_IP_WINDOW = parseInt(process.env.FILE_UPLOAD_IP_WINDOW) || 15;
|
||||||
const FILE_UPLOAD_USER_MAX = parseInt(process.env.FILE_UPLOAD_USER_MAX) || 50;
|
const FILE_UPLOAD_USER_MAX = parseInt(process.env.FILE_UPLOAD_USER_MAX) || 50;
|
||||||
const FILE_UPLOAD_USER_WINDOW = parseInt(process.env.FILE_UPLOAD_USER_WINDOW) || 15;
|
const FILE_UPLOAD_USER_WINDOW = parseInt(process.env.FILE_UPLOAD_USER_WINDOW) || 15;
|
||||||
|
const FILE_UPLOAD_VIOLATION_SCORE = process.env.FILE_UPLOAD_VIOLATION_SCORE;
|
||||||
|
|
||||||
const fileUploadIpWindowMs = FILE_UPLOAD_IP_WINDOW * 60 * 1000;
|
const fileUploadIpWindowMs = FILE_UPLOAD_IP_WINDOW * 60 * 1000;
|
||||||
const fileUploadIpMax = FILE_UPLOAD_IP_MAX;
|
const fileUploadIpMax = FILE_UPLOAD_IP_MAX;
|
||||||
|
@ -27,6 +28,7 @@ const getEnvironmentVariables = () => {
|
||||||
fileUploadUserWindowMs,
|
fileUploadUserWindowMs,
|
||||||
fileUploadUserMax,
|
fileUploadUserMax,
|
||||||
fileUploadUserWindowInMinutes,
|
fileUploadUserWindowInMinutes,
|
||||||
|
fileUploadViolationScore: FILE_UPLOAD_VIOLATION_SCORE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,6 +38,7 @@ const createFileUploadHandler = (ip = true) => {
|
||||||
fileUploadIpWindowInMinutes,
|
fileUploadIpWindowInMinutes,
|
||||||
fileUploadUserMax,
|
fileUploadUserMax,
|
||||||
fileUploadUserWindowInMinutes,
|
fileUploadUserWindowInMinutes,
|
||||||
|
fileUploadViolationScore,
|
||||||
} = getEnvironmentVariables();
|
} = getEnvironmentVariables();
|
||||||
|
|
||||||
return async (req, res) => {
|
return async (req, res) => {
|
||||||
|
@ -47,7 +50,7 @@ const createFileUploadHandler = (ip = true) => {
|
||||||
windowInMinutes: ip ? fileUploadIpWindowInMinutes : fileUploadUserWindowInMinutes,
|
windowInMinutes: ip ? fileUploadIpWindowInMinutes : fileUploadUserWindowInMinutes,
|
||||||
};
|
};
|
||||||
|
|
||||||
await logViolation(req, res, type, errorMessage);
|
await logViolation(req, res, type, errorMessage, fileUploadViolationScore);
|
||||||
res.status(429).json({ message: 'Too many file upload requests. Try again later' });
|
res.status(429).json({ message: 'Too many file upload requests. Try again later' });
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,15 @@ const config: PlaywrightTestConfig = {
|
||||||
CONCURRENT_VIOLATION_SCORE: '0',
|
CONCURRENT_VIOLATION_SCORE: '0',
|
||||||
MESSAGE_VIOLATION_SCORE: '0',
|
MESSAGE_VIOLATION_SCORE: '0',
|
||||||
NON_BROWSER_VIOLATION_SCORE: '0',
|
NON_BROWSER_VIOLATION_SCORE: '0',
|
||||||
|
FORK_VIOLATION_SCORE: '0',
|
||||||
|
IMPORT_VIOLATION_SCORE: '0',
|
||||||
|
TTS_VIOLATION_SCORE: '0',
|
||||||
|
STT_VIOLATION_SCORE: '0',
|
||||||
|
FILE_UPLOAD_VIOLATION_SCORE: '0',
|
||||||
|
RESET_PASSWORD_VIOLATION_SCORE: '0',
|
||||||
|
VERIFY_EMAIL_VIOLATION_SCORE: '0',
|
||||||
|
TOOL_CALL_VIOLATION_SCORE: '0',
|
||||||
|
CONVO_ACCESS_VIOLATION_SCORE: '0',
|
||||||
ILLEGAL_MODEL_REQ_SCORE: '0',
|
ILLEGAL_MODEL_REQ_SCORE: '0',
|
||||||
LOGIN_MAX: '20',
|
LOGIN_MAX: '20',
|
||||||
LOGIN_WINDOW: '1',
|
LOGIN_WINDOW: '1',
|
||||||
|
|
|
@ -26,6 +26,15 @@ const config: PlaywrightTestConfig = {
|
||||||
CONCURRENT_VIOLATION_SCORE: '0',
|
CONCURRENT_VIOLATION_SCORE: '0',
|
||||||
MESSAGE_VIOLATION_SCORE: '0',
|
MESSAGE_VIOLATION_SCORE: '0',
|
||||||
NON_BROWSER_VIOLATION_SCORE: '0',
|
NON_BROWSER_VIOLATION_SCORE: '0',
|
||||||
|
FORK_VIOLATION_SCORE: '0',
|
||||||
|
IMPORT_VIOLATION_SCORE: '0',
|
||||||
|
TTS_VIOLATION_SCORE: '0',
|
||||||
|
STT_VIOLATION_SCORE: '0',
|
||||||
|
FILE_UPLOAD_VIOLATION_SCORE: '0',
|
||||||
|
RESET_PASSWORD_VIOLATION_SCORE: '0',
|
||||||
|
VERIFY_EMAIL_VIOLATION_SCORE: '0',
|
||||||
|
TOOL_CALL_VIOLATION_SCORE: '0',
|
||||||
|
CONVO_ACCESS_VIOLATION_SCORE: '0',
|
||||||
ILLEGAL_MODEL_REQ_SCORE: '0',
|
ILLEGAL_MODEL_REQ_SCORE: '0',
|
||||||
LOGIN_MAX: '20',
|
LOGIN_MAX: '20',
|
||||||
LOGIN_WINDOW: '1',
|
LOGIN_WINDOW: '1',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue