repatch path normalization (#1516)

This commit is contained in:
Timothy Carambat 2024-05-23 14:52:04 -05:00 committed by GitHub
parent 05488c81e0
commit a89812703b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 59 additions and 39 deletions

View File

@ -49,9 +49,9 @@ function writeToServerDocuments(
const destination = destinationOverride const destination = destinationOverride
? path.resolve(destinationOverride) ? path.resolve(destinationOverride)
: path.resolve( : path.resolve(
__dirname, __dirname,
"../../../server/storage/documents/custom-documents" "../../../server/storage/documents/custom-documents"
); );
if (!fs.existsSync(destination)) if (!fs.existsSync(destination))
fs.mkdirSync(destination, { recursive: true }); fs.mkdirSync(destination, { recursive: true });
const destinationFilePath = path.resolve(destination, filename) + ".json"; const destinationFilePath = path.resolve(destination, filename) + ".json";
@ -82,7 +82,7 @@ async function wipeCollectorStorage() {
if (file === "__HOTDIR__.md") continue; if (file === "__HOTDIR__.md") continue;
try { try {
fs.rmSync(path.join(directory, file)); fs.rmSync(path.join(directory, file));
} catch { } } catch {}
} }
resolve(); resolve();
}); });
@ -97,7 +97,7 @@ async function wipeCollectorStorage() {
if (file === ".placeholder") continue; if (file === ".placeholder") continue;
try { try {
fs.rmSync(path.join(directory, file)); fs.rmSync(path.join(directory, file));
} catch { } } catch {}
} }
resolve(); resolve();
}); });

View File

@ -5,6 +5,7 @@ const {
viewLocalFiles, viewLocalFiles,
findDocumentInDocuments, findDocumentInDocuments,
normalizePath, normalizePath,
isWithin,
} = require("../../../utils/files"); } = require("../../../utils/files");
const { reqBody } = require("../../../utils/http"); const { reqBody } = require("../../../utils/http");
const { EventLogs } = require("../../../models/eventLogs"); const { EventLogs } = require("../../../models/eventLogs");
@ -603,6 +604,8 @@ function apiDocumentEndpoints(app) {
try { try {
const { name } = reqBody(request); const { name } = reqBody(request);
const storagePath = path.join(documentsPath, normalizePath(name)); const storagePath = path.join(documentsPath, normalizePath(name));
if (!isWithin(path.resolve(documentsPath), path.resolve(storagePath)))
throw new Error("Invalid path name");
if (fs.existsSync(storagePath)) { if (fs.existsSync(storagePath)) {
response.status(500).json({ response.status(500).json({

View File

@ -1,5 +1,5 @@
const { Document } = require("../models/documents"); const { Document } = require("../models/documents");
const { normalizePath, documentsPath } = require("../utils/files"); const { normalizePath, documentsPath, isWithin } = require("../utils/files");
const { reqBody } = require("../utils/http"); const { reqBody } = require("../utils/http");
const { const {
flexUserRoleValid, flexUserRoleValid,
@ -18,6 +18,8 @@ function documentEndpoints(app) {
try { try {
const { name } = reqBody(request); const { name } = reqBody(request);
const storagePath = path.join(documentsPath, normalizePath(name)); const storagePath = path.join(documentsPath, normalizePath(name));
if (!isWithin(path.resolve(documentsPath), path.resolve(storagePath)))
throw new Error("Invalid folder name.");
if (fs.existsSync(storagePath)) { if (fs.existsSync(storagePath)) {
response.status(500).json({ response.status(500).json({

View File

@ -1,7 +1,7 @@
process.env.NODE_ENV === "development" process.env.NODE_ENV === "development"
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }) ? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
: require("dotenv").config(); : require("dotenv").config();
const { viewLocalFiles, normalizePath } = require("../utils/files"); const { viewLocalFiles, normalizePath, isWithin } = require("../utils/files");
const { purgeDocument, purgeFolder } = require("../utils/files/purgeDocument"); const { purgeDocument, purgeFolder } = require("../utils/files/purgeDocument");
const { getVectorDbClass } = require("../utils/helpers"); const { getVectorDbClass } = require("../utils/helpers");
const { updateENV, dumpENV } = require("../utils/helpers/updateENV"); const { updateENV, dumpENV } = require("../utils/helpers/updateENV");
@ -622,11 +622,13 @@ function systemEndpoints(app) {
const userRecord = await User.get({ id: user.id }); const userRecord = await User.get({ id: user.id });
const oldPfpFilename = userRecord.pfpFilename; const oldPfpFilename = userRecord.pfpFilename;
if (oldPfpFilename) { if (oldPfpFilename) {
const storagePath = path.join(__dirname, "../storage/assets/pfp");
const oldPfpPath = path.join( const oldPfpPath = path.join(
__dirname, storagePath,
`../storage/assets/pfp/${normalizePath(userRecord.pfpFilename)}` normalizePath(userRecord.pfpFilename)
); );
if (!isWithin(path.resolve(storagePath), path.resolve(oldPfpPath)))
throw new Error("Invalid path name");
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath); if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
} }
@ -655,13 +657,14 @@ function systemEndpoints(app) {
const userRecord = await User.get({ id: user.id }); const userRecord = await User.get({ id: user.id });
const oldPfpFilename = userRecord.pfpFilename; const oldPfpFilename = userRecord.pfpFilename;
console.log("oldPfpFilename", oldPfpFilename);
if (oldPfpFilename) { if (oldPfpFilename) {
const storagePath = path.join(__dirname, "../storage/assets/pfp");
const oldPfpPath = path.join( const oldPfpPath = path.join(
__dirname, storagePath,
`../storage/assets/pfp/${normalizePath(oldPfpFilename)}` normalizePath(oldPfpFilename)
); );
if (!isWithin(path.resolve(storagePath), path.resolve(oldPfpPath)))
throw new Error("Invalid path name");
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath); if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
} }

View File

@ -6,7 +6,7 @@ const {
userFromSession, userFromSession,
safeJsonParse, safeJsonParse,
} = require("../utils/http"); } = require("../utils/http");
const { normalizePath } = require("../utils/files"); const { normalizePath, isWithin } = require("../utils/files");
const { Workspace } = require("../models/workspace"); const { Workspace } = require("../models/workspace");
const { Document } = require("../models/documents"); const { Document } = require("../models/documents");
const { DocumentVectors } = require("../models/vectors"); const { DocumentVectors } = require("../models/vectors");
@ -629,13 +629,13 @@ function workspaceEndpoints(app) {
const oldPfpFilename = workspaceRecord.pfpFilename; const oldPfpFilename = workspaceRecord.pfpFilename;
if (oldPfpFilename) { if (oldPfpFilename) {
const storagePath = path.join(__dirname, "../storage/assets/pfp");
const oldPfpPath = path.join( const oldPfpPath = path.join(
__dirname, storagePath,
`../storage/assets/pfp/${normalizePath( normalizePath(workspaceRecord.pfpFilename)
workspaceRecord.pfpFilename
)}`
); );
if (!isWithin(path.resolve(storagePath), path.resolve(oldPfpPath)))
throw new Error("Invalid path name");
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath); if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
} }
@ -670,11 +670,13 @@ function workspaceEndpoints(app) {
const oldPfpFilename = workspaceRecord.pfpFilename; const oldPfpFilename = workspaceRecord.pfpFilename;
if (oldPfpFilename) { if (oldPfpFilename) {
const storagePath = path.join(__dirname, "../storage/assets/pfp");
const oldPfpPath = path.join( const oldPfpPath = path.join(
__dirname, storagePath,
`../storage/assets/pfp/${normalizePath(oldPfpFilename)}` normalizePath(oldPfpFilename)
); );
if (!isWithin(path.resolve(storagePath), path.resolve(oldPfpPath)))
throw new Error("Invalid path name");
if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath); if (fs.existsSync(oldPfpPath)) fs.unlinkSync(oldPfpPath);
} }

View File

@ -3,7 +3,7 @@ const fs = require("fs");
const { getType } = require("mime"); const { getType } = require("mime");
const { v4 } = require("uuid"); const { v4 } = require("uuid");
const { SystemSettings } = require("../../models/systemSettings"); const { SystemSettings } = require("../../models/systemSettings");
const { normalizePath } = require("."); const { normalizePath, isWithin } = require(".");
const LOGO_FILENAME = "anything-llm.png"; const LOGO_FILENAME = "anything-llm.png";
function validFilename(newFilename = "") { function validFilename(newFilename = "") {
@ -23,6 +23,8 @@ async function determineLogoFilepath(defaultFilename = LOGO_FILENAME) {
if (currentLogoFilename && validFilename(currentLogoFilename)) { if (currentLogoFilename && validFilename(currentLogoFilename)) {
customLogoPath = path.join(basePath, normalizePath(currentLogoFilename)); customLogoPath = path.join(basePath, normalizePath(currentLogoFilename));
if (!isWithin(path.resolve(basePath), path.resolve(customLogoPath)))
return defaultFilepath;
return fs.existsSync(customLogoPath) ? customLogoPath : defaultFilepath; return fs.existsSync(customLogoPath) ? customLogoPath : defaultFilepath;
} }
@ -52,17 +54,17 @@ function fetchLogo(logoPath) {
async function renameLogoFile(originalFilename = null) { async function renameLogoFile(originalFilename = null) {
const extname = path.extname(originalFilename) || ".png"; const extname = path.extname(originalFilename) || ".png";
const newFilename = `${v4()}${extname}`; const newFilename = `${v4()}${extname}`;
const originalFilepath = process.env.STORAGE_DIR const assetsDirectory = process.env.STORAGE_DIR
? path.join( ? path.join(process.env.STORAGE_DIR, "assets")
process.env.STORAGE_DIR, : path.join(__dirname, `../../storage/assets`);
"assets", const originalFilepath = path.join(
normalizePath(originalFilename) assetsDirectory,
) normalizePath(originalFilename)
: path.join( );
__dirname, if (!isWithin(path.resolve(assetsDirectory), path.resolve(originalFilepath)))
`../../storage/assets`, throw new Error("Invalid file path.");
normalizePath(originalFilename)
); // The output always uses a random filename.
const outputFilepath = process.env.STORAGE_DIR const outputFilepath = process.env.STORAGE_DIR
? path.join(process.env.STORAGE_DIR, "assets", normalizePath(newFilename)) ? path.join(process.env.STORAGE_DIR, "assets", normalizePath(newFilename))
: path.join(__dirname, `../../storage/assets`, normalizePath(newFilename)); : path.join(__dirname, `../../storage/assets`, normalizePath(newFilename));
@ -73,9 +75,13 @@ async function renameLogoFile(originalFilename = null) {
async function removeCustomLogo(logoFilename = LOGO_FILENAME) { async function removeCustomLogo(logoFilename = LOGO_FILENAME) {
if (!logoFilename || !validFilename(logoFilename)) return false; if (!logoFilename || !validFilename(logoFilename)) return false;
const logoPath = process.env.STORAGE_DIR const assetsDirectory = process.env.STORAGE_DIR
? path.join(process.env.STORAGE_DIR, `assets`, normalizePath(logoFilename)) ? path.join(process.env.STORAGE_DIR, "assets")
: path.join(__dirname, `../../storage/assets`, normalizePath(logoFilename)); : path.join(__dirname, `../../storage/assets`);
const logoPath = path.join(assetsDirectory, normalizePath(logoFilename));
if (!isWithin(path.resolve(assetsDirectory), path.resolve(logoPath)))
throw new Error("Invalid file path.");
if (fs.existsSync(logoPath)) fs.unlinkSync(logoPath); if (fs.existsSync(logoPath)) fs.unlinkSync(logoPath);
return true; return true;
} }

View File

@ -2,7 +2,7 @@ const path = require("path");
const fs = require("fs"); const fs = require("fs");
const { getType } = require("mime"); const { getType } = require("mime");
const { User } = require("../../models/user"); const { User } = require("../../models/user");
const { normalizePath } = require("."); const { normalizePath, isWithin } = require(".");
const { Workspace } = require("../../models/workspace"); const { Workspace } = require("../../models/workspace");
function fetchPfp(pfpPath) { function fetchPfp(pfpPath) {
@ -35,6 +35,8 @@ async function determinePfpFilepath(id) {
? path.join(process.env.STORAGE_DIR, "assets/pfp") ? path.join(process.env.STORAGE_DIR, "assets/pfp")
: path.join(__dirname, "../../storage/assets/pfp"); : path.join(__dirname, "../../storage/assets/pfp");
const pfpFilepath = path.join(basePath, normalizePath(pfpFilename)); const pfpFilepath = path.join(basePath, normalizePath(pfpFilename));
if (!isWithin(path.resolve(basePath), path.resolve(pfpFilepath))) return null;
if (!fs.existsSync(pfpFilepath)) return null; if (!fs.existsSync(pfpFilepath)) return null;
return pfpFilepath; return pfpFilepath;
} }
@ -48,6 +50,8 @@ async function determineWorkspacePfpFilepath(slug) {
? path.join(process.env.STORAGE_DIR, "assets/pfp") ? path.join(process.env.STORAGE_DIR, "assets/pfp")
: path.join(__dirname, "../../storage/assets/pfp"); : path.join(__dirname, "../../storage/assets/pfp");
const pfpFilepath = path.join(basePath, normalizePath(pfpFilename)); const pfpFilepath = path.join(basePath, normalizePath(pfpFilename));
if (!isWithin(path.resolve(basePath), path.resolve(pfpFilepath))) return null;
if (!fs.existsSync(pfpFilepath)) return null; if (!fs.existsSync(pfpFilepath)) return null;
return pfpFilepath; return pfpFilepath;
} }