Files
anything-llm/server/utils/middleware/embedMiddleware.js
Marcello Fitton 4a4378ed99 chore: add ESLint to /server (#5126)
* add eslint config to server

* add break statements to switch case

* add support for browser globals and turn off empty catch blocks

* disable lines with useless try/catch wrappers

* format

* fix no-undef errors

* disbale lines violating no-unsafe-finally

* ignore syncStaticLists.mjs

* use proper null check for creatorId instead of unreachable nullish coalescing

* remove unneeded typescript eslint comment

* make no-unused-private-class-members a warning

* disable line for no-empty-objects

* add new lint script

* fix no-unused-vars violations

* make no-unsued-vars an error

---------

Co-authored-by: shatfield4 <seanhatfield5@gmail.com>
Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
2026-03-05 16:32:45 -08:00

179 lines
4.5 KiB
JavaScript

const { v4: uuidv4, validate } = require("uuid");
const { VALID_CHAT_MODE } = require("../chats/stream");
const { EmbedChats } = require("../../models/embedChats");
const { EmbedConfig } = require("../../models/embedConfig");
const { reqBody } = require("../http");
// Finds or Aborts request for a /:embedId/ url. This should always
// be the first middleware and the :embedID should be in the URL.
async function validEmbedConfig(request, response, next) {
const { embedId } = request.params;
const embed = await EmbedConfig.getWithWorkspace({ uuid: embedId });
if (!embed) {
response.sendStatus(404).end();
return;
}
response.locals.embedConfig = embed;
next();
}
function setConnectionMeta(request, response, next) {
response.locals.connection = {
host: request.headers?.origin,
ip: request?.ip,
};
next();
}
async function validEmbedConfigId(request, response, next) {
const { embedId } = request.params;
const embed = await EmbedConfig.get({ id: Number(embedId) });
if (!embed) {
response.sendStatus(404).end();
return;
}
response.locals.embedConfig = embed;
next();
}
async function canRespond(request, response, next) {
try {
const embed = response.locals.embedConfig;
if (!embed) {
response.sendStatus(404).end();
return;
}
// Block if disabled by admin.
if (!embed.enabled) {
response.status(503).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error:
"This chat has been disabled by the administrator - try again later.",
});
return;
}
// Check if requester hostname is in the valid allowlist of domains.
const host = request.headers.origin ?? "";
const allowedHosts = EmbedConfig.parseAllowedHosts(embed);
if (allowedHosts !== null && !allowedHosts.includes(host)) {
response.status(401).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: "Invalid request.",
});
return;
}
const { sessionId, message } = reqBody(request);
if (typeof sessionId !== "string" || !validate(String(sessionId))) {
response.status(404).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: "Invalid session ID.",
});
return;
}
if (!message?.length || !VALID_CHAT_MODE.includes(embed.chat_mode)) {
response.status(400).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: !message?.length
? "Message is empty."
: `${embed.chat_mode} is not a valid mode.`,
});
return;
}
if (
!isNaN(embed.max_chats_per_day) &&
Number(embed.max_chats_per_day) > 0
) {
const dailyChatCount = await EmbedChats.count({
embed_id: embed.id,
createdAt: {
gte: new Date(new Date() - 24 * 60 * 60 * 1000),
},
});
if (dailyChatCount >= Number(embed.max_chats_per_day)) {
response.status(429).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: "Rate limit exceeded",
errorMsg:
"The quota for this chat has been reached. Try again later or contact the site owner.",
});
return;
}
}
if (
!isNaN(embed.max_chats_per_session) &&
Number(embed.max_chats_per_session) > 0
) {
const dailySessionCount = await EmbedChats.count({
embed_id: embed.id,
session_id: sessionId,
createdAt: {
gte: new Date(new Date() - 24 * 60 * 60 * 1000),
},
});
if (dailySessionCount >= Number(embed.max_chats_per_session)) {
response.status(429).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error:
"Your quota for this chat has been reached. Try again later or contact the site owner.",
});
return;
}
}
next();
} catch {
response.status(500).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: "Invalid request.",
});
return;
}
}
module.exports = {
setConnectionMeta,
validEmbedConfig,
validEmbedConfigId,
canRespond,
};