Skip to content

Commit

Permalink
Merge pull request cthackers#489 from 5saviahv/master
Browse files Browse the repository at this point in the history
Fixed extractAllToAsync callback
  • Loading branch information
5saviahv authored May 17, 2024
2 parents 09f874f + 1f2265f commit 21a4023
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 61 deletions.
84 changes: 41 additions & 43 deletions adm-zip.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 : [];
},

Expand Down Expand Up @@ -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));
Expand All @@ -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);
}
});

Expand All @@ -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)();
},

/**
Expand Down
2 changes: 1 addition & 1 deletion headers/mainHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,4 @@ module.exports = function () {
}
};
};
// Misspelled
// Misspelled
2 changes: 1 addition & 1 deletion methods/inflater.js
Original file line number Diff line number Diff line change
@@ -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");
Expand Down
2 changes: 1 addition & 1 deletion methods/zipcrypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 3 additions & 7 deletions test/issue_471/infozip-password.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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");

});
});

2 changes: 1 addition & 1 deletion test/methods/zipcrypto.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("method - zipcrypto decrypt", () => {
pwdbad: "Secret",
flagsencrypted: 0x01,
flagsinfozipencrypted: 0x09,
timeHighByte: 0xD8,
timeHighByte: 0xd8,
// result
result: Buffer.from("test", "ascii")
};
Expand Down
84 changes: 79 additions & 5 deletions test/mocha.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand All @@ -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) => {
Expand All @@ -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();
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 21a4023

Please sign in to comment.