Reject unsafe ZIP paths
This commit is contained in:
@@ -9,6 +9,13 @@ function makeFile(data, name) {
|
||||
return new File([data], name);
|
||||
}
|
||||
|
||||
function safeEntryParts(entryName) {
|
||||
if (!entryName || entryName.startsWith('/') || entryName.includes('\\')) return null;
|
||||
const parts = entryName.split('/');
|
||||
if (parts.some((part) => !part || part === '.' || part === '..')) return null;
|
||||
return parts;
|
||||
}
|
||||
|
||||
function node(kind, name, path, children = [], file = null) {
|
||||
return { id: crypto.randomUUID(), kind, name, path, children, file, expanded: true };
|
||||
}
|
||||
@@ -42,17 +49,20 @@ async function listEntries(data, zipName, allowedExt, depth) {
|
||||
|
||||
for (const [entryName, entryData] of Object.entries(entries)) {
|
||||
if (entryName.endsWith('/')) continue;
|
||||
if (entryName.toLowerCase().endsWith('.zip')) {
|
||||
const parts = safeEntryParts(entryName);
|
||||
if (!parts) continue;
|
||||
const normalizedName = parts.join('/');
|
||||
if (normalizedName.toLowerCase().endsWith('.zip')) {
|
||||
const nested = await listEntries(entryData, entryName, allowedExt, depth + 1);
|
||||
if (nested) {
|
||||
rebaseTree(nested, zipName);
|
||||
nested.name = entryName.split('/').pop();
|
||||
addPath(root, entryName.split('/'), nested);
|
||||
nested.name = parts.at(-1);
|
||||
addPath(root, parts, nested);
|
||||
}
|
||||
} else if (extensionAllowed(entryName, allowedExt)) {
|
||||
const path = `${zipName}/${entryName}`;
|
||||
} else if (extensionAllowed(normalizedName, allowedExt)) {
|
||||
const path = `${zipName}/${normalizedName}`;
|
||||
const file = makeFile(entryData, path);
|
||||
addPath(root, entryName.split('/'), node('file', entryName.split('/').pop(), path, [], file));
|
||||
addPath(root, parts, node('file', parts.at(-1), path, [], file));
|
||||
}
|
||||
}
|
||||
return root.children.length ? root : null;
|
||||
|
||||
Reference in New Issue
Block a user