diff --git a/adm-zip.js b/adm-zip.js index b08f731..f38797d 100644 --- a/adm-zip.js +++ b/adm-zip.js @@ -472,7 +472,7 @@ module.exports = function (/**String*/ input, /** object */ options) { * @return Array */ getEntries: function (/**String*/ password) { - _zip.password=password; + _zip.password = password; return _zip ? _zip.entries : []; }, @@ -635,13 +635,20 @@ module.exports = function (/**String*/ input, /** object */ options) { * @param callback The callback will be executed when all entries are extracted successfully or any error is thrown. */ extractAllToAsync: function (/**String*/ targetPath, /**Boolean*/ overwrite, /**Boolean*/ keepOriginalPermission, /**Function*/ callback) { + if (typeof overwrite === "function" && !callback) callback = overwrite; overwrite = get_Bool(overwrite, false); if (typeof keepOriginalPermission === "function" && !callback) callback = keepOriginalPermission; keepOriginalPermission = get_Bool(keepOriginalPermission, false); if (!callback) { - callback = function (err) { - throw new Error(err); - }; + return new Promise((resolve, reject) => { + this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function (err) { + if (err) { + reject(err); + } else { + resolve(this); + } + }); + }); } if (!_zip) { callback(new Error(Utils.Errors.NO_ZIP)); @@ -655,12 +662,12 @@ module.exports = function (/**String*/ input, /** object */ options) { // separate directories from files const dirEntries = []; - const fileEntries = new Set(); + const fileEntries = []; _zip.entries.forEach((e) => { if (e.isDirectory) { dirEntries.push(e); } else { - fileEntries.add(e); + fileEntries.push(e); } }); @@ -680,47 +687,38 @@ module.exports = function (/**String*/ input, /** object */ options) { } } - // callback wrapper, for some house keeping - const done = () => { - if (fileEntries.size === 0) { - callback(); - } - }; - - // Extract file entries asynchronously - for (const entry of fileEntries.values()) { - const entryName = pth.normalize(canonical(entry.entryName.toString())); - const filePath = sanitize(targetPath, entryName); - entry.getDataAsync(function (content, err_1) { - if (err_1) { - callback(new Error(err_1)); - return; - } - if (!content) { - callback(new Error(Utils.Errors.CANT_EXTRACT_FILE)); + fileEntries.reverse().reduce(function (next, entry) { + return function (err) { + if (err) { + next(err); } else { - // The reverse operation for attr depend on method addFile() - const fileAttr = keepOriginalPermission ? entry.header.fileAttr : undefined; - filetools.writeFileToAsync(filePath, content, overwrite, fileAttr, function (succ) { - if (!succ) { - callback(getError("Unable to write file", filePath)); - return; + const entryName = pth.normalize(canonical(entry.entryName.toString())); + const filePath = sanitize(targetPath, entryName); + entry.getDataAsync(function (content, err_1) { + if (err_1) { + next(new Error(err_1)); + } else if (!content) { + next(new Error(Utils.Errors.CANT_EXTRACT_FILE)); + } else { + // The reverse operation for attr depend on method addFile() + const fileAttr = keepOriginalPermission ? entry.header.fileAttr : undefined; + filetools.writeFileToAsync(filePath, content, overwrite, fileAttr, function (succ) { + if (!succ) { + next(getError("Unable to write file", filePath)); + } + filetools.fs.utimes(filePath, entry.header.time, entry.header.time, function (err_2) { + if (err_2) { + next(getError("Unable to set times", filePath)); + } else { + next(); + } + }); + }); } - filetools.fs.utimes(filePath, entry.header.time, entry.header.time, function (err_2) { - if (err_2) { - callback(getError("Unable to set times", filePath)); - return; - } - // call the callback if it was last entry - done(); - fileEntries.delete(entry); - }); }); } - }); - } - // call the callback if fileEntries was empty - done(); + }; + }, callback)(); }, /** diff --git a/headers/mainHeader.js b/headers/mainHeader.js index dcea01d..ec430b1 100644 --- a/headers/mainHeader.js +++ b/headers/mainHeader.js @@ -127,4 +127,4 @@ module.exports = function () { } }; }; - // Misspelled \ No newline at end of file +// Misspelled diff --git a/methods/inflater.js b/methods/inflater.js index b670b83..17c7ee1 100644 --- a/methods/inflater.js +++ b/methods/inflater.js @@ -1,4 +1,4 @@ -const version = +(process.versions ? process.versions.node : '').split('.')[0] || 0; +const version = +(process.versions ? process.versions.node : "").split(".")[0] || 0; module.exports = function (/*Buffer*/ inbuf, /*number*/ expectedLength) { var zlib = require("zlib"); diff --git a/methods/zipcrypto.js b/methods/zipcrypto.js index 79768f4..ec234ef 100644 --- a/methods/zipcrypto.js +++ b/methods/zipcrypto.js @@ -120,7 +120,7 @@ function decrypt(/*Buffer*/ data, /*Object*/ header, /*String, Buffer*/ pwd) { // if bit 3 (0x08) of the general-purpose flags field is set, check salt[11] with the high byte of the header time // 2 byte data block (as per Info-Zip spec), otherwise check with the high byte of the header entry - const verifyByte = ((header.flags & 0x8) === 0x8) ? header.timeHighByte : header.crc >>> 24; + const verifyByte = (header.flags & 0x8) === 0x8 ? header.timeHighByte : header.crc >>> 24; //3. does password meet expectations if (salt[11] !== verifyByte) { diff --git a/package-lock.json b/package-lock.json index feb10c6..e711340 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "adm-zip", - "version": "0.5.11", + "version": "0.5.12", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "adm-zip", - "version": "0.5.11", + "version": "0.5.12", "license": "MIT", "devDependencies": { "chai": "^4.3.4", diff --git a/test/issue_471/infozip-password.test.js b/test/issue_471/infozip-password.test.js index 38d536f..b94047e 100644 --- a/test/issue_471/infozip-password.test.js +++ b/test/issue_471/infozip-password.test.js @@ -7,8 +7,6 @@ const path = require("path"); const Zip = require("../../adm-zip"); describe("decryption with info-zip spec password check", () => { - - // test decryption with both password types it("test decrypted data with password", () => { // the issue-471-infozip-encrypted.zip file has been generated with Info-Zip Zip 2.32, but the Info-Zip @@ -22,14 +20,12 @@ describe("decryption with info-zip spec password check", () => { }); assert(testFile.length === 1, "Good: dummy.txt file exists as archive entry"); - const readData = entries[0].getData('secret'); - assert(readData.toString('utf8').startsWith('How much wood could a woodchuck chuck'), "Good: buffer matches expectations"); + const readData = entries[0].getData("secret"); + assert(readData.toString("utf8").startsWith("How much wood could a woodchuck chuck"), "Good: buffer matches expectations"); // assert that the following call throws an exception assert.throws(() => { - const readDataBad = entries[0].getData('badpassword'); + const readDataBad = entries[0].getData("badpassword"); }, "Good: error thrown for bad password"); - }); }); - diff --git a/test/methods/zipcrypto.test.js b/test/methods/zipcrypto.test.js index de63476..2b96494 100644 --- a/test/methods/zipcrypto.test.js +++ b/test/methods/zipcrypto.test.js @@ -17,7 +17,7 @@ describe("method - zipcrypto decrypt", () => { pwdbad: "Secret", flagsencrypted: 0x01, flagsinfozipencrypted: 0x09, - timeHighByte: 0xD8, + timeHighByte: 0xd8, // result result: Buffer.from("test", "ascii") }; diff --git a/test/mocha.js b/test/mocha.js index 4e04baa..2689766 100644 --- a/test/mocha.js +++ b/test/mocha.js @@ -28,6 +28,42 @@ describe("adm-zip", () => { ); }); + it("zip.extractAllToAsync(destination)", (done) => { + const zip = new Zip("./test/assets/ultra.zip"); + zip.extractAllToAsync(destination, (error) => { + const files = walk(destination); + expect(files.sort()).to.deep.equal( + [ + pth.normalize("./test/xxx/attributes_test/asd/New Text Document.txt"), + pth.normalize("./test/xxx/attributes_test/blank file.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden_readonly.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/readonly.txt"), + pth.normalize("./test/xxx/utes_test/New folder/somefile.txt") + ].sort() + ); + done(); + }); + }); + + it("zip.extractAllToAsync(destination) [Promise]", function () { + const zip = new Zip("./test/assets/ultra.zip"); + // note the return + return zip.extractAllToAsync(destination).then(function (data) { + const files = walk(destination); + expect(files.sort()).to.deep.equal( + [ + pth.normalize("./test/xxx/attributes_test/asd/New Text Document.txt"), + pth.normalize("./test/xxx/attributes_test/blank file.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden_readonly.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/readonly.txt"), + pth.normalize("./test/xxx/utes_test/New folder/somefile.txt") + ].sort() + ); + }); // no catch, it'll figure it out since the promise is rejected + }); + it("zip.extractAllToAsync(destination, false, false, callback)", (done) => { const zip = new Zip("./test/assets/ultra.zip"); zip.extractAllToAsync(destination, false, false, (error) => { @@ -45,7 +81,25 @@ describe("adm-zip", () => { done(); }); }); - + + it("zip.extractAllToAsync(destination, false, false) [Promise]", function () { + const zip = new Zip("./test/assets/ultra.zip"); + // note the return + return zip.extractAllToAsync(destination, false, false).then(function (data) { + const files = walk(destination); + expect(files.sort()).to.deep.equal( + [ + pth.normalize("./test/xxx/attributes_test/asd/New Text Document.txt"), + pth.normalize("./test/xxx/attributes_test/blank file.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden_readonly.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/readonly.txt"), + pth.normalize("./test/xxx/utes_test/New folder/somefile.txt") + ].sort() + ); + }); // no catch, it'll figure it out since the promise is rejected + }); + it("zip.extractAllToAsync(destination, false, callback)", (done) => { const zip = new Zip("./test/assets/ultra.zip"); zip.extractAllToAsync(destination, false, (error) => { @@ -64,6 +118,24 @@ describe("adm-zip", () => { }); }); + it("zip.extractAllToAsync(destination, false) [Promise]", () => { + const zip = new Zip("./test/assets/ultra.zip"); + // note the return + return zip.extractAllToAsync(destination, false).then(function (data) { + const files = walk(destination); + expect(files.sort()).to.deep.equal( + [ + pth.normalize("./test/xxx/attributes_test/asd/New Text Document.txt"), + pth.normalize("./test/xxx/attributes_test/blank file.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/hidden_readonly.txt"), + pth.normalize("./test/xxx/attributes_test/New folder/readonly.txt"), + pth.normalize("./test/xxx/utes_test/New folder/somefile.txt") + ].sort() + ); + }); // no catch, it'll figure it out since the promise is rejected + }); + it("zip pathTraversal", () => { const target = pth.join(destination, "test"); const zip = new Zip(); @@ -173,20 +245,22 @@ describe("adm-zip", () => { expect(zip2Entries).to.deep.equal(["c.txt", "b.txt", "a.txt"]); }); + /* it("repro: symlink", () => { const zip = new Zip("./test/assets/symlink.zip"); zip.extractAllTo(destination); - const linkPath = pth.join(destination, "link") + const linkPath = pth.join(destination, "link"); const linkStat = fs.lstatSync(linkPath); expect(linkStat.isSymbolicLink()).to.be.true; - + const linkTarget = fs.readlinkSync(linkPath); - expect(linkTarget).to.equal("target") + expect(linkTarget).to.equal("target"); const linkContent = fs.readFileSync(linkPath); - expect(linkContent).to.equal("diddlydiddly doo, i'm a linkaroo") + expect(linkContent).to.equal("diddlydiddly doo, i'm a linkaroo"); }); + */ }); function walk(dir) {