Skip to content

Commit 27fe7b9

Browse files
committed
harden js based postinstall.js
1 parent b7a75a6 commit 27fe7b9

File tree

3 files changed

+71
-58
lines changed

3 files changed

+71
-58
lines changed

node/package-lock.json

Lines changed: 11 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

node/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"prepublishOnly": "cp ../README.md . && npm i && npm run compile"
1919
},
2020
"dependencies": {
21-
"adm-zip": "^0.5.16"
21+
"@zip.js/zip.js": "^2.6.15"
2222
},
2323
"devDependencies": {
2424
"@types/jest": "^27.4.1",

node/postinstall.js

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,64 @@
1-
const { execSync } = require('child_process')
1+
const { ZipReader, BlobReader, Uint8ArrayWriter } = require('@zip.js/zip.js');
22
const { createHash } = require('crypto')
33
const fs = require('fs')
44
const https = require('https')
55
const path = require('path')
6-
const { promisify } = require('util')
7-
const { pipeline } = require('stream')
8-
const streamPipeline = promisify(pipeline)
9-
6+
const os = require('os')
107
const tag = require('./package.json').version
11-
const os = process.platform
8+
9+
const platform = process.platform
1210
const cpu = process.arch
1311

1412
// Map Node.js platform and architecture to binary names
1513
function getBinaryInfo() {
16-
const buildMap = {
17-
'linux-ia32': 'linux-32-bit',
18-
'linux-x32': 'linux-32-bit',
19-
'linux-x64': 'linux-64-bit',
20-
'linux-arm64': 'linux-arm',
21-
'darwin-x64': 'macos-64-bit',
22-
'darwin-arm64': 'macos-arm',
23-
'win32-ia32': 'windows-32-bit',
24-
'win32-x32': 'windows-32-bit',
25-
'win32-x64': 'windows-64-bit',
26-
}
27-
28-
const key = `${os}-${cpu}`
29-
const build = buildMap[key]
30-
31-
if (!build) {
32-
throw new Error(`Unsupported platform: ${os}-${cpu}`)
14+
let build = ''
15+
if (platform === 'darwin') {
16+
if (cpu === 'arm64') {
17+
build = 'macos-arm'
18+
} else {
19+
build = 'macos-64-bit'
20+
}
21+
} else if (platform === 'win32') {
22+
if (cpu === 'x64') {
23+
build = 'windows-64-bit'
24+
} else {
25+
build = 'windows-32-bit'
26+
}
27+
} else if (platform === 'linux') {
28+
if (cpu === 'x64') {
29+
build = 'linux-64-bit'
30+
} else if (cpu === 'arm64') {
31+
build = 'linux-arm'
32+
} else {
33+
build = 'linux-32-bit'
34+
}
35+
} else {
36+
throw new Error(`Unsupported platform: ${platform}-${cpu}`)
3337
}
3438

3539
return {
3640
build,
3741
filename: `sqlx-ts-v${tag}-${build}.zip`,
38-
binaryName: os === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts'
42+
binaryName: platform === 'win32' ? 'sqlx-ts.exe' : 'sqlx-ts'
3943
}
4044
}
4145

4246
// Download file from URL
43-
function downloadFile(url, destination) {
47+
function downloadFile(url, destination, redirectCount = 0) {
4448
return new Promise((resolve, reject) => {
49+
if (redirectCount > 5) {
50+
return reject(new Error("Too many redirects while downloading file"))
51+
}
52+
4553
const file = fs.createWriteStream(destination)
4654
https.get(url, (response) => {
4755
if (response.statusCode === 302 || response.statusCode === 301) {
48-
// Handle redirect
56+
// Handle redirects
57+
// Close the current file and delete it
58+
// Then download from the new location
4959
file.close()
5060
fs.unlinkSync(destination)
51-
return downloadFile(response.headers.location, destination)
61+
return downloadFile(response.headers.location, destination, redirectCount + 1)
5262
.then(resolve)
5363
.catch(reject)
5464
}
@@ -82,7 +92,6 @@ function calculateSHA256(filePath) {
8292
})
8393
}
8494

85-
// Verify file hash
8695
async function verifyHash(filePath, expectedHash) {
8796
const actualHash = await calculateSHA256(filePath)
8897

@@ -98,38 +107,40 @@ async function verifyHash(filePath, expectedHash) {
98107
return true
99108
}
100109

101-
// Extract binary from zip
102-
function extractBinary(zipPath, binaryName, targetPath) {
103-
const AdmZip = require('adm-zip')
104-
const zip = new AdmZip(zipPath)
105-
const zipEntries = zip.getEntries()
106-
107-
for (const entry of zipEntries) {
108-
if (entry.entryName.endsWith(binaryName)) {
109-
// Extract the entry's content directly
110-
const data = entry.getData()
111-
fs.writeFileSync(targetPath, data)
112-
fs.chmodSync(targetPath, 0o755)
113-
return
110+
async function extractBinary(zipPath, binaryName, targetPath) {
111+
const zipData = fs.readFileSync(zipPath);
112+
const reader = new ZipReader(new BlobReader(new Blob([zipData])));
113+
114+
const entries = await reader.getEntries();
115+
116+
for (const entry of entries) {
117+
if (entry.filename.endsWith(binaryName)) {
118+
const writer = new Uint8ArrayWriter();
119+
const data = await entry.getData(writer);
120+
fs.writeFileSync(targetPath, Buffer.from(data));
121+
fs.chmodSync(targetPath, 0o755);
122+
await reader.close();
123+
return;
114124
}
115125
}
116126

117-
throw new Error(`Binary ${binaryName} not found in archive`)
127+
throw new Error(`Binary ${binaryName} not found in zip`);
118128
}
119129

120130
async function install() {
121131
try {
122-
const { build, filename, binaryName } = getBinaryInfo()
132+
const { filename, binaryName } = getBinaryInfo()
123133
const baseUrl = `https://github.com/JasonShin/sqlx-ts/releases/download/v${tag}`
124134
const zipUrl = `${baseUrl}/${filename}`
125135
const checksumUrl = `${zipUrl}.sha256`
126136

127-
const tmpDir = fs.mkdtempSync(path.join(require('os').tmpdir(), 'sqlx-ts-'))
137+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sqlx-ts-'))
128138
const zipPath = path.join(tmpDir, filename)
129139
const checksumPath = path.join(tmpDir, `${filename}.sha256`)
130-
const targetPath = path.join(__dirname, 'sqlx-ts' + (os === 'win32' ? '.exe' : ''))
140+
console.log('checking checksum url:', checksumUrl)
141+
const targetPath = path.join(__dirname, 'sqlx-ts' + (platform === 'win32' ? '.exe' : ''))
131142

132-
console.info(`Downloading sqlx-ts v${tag} for ${os}-${cpu}...`)
143+
console.info(`Downloading sqlx-ts v${tag} for ${platform}-${cpu}...`)
133144
console.info(`URL: ${zipUrl}`)
134145

135146
// Download the zip file
@@ -156,12 +167,13 @@ async function install() {
156167

157168
// Extract the binary
158169
console.info('Extracting binary...')
159-
extractBinary(zipPath, binaryName, targetPath)
170+
await extractBinary(zipPath, binaryName, targetPath)
160171

161172
// Cleanup
162173
fs.rmSync(tmpDir, { recursive: true, force: true })
163174

164175
console.info('sqlx-ts installation successful')
176+
process.exit(0)
165177
} catch (error) {
166178
console.error('Installation failed:', error.message)
167179
process.exit(1)

0 commit comments

Comments
 (0)