zip-lib 0.7.0 → 0.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cancelable.d.ts +1 -1
- package/lib/cancelable.js +1 -2
- package/lib/fs.js +0 -1
- package/lib/index.js +6 -3
- package/lib/unzip.js +80 -29
- package/lib/util.js +0 -1
- package/lib/zip.js +2 -3
- package/package.json +12 -7
package/lib/cancelable.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare class CancellationToken {
|
|
|
14
14
|
/**
|
|
15
15
|
* Subscribe a callback when cancellation is requested. The callback
|
|
16
16
|
* only ever fires `once` as cancellation can only happen once.
|
|
17
|
-
* @param cb A function will be called
|
|
17
|
+
* @param cb A function will be called when cancellation is requested.
|
|
18
18
|
* @returns A function that Unsubscribe the cancellation callback.
|
|
19
19
|
*/
|
|
20
20
|
onCancelled(cb: () => void): () => void;
|
package/lib/cancelable.js
CHANGED
|
@@ -15,7 +15,7 @@ class CancellationToken {
|
|
|
15
15
|
/**
|
|
16
16
|
* Subscribe a callback when cancellation is requested. The callback
|
|
17
17
|
* only ever fires `once` as cancellation can only happen once.
|
|
18
|
-
* @param cb A function will be called
|
|
18
|
+
* @param cb A function will be called when cancellation is requested.
|
|
19
19
|
* @returns A function that Unsubscribe the cancellation callback.
|
|
20
20
|
*/
|
|
21
21
|
onCancelled(cb) {
|
|
@@ -63,4 +63,3 @@ class Cancelable {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
exports.Cancelable = Cancelable;
|
|
66
|
-
//# sourceMappingURL=cancelable.js.map
|
package/lib/fs.js
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
8
12
|
}));
|
|
9
13
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
15
|
};
|
|
12
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
17
|
exports.extract = exports.archiveFolder = exports.archiveFile = void 0;
|
|
@@ -50,4 +54,3 @@ function extract(zipFile, targetFolder, options) {
|
|
|
50
54
|
return unzip.extract(zipFile, targetFolder);
|
|
51
55
|
}
|
|
52
56
|
exports.extract = extract;
|
|
53
|
-
//# sourceMappingURL=index.js.map
|
package/lib/unzip.js
CHANGED
|
@@ -34,6 +34,50 @@ class EntryEvent {
|
|
|
34
34
|
this._isPrevented = false;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
class EntryContext {
|
|
38
|
+
constructor(_targetFolder, _realTargetFolder, symlinkAsFileOnWindows) {
|
|
39
|
+
this._targetFolder = _targetFolder;
|
|
40
|
+
this._realTargetFolder = _realTargetFolder;
|
|
41
|
+
this.symlinkAsFileOnWindows = symlinkAsFileOnWindows;
|
|
42
|
+
this._symlinkFileNames = [];
|
|
43
|
+
}
|
|
44
|
+
get decodeEntryFileName() {
|
|
45
|
+
return this._decodeEntryFileName;
|
|
46
|
+
}
|
|
47
|
+
set decodeEntryFileName(name) {
|
|
48
|
+
this._decodeEntryFileName = name;
|
|
49
|
+
}
|
|
50
|
+
get targetFolder() {
|
|
51
|
+
return this._targetFolder;
|
|
52
|
+
}
|
|
53
|
+
get realTargetFolder() {
|
|
54
|
+
return this._realTargetFolder;
|
|
55
|
+
}
|
|
56
|
+
get symlinkFileNames() {
|
|
57
|
+
return this._symlinkFileNames;
|
|
58
|
+
}
|
|
59
|
+
getFilePath() {
|
|
60
|
+
return path.join(this.targetFolder, this.decodeEntryFileName);
|
|
61
|
+
}
|
|
62
|
+
async isOutsideTargetFolder(tpath) {
|
|
63
|
+
if (this.symlinkFileNames.length === 0) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (process.platform === "win32" &&
|
|
67
|
+
this.symlinkAsFileOnWindows) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
for (const fileName of this.symlinkFileNames) {
|
|
71
|
+
if (tpath.includes(fileName)) {
|
|
72
|
+
const realFilePath = await util.realpath(tpath);
|
|
73
|
+
if (realFilePath.indexOf(this.realTargetFolder) !== 0) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
37
81
|
/**
|
|
38
82
|
* Extract the zip file.
|
|
39
83
|
*/
|
|
@@ -62,6 +106,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
62
106
|
return Promise.reject(this.canceledError());
|
|
63
107
|
}
|
|
64
108
|
await exfs.ensureFolder(targetFolder);
|
|
109
|
+
const realTargetFolder = await util.realpath(targetFolder);
|
|
65
110
|
const zfile = await this.openZip(zipFile, token);
|
|
66
111
|
this.zipFile = zfile;
|
|
67
112
|
zfile.readEntry();
|
|
@@ -93,6 +138,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
93
138
|
this.closeZip();
|
|
94
139
|
return;
|
|
95
140
|
}
|
|
141
|
+
const entryContext = new EntryContext(targetFolder, realTargetFolder, this.symlinkToFile());
|
|
96
142
|
const entryEvent = new EntryEvent(total);
|
|
97
143
|
zfile.on("entry", async (entry) => {
|
|
98
144
|
// use UTF-8 in all situations
|
|
@@ -111,13 +157,14 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
111
157
|
}
|
|
112
158
|
entryEvent.entryName = fileName;
|
|
113
159
|
this.onEntryCallback(entryEvent);
|
|
160
|
+
entryContext.decodeEntryFileName = fileName;
|
|
114
161
|
try {
|
|
115
162
|
if (entryEvent.isPrevented) {
|
|
116
163
|
entryEvent.reset();
|
|
117
164
|
zfile.readEntry();
|
|
118
165
|
}
|
|
119
166
|
else {
|
|
120
|
-
await this.handleEntry(zfile, entry,
|
|
167
|
+
await this.handleEntry(zfile, entry, entryContext, token);
|
|
121
168
|
}
|
|
122
169
|
extractedEntriesCount++;
|
|
123
170
|
if (extractedEntriesCount === total) {
|
|
@@ -165,17 +212,17 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
165
212
|
});
|
|
166
213
|
});
|
|
167
214
|
}
|
|
168
|
-
async handleEntry(zfile, entry,
|
|
169
|
-
if (/\/$/.test(decodeEntryFileName)) {
|
|
215
|
+
async handleEntry(zfile, entry, entryContext, token) {
|
|
216
|
+
if (/\/$/.test(entryContext.decodeEntryFileName)) {
|
|
170
217
|
// Directory file names end with '/'.
|
|
171
218
|
// Note that entires for directories themselves are optional.
|
|
172
219
|
// An entry's fileName implicitly requires its parent directories to exist.
|
|
173
|
-
await exfs.ensureFolder(
|
|
220
|
+
await exfs.ensureFolder(entryContext.getFilePath());
|
|
174
221
|
zfile.readEntry();
|
|
175
222
|
}
|
|
176
223
|
else {
|
|
177
224
|
// file entry
|
|
178
|
-
await this.extractEntry(zfile, entry,
|
|
225
|
+
await this.extractEntry(zfile, entry, entryContext, token);
|
|
179
226
|
}
|
|
180
227
|
}
|
|
181
228
|
openZipFileStream(zfile, entry, token) {
|
|
@@ -190,22 +237,21 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
190
237
|
});
|
|
191
238
|
});
|
|
192
239
|
}
|
|
193
|
-
async extractEntry(zfile, entry,
|
|
194
|
-
const filePath =
|
|
240
|
+
async extractEntry(zfile, entry, entryContext, token) {
|
|
241
|
+
const filePath = entryContext.getFilePath();
|
|
195
242
|
const fileDir = path.dirname(filePath);
|
|
196
243
|
await exfs.ensureFolder(fileDir);
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const error = new Error(`Refuse to write file outside "${targetPath}", path: "${realFilePath}"`);
|
|
244
|
+
const outside = await entryContext.isOutsideTargetFolder(fileDir);
|
|
245
|
+
if (outside) {
|
|
246
|
+
const error = new Error(`Refuse to write file outside "${entryContext.targetFolder}", file: "${filePath}"`);
|
|
201
247
|
error.name = "AFWRITE";
|
|
202
248
|
return Promise.reject(error);
|
|
203
249
|
}
|
|
204
250
|
const readStream = await this.openZipFileStream(zfile, entry, token);
|
|
205
|
-
await this.writeEntryToFile(readStream, entry,
|
|
251
|
+
await this.writeEntryToFile(readStream, entry, entryContext, token);
|
|
206
252
|
zfile.readEntry();
|
|
207
253
|
}
|
|
208
|
-
async writeEntryToFile(readStream, entry,
|
|
254
|
+
async writeEntryToFile(readStream, entry, entryContext, token) {
|
|
209
255
|
let fileStream;
|
|
210
256
|
token.onCancelled(() => {
|
|
211
257
|
if (fileStream) {
|
|
@@ -215,12 +261,16 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
215
261
|
});
|
|
216
262
|
return new Promise(async (c, e) => {
|
|
217
263
|
try {
|
|
264
|
+
const filePath = entryContext.getFilePath();
|
|
218
265
|
const mode = this.modeFromEntry(entry);
|
|
219
266
|
// see https://unix.stackexchange.com/questions/193465/what-file-mode-is-a-symlink
|
|
220
267
|
const isSymlink = ((mode & 0o170000) === 0o120000);
|
|
221
268
|
readStream.once("error", (err) => {
|
|
222
269
|
e(this.wrapError(err, token.isCancelled));
|
|
223
270
|
});
|
|
271
|
+
if (isSymlink) {
|
|
272
|
+
entryContext.symlinkFileNames.push(entryContext.decodeEntryFileName);
|
|
273
|
+
}
|
|
224
274
|
if (isSymlink && !this.symlinkToFile()) {
|
|
225
275
|
let linkContent = "";
|
|
226
276
|
readStream.on("data", (chunk) => {
|
|
@@ -236,7 +286,7 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
236
286
|
});
|
|
237
287
|
}
|
|
238
288
|
else {
|
|
239
|
-
fileStream = fs_1.createWriteStream(filePath, { mode });
|
|
289
|
+
fileStream = (0, fs_1.createWriteStream)(filePath, { mode });
|
|
240
290
|
fileStream.once("close", () => c());
|
|
241
291
|
fileStream.once("error", (err) => {
|
|
242
292
|
e(this.wrapError(err, token.isCancelled));
|
|
@@ -257,22 +307,24 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
257
307
|
}
|
|
258
308
|
async createSymlink(linkContent, des) {
|
|
259
309
|
let linkType = "file";
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
else {
|
|
264
|
-
let targetPath = linkContent;
|
|
265
|
-
if (!path.isAbsolute(linkContent)) {
|
|
266
|
-
targetPath = path.join(path.dirname(des), linkContent);
|
|
310
|
+
if (process.platform === 'win32') {
|
|
311
|
+
if (/\/$/.test(linkContent)) {
|
|
312
|
+
linkType = "dir";
|
|
267
313
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (
|
|
271
|
-
|
|
314
|
+
else {
|
|
315
|
+
let targetPath = linkContent;
|
|
316
|
+
if (!path.isAbsolute(linkContent)) {
|
|
317
|
+
targetPath = path.join(path.dirname(des), linkContent);
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
const stat = await util.stat(targetPath);
|
|
321
|
+
if (stat.isDirectory()) {
|
|
322
|
+
linkType = "dir";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
// ignore
|
|
272
327
|
}
|
|
273
|
-
}
|
|
274
|
-
catch (error) {
|
|
275
|
-
// ignore
|
|
276
328
|
}
|
|
277
329
|
}
|
|
278
330
|
await util.symlink(linkContent, des, linkType);
|
|
@@ -304,4 +356,3 @@ class Unzip extends cancelable_1.Cancelable {
|
|
|
304
356
|
}
|
|
305
357
|
}
|
|
306
358
|
exports.Unzip = Unzip;
|
|
307
|
-
//# sourceMappingURL=unzip.js.map
|
package/lib/util.js
CHANGED
package/lib/zip.js
CHANGED
|
@@ -70,7 +70,7 @@ class Zip extends cancelable_1.Cancelable {
|
|
|
70
70
|
});
|
|
71
71
|
const zip = this.yazlFile;
|
|
72
72
|
if (!token.isCancelled) {
|
|
73
|
-
this.zipStream = fs_1.createWriteStream(zipFile);
|
|
73
|
+
this.zipStream = (0, fs_1.createWriteStream)(zipFile);
|
|
74
74
|
this.zipStream.once("error", (err) => {
|
|
75
75
|
e(this.wrapError(err, token.isCancelled));
|
|
76
76
|
});
|
|
@@ -145,7 +145,7 @@ class Zip extends cancelable_1.Cancelable {
|
|
|
145
145
|
}
|
|
146
146
|
addFileStream(zip, file, metadataPath, token) {
|
|
147
147
|
return new Promise((c, e) => {
|
|
148
|
-
const fileStream = fs_1.createReadStream(file.path);
|
|
148
|
+
const fileStream = (0, fs_1.createReadStream)(file.path);
|
|
149
149
|
fileStream.once("error", (err) => {
|
|
150
150
|
const wrappedError = this.wrapError(err, token.isCancelled);
|
|
151
151
|
this.stopPipe(wrappedError);
|
|
@@ -211,4 +211,3 @@ class Zip extends cancelable_1.Cancelable {
|
|
|
211
211
|
}
|
|
212
212
|
}
|
|
213
213
|
exports.Zip = Zip;
|
|
214
|
-
//# sourceMappingURL=zip.js.map
|
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zip-lib",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "zip and unzip library for node",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"compile": "rimraf ./lib && tsc -p ./src/tsconfig.json",
|
|
8
|
+
"release": "rimraf ./lib && tsc -p ./src/tsconfig.release.json",
|
|
8
9
|
"compile-test": "rimraf ./test/out && tsc -p ./test/src/tsconfig.json",
|
|
9
|
-
"test": "node ./test/src/before.js && mocha ./test/out --timeout 10000"
|
|
10
|
+
"test": "node ./test/src/before.js && mocha ./test/out --timeout 10000",
|
|
11
|
+
"pack": "npm run release && npm pack"
|
|
10
12
|
},
|
|
11
13
|
"repository": {
|
|
12
14
|
"type": "git",
|
|
@@ -17,9 +19,12 @@
|
|
|
17
19
|
},
|
|
18
20
|
"keywords": [
|
|
19
21
|
"zip",
|
|
22
|
+
"folder",
|
|
20
23
|
"unzip",
|
|
21
24
|
"archive",
|
|
22
|
-
"extract"
|
|
25
|
+
"extract",
|
|
26
|
+
"promise",
|
|
27
|
+
"async"
|
|
23
28
|
],
|
|
24
29
|
"author": "fpsqdb",
|
|
25
30
|
"license": "MIT",
|
|
@@ -28,12 +33,12 @@
|
|
|
28
33
|
"yazl": "^2.5.1"
|
|
29
34
|
},
|
|
30
35
|
"devDependencies": {
|
|
31
|
-
"@types/mocha": "^
|
|
32
|
-
"@types/node": "^8.10.
|
|
36
|
+
"@types/mocha": "^9.1.0",
|
|
37
|
+
"@types/node": "^8.10.66",
|
|
33
38
|
"@types/yauzl": "^2.9.1",
|
|
34
39
|
"@types/yazl": "^2.4.2",
|
|
35
|
-
"mocha": "^
|
|
40
|
+
"mocha": "^9.2.0",
|
|
36
41
|
"rimraf": "^3.0.2",
|
|
37
|
-
"typescript": "^
|
|
42
|
+
"typescript": "^4.1.3"
|
|
38
43
|
}
|
|
39
44
|
}
|