@zowe/db2-for-zowe-cli 6.1.18 → 6.1.19
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/node_modules/adm-zip/adm-zip.js +32 -6
- package/node_modules/adm-zip/headers/entryHeader.js +13 -1
- package/node_modules/adm-zip/methods/inflater.js +33 -3
- package/node_modules/adm-zip/package.json +2 -2
- package/node_modules/adm-zip/util/errors.js +3 -0
- package/node_modules/adm-zip/util/utils.js +102 -14
- package/node_modules/adm-zip/zipEntry.js +43 -18
- package/node_modules/adm-zip/zipFile.js +10 -0
- package/node_modules/axios/README.md +41 -106
- package/node_modules/axios/dist/axios.js +931 -278
- package/node_modules/axios/dist/axios.min.js +2 -2
- package/node_modules/axios/dist/axios.min.js.map +1 -1
- package/node_modules/axios/dist/browser/axios.cjs +948 -268
- package/node_modules/axios/dist/esm/axios.js +948 -268
- package/node_modules/axios/dist/esm/axios.min.js +2 -2
- package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
- package/node_modules/axios/dist/node/axios.cjs +925 -242
- package/node_modules/axios/index.d.cts +20 -1
- package/node_modules/axios/index.d.ts +18 -1
- package/node_modules/axios/lib/adapters/fetch.js +73 -20
- package/node_modules/axios/lib/adapters/http.js +145 -26
- package/node_modules/axios/lib/adapters/xhr.js +120 -13
- package/node_modules/axios/lib/core/Axios.js +67 -12
- package/node_modules/axios/lib/core/AxiosError.js +59 -0
- package/node_modules/axios/lib/core/AxiosHeaders.js +17 -4
- package/node_modules/axios/lib/core/InterceptorManager.js +13 -2
- package/node_modules/axios/lib/core/assertParamsAcyclic.js +49 -0
- package/node_modules/axios/lib/core/createMultipartBody.js +37 -0
- package/node_modules/axios/lib/core/dispatchRequest.js +20 -0
- package/node_modules/axios/lib/core/mergeConfig.js +183 -120
- package/node_modules/axios/lib/defaults/transitional.js +1 -0
- package/node_modules/axios/lib/env/data.js +1 -1
- package/node_modules/axios/lib/helpers/AxiosTransformStream.js +11 -2
- package/node_modules/axios/lib/helpers/Http2Sessions.js +2 -1
- package/node_modules/axios/lib/helpers/composeSignals.js +6 -3
- package/node_modules/axios/lib/helpers/cookies.js +30 -6
- package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +34 -7
- package/node_modules/axios/lib/helpers/formDataToBlob.js +113 -0
- package/node_modules/axios/lib/helpers/formDataToJSON.js +25 -1
- package/node_modules/axios/lib/helpers/fromDataURI.js +8 -2
- package/node_modules/axios/lib/helpers/isURLSameOrigin.js +4 -9
- package/node_modules/axios/lib/helpers/parseHeaders.js +2 -1
- package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
- package/node_modules/axios/lib/helpers/resolveConfig.js +16 -3
- package/node_modules/axios/lib/helpers/shouldBypassProxy.js +16 -1
- package/node_modules/axios/lib/utils.js +61 -10
- package/node_modules/axios/package.json +1 -2
- package/node_modules/follow-redirects/README.md +27 -1
- package/node_modules/follow-redirects/index.js +11 -6
- package/node_modules/follow-redirects/package.json +1 -1
- package/node_modules/fs-extra/README.md +0 -1
- package/node_modules/fs-extra/lib/empty/index.js +4 -2
- package/node_modules/fs-extra/lib/util/stat.js +12 -2
- package/node_modules/fs-extra/package.json +1 -1
- package/node_modules/string_decoder/node_modules/safe-buffer/LICENSE +21 -0
- package/node_modules/string_decoder/node_modules/safe-buffer/README.md +584 -0
- package/node_modules/string_decoder/node_modules/safe-buffer/index.d.ts +187 -0
- package/node_modules/string_decoder/node_modules/safe-buffer/index.js +62 -0
- package/node_modules/string_decoder/node_modules/safe-buffer/package.json +37 -0
- package/node_modules/which-typed-array/CHANGELOG.md +14 -0
- package/node_modules/which-typed-array/README.md +0 -2
- package/node_modules/which-typed-array/index.d.ts +288 -11
- package/node_modules/which-typed-array/index.js +6 -7
- package/node_modules/which-typed-array/package.json +12 -11
- package/package.json +1 -6
- package/node_modules/which-typed-array/eslint.config.mjs +0 -12
- package/node_modules/which-typed-array/test/index.js +0 -105
- /package/node_modules/{tar-fs/node_modules/chownr → chownr}/LICENSE +0 -0
- /package/node_modules/{tar-fs/node_modules/chownr → chownr}/README.md +0 -0
- /package/node_modules/{tar-fs/node_modules/chownr → chownr}/chownr.js +0 -0
- /package/node_modules/{tar-fs/node_modules/chownr → chownr}/package.json +0 -0
- /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/.travis.yml +0 -0
- /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/LICENSE +0 -0
- /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/README.md +0 -0
- /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/lib/string_decoder.js +0 -0
- /package/node_modules/{tar-stream/node_modules/string_decoder → string_decoder}/package.json +0 -0
|
@@ -498,7 +498,11 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
498
498
|
addLocalFolderAsync2: function (options, callback) {
|
|
499
499
|
const self = this;
|
|
500
500
|
options = typeof options === "object" ? options : { localPath: options };
|
|
501
|
-
|
|
501
|
+
// Resolve the local filesystem path with the platform resolver. Do NOT
|
|
502
|
+
// run it through fixPath: that normalizes ZIP-internal paths to POSIX
|
|
503
|
+
// and prepends "/", which turns a Windows path like C:\dir into
|
|
504
|
+
// \C:\dir, so readdir finds nothing and the archive comes out empty.
|
|
505
|
+
const localPath = pth.resolve(options.localPath);
|
|
502
506
|
let { zipPath, filter, namefix } = options;
|
|
503
507
|
|
|
504
508
|
if (filter instanceof RegExp) {
|
|
@@ -533,14 +537,21 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
533
537
|
|
|
534
538
|
filetools.fs.open(localPath, "r", function (err) {
|
|
535
539
|
if (err && err.code === "ENOENT") {
|
|
536
|
-
callback(
|
|
540
|
+
// callback is (err, done); errors belong in the first argument,
|
|
541
|
+
// otherwise addLocalFolderPromise treats the error as "done" and
|
|
542
|
+
// resolves instead of rejecting.
|
|
543
|
+
callback(Utils.Errors.FILE_NOT_FOUND(localPath), false);
|
|
537
544
|
} else if (err) {
|
|
538
|
-
callback(
|
|
545
|
+
callback(err, false);
|
|
539
546
|
} else {
|
|
540
547
|
filetools.findFilesAsync(localPath, function (err, fileEntries) {
|
|
541
|
-
if (err) return callback(err);
|
|
548
|
+
if (err) return callback(err, false);
|
|
542
549
|
fileEntries = fileEntries.filter((dir) => filter(relPathFix(dir)));
|
|
543
|
-
|
|
550
|
+
// Nothing to add (empty folder or everything filtered out) is a
|
|
551
|
+
// success, not an error. Report done and stop, otherwise the
|
|
552
|
+
// reduce below runs and the callback fires a second time -- and
|
|
553
|
+
// signalling done=false left addLocalFolderPromise hanging.
|
|
554
|
+
if (!fileEntries.length) return callback(undefined, true);
|
|
544
555
|
|
|
545
556
|
setImmediate(
|
|
546
557
|
fileEntries.reverse().reduce(function (next, entry) {
|
|
@@ -575,7 +586,7 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
575
586
|
addLocalFolderPromise: function (localPath, props) {
|
|
576
587
|
return new Promise((resolve, reject) => {
|
|
577
588
|
this.addLocalFolderAsync2(Object.assign({ localPath }, props), (err, done) => {
|
|
578
|
-
if (err) reject(err);
|
|
589
|
+
if (err) return reject(err);
|
|
579
590
|
if (done) resolve(this);
|
|
580
591
|
});
|
|
581
592
|
});
|
|
@@ -709,6 +720,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
709
720
|
// collapsed subdirectories together (issue #306).
|
|
710
721
|
var name = canonical(maintainEntryPath ? child.entryName : child.entryName.substring(item.entryName.length));
|
|
711
722
|
var childName = sanitize(targetPath, name);
|
|
723
|
+
// reject writing through a pre-existing symlink inside the target
|
|
724
|
+
filetools.assertPathSafe(targetPath, childName);
|
|
712
725
|
// The reverse operation for attr depend on method addFile()
|
|
713
726
|
const fileAttr = keepOriginalPermission ? child.header.fileAttr : undefined;
|
|
714
727
|
filetools.writeFileTo(childName, content, overwrite, fileAttr);
|
|
@@ -719,6 +732,9 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
719
732
|
var content = item.getData(_zip.password);
|
|
720
733
|
if (!content) throw Utils.Errors.CANT_EXTRACT_FILE();
|
|
721
734
|
|
|
735
|
+
// reject writing through a pre-existing symlink inside the target
|
|
736
|
+
filetools.assertPathSafe(targetPath, target);
|
|
737
|
+
|
|
722
738
|
if (filetools.fs.existsSync(target) && !overwrite) {
|
|
723
739
|
throw Utils.Errors.CANT_OVERRIDE();
|
|
724
740
|
}
|
|
@@ -775,6 +791,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
775
791
|
const dirEntries = [];
|
|
776
792
|
_zip.entries.forEach(function (entry) {
|
|
777
793
|
var entryName = sanitize(targetPath, canonical(entry.entryName));
|
|
794
|
+
// reject writing through a pre-existing symlink inside the target
|
|
795
|
+
filetools.assertPathSafe(targetPath, entryName);
|
|
778
796
|
if (entry.isDirectory) {
|
|
779
797
|
filetools.makeDir(entryName);
|
|
780
798
|
// defer restoring the directory permission until its files are written
|
|
@@ -854,6 +872,8 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
854
872
|
// The reverse operation for attr depend on method addFile()
|
|
855
873
|
const dirAttr = keepOriginalPermission ? entry.header.fileAttr : undefined;
|
|
856
874
|
try {
|
|
875
|
+
// reject writing through a pre-existing symlink inside the target
|
|
876
|
+
filetools.assertPathSafe(targetPath, dirPath);
|
|
857
877
|
filetools.makeDir(dirPath);
|
|
858
878
|
} catch (er) {
|
|
859
879
|
callback(getError("Unable to create folder", dirPath));
|
|
@@ -890,6 +910,12 @@ module.exports = function (/**String*/ input, /** object */ options) {
|
|
|
890
910
|
} else {
|
|
891
911
|
const entryName = pth.normalize(canonical(entry.entryName));
|
|
892
912
|
const filePath = sanitize(targetPath, entryName);
|
|
913
|
+
try {
|
|
914
|
+
// reject writing through a pre-existing symlink inside the target
|
|
915
|
+
filetools.assertPathSafe(targetPath, filePath);
|
|
916
|
+
} catch (er) {
|
|
917
|
+
return next(er);
|
|
918
|
+
}
|
|
893
919
|
entry.getDataAsync(function (content, err_1) {
|
|
894
920
|
if (err_1) {
|
|
895
921
|
next(err_1);
|
|
@@ -185,7 +185,12 @@ module.exports = function () {
|
|
|
185
185
|
|
|
186
186
|
// get Unix file permissions
|
|
187
187
|
get fileAttr() {
|
|
188
|
-
|
|
188
|
+
// Mask to the 9 rwxrwxrwx bits only. The setuid (0o4000), setgid
|
|
189
|
+
// (0o2000) and sticky (0o1000) bits are attacker-controlled archive
|
|
190
|
+
// metadata; preserving them on extraction (keepOriginalPermission)
|
|
191
|
+
// lets a crafted zip plant a setuid-root binary when extracting as
|
|
192
|
+
// root, a local privilege escalation (GHSA-679w-jf3m-wh39).
|
|
193
|
+
return ((_attr || 0) >> 16) & 0o777;
|
|
189
194
|
},
|
|
190
195
|
|
|
191
196
|
get offset() {
|
|
@@ -212,6 +217,13 @@ module.exports = function () {
|
|
|
212
217
|
},
|
|
213
218
|
|
|
214
219
|
loadLocalHeaderFromBinary: function (/*Buffer*/ input) {
|
|
220
|
+
// The LOC offset comes from the central directory and is attacker
|
|
221
|
+
// controlled. Reject one that would read past the end of the buffer,
|
|
222
|
+
// otherwise readUInt32LE below throws a raw RangeError instead of a
|
|
223
|
+
// clean INVALID_LOC (and escapes the async error path).
|
|
224
|
+
if (_offset < 0 || _offset + Constants.LOCHDR > input.length) {
|
|
225
|
+
throw Utils.Errors.INVALID_LOC();
|
|
226
|
+
}
|
|
215
227
|
var data = input.slice(_offset, _offset + Constants.LOCHDR);
|
|
216
228
|
// 30 bytes and should start with "PK\003\004"
|
|
217
229
|
if (data.readUInt32LE(0) !== Constants.LOCSIG) {
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
const version = +(process?.versions?.node ?? "").split(".")[0] || 0;
|
|
2
|
+
const Errors = require("../util/errors");
|
|
2
3
|
|
|
3
4
|
module.exports = function (/*Buffer*/ inbuf, /*number*/ expectedLength) {
|
|
4
5
|
var zlib = require("zlib");
|
|
5
|
-
|
|
6
|
+
// Cap decompression output at the entry's declared uncompressed size to bound
|
|
7
|
+
// decompression bombs (CVE-2026-39244). A declared size of 0 must not disable
|
|
8
|
+
// the cap: a genuinely empty entry inflates to 0 bytes, so a 1-byte floor
|
|
9
|
+
// still lets it through while stopping a bomb that lies about its size
|
|
10
|
+
// (GHSA-rcw4-f5rp-g42v). zlib requires maxOutputLength >= 1.
|
|
11
|
+
const maxOutputLength = expectedLength > 0 ? expectedLength : 1;
|
|
12
|
+
const option = version >= 15 ? { maxOutputLength } : {};
|
|
6
13
|
|
|
7
14
|
return {
|
|
8
15
|
inflate: function () {
|
|
@@ -12,12 +19,35 @@ module.exports = function (/*Buffer*/ inbuf, /*number*/ expectedLength) {
|
|
|
12
19
|
inflateAsync: function (/*Function*/ callback) {
|
|
13
20
|
var tmp = zlib.createInflateRaw(option),
|
|
14
21
|
parts = [],
|
|
15
|
-
total = 0
|
|
22
|
+
total = 0,
|
|
23
|
+
done = false;
|
|
24
|
+
const fail = function (err) {
|
|
25
|
+
if (done) return;
|
|
26
|
+
done = true;
|
|
27
|
+
tmp.destroy();
|
|
28
|
+
callback && callback(Buffer.alloc(0), err);
|
|
29
|
+
};
|
|
30
|
+
// Route stream errors (e.g. Z_DATA_ERROR on malformed input) through the
|
|
31
|
+
// callback. Without an "error" listener zlib re-throws the event as an
|
|
32
|
+
// uncaught exception on a later tick, crashing the host process instead
|
|
33
|
+
// of failing the call (GHSA-8238-w5pm-2374).
|
|
34
|
+
tmp.on("error", function (err) {
|
|
35
|
+
fail(err);
|
|
36
|
+
});
|
|
16
37
|
tmp.on("data", function (data) {
|
|
17
|
-
|
|
38
|
+
if (done) return;
|
|
18
39
|
total += data.length;
|
|
40
|
+
// The streaming API ignores maxOutputLength, so enforce the cap by
|
|
41
|
+
// hand; otherwise the async path decompresses without limit while the
|
|
42
|
+
// sync path is capped (GHSA-v429-h5qx-84wm, GHSA-c6fg-446q-cg94).
|
|
43
|
+
if (total > maxOutputLength) {
|
|
44
|
+
return fail(Errors.MAX_OUTPUT_EXCEEDED());
|
|
45
|
+
}
|
|
46
|
+
parts.push(data);
|
|
19
47
|
});
|
|
20
48
|
tmp.on("end", function () {
|
|
49
|
+
if (done) return;
|
|
50
|
+
done = true;
|
|
21
51
|
var buf = Buffer.alloc(total),
|
|
22
52
|
written = 0;
|
|
23
53
|
buf.fill(0);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adm-zip",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Javascript implementation of zip for nodejs with support for electron original-fs. Allows user to create or extract zip files both in memory or to/from disk",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "mocha -R spec",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"chai": "^6.2.2",
|
|
51
51
|
"iconv-lite": "^0.7.2",
|
|
52
|
-
"mocha": "12.0.0
|
|
52
|
+
"mocha": "^12.0.0",
|
|
53
53
|
"prettier": "^3.8.1",
|
|
54
54
|
"rimraf": "^3.0.2"
|
|
55
55
|
}
|
|
@@ -12,6 +12,7 @@ const errors = {
|
|
|
12
12
|
/* ZipEntry error messages*/
|
|
13
13
|
NO_DATA: "Nothing to decompress",
|
|
14
14
|
BAD_CRC: "CRC32 checksum failed {0}",
|
|
15
|
+
MAX_OUTPUT_EXCEEDED: "Decompressed data exceeds the declared uncompressed size",
|
|
15
16
|
FILE_IN_THE_WAY: "There is a file in the way: {0}",
|
|
16
17
|
UNKNOWN_METHOD: "Invalid/unsupported compression method",
|
|
17
18
|
|
|
@@ -33,11 +34,13 @@ const errors = {
|
|
|
33
34
|
DISK_ENTRY_TOO_LARGE: "Number of disk entries is too large",
|
|
34
35
|
NO_ZIP: "No zip file was loaded",
|
|
35
36
|
NO_ENTRY: "Entry doesn't exist",
|
|
37
|
+
DUPLICATE_ENTRY: "Duplicate entry name {0}",
|
|
36
38
|
DIRECTORY_CONTENT_ERROR: "A directory cannot have content",
|
|
37
39
|
FILE_NOT_FOUND: 'File not found: "{0}"',
|
|
38
40
|
NOT_IMPLEMENTED: "Not implemented",
|
|
39
41
|
INVALID_FILENAME: "Invalid filename",
|
|
40
42
|
INVALID_FORMAT: "Invalid or unsupported zip format. No END header found",
|
|
43
|
+
ZIP64_VALUE_TOO_LARGE: "Zip64 value exceeds the maximum safe integer",
|
|
41
44
|
INVALID_PASS_PARAM: "Incompatible password parameter",
|
|
42
45
|
WRONG_PASSWORD: "Wrong Password",
|
|
43
46
|
|
|
@@ -159,8 +159,59 @@ Utils.prototype.writeFileToAsync = function (/*String*/ path, /*Buffer*/ content
|
|
|
159
159
|
});
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
// Guard extraction against writing through a symlink that already exists inside
|
|
163
|
+
// the target directory. sanitize() only proves the textual path stays under the
|
|
164
|
+
// root; it cannot see that a component on disk is a symlink pointing elsewhere,
|
|
165
|
+
// so open()/mkdir() would follow it and write outside the root. Walk every path
|
|
166
|
+
// component strictly below root and reject any that is a symlink. Components at
|
|
167
|
+
// or above root are the caller's own choice and are left untouched, so a root
|
|
168
|
+
// that itself lives under a symlink (e.g. /tmp on macOS) still extracts.
|
|
169
|
+
Utils.prototype.assertPathSafe = function (/*String*/ root, /*String*/ target) {
|
|
170
|
+
const self = this;
|
|
171
|
+
if (typeof self.fs.lstatSync !== "function") return;
|
|
172
|
+
|
|
173
|
+
const resolvedRoot = pth.resolve(root);
|
|
174
|
+
const resolvedTarget = pth.resolve(target);
|
|
175
|
+
if (resolvedTarget === resolvedRoot) return;
|
|
176
|
+
|
|
177
|
+
const rel = pth.relative(resolvedRoot, resolvedTarget);
|
|
178
|
+
// Not under root: sanitize() is responsible for that case; nothing to walk.
|
|
179
|
+
if (!rel || rel === ".." || rel.startsWith(".." + pth.sep) || pth.isAbsolute(rel)) return;
|
|
180
|
+
|
|
181
|
+
let cur = resolvedRoot;
|
|
182
|
+
for (const part of rel.split(pth.sep)) {
|
|
183
|
+
if (!part || part === ".") continue;
|
|
184
|
+
cur = pth.join(cur, part);
|
|
185
|
+
let stat;
|
|
186
|
+
try {
|
|
187
|
+
stat = self.fs.lstatSync(cur);
|
|
188
|
+
} catch (e) {
|
|
189
|
+
break; // component does not exist yet: nothing below it can be a symlink
|
|
190
|
+
}
|
|
191
|
+
if (stat.isSymbolicLink()) throw Errors.FILE_IN_THE_WAY(`"${cur}"`);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
162
195
|
Utils.prototype.findFiles = function (/*String*/ path) {
|
|
163
196
|
const self = this;
|
|
197
|
+
const canLstat = typeof self.fs.lstatSync === "function";
|
|
198
|
+
const rootReal = self.fs.realpathSync(path);
|
|
199
|
+
|
|
200
|
+
// A symlink whose target lies outside the folder being archived must not be
|
|
201
|
+
// followed: statSync would dereference it and copy the target's contents into
|
|
202
|
+
// the archive, disclosing files outside the root (GHSA-wx42-xcp7-pgr4). Allow
|
|
203
|
+
// symlinks that resolve to a location inside the root, reject any that escape.
|
|
204
|
+
function escapesRoot(/*String*/ p) {
|
|
205
|
+
if (!canLstat) return false;
|
|
206
|
+
if (!self.fs.lstatSync(p).isSymbolicLink()) return false;
|
|
207
|
+
let real;
|
|
208
|
+
try {
|
|
209
|
+
real = self.fs.realpathSync(p);
|
|
210
|
+
} catch (e) {
|
|
211
|
+
return true; // dangling or unresolvable symlink: do not follow
|
|
212
|
+
}
|
|
213
|
+
return !(real === rootReal || real.startsWith(rootReal + pth.sep));
|
|
214
|
+
}
|
|
164
215
|
|
|
165
216
|
function findSync(/*String*/ dir, /*RegExp*/ pattern, /*Boolean*/ recursive, /*Set*/ visited) {
|
|
166
217
|
if (typeof pattern === "boolean") {
|
|
@@ -170,6 +221,9 @@ Utils.prototype.findFiles = function (/*String*/ path) {
|
|
|
170
221
|
let files = [];
|
|
171
222
|
self.fs.readdirSync(dir).forEach(function (file) {
|
|
172
223
|
const path = pth.join(dir, file);
|
|
224
|
+
|
|
225
|
+
if (escapesRoot(path)) return;
|
|
226
|
+
|
|
173
227
|
const stat = self.fs.statSync(path);
|
|
174
228
|
|
|
175
229
|
if (!pattern || pattern.test(path)) {
|
|
@@ -191,7 +245,7 @@ Utils.prototype.findFiles = function (/*String*/ path) {
|
|
|
191
245
|
return files;
|
|
192
246
|
}
|
|
193
247
|
|
|
194
|
-
return findSync(path, undefined, true, new Set([
|
|
248
|
+
return findSync(path, undefined, true, new Set([rootReal]));
|
|
195
249
|
};
|
|
196
250
|
|
|
197
251
|
/**
|
|
@@ -217,6 +271,25 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
|
|
|
217
271
|
cb(err, err ? undefined : results);
|
|
218
272
|
};
|
|
219
273
|
|
|
274
|
+
const canLstat = typeof self.fs.lstat === "function";
|
|
275
|
+
let rootReal = null;
|
|
276
|
+
|
|
277
|
+
// Reject a symlink whose target escapes the root being archived, so its
|
|
278
|
+
// contents are not dereferenced and copied into the archive
|
|
279
|
+
// (GHSA-wx42-xcp7-pgr4). A symlink resolving to a location inside the root is
|
|
280
|
+
// allowed; a dangling or escaping one is skipped. Calls back (err, escapes).
|
|
281
|
+
const escapesRoot = function (file, cb) {
|
|
282
|
+
if (!canLstat) return cb(null, false);
|
|
283
|
+
self.fs.lstat(file, function (err, lst) {
|
|
284
|
+
if (err) return cb(err);
|
|
285
|
+
if (!lst || !lst.isSymbolicLink()) return cb(null, false);
|
|
286
|
+
self.fs.realpath(file, function (err, real) {
|
|
287
|
+
if (err) return cb(null, true); // dangling: do not follow
|
|
288
|
+
cb(null, !(real === rootReal || real.startsWith(rootReal + pth.sep)));
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
|
|
220
293
|
// Descend by resolved real path and skip directories already visited, so a
|
|
221
294
|
// symlink pointing back to an ancestor cannot recurse forever (issue #541).
|
|
222
295
|
const walk = function (dir, visited, done) {
|
|
@@ -226,27 +299,34 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
|
|
|
226
299
|
if (!pending) return done();
|
|
227
300
|
list.forEach(function (name) {
|
|
228
301
|
const file = pth.join(dir, name);
|
|
229
|
-
|
|
302
|
+
escapesRoot(file, function (err, escapes) {
|
|
230
303
|
if (err) return done(err);
|
|
231
|
-
if (
|
|
232
|
-
if (!--pending) done();
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
results.push(pth.normalize(file) + (stat.isDirectory() ? self.sep : ""));
|
|
236
|
-
if (!stat.isDirectory()) {
|
|
304
|
+
if (escapes) {
|
|
237
305
|
if (!--pending) done();
|
|
238
306
|
return;
|
|
239
307
|
}
|
|
240
|
-
self.fs.
|
|
308
|
+
self.fs.stat(file, function (err, stat) {
|
|
241
309
|
if (err) return done(err);
|
|
242
|
-
if (
|
|
310
|
+
if (!stat) {
|
|
243
311
|
if (!--pending) done();
|
|
244
312
|
return;
|
|
245
313
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (err) return done(err);
|
|
314
|
+
results.push(pth.normalize(file) + (stat.isDirectory() ? self.sep : ""));
|
|
315
|
+
if (!stat.isDirectory()) {
|
|
249
316
|
if (!--pending) done();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
self.fs.realpath(file, function (err, realDir) {
|
|
320
|
+
if (err) return done(err);
|
|
321
|
+
if (visited.has(realDir)) {
|
|
322
|
+
if (!--pending) done();
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
visited.add(realDir);
|
|
326
|
+
walk(file, visited, function (err) {
|
|
327
|
+
if (err) return done(err);
|
|
328
|
+
if (!--pending) done();
|
|
329
|
+
});
|
|
250
330
|
});
|
|
251
331
|
});
|
|
252
332
|
});
|
|
@@ -256,6 +336,7 @@ Utils.prototype.findFilesAsync = function (dir, cb) {
|
|
|
256
336
|
|
|
257
337
|
self.fs.realpath(dir, function (err, realDir) {
|
|
258
338
|
if (err) return finish(err);
|
|
339
|
+
rootReal = realDir;
|
|
259
340
|
walk(dir, new Set([realDir]), finish);
|
|
260
341
|
});
|
|
261
342
|
};
|
|
@@ -365,7 +446,14 @@ Utils.toBuffer = function toBuffer(/*buffer, Uint8Array, string*/ input, /* func
|
|
|
365
446
|
Utils.readBigUInt64LE = function (/*Buffer*/ buffer, /*int*/ index) {
|
|
366
447
|
const lo = buffer.readUInt32LE(index);
|
|
367
448
|
const hi = buffer.readUInt32LE(index + 4);
|
|
368
|
-
|
|
449
|
+
const value = hi * 0x100000000 + lo;
|
|
450
|
+
// The result is a JS number, so values above 2^53 - 1 cannot be represented
|
|
451
|
+
// exactly. These are zip64 sizes/offsets/counts used as buffer indices; a
|
|
452
|
+
// silently rounded value would misparse the archive. Reject instead.
|
|
453
|
+
if (value > Number.MAX_SAFE_INTEGER) {
|
|
454
|
+
throw Errors.ZIP64_VALUE_TOO_LARGE();
|
|
455
|
+
}
|
|
456
|
+
return value;
|
|
369
457
|
};
|
|
370
458
|
|
|
371
459
|
Utils.writeBigUInt64LE = function (/*Buffer*/ buffer, /*Number*/ value, /*int*/ index) {
|
|
@@ -25,7 +25,16 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
|
|
|
25
25
|
return Buffer.alloc(0);
|
|
26
26
|
}
|
|
27
27
|
_extralocal = _centralHeader.loadLocalHeaderFromBinary(input);
|
|
28
|
-
|
|
28
|
+
const dataOffset = _centralHeader.realDataOffset;
|
|
29
|
+
const dataEnd = dataOffset + _centralHeader.compressedSize;
|
|
30
|
+
// The offsets and sizes come from attacker-controlled headers. Require the
|
|
31
|
+
// declared compressed extent to be fully present rather than letting slice()
|
|
32
|
+
// silently clamp to a short buffer (which only surfaces later as a CRC
|
|
33
|
+
// failure). Fail loudly with a header error instead (GHSA-wwrv-q5gf-5843).
|
|
34
|
+
if (dataOffset < 0 || dataEnd < dataOffset || dataEnd > input.length) {
|
|
35
|
+
throw Utils.Errors.INVALID_LOC();
|
|
36
|
+
}
|
|
37
|
+
return input.slice(dataOffset, dataEnd);
|
|
29
38
|
}
|
|
30
39
|
|
|
31
40
|
function crc32OK(data) {
|
|
@@ -60,19 +69,32 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
|
|
|
60
69
|
return Buffer.alloc(0);
|
|
61
70
|
}
|
|
62
71
|
|
|
63
|
-
var compressedData
|
|
72
|
+
var compressedData;
|
|
73
|
+
try {
|
|
74
|
+
compressedData = getCompressedDataFromZip();
|
|
64
75
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
if (compressedData.length === 0) {
|
|
77
|
+
// File is empty, nothing to decompress.
|
|
78
|
+
if (async && callback) callback(compressedData);
|
|
79
|
+
return compressedData;
|
|
80
|
+
}
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
if (_centralHeader.encrypted) {
|
|
83
|
+
if ("string" !== typeof pass && !Buffer.isBuffer(pass)) {
|
|
84
|
+
throw Utils.Errors.INVALID_PASS_PARAM();
|
|
85
|
+
}
|
|
86
|
+
compressedData = Methods.ZipCrypto.decrypt(compressedData, _centralHeader, pass);
|
|
87
|
+
}
|
|
88
|
+
} catch (err) {
|
|
89
|
+
// These synchronous parse/setup steps run before any callback fires.
|
|
90
|
+
// In async mode a malformed local header (e.g. a bad LOC offset) would
|
|
91
|
+
// otherwise throw out of getDataAsync and bypass the callback error
|
|
92
|
+
// channel, crashing the caller. Route it through the callback instead.
|
|
93
|
+
if (async && callback) {
|
|
94
|
+
callback(Buffer.alloc(0), err);
|
|
95
|
+
return Buffer.alloc(0);
|
|
74
96
|
}
|
|
75
|
-
|
|
97
|
+
throw err;
|
|
76
98
|
}
|
|
77
99
|
|
|
78
100
|
var data;
|
|
@@ -107,13 +129,16 @@ module.exports = function (/** object */ options, /*Buffer*/ input) {
|
|
|
107
129
|
}
|
|
108
130
|
return data;
|
|
109
131
|
} else {
|
|
110
|
-
inflater.inflateAsync(function (result) {
|
|
111
|
-
if (callback)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
132
|
+
inflater.inflateAsync(function (result, err) {
|
|
133
|
+
if (!callback) return;
|
|
134
|
+
if (err) {
|
|
135
|
+
// surface inflater/stream failures instead of validating
|
|
136
|
+
// the empty placeholder buffer against the CRC
|
|
137
|
+
callback(Buffer.alloc(0), err);
|
|
138
|
+
} else if (!crc32OK(result)) {
|
|
139
|
+
callback(result, Utils.Errors.BAD_CRC()); //si added error
|
|
140
|
+
} else {
|
|
141
|
+
callback(result);
|
|
117
142
|
}
|
|
118
143
|
});
|
|
119
144
|
}
|
|
@@ -78,6 +78,16 @@ module.exports = function (/*Buffer|null*/ inBuffer, /** object */ options) {
|
|
|
78
78
|
|
|
79
79
|
index += entry.header.centralHeaderSize;
|
|
80
80
|
|
|
81
|
+
// Reject archives that declare the same entry name twice. adm-zip keeps
|
|
82
|
+
// every entry in entryList but only the last in entryTable, so getEntry()
|
|
83
|
+
// (table) and extractAllTo() (list) could resolve one name to different
|
|
84
|
+
// content: an app that validates entry bytes via getEntry() before
|
|
85
|
+
// extracting could approve one file while a different one lands on disk
|
|
86
|
+
// (GHSA-p634-w6r4-rjp2). Fail closed on the ambiguity.
|
|
87
|
+
if (entry.entryName in entryTable) {
|
|
88
|
+
throw Utils.Errors.DUPLICATE_ENTRY(`"${entry.entryName}"`);
|
|
89
|
+
}
|
|
90
|
+
|
|
81
91
|
entryList[i] = entry;
|
|
82
92
|
entryTable[entry.entryName] = entry;
|
|
83
93
|
}
|