unzipper-esm
Version:
Unzip cross-platform streaming API
65 lines (51 loc) • 1.9 kB
JavaScript
import fs from 'fs'; // 'node:fs'
import path from 'path'; // 'node:path'
import { Writable } from 'stream'; // 'node:stream'
import DuplexStream from './DuplexStream.js';
import Parse from './parse.js';
import ensureDir from './ensureDir.js';
export default function Extract (opts) {
// make sure path is normalized before using it
opts.path = path.resolve(path.normalize(opts.path));
const parser = Parse(opts);
const outStream = new Writable({
objectMode: true,
write: async function(entry, encoding, 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.
// NOTE: Need to normalize to forward slashes for UNIX OS's to properly
// ignore the zip slipped file entirely
const extractPath = path.join(opts.path, entry.path.replace(/\\/g, '/'));
if (extractPath.indexOf(opts.path) != 0) {
return cb();
}
if (entry.type == 'Directory') {
await ensureDir(extractPath);
return cb();
}
await ensureDir(path.dirname(extractPath));
const writer = opts.getWriter ? opts.getWriter({path: extractPath}) : fs.createWriteStream(extractPath);
entry.pipe(writer)
.on('error', cb)
.on('close', cb);
}
});
// Create a combined stream
const extract = new DuplexStream(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;
}