|
|
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"); |
|
|
|
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
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; |
|
|
} |
|
|
|
|
|
|
|
|
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 (e) { |
|
|
response.status(500).json({ |
|
|
id: uuidv4(), |
|
|
type: "abort", |
|
|
textResponse: null, |
|
|
sources: [], |
|
|
close: true, |
|
|
error: "Invalid request.", |
|
|
}); |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
setConnectionMeta, |
|
|
validEmbedConfig, |
|
|
validEmbedConfigId, |
|
|
canRespond, |
|
|
}; |
|
|
|