diff --git a/src/features/file-system/controllers/store.ts b/src/features/file-system/controllers/store.ts index c71a5ec7..55f598e6 100644 --- a/src/features/file-system/controllers/store.ts +++ b/src/features/file-system/controllers/store.ts @@ -418,8 +418,51 @@ export const useFileSystemStore = createSelectors( fileName = prompt("Enter the name for the new file:") ?? undefined; if (!fileName) return; } + // Split the input path into parts + const parts = fileName.split("/").filter(Boolean); + // Validate input + if (parts.length === 0) { + alert("Invalid file name"); + return; + } + + const finalFileName = parts.pop()!; + + // Block path traversal and illegal separators + const hasIllegalCharacters = (segment: string) => + segment === ".." || segment === "." || segment.includes("\\") || segment.includes("/"); + + // Check all directory parts AND the final filename + if (parts.some(hasIllegalCharacters) || hasIllegalCharacters(finalFileName)) { + alert("Invalid file name: path traversal and special characters are not allowed"); + return; + } - return get().createFile(dirPath, fileName); + let currentPath = dirPath; + // Create intermediate folders if they don't exist + try { + for (const folder of parts) { + const potentialPath = await join(currentPath, folder); + // Check if directory already exists in the file tree + const existingFolder = findFileInTree(get().files, potentialPath); + + if (existingFolder?.isDir) { + // Directory already exists, just use its path + currentPath = potentialPath; + } else { + // Create the directory if it doesn't exist + currentPath = await get().createDirectory(currentPath, folder); + } + } + // Finally create the file inside the deepest folder + return await get().createFile(currentPath, finalFileName); + } catch (error) { + console.error("Failed to create nested file:", error); + alert( + `Failed to create file: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + return; + } }, handleCreateNewFolder: async () => {