extract.js 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. module.exports = Extract;
  2. var Parse = require('./parse');
  3. var Writer = require('fstream').Writer;
  4. var path = require('path');
  5. var stream = require('stream');
  6. var duplexer2 = require('duplexer2');
  7. var Promise = require('bluebird');
  8. function Extract (opts) {
  9. // make sure path is normalized before using it
  10. opts.path = path.resolve(path.normalize(opts.path));
  11. var parser = new Parse(opts);
  12. var outStream = new stream.Writable({objectMode: true});
  13. outStream._write = function(entry, encoding, cb) {
  14. if (entry.type == 'Directory') return cb();
  15. // to avoid zip slip (writing outside of the destination), we resolve
  16. // the target path, and make sure it's nested in the intended
  17. // destination, or not extract it otherwise.
  18. var extractPath = path.join(opts.path, entry.path);
  19. if (extractPath.indexOf(opts.path) != 0) {
  20. return cb();
  21. }
  22. const writer = opts.getWriter ? opts.getWriter({path: extractPath}) : Writer({ path: extractPath });
  23. entry.pipe(writer)
  24. .on('error', cb)
  25. .on('close', cb);
  26. };
  27. var extract = duplexer2(parser,outStream);
  28. parser.once('crx-header', function(crxHeader) {
  29. extract.crxHeader = crxHeader;
  30. });
  31. parser
  32. .pipe(outStream)
  33. .on('finish',function() {
  34. extract.emit('close');
  35. });
  36. extract.promise = function() {
  37. return new Promise(function(resolve, reject) {
  38. extract.on('close', resolve);
  39. extract.on('error',reject);
  40. });
  41. };
  42. return extract;
  43. }