diff --git a/node_modules/tar/lib/pack.js b/node_modules/tar/lib/pack.js index 938ece8e73145..d533a068f579f 100644 --- a/node_modules/tar/lib/pack.js +++ b/node_modules/tar/lib/pack.js @@ -79,14 +79,26 @@ const Pack = warner(class Pack extends Minipass { this.portable = !!opt.portable this.zip = null - if (opt.gzip) { - if (typeof opt.gzip !== 'object') { - opt.gzip = {} + + if (opt.gzip || opt.brotli) { + if (opt.gzip && opt.brotli) { + throw new TypeError('gzip and brotli are mutually exclusive') } - if (this.portable) { - opt.gzip.portable = true + if (opt.gzip) { + if (typeof opt.gzip !== 'object') { + opt.gzip = {} + } + if (this.portable) { + opt.gzip.portable = true + } + this.zip = new zlib.Gzip(opt.gzip) + } + if (opt.brotli) { + if (typeof opt.brotli !== 'object') { + opt.brotli = {} + } + this.zip = new zlib.BrotliCompress(opt.brotli) } - this.zip = new zlib.Gzip(opt.gzip) this.zip.on('data', chunk => super.write(chunk)) this.zip.on('end', _ => super.end()) this.zip.on('drain', _ => this[ONDRAIN]()) diff --git a/node_modules/tar/lib/parse.js b/node_modules/tar/lib/parse.js index 4b85915cbe01e..94e53042fad56 100644 --- a/node_modules/tar/lib/parse.js +++ b/node_modules/tar/lib/parse.js @@ -97,6 +97,16 @@ module.exports = warner(class Parser extends EE { this.strict = !!opt.strict this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize this.filter = typeof opt.filter === 'function' ? opt.filter : noop + // Unlike gzip, brotli doesn't have any magic bytes to identify it + // Users need to explicitly tell us they're extracting a brotli file + // Or we infer from the file extension + const isTBR = (opt.file && ( + opt.file.endsWith('.tar.br') || opt.file.endsWith('.tbr'))) + // if it's a tbr file it MIGHT be brotli, but we don't know until + // we look at it and verify it's not a valid tar file. + this.brotli = !opt.gzip && opt.brotli !== undefined ? opt.brotli + : isTBR ? undefined + : false // have to set this so that streams are ok piping into it this.writable = true @@ -347,7 +357,9 @@ module.exports = warner(class Parser extends EE { } // first write, might be gzipped - if (this[UNZIP] === null && chunk) { + const needSniff = this[UNZIP] === null || + this.brotli === undefined && this[UNZIP] === false + if (needSniff && chunk) { if (this[BUFFER]) { chunk = Buffer.concat([this[BUFFER], chunk]) this[BUFFER] = null @@ -356,15 +368,45 @@ module.exports = warner(class Parser extends EE { this[BUFFER] = chunk return true } + + // look for gzip header for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) { if (chunk[i] !== gzipHeader[i]) { this[UNZIP] = false } } - if (this[UNZIP] === null) { + + const maybeBrotli = this.brotli === undefined + if (this[UNZIP] === false && maybeBrotli) { + // read the first header to see if it's a valid tar file. If so, + // we can safely assume that it's not actually brotli, despite the + // .tbr or .tar.br file extension. + // if we ended before getting a full chunk, yes, def brotli + if (chunk.length < 512) { + if (this[ENDED]) { + this.brotli = true + } else { + this[BUFFER] = chunk + return true + } + } else { + // if it's tar, it's pretty reliably not brotli, chances of + // that happening are astronomical. + try { + new Header(chunk.slice(0, 512)) + this.brotli = false + } catch (_) { + this.brotli = true + } + } + } + + if (this[UNZIP] === null || (this[UNZIP] === false && this.brotli)) { const ended = this[ENDED] this[ENDED] = false - this[UNZIP] = new zlib.Unzip() + this[UNZIP] = this[UNZIP] === null + ? new zlib.Unzip() + : new zlib.BrotliDecompress() this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk)) this[UNZIP].on('error', er => this.abort(er)) this[UNZIP].on('end', _ => { @@ -502,6 +544,7 @@ module.exports = warner(class Parser extends EE { this[UNZIP].end(chunk) } else { this[ENDED] = true + if (this.brotli === undefined) chunk = chunk || Buffer.alloc(0) this.write(chunk) } } diff --git a/node_modules/tar/lib/replace.js b/node_modules/tar/lib/replace.js index c6e619be6f032..8db6800bdf464 100644 --- a/node_modules/tar/lib/replace.js +++ b/node_modules/tar/lib/replace.js @@ -23,7 +23,7 @@ module.exports = (opt_, files, cb) => { throw new TypeError('file is required') } - if (opt.gzip) { + if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { throw new TypeError('cannot append to compressed archives') } diff --git a/node_modules/tar/lib/update.js b/node_modules/tar/lib/update.js index ded977dc1dec0..4d328543b315e 100644 --- a/node_modules/tar/lib/update.js +++ b/node_modules/tar/lib/update.js @@ -13,7 +13,7 @@ module.exports = (opt_, files, cb) => { throw new TypeError('file is required') } - if (opt.gzip) { + if (opt.gzip || opt.brotli || opt.file.endsWith('.br') || opt.file.endsWith('.tbr')) { throw new TypeError('cannot append to compressed archives') } diff --git a/node_modules/tar/package.json b/node_modules/tar/package.json index f59f54ae837bd..46d91ee1b299c 100644 --- a/node_modules/tar/package.json +++ b/node_modules/tar/package.json @@ -2,20 +2,15 @@ "author": "GitHub Inc.", "name": "tar", "description": "tar for node", - "version": "6.1.15", + "version": "6.2.0", "repository": { "type": "git", "url": "https://github.com/isaacs/node-tar.git" }, "scripts": { "genparse": "node scripts/generate-parse-fixtures.js", - "template-oss-apply": "template-oss-apply --force", - "lint": "eslint \"**/*.js\"", - "postlint": "template-oss-check", - "lintfix": "npm run lint -- --fix", "snap": "tap", - "test": "tap", - "posttest": "npm run lint" + "test": "tap" }, "dependencies": { "chownr": "^2.0.0", diff --git a/package-lock.json b/package-lock.json index 83306d5680968..0a652a78e00b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -153,7 +153,7 @@ "ssri": "^10.0.5", "strip-ansi": "^6.0.1", "supports-color": "^9.4.0", - "tar": "^6.1.15", + "tar": "^6.2.0", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", @@ -15648,9 +15648,9 @@ } }, "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", "inBundle": true, "dependencies": { "chownr": "^2.0.0", @@ -17106,7 +17106,7 @@ "minimatch": "^9.0.0", "npm-package-arg": "^11.0.1", "pacote": "^17.0.4", - "tar": "^6.1.13" + "tar": "^6.2.0" }, "devDependencies": { "@npmcli/eslint-config": "^4.0.0", diff --git a/package.json b/package.json index 35de6c0874272..8612751859173 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "ssri": "^10.0.5", "strip-ansi": "^6.0.1", "supports-color": "^9.4.0", - "tar": "^6.1.15", + "tar": "^6.2.0", "text-table": "~0.2.0", "tiny-relative-date": "^1.3.0", "treeverse": "^3.0.0", diff --git a/workspaces/libnpmdiff/package.json b/workspaces/libnpmdiff/package.json index 321e003eb0020..8c3fe09bad764 100644 --- a/workspaces/libnpmdiff/package.json +++ b/workspaces/libnpmdiff/package.json @@ -54,7 +54,7 @@ "minimatch": "^9.0.0", "npm-package-arg": "^11.0.1", "pacote": "^17.0.4", - "tar": "^6.1.13" + "tar": "^6.2.0" }, "templateOSS": { "//@npmcli/template-oss": "This file is partially managed by @npmcli/template-oss. Edits may be overwritten.",