diff --git a/src/endpoints/chats.js b/src/endpoints/chats.js index d10a17581..a0202be5e 100644 --- a/src/endpoints/chats.js +++ b/src/endpoints/chats.js @@ -20,6 +20,7 @@ import { tryReadFileSync, tryDeleteFile, readFirstLine, + isPathUnderParent, } from '../util.js'; const isBackupEnabled = !!getConfigValue('backups.chat.enabled', true, 'boolean'); @@ -473,6 +474,9 @@ router.post('/save', validateAvatarUrlMiddleware, async function (request, respo const chatData = request.body.chat; const chatFileName = `${String(request.body.file_name)}.jsonl`; const chatFilePath = path.join(request.user.directories.chats, cardName, sanitize(chatFileName)); + if (!isPathUnderParent(request.user.directories.chats, chatFilePath)) { + return response.sendStatus(400); + } if (Array.isArray(chatData)) { await trySaveChat(chatData, chatFilePath, request.body.force, handle, cardName, request.user.directories.backups); @@ -514,6 +518,9 @@ router.post('/get', validateAvatarUrlMiddleware, function (request, response) { try { const dirName = String(request.body.avatar_url).replace('.png', ''); const directoryPath = path.join(request.user.directories.chats, dirName); + if (!isPathUnderParent(request.user.directories.chats, directoryPath)) { + return response.sendStatus(400); + } const chatDirExists = fs.existsSync(directoryPath); //if no chat dir for the character is found, make one with the character name @@ -545,6 +552,9 @@ router.post('/rename', validateAvatarUrlMiddleware, async function (request, res const pathToFolder = request.body.is_group ? request.user.directories.groupChats : path.join(request.user.directories.chats, String(request.body.avatar_url).replace('.png', '')); + if (!request.body.is_group && !isPathUnderParent(request.user.directories.chats, pathToFolder)) { + return response.sendStatus(400); + } const pathToOriginalFile = path.join(pathToFolder, sanitize(request.body.original_file)); const pathToRenamedFile = path.join(pathToFolder, sanitize(request.body.renamed_file)); const sanitizedFileName = path.parse(pathToRenamedFile).name; @@ -575,6 +585,9 @@ router.post('/delete', validateAvatarUrlMiddleware, function (request, response) const dirName = String(request.body.avatar_url).replace('.png', ''); const chatFileName = String(request.body.chatfile); const chatFilePath = path.join(request.user.directories.chats, dirName, sanitize(chatFileName)); + if (!isPathUnderParent(request.user.directories.chats, chatFilePath)) { + return response.sendStatus(400); + } //Return success if the file was deleted. if (tryDeleteFile(chatFilePath)) { return response.send({ ok: true }); @@ -595,7 +608,10 @@ router.post('/export', validateAvatarUrlMiddleware, async function (request, res const pathToFolder = request.body.is_group ? request.user.directories.groupChats : path.join(request.user.directories.chats, String(request.body.avatar_url).replace('.png', '')); - let filename = path.join(pathToFolder, sanitize(request.body.file)); + const filename = path.join(pathToFolder, sanitize(request.body.file)); + if (!request.body.is_group && !isPathUnderParent(request.user.directories.chats, filename)) { + return response.sendStatus(400); + } let exportfilename = request.body.exportfilename; if (!fs.existsSync(filename)) { const errorMessage = { @@ -690,6 +706,11 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) return response.sendStatus(400); } + const directoryPath = path.join(request.user.directories.chats, avatarUrl); + if (!isPathUnderParent(request.user.directories.chats, directoryPath)) { + return response.sendStatus(400); + } + try { const pathToUpload = path.join(request.file.destination, request.file.filename); const data = fs.readFileSync(pathToUpload, 'utf8'); @@ -718,7 +739,7 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) const handleChat = (chat) => { const fileName = `${characterName} - ${humanizedDateTime()} imported.jsonl`; - const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); + const filePath = path.join(directoryPath, fileName); fileNames.push(fileName); writeFileAtomicSync(filePath, chat, 'utf8'); }; @@ -757,7 +778,7 @@ router.post('/import', validateAvatarUrlMiddleware, function (request, response) } const fileName = `${characterName} - ${humanizedDateTime()} imported.jsonl`; - const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); + const filePath = path.join(directoryPath, fileName); fileNames.push(fileName); if (flattenedChat !== data) { writeFileAtomicSync(filePath, flattenedChat, 'utf8');