Skip to content

Commit

Permalink
Merge pull request #128 from ZJONSSON/broken-zip
Browse files Browse the repository at this point in the history
Rewrite extract to user duplexer2
  • Loading branch information
ZJONSSON authored May 22, 2019
2 parents 96286cf + 59b87ff commit f594c65
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 37 deletions.
65 changes: 28 additions & 37 deletions lib/extract.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,51 @@ module.exports = Extract;

var Parse = require('./parse');
var Writer = require('fstream').Writer;
var util = require('util');
var path = require('path');

util.inherits(Extract, Parse);
var stream = require('stream');
var duplexer2 = require('duplexer2');
var Promise = require('bluebird');

function Extract (opts) {
if (!(this instanceof Extract))
return new Extract(opts);

var self = this;

var finishCb;
var pending = 0;
var _final = typeof this._final === 'function' ? this._final : undefined;

function checkFinished() {
if (pending === 0 && finishCb) {
_final ? _final(finishCb) : finishCb();
}
}

this._final = function(cb) {
finishCb = cb;
checkFinished();
};

// make sure path is normalized before using it
opts.path = path.normalize(opts.path);

Parse.call(self,opts);
var parser = new Parse(opts);

self.on('entry', function(entry) {
if (entry.type == 'Directory') return;
var outStream = new stream.Writable({objectMode: true});
outStream._write = function(entry, encoding, cb) {

if (entry.type == 'Directory') return cb();

// to avoid zip slip (writing outside of the destination), we resolve
// the target path, and make sure it's nested in the intended
// destination, or not extract it otherwise.
var extractPath = path.join(opts.path, entry.path);
if (extractPath.indexOf(opts.path) != 0) {
return;
return cb();
}

const writer = opts.getWriter ? opts.getWriter({path: extractPath}) : Writer({ path: extractPath });

pending += 1;
entry.pipe(writer)
.on('error',function(e) {
self.emit('error',e);
pending -= 1;
checkFinished();
})
.on('close', function() {
pending -= 1;
checkFinished();
.on('error', cb)
.on('close', cb);
};

var extract = duplexer2(parser,outStream);

parser
.pipe(outStream)
.on('finish',function() {
extract.emit('close');
});
});

extract.promise = function() {
return new Promise(function(resolve, reject) {
extract.on('finish', resolve);
extract.on('error',reject);
});
};

return extract;
}
43 changes: 43 additions & 0 deletions test/broken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';

var test = require('tap').test;
var fs = require('fs');
var path = require('path');
var temp = require('temp');
var unzip = require('../');


test("Parse a broken zipfile", function (t) {
var archive = path.join(__dirname, '../testData/compressed-standard/broken.zip');

fs.createReadStream(archive)
.pipe(unzip.Parse())
.on('entry', function(entry) {
return entry.autodrain();
})
.promise()
.catch(function(e) {
t.same(e.message, 'FILE_ENDED');
t.end();
});
});


test("extract a broken", function (t) {
var archive = path.join(__dirname, '../testData/compressed-standard/broken.zip');

temp.mkdir('node-unzip-', function (err, dirPath) {
if (err) {
throw err;
}
var unzipExtractor = unzip.Extract({ path: dirPath });

fs.createReadStream(archive)
.pipe(unzipExtractor)
.promise()
.catch(function(e) {
t.same(e.message,'FILE_ENDED');
t.end();
});
});
});
Binary file added testData/compressed-standard/broken.zip
Binary file not shown.

0 comments on commit f594c65

Please sign in to comment.