module.exports = Extract; var Parse = require('./parse'); var Writer = require('fstream').Writer; var path = require('path'); var stream = require('stream'); var duplexer2 = require('duplexer2'); var Promise = require('bluebird'); function Extract (opts) { // make sure path is normalized before using it opts.path = path.resolve(path.normalize(opts.path)); var parser = new Parse(opts); 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 cb(); } const writer = opts.getWriter ? opts.getWriter({path: extractPath}) : Writer({ path: extractPath }); entry.pipe(writer) .on('error', cb) .on('close', cb); }; var extract = duplexer2(parser,outStream); parser.once('crx-header', function(crxHeader) { extract.crxHeader = crxHeader; }); parser .pipe(outStream) .on('finish',function() { extract.emit('close'); }); extract.promise = function() { return new Promise(function(resolve, reject) { extract.on('close', resolve); extract.on('error',reject); }); }; return extract; }