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.
@@ -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 whent cancellation is requested.
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 whent cancellation is requested.
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
@@ -173,4 +173,3 @@ function isRootPath(target) {
173
173
  return false;
174
174
  }
175
175
  exports.isRootPath = isRootPath;
176
- //# sourceMappingURL=fs.js.map
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.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
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" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
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, fileName, targetFolder, token);
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, decodeEntryFileName, targetPath, token) {
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(path.join(targetPath, decodeEntryFileName));
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, decodeEntryFileName, targetPath, token);
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, decodeEntryFileName, targetPath, token) {
194
- const filePath = path.join(targetPath, decodeEntryFileName);
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 realFilePath = await util.realpath(fileDir);
198
- const realTargetPath = await util.realpath(targetPath);
199
- if (realFilePath.indexOf(realTargetPath) !== 0) {
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, filePath, token);
251
+ await this.writeEntryToFile(readStream, entry, entryContext, token);
206
252
  zfile.readEntry();
207
253
  }
208
- async writeEntryToFile(readStream, entry, filePath, token) {
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 (/\/$/.test(linkContent)) {
261
- linkType = "dir";
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
- try {
269
- const stat = await util.stat(targetPath);
270
- if (stat.isDirectory()) {
271
- linkType = "dir";
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
@@ -47,4 +47,3 @@ function readlink(path) {
47
47
  return util.promisify(fs.readlink)(path);
48
48
  }
49
49
  exports.readlink = readlink;
50
- //# sourceMappingURL=util.js.map
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.0",
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": "^7.0.2",
32
- "@types/node": "^8.10.61",
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": "^7.2.0",
40
+ "mocha": "^9.2.0",
36
41
  "rimraf": "^3.0.2",
37
- "typescript": "^3.9.3"
42
+ "typescript": "^4.1.3"
38
43
  }
39
44
  }