From 8bec3d2efc0dbd4028b827662151cb03c493f31c Mon Sep 17 00:00:00 2001 From: Rohit Kushwaha Date: Fri, 10 Jul 2026 15:32:07 +0530 Subject: [PATCH 1/3] fix: zip project import This reverts commit 411f55bb9ca3fd3d9dab00b709194d0c8c2b7338. --- src/pages/fileBrowser/fileBrowser.js | 139 ++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 14 deletions(-) diff --git a/src/pages/fileBrowser/fileBrowser.js b/src/pages/fileBrowser/fileBrowser.js index 34ee260cb..9cbbb3bd5 100644 --- a/src/pages/fileBrowser/fileBrowser.js +++ b/src/pages/fileBrowser/fileBrowser.js @@ -294,41 +294,144 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) { if (!zipFile) break; + let isCancelled = false; const loadingLoader = loader.create( strings["loading"], "Importing zip file...", - { timeout: 10000 }, + { + timeout: 10000, + oncancel: () => { + isCancelled = true; + }, + }, ); + const zipName = Url.basename(zipFile).replace(/\.zip$/, ""); + const targetDir = currentDir.url; + const extractDir = Url.join(targetDir, zipName); + try { const zipContent = await fsOperation(zipFile).readFile(); const zip = await JSZip.loadAsync(zipContent); - const targetDir = currentDir.url; - const targetFs = fsOperation(targetDir); - // Create folder with zip name - const zipName = Url.basename(zipFile).replace(/\.zip$/, ""); - const extractDir = Url.join(targetDir, zipName); - await targetFs.createDirectory(zipName); + const targetFs = fsOperation(targetDir); + if (!(await fsOperation(extractDir).exists())) { + await targetFs.createDirectory(zipName); + } const files = Object.keys(zip.files); const total = files.length; let current = 0; + // Internal helper to recursively construct folders or empty files + const createFileRecursive = async (parent, dir, shouldBeDirAtEnd) => { + let wantDirEnd = !!shouldBeDirAtEnd; + let parts; + if (typeof dir === "string") { + if (dir.endsWith("/")) wantDirEnd = true; + dir = dir.replace(/\\/g, "/"); + parts = dir.split("/"); + } else { + parts = dir; + } + parts = parts.filter((d) => d); + const cd = parts.shift(); + if (!cd) return; + const newParent = Url.join(parent, cd); + + const isLast = parts.length === 0; + const needDir = !isLast || wantDirEnd; + if (!(await fsOperation(newParent).exists())) { + if (needDir) { + try { + await fsOperation(parent).createDirectory(cd); + } catch (e) { + if (!(await fsOperation(newParent).exists())) throw e; + } + } else { + try { + await fsOperation(parent).createFile(cd); + } catch (e) { + if (!(await fsOperation(newParent).exists())) throw e; + } + } + } + if (parts.length) { + await createFileRecursive(newParent, parts, wantDirEnd); + } + }; + + const sanitizeZipPath = (p, isDir) => { + if (!p) return ""; + let path = String(p); + path = path.replace(/\\/g, "/"); + path = path.replace(/^[a-zA-Z]+:\/\//, ""); + path = path.replace(/^\/+/, ""); + path = path.replace(/^[A-Za-z]:\//, ""); + + const parts = path.split("/"); + const stack = []; + for (const part of parts) { + if (!part || part === ".") continue; + if (part === "..") { + if (stack.length) stack.pop(); + continue; + } + stack.push(part); + } + let safe = stack.join("/"); + if (isDir && safe && !safe.endsWith("/")) safe += "/"; + return safe; + }; + + const isUnsafeAbsolutePath = (p) => { + if (!p) return false; + const s = String(p); + if (/^[A-Za-z]:[\\\/]/.test(s)) return true; + if (s.startsWith("//")) return true; + if (s.startsWith("/")) return true; + return false; + }; + for (const filePath of files) { - const file = zip.files[filePath]; + if (isCancelled) { + throw new Error("Cancelled"); + } + + const entry = zip.files[filePath]; current++; loadingLoader.setMessage( `Extracting ${filePath} (${Math.round((current / total) * 100)}%)`, ); - if (file.dir) { - await fsOperation(extractDir).createDirectory(filePath); - } else { - const content = await file.async("arraybuffer"); - await fsOperation(extractDir).createFile(filePath, content); + let correctFile = filePath.replace(/\\/g, "/"); + const isDirEntry = entry.dir || correctFile.endsWith("/"); + + if (isUnsafeAbsolutePath(filePath)) { + continue; + } + + correctFile = sanitizeZipPath(correctFile, isDirEntry); + if (!correctFile) continue; + + const fileUrl = Url.join(extractDir, correctFile); + + if (isDirEntry) { + await createFileRecursive(extractDir, correctFile, true); + continue; + } + + const lastSlash = correctFile.lastIndexOf("/"); + if (lastSlash !== -1) { + const parentRel = correctFile.slice(0, lastSlash + 1); + await createFileRecursive(extractDir, parentRel, true); } + + await createFileRecursive(extractDir, correctFile, false); + + const content = await entry.async("arraybuffer"); + await fsOperation(fileUrl).writeFile(content); } loadingLoader.destroy(); @@ -336,7 +439,15 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) { reload(); } catch (err) { loadingLoader.destroy(); - helpers.error(err); + if (err && err.message === "Cancelled") { + try { + await fsOperation(extractDir).delete(); + } catch (deleteErr) { + console.error("Cleanup failed:", deleteErr); + } + } else { + helpers.error(err); + } } break; } From 6f9524f94f2953c67304cc0235929d09da510cea Mon Sep 17 00:00:00 2001 From: Rohit Kushwaha Date: Fri, 10 Jul 2026 15:32:29 +0530 Subject: [PATCH 2/3] format This reverts commit cd23041ec43829d166f842d8fa7b427e3fd51381. --- src/pages/fileBrowser/fileBrowser.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/fileBrowser/fileBrowser.js b/src/pages/fileBrowser/fileBrowser.js index 9cbbb3bd5..01db29815 100644 --- a/src/pages/fileBrowser/fileBrowser.js +++ b/src/pages/fileBrowser/fileBrowser.js @@ -324,7 +324,11 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) { let current = 0; // Internal helper to recursively construct folders or empty files - const createFileRecursive = async (parent, dir, shouldBeDirAtEnd) => { + const createFileRecursive = async ( + parent, + dir, + shouldBeDirAtEnd, + ) => { let wantDirEnd = !!shouldBeDirAtEnd; let parts; if (typeof dir === "string") { From 581404907f5afc986aacc01d537b4238ec5f64cd Mon Sep 17 00:00:00 2001 From: Rohit Kushwaha Date: Sat, 11 Jul 2026 17:13:54 +0530 Subject: [PATCH 3/3] fix: file override --- src/pages/fileBrowser/fileBrowser.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/fileBrowser/fileBrowser.js b/src/pages/fileBrowser/fileBrowser.js index 01db29815..d634b08e4 100644 --- a/src/pages/fileBrowser/fileBrowser.js +++ b/src/pages/fileBrowser/fileBrowser.js @@ -306,18 +306,20 @@ function FileBrowserInclude(mode, info, doesOpenLast = true) { }, ); - const zipName = Url.basename(zipFile).replace(/\.zip$/, ""); + let zipName = Url.basename(zipFile).replace(/\.zip$/, ""); const targetDir = currentDir.url; - const extractDir = Url.join(targetDir, zipName); + let extractDir = Url.join(targetDir, zipName); try { const zipContent = await fsOperation(zipFile).readFile(); const zip = await JSZip.loadAsync(zipContent); const targetFs = fsOperation(targetDir); - if (!(await fsOperation(extractDir).exists())) { - await targetFs.createDirectory(zipName); + if (await fsOperation(extractDir).exists()) { + zipName = `${zipName}_${helpers.uuid()}`; + extractDir = Url.join(targetDir, zipName); } + await targetFs.createDirectory(zipName); const files = Object.keys(zip.files); const total = files.length;