module.exports = Extract; var Parse = require('./parse'); var Writer = require('fstream').Writer; var util = require('util'); var path = require('path'); util.inherits(Extract, Parse); 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); self.on('entry', function(entry) { if (entry.type == 'Directory') return; // 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; } 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(); }); }); }