UNPKG

5.26 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.extractArchiveTo = exports.convertToZip = exports.makeArchiveFromDirectory = void 0;
4const tslib_1 = require("tslib");
5const fslib_1 = require("@yarnpkg/fslib");
6const libzip_1 = require("@yarnpkg/libzip");
7const tar_stream_1 = tslib_1.__importDefault(require("tar-stream"));
8const util_1 = require("util");
9const zlib_1 = tslib_1.__importDefault(require("zlib"));
10const gunzip = util_1.promisify(zlib_1.default.gunzip);
11async function makeArchiveFromDirectory(source, { baseFs = new fslib_1.NodeFS(), prefixPath = fslib_1.PortablePath.root, compressionLevel, inMemory = false } = {}) {
12 const libzip = await libzip_1.getLibzipPromise();
13 let zipFs;
14 if (inMemory) {
15 zipFs = new fslib_1.ZipFS(null, { libzip, level: compressionLevel });
16 }
17 else {
18 const tmpFolder = await fslib_1.xfs.mktempPromise();
19 const tmpFile = fslib_1.ppath.join(tmpFolder, `archive.zip`);
20 zipFs = new fslib_1.ZipFS(tmpFile, { create: true, libzip, level: compressionLevel });
21 }
22 const target = fslib_1.ppath.resolve(fslib_1.PortablePath.root, prefixPath);
23 await zipFs.copyPromise(target, source, { baseFs, stableTime: true, stableSort: true });
24 return zipFs;
25}
26exports.makeArchiveFromDirectory = makeArchiveFromDirectory;
27async function convertToZip(tgz, opts) {
28 const tmpFolder = await fslib_1.xfs.mktempPromise();
29 const tmpFile = fslib_1.ppath.join(tmpFolder, `archive.zip`);
30 const { compressionLevel, ...bufferOpts } = opts;
31 return await extractArchiveTo(tgz, new fslib_1.ZipFS(tmpFile, { create: true, libzip: await libzip_1.getLibzipPromise(), level: compressionLevel }), bufferOpts);
32}
33exports.convertToZip = convertToZip;
34async function extractArchiveTo(tgz, targetFs, { stripComponents = 0, prefixPath = fslib_1.PortablePath.dot } = {}) {
35 // 1980-01-01, like Fedora
36 const defaultTime = 315532800;
37 const parser = tar_stream_1.default.extract();
38 function ignore(entry) {
39 // Disallow absolute paths; might be malicious (ex: /etc/passwd)
40 if (entry.name[0] === `/`)
41 return true;
42 const parts = entry.name.split(/\//g);
43 // We also ignore paths that could lead to escaping outside the archive
44 if (parts.some((part) => part === `..`))
45 return true;
46 if (parts.length <= stripComponents)
47 return true;
48 return false;
49 }
50 parser.on(`entry`, (header, stream, next) => {
51 var _a, _b;
52 if (ignore(header)) {
53 next();
54 return;
55 }
56 const parts = fslib_1.ppath.normalize(fslib_1.npath.toPortablePath(header.name)).replace(/\/$/, ``).split(/\//g);
57 if (parts.length <= stripComponents) {
58 stream.resume();
59 next();
60 return;
61 }
62 const slicePath = parts.slice(stripComponents).join(`/`);
63 const mappedPath = fslib_1.ppath.join(prefixPath, slicePath);
64 let mode = 0o644;
65 // If a single executable bit is set, normalize so that all are
66 if (header.type === `directory` || (((_a = header.mode) !== null && _a !== void 0 ? _a : 0) & 0o111) !== 0)
67 mode |= 0o111;
68 switch (header.type) {
69 case `directory`:
70 {
71 targetFs.mkdirpSync(fslib_1.ppath.dirname(mappedPath), { chmod: 0o755, utimes: [defaultTime, defaultTime] });
72 targetFs.mkdirSync(mappedPath);
73 targetFs.chmodSync(mappedPath, mode);
74 targetFs.utimesSync(mappedPath, defaultTime, defaultTime);
75 next();
76 }
77 break;
78 case `file`:
79 {
80 targetFs.mkdirpSync(fslib_1.ppath.dirname(mappedPath), { chmod: 0o755, utimes: [defaultTime, defaultTime] });
81 const chunks = [];
82 stream.on(`data`, (chunk) => chunks.push(chunk));
83 stream.on(`end`, () => {
84 targetFs.writeFileSync(mappedPath, Buffer.concat(chunks));
85 targetFs.chmodSync(mappedPath, mode);
86 targetFs.utimesSync(mappedPath, defaultTime, defaultTime);
87 next();
88 });
89 }
90 break;
91 case `symlink`:
92 {
93 targetFs.mkdirpSync(fslib_1.ppath.dirname(mappedPath), { chmod: 0o755, utimes: [defaultTime, defaultTime] });
94 targetFs.symlinkSync(header.linkname, mappedPath);
95 (_b = targetFs.lutimesSync) === null || _b === void 0 ? void 0 : _b.call(targetFs, mappedPath, defaultTime, defaultTime);
96 next();
97 }
98 break;
99 default: {
100 stream.resume();
101 next();
102 }
103 }
104 });
105 const gunzipped = await gunzip(tgz);
106 return await new Promise((resolve, reject) => {
107 parser.on(`error`, (error) => {
108 reject(error);
109 });
110 parser.on(`finish`, () => {
111 resolve(targetFs);
112 });
113 parser.end(gunzipped);
114 });
115}
116exports.extractArchiveTo = extractArchiveTo;