From 943ea99ecc0e4160d57c70b1a27acf0bfd6cab74 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Tue, 22 Oct 2024 14:02:01 +0200 Subject: [PATCH 1/3] Replace tar with tar-stream --- package.json | 3 +- script/download-git.js | 36 +++++++++----- yarn.lock | 107 +++++++++++++++++------------------------ 3 files changed, 70 insertions(+), 76 deletions(-) diff --git a/package.json b/package.json index fafda950..40010141 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,12 @@ "homepage": "https://github.com/desktop/dugite#readme", "dependencies": { "progress": "^2.0.3", - "tar": "^7.1.0" + "tar-stream": "^3.1.7" }, "devDependencies": { "@types/node": "18", "@types/progress": "^2.0.1", "@types/rimraf": "2.0.2", - "@types/tar": "^6.1.2", "@types/temp": "^0.9.4", "find-git-exec": "^0.0.4", "node-test-github-reporter": "^1.2.0", diff --git a/script/download-git.js b/script/download-git.js index cfd542f4..47513e47 100644 --- a/script/download-git.js +++ b/script/download-git.js @@ -1,10 +1,11 @@ const ProgressBar = require('progress') -const tar = require('tar') const { createHash } = require('crypto') const { createReadStream, createWriteStream } = require('fs') - -const { rm, mkdir, access } = require('fs/promises') - +const { rm, mkdir, access, symlink } = require('fs/promises') +const { extract } = require('tar-stream') +const { createGunzip } = require('zlib') +const { resolve: resolvePath } = require('path') +const assert = require('node:assert') /** * Returns a value indicating whether or not the provided path exists (as in * whether it's visible to the current process or not). @@ -41,9 +42,25 @@ const verifyFile = function (file, callback) { } const unpackFile = file => - tar.x({ cwd: config.outputPath, file }).catch(e => { - console.log('Unable to extract archive, aborting...', e) - process.exit(1) + new Promise((resolve, reject) => { + createReadStream(file) + .pipe(new createGunzip()) + .pipe(extract()) + .on('entry', ({ type, name, mode, linkname }, stream, next) => { + const p = resolvePath(config.outputPath, name) + assert.ok(p.startsWith(config.outputPath)) + if (type === 'file') { + stream.pipe(createWriteStream(p, { mode })).on('finish', next) + } else if (type === 'directory') { + mkdir(p).then(next) + } else if (type === 'symlink') { + symlink(linkname, p).then(next) + } else { + throw new Error(`unknown file type: ${type}`) + } + }) + .on('error', reject) + .on('finish', resolve) }) const downloadAndUnpack = async url => { @@ -98,11 +115,6 @@ const downloadAndUnpack = async url => { process.exit(1) }) - await mkdir(config.outputPath, { recursive: true }).catch(error => { - console.log(`Unable to create directory at ${config.outputPath}`, error) - process.exit(1) - }) - const tempFile = config.tempFile if (await pathExists(tempFile)) { diff --git a/yarn.lock b/yarn.lock index cb12eaea..71c120f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -167,13 +167,6 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@isaacs/fs-minipass@^4.0.0": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32" - integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w== - dependencies: - minipass "^7.0.4" - "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -224,14 +217,6 @@ "@types/glob" "*" "@types/node" "*" -"@types/tar@^6.1.2": - version "6.1.2" - resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.2.tgz#e60108a7d1b08cc91bf2faf1286cc08fdad48bbe" - integrity sha512-bnX3RRm70/n1WMwmevdOAeDU4YP7f5JSubgnuU+yrO+xQQjwDboJj3u2NTJI5ngCQhXihqVVAH5h5J8YpdpEvg== - dependencies: - "@types/node" "*" - minipass "^3.3.5" - "@types/temp@^0.9.4": version "0.9.4" resolved "https://registry.yarnpkg.com/@types/temp/-/temp-0.9.4.tgz#69bd4b0e8fc4d54db06bd1b613c19292d333350b" @@ -266,11 +251,21 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bare-events@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.0.tgz#305b511e262ffd8b9d5616b056464f8e1b3329cc" + integrity sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -286,11 +281,6 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -chownr@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" - integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== - color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -374,6 +364,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + find-git-exec@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/find-git-exec/-/find-git-exec-0.0.4.tgz#f1d0d35f93ad99bc81aacd357388d00ae902bc92" @@ -488,26 +483,11 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== -minipass@^3.3.5: - version "3.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.5.tgz#6da7e53a48db8a856eeb9153d85b230a2119e819" - integrity sha512-rQ/p+KfKBkeNwo04U15i+hOwoVBVmekmm/HcfTkTN2t9pbQKCMm4eN5gFeqgrrSp/kH/7BYYhTIHOxGqzbBPaA== - dependencies: - yallist "^4.0.0" - -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2: +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== -minizlib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012" - integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg== - dependencies: - minipass "^7.0.4" - rimraf "^5.0.5" - mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -515,11 +495,6 @@ mkdirp@^0.5.1: dependencies: minimist "^1.2.6" -mkdirp@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" - integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== - node-test-github-reporter@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/node-test-github-reporter/-/node-test-github-reporter-1.2.0.tgz#316914021ae66fc944c216080971da4d388e5283" @@ -575,12 +550,17 @@ progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -rimraf@^5.0.5, rimraf@^5.0.7: +rimraf@^5.0.7: version "5.0.10" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.10.tgz#23b9843d3dc92db71f96e1a2ce92e39fd2a8221c" integrity sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ== @@ -623,6 +603,17 @@ stackframe@^1.3.4: resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== +streamx@^2.15.0: + version "2.20.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.20.1.tgz#471c4f8b860f7b696feb83d5b125caab2fdbb93c" + integrity sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA== + dependencies: + fast-fifo "^1.3.2" + queue-tick "^1.0.1" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -671,17 +662,14 @@ strip-ansi@^7.0.1: dependencies: ansi-regex "^6.0.1" -tar@^7.1.0: - version "7.4.3" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.3.tgz#88bbe9286a3fcd900e94592cda7a22b192e80571" - integrity sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw== +tar-stream@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== dependencies: - "@isaacs/fs-minipass" "^4.0.0" - chownr "^3.0.0" - minipass "^7.1.2" - minizlib "^3.0.1" - mkdirp "^3.0.1" - yallist "^5.0.0" + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" temp@^0.9.4: version "0.9.4" @@ -691,6 +679,11 @@ temp@^0.9.4: mkdirp "^0.5.1" rimraf "~2.6.2" +text-decoder@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.1.tgz#e173f5121d97bfa3ff8723429ad5ba92e1ead67e" + integrity sha512-x9v3H/lTKIJKQQe7RPQkLfKAnc9lUTkWDypIQgTzPJAq+5/GCDHonmshfvlsNSj58yyshbIJJDLmU15qNERrXQ== + tsx@^4.10.5: version "4.19.1" resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.19.1.tgz#b7bffdf4b565813e4dea14b90872af279cd0090b" @@ -752,13 +745,3 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yallist@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533" - integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw== From 0554c659aed9cba6e3fed0051fb6598d061c5a00 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Tue, 22 Oct 2024 14:10:31 +0200 Subject: [PATCH 2/3] Appease GHAS --- script/download-git.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/script/download-git.js b/script/download-git.js index 47513e47..9d4c657f 100644 --- a/script/download-git.js +++ b/script/download-git.js @@ -47,6 +47,9 @@ const unpackFile = file => .pipe(new createGunzip()) .pipe(extract()) .on('entry', ({ type, name, mode, linkname }, stream, next) => { + if (name.includes('..')) { + throw new Error(`invalid file name: ${name}`) + } const p = resolvePath(config.outputPath, name) assert.ok(p.startsWith(config.outputPath)) if (type === 'file') { From e7139a86a8e6e03d4ddc97328c56ecea183f0793 Mon Sep 17 00:00:00 2001 From: Markus Olsson Date: Tue, 22 Oct 2024 14:19:36 +0200 Subject: [PATCH 3/3] Guess we don't need this, GHAS is happy with the check for .. --- script/download-git.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/script/download-git.js b/script/download-git.js index 9d4c657f..2f27d20f 100644 --- a/script/download-git.js +++ b/script/download-git.js @@ -4,7 +4,7 @@ const { createReadStream, createWriteStream } = require('fs') const { rm, mkdir, access, symlink } = require('fs/promises') const { extract } = require('tar-stream') const { createGunzip } = require('zlib') -const { resolve: resolvePath } = require('path') +const { join } = require('path') const assert = require('node:assert') /** * Returns a value indicating whether or not the provided path exists (as in @@ -50,8 +50,7 @@ const unpackFile = file => if (name.includes('..')) { throw new Error(`invalid file name: ${name}`) } - const p = resolvePath(config.outputPath, name) - assert.ok(p.startsWith(config.outputPath)) + const p = join(config.outputPath, name) if (type === 'file') { stream.pipe(createWriteStream(p, { mode })).on('finish', next) } else if (type === 'directory') {