UNPKG

hfs

Version:
96 lines (95 loc) 5.07 kB
"use strict"; // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.zipStreamFromFolder = zipStreamFromFolder; const vfs_1 = require("./vfs"); const misc_1 = require("./misc"); const QuickZipStream_1 = require("./QuickZipStream"); const fs_1 = require("fs"); const promises_1 = __importDefault(require("fs/promises")); const config_1 = require("./config"); const path_1 = require("path"); const serveFile_1 = require("./serveFile"); const const_1 = require("./const"); const api_get_file_list_1 = require("./api.get_file_list"); const comments_1 = require("./comments"); // expects 'node' to have had permissions checked by caller async function zipStreamFromFolder(node, ctx) { var _a; const list = (_a = (0, misc_1.wantArray)(ctx.query.list)[0]) === null || _a === void 0 ? void 0 : _a.split('//'); // slash is the only char not allowed in file names both for windows and unix, but still we need to encode whole paths, so the only safe choice to separate the entries is the double slash if (!list && (0, vfs_1.statusCodeForMissingPerm)(node, 'can_archive', ctx)) return; ctx.status = const_1.HTTP_OK; ctx.mime = 'zip'; // ctx.query.list is undefined | string | string[] const name = (list === null || list === void 0 ? void 0 : list.length) === 1 ? (0, misc_1.safeDecodeURIComponent)((0, path_1.basename)(list[0])) : (0, vfs_1.getNodeName)(node); (0, serveFile_1.forceDownload)(ctx, ((0, misc_1.isWindowsDrive)(name) ? name[0] : (name || 'archive')) + '.zip'); const { filterName, filterComment } = (0, api_get_file_list_1.paramsToFilter)(ctx.query); const walker = !list ? (0, vfs_1.walkNode)(node, { ctx, requiredPerm: 'can_archive' }) : (async function* () { for await (const uri of list) { if (ctx.isAborted()) return; const subNode = await (0, vfs_1.urlToNode)(uri, ctx, node); if (!subNode) continue; if (await (0, vfs_1.nodeIsDirectory)(subNode)) { // a directory needs to walked if ((0, vfs_1.hasPermission)(subNode, 'can_list', ctx) && (0, vfs_1.hasPermission)(subNode, 'can_archive', ctx)) { yield subNode; // it could be empty yield* (0, vfs_1.walkNode)(subNode, { ctx, prefixPath: decodeURI(uri) + '/', requiredPerm: 'can_archive' }); } continue; } let folder = (0, path_1.dirname)((0, misc_1.safeDecodeURIComponent)(uri)); // decodeURI() won't account for %23=# folder = folder === '.' ? '' : folder + '/'; yield { ...subNode, name: folder + (0, vfs_1.getNodeName)(subNode) }; // reflect relative path in archive, otherwise way may have name-clashes } })(); const mappedWalker = (0, misc_1.filterMapGenerator)(walker, async (el) => { if ((0, vfs_1.nodeIsLink)(el)) return; if (!(0, vfs_1.hasPermission)(el, 'can_archive', ctx)) return; // the fact you see it doesn't mean you can get it const { source } = el; let name = (0, vfs_1.getNodeName)(el); if (!const_1.IS_WINDOWS) // posix supports \ in file names, but zip tools don't name = name.replaceAll('\\', '_'); if (filterName && !filterName(name) || filterComment && !filterComment(await (0, comments_1.getCommentFor)(source) || '')) return; try { if (el.isFolder) return { path: name + '/' }; if (!source) return; const st = el.stats || await promises_1.default.stat(source); if (!st || !st.isFile()) return; return { path: name, size: st.size, ts: st.mtime, mode: st.mode, sourcePath: source, getData: () => (0, fs_1.createReadStream)(source, { start: 0, end: Math.max(0, st.size - 1) }) }; } catch (_a) { } }); const zip = new QuickZipStream_1.QuickZipStream(mappedWalker); const time = 1000 * zipSeconds.get(); const size = await zip.calculateSize(time); const range = (0, serveFile_1.applyRange)(ctx, size); // keep var size as ctx.response.length won't preserve a NaN if (ctx.status >= 400) return; if (range) zip.applyRange(range.start, range.end); ctx.body = zip; ctx.req.on('close', () => zip.destroy()); ctx.state.archive = 'zip'; (0, serveFile_1.monitorAsDownload)(ctx, size, range === null || range === void 0 ? void 0 : range.start); } const zipSeconds = (0, config_1.defineConfig)('zip_calculate_size_for_seconds', 1);