From 22357494f424178cb416cdb7d93b26dd4f824b36 Mon Sep 17 00:00:00 2001 From: Michael Aquilina Date: Mon, 14 Jun 2021 12:28:46 +0100 Subject: [PATCH 1/3] fix: Use a null prototype object for this.files This approach is taken to prevent overriding object methods that would exist on a normal object Object.create({}) --- lib/index.js | 5 ++++- lib/object.js | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index b4498772..b4c95bad 100644 --- a/lib/index.js +++ b/lib/index.js @@ -19,7 +19,10 @@ function JSZip() { // "folder/" : {...}, // "folder/data.txt" : {...} // } - this.files = {}; + // NOTE: we use a null prototype because we do not + // want filenames like "toString" coming from a zip file + // to overwrite methods and attributes in a normal Object. + this.files = Object.create(null); this.comment = null; diff --git a/lib/object.js b/lib/object.js index 1c9d8e80..aec3db78 100644 --- a/lib/object.js +++ b/lib/object.js @@ -179,16 +179,16 @@ var out = { */ forEach: function(cb) { var filename, relativePath, file; + /* jshint ignore:start */ + // ignore warning about unwanted properties because this.files is a null prototype object for (filename in this.files) { - if (!this.files.hasOwnProperty(filename)) { - continue; - } file = this.files[filename]; relativePath = filename.slice(this.root.length, filename.length); if (relativePath && filename.slice(0, this.root.length) === this.root) { // the file is in the current root cb(relativePath, file); // TODO reverse the parameters ? need to be clean AND consistent with the filter search fn... } } + /* jshint ignore:end */ }, /** From d024c22adbbf51d842acf8660e49d87a9f02ad1c Mon Sep 17 00:00:00 2001 From: Michael Aquilina Date: Mon, 14 Jun 2021 14:06:24 +0100 Subject: [PATCH 2/3] test: Add test case for loading zip filenames which shadow method names --- test/asserts/load.js | 13 +++++++++++++ test/ref/pollution.zip | Bin 0 -> 480 bytes 2 files changed, 13 insertions(+) create mode 100644 test/ref/pollution.zip diff --git a/test/asserts/load.js b/test/asserts/load.js index c89978d5..4b9db830 100644 --- a/test/asserts/load.js +++ b/test/asserts/load.js @@ -17,6 +17,19 @@ QUnit.module("load", function () { })['catch'](JSZipTestUtils.assertNoError); }); + JSZipTestUtils.testZipFile("Load files which shadow Object prototype methods", "ref/pollution.zip", function(assert, file) { + var done = assert.async(); + assert.ok(typeof file === "string"); + JSZip.loadAsync(file) + .then(function (zip) { + return zip.file("toString").async("string"); + }) + .then(function(result) { + assert.equal(result, "hello\n", "the zip was correctly read."); + done(); + })['catch'](JSZipTestUtils.assertNoError); + }); + JSZipTestUtils.testZipFile("load(string) handles bytes > 255", "ref/all.zip", function(assert, file) { var done = assert.async(); // the method used to load zip with ajax will remove the extra bits. diff --git a/test/ref/pollution.zip b/test/ref/pollution.zip new file mode 100644 index 0000000000000000000000000000000000000000..c673c0a0aadaddb43a88460c871aad0f41d206f3 GIT binary patch literal 480 zcmWIWW@h1H0D-8yb3qCQR%UEKHVAVt$S{=T2bUCO=B0;*a56Bj2{@hr!lf1542&!< zm>C#YQh@3*Qgd?hxdPzkB%+za2{b1@zMv?-BtJeLY|vJqA=?NWRE}m4H_)Ku{Ji3l zqSEA&{35VX4}r!!!fg~IlN>WH-$?-7&cMJ3#7i1MEQDWKA$~>kXMi`tG)zAto8|#D s4avtq<3K*fV;rVWk&T-OG!DhzKm$Sk#xRf-6m1O5K==+w-vMzL06Aq~cmMzZ literal 0 HcmV?d00001 From bb38812e1a3e93202aaba41465d41de382226d51 Mon Sep 17 00:00:00 2001 From: Stuart Knightley Date: Wed, 23 Jun 2021 09:34:53 -0700 Subject: [PATCH 3/3] Ensure prototype isn't modified by zip file --- test/asserts/load.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/asserts/load.js b/test/asserts/load.js index 4b9db830..ce073cc3 100644 --- a/test/asserts/load.js +++ b/test/asserts/load.js @@ -22,8 +22,8 @@ QUnit.module("load", function () { assert.ok(typeof file === "string"); JSZip.loadAsync(file) .then(function (zip) { - return zip.file("toString").async("string"); - }) + assert.notEqual(Object.getPrototypeOf(zip.files), zip.files.__proto__); + return zip.file("__proto__").async("string"); }) .then(function(result) { assert.equal(result, "hello\n", "the zip was correctly read."); done();