herozion 1.1.74 → 1.1.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/checksums.json +8 -0
- package/install.js +66 -28
- package/package.json +2 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "SHA-256 hashes for each platform binary. Auto-generated in CI from release CHECKSUMS.sha256. DO NOT edit manually.",
|
|
3
|
+
"_version": "1.1.76",
|
|
4
|
+
"herozion-linux-amd64": "388813017d4212e1615132e8ea98cba63eefa8b6885d9b8509f64e9d9c7f46d1",
|
|
5
|
+
"herozion-macos-amd64": "50145d9ac239c0380fe60c2e775ed43bd9588efd32538fe4bcee4c89a6a92cbd",
|
|
6
|
+
"herozion-macos-arm64": "5fe6d4c03b5d7d944e14d59371477b9a5a2e456a8a2ee3f051022587303594cc",
|
|
7
|
+
"herozion-windows-amd64.exe": "1a64cc8460e5cf92b4806e0ecd69b857bc70d2b7fe42981842ff9b8cf24d558f"
|
|
8
|
+
}
|
package/install.js
CHANGED
|
@@ -42,6 +42,13 @@ function getBinaryName() {
|
|
|
42
42
|
const { platform, arch } = process;
|
|
43
43
|
|
|
44
44
|
if (platform === "win32" && arch === "x64") return "herozion-windows-amd64.exe";
|
|
45
|
+
if (platform === "linux" && arch === "arm64") {
|
|
46
|
+
throw new Error(
|
|
47
|
+
"Herozion: Linux ARM64 is not supported by the npm binary installer yet.\n" +
|
|
48
|
+
"Use: pip install herozion OR download from:\n" +
|
|
49
|
+
" https://github.com/Herozion/scanner-releases/releases/latest"
|
|
50
|
+
);
|
|
51
|
+
}
|
|
45
52
|
if (platform === "linux" && (arch === "x64" || arch === "ia32")) return "herozion-linux-amd64";
|
|
46
53
|
if (platform === "darwin" && arch === "arm64") return "herozion-macos-arm64";
|
|
47
54
|
if (platform === "darwin" && (arch === "x64" || arch === "ia32")) return "herozion-macos-amd64";
|
|
@@ -59,8 +66,18 @@ const _ALLOWED_REDIRECT_HOSTS = new Set([
|
|
|
59
66
|
"objects.githubusercontent.com",
|
|
60
67
|
"codeload.github.com",
|
|
61
68
|
"releases.githubusercontent.com",
|
|
69
|
+
"release-assets.githubusercontent.com",
|
|
62
70
|
]);
|
|
63
71
|
|
|
72
|
+
function _isAllowedRedirectHost(host) {
|
|
73
|
+
if (_ALLOWED_REDIRECT_HOSTS.has(host)) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
// GitHub release binaries are served from various *.githubusercontent.com CDNs.
|
|
77
|
+
// Allow the suffix so new CDN hostnames do not break installs.
|
|
78
|
+
return host.endsWith(".githubusercontent.com");
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
function _validateRedirectUrl(location) {
|
|
65
82
|
if (!location || !location.startsWith("https://")) {
|
|
66
83
|
throw new Error(`Redirect to non-HTTPS URL rejected: ${location}`);
|
|
@@ -69,10 +86,10 @@ function _validateRedirectUrl(location) {
|
|
|
69
86
|
try { host = new URL(location).hostname; } catch (_) {
|
|
70
87
|
throw new Error(`Invalid redirect URL: ${location}`);
|
|
71
88
|
}
|
|
72
|
-
if (!
|
|
89
|
+
if (!_isAllowedRedirectHost(host)) {
|
|
73
90
|
throw new Error(
|
|
74
91
|
`Redirect to untrusted host rejected: ${host}\n` +
|
|
75
|
-
"Only github.com and githubusercontent.com are allowed."
|
|
92
|
+
"Only github.com and *.githubusercontent.com are allowed."
|
|
76
93
|
);
|
|
77
94
|
}
|
|
78
95
|
}
|
|
@@ -159,10 +176,22 @@ async function main() {
|
|
|
159
176
|
// ── Load bundled checksums (primary trust anchor) ─────────────────────────
|
|
160
177
|
const bundledChecksumsPath = path.join(__dirname, "bin", "checksums.json");
|
|
161
178
|
let bundledHash = "";
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
if (fs.existsSync(bundledChecksumsPath)) {
|
|
180
|
+
try {
|
|
181
|
+
const bundled = JSON.parse(fs.readFileSync(bundledChecksumsPath, "utf8"));
|
|
182
|
+
bundledHash = (bundled[binaryName] || "").toLowerCase().trim();
|
|
183
|
+
if (!bundledHash) {
|
|
184
|
+
console.warn(`herozion: WARNING — no bundled hash entry for ${binaryName}.`);
|
|
185
|
+
}
|
|
186
|
+
} catch (parseErr) {
|
|
187
|
+
console.warn(`herozion: WARNING — invalid checksums.json: ${parseErr.message}`);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
console.warn(
|
|
191
|
+
"herozion: WARNING — bin/checksums.json missing from npm package; " +
|
|
192
|
+
"falling back to remote CHECKSUMS.sha256 verification."
|
|
193
|
+
);
|
|
194
|
+
}
|
|
166
195
|
|
|
167
196
|
console.log(`herozion: downloading ${binaryName} v${VERSION}...`);
|
|
168
197
|
try {
|
|
@@ -170,6 +199,8 @@ async function main() {
|
|
|
170
199
|
await download(url, tmpPath);
|
|
171
200
|
|
|
172
201
|
const actualHash = sha256File(tmpPath);
|
|
202
|
+
let bundledVerified = false;
|
|
203
|
+
let remoteVerified = false;
|
|
173
204
|
|
|
174
205
|
// ── Primary check: bundled checksum (trust anchor inside the npm package) ─
|
|
175
206
|
if (bundledHash) {
|
|
@@ -183,6 +214,7 @@ async function main() {
|
|
|
183
214
|
"This may indicate a supply-chain attack. Aborting installation."
|
|
184
215
|
);
|
|
185
216
|
}
|
|
217
|
+
bundledVerified = true;
|
|
186
218
|
}
|
|
187
219
|
|
|
188
220
|
// ── Secondary check: CHECKSUMS.sha256 from GitHub Releases ────────────────
|
|
@@ -198,56 +230,62 @@ async function main() {
|
|
|
198
230
|
}
|
|
199
231
|
return "";
|
|
200
232
|
})();
|
|
201
|
-
if (remoteHash
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
233
|
+
if (remoteHash) {
|
|
234
|
+
if (actualHash !== remoteHash) {
|
|
235
|
+
fs.unlinkSync(tmpPath);
|
|
236
|
+
throw new Error(
|
|
237
|
+
`Remote checksum mismatch for ${binaryName}.\n` +
|
|
238
|
+
` Expected (remote) : ${remoteHash}\n` +
|
|
239
|
+
` Got : ${actualHash}\n` +
|
|
240
|
+
"The downloaded binary does not match the GitHub Releases CHECKSUMS.sha256 file."
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
remoteVerified = true;
|
|
209
244
|
}
|
|
210
245
|
} catch (checksumErr) {
|
|
211
|
-
// If
|
|
212
|
-
if (!
|
|
246
|
+
// If bundled verification already passed, remote failure is non-fatal.
|
|
247
|
+
if (!bundledVerified) {
|
|
213
248
|
throw checksumErr;
|
|
214
249
|
}
|
|
215
250
|
console.warn(`herozion: WARNING — could not verify remote checksum: ${checksumErr.message}`);
|
|
216
251
|
console.warn("Proceeding because bundled checksum verification passed.");
|
|
217
252
|
}
|
|
218
253
|
|
|
219
|
-
// Fail closed:
|
|
220
|
-
if (!
|
|
221
|
-
// We reach here only when bundledHash is empty AND remote check was skipped/failed.
|
|
222
|
-
// Secondary catch block re-throws when !bundledHash, so this path is belt-and-suspenders.
|
|
254
|
+
// Fail closed: require at least one independent verification source.
|
|
255
|
+
if (!bundledVerified && !remoteVerified) {
|
|
223
256
|
fs.unlinkSync(tmpPath);
|
|
224
257
|
throw new Error(
|
|
225
|
-
`Cannot verify ${binaryName}: no bundled hash
|
|
258
|
+
`Cannot verify ${binaryName}: no bundled hash in package and remote checksum unavailable.\n` +
|
|
226
259
|
"Installation aborted to prevent supply-chain risk.\n" +
|
|
227
260
|
`Download manually from: ${BASE_URL}/${binaryName}`
|
|
228
261
|
);
|
|
229
262
|
}
|
|
230
263
|
|
|
231
|
-
//
|
|
264
|
+
// Verification passed — move binary into place
|
|
232
265
|
fs.renameSync(tmpPath, destPath);
|
|
233
266
|
if (!isWindows) {
|
|
234
267
|
fs.chmodSync(destPath, 0o755);
|
|
235
268
|
}
|
|
236
269
|
// Write version marker so we don't re-download on repeated installs
|
|
237
270
|
fs.writeFileSync(markerPath, VERSION, "utf8");
|
|
238
|
-
const verifiedBy =
|
|
271
|
+
const verifiedBy = bundledVerified && remoteVerified
|
|
272
|
+
? "bundled + remote SHA-256"
|
|
273
|
+
: bundledVerified
|
|
274
|
+
? "bundled SHA-256"
|
|
275
|
+
: "remote SHA-256";
|
|
239
276
|
console.log(`herozion: binary installed successfully (verified: ${verifiedBy}).`);
|
|
240
277
|
} catch (err) {
|
|
241
278
|
// Clean up temp file if it exists
|
|
242
279
|
try { fs.unlinkSync(tmpPath); } catch (_) {}
|
|
243
|
-
|
|
244
|
-
console.
|
|
245
|
-
console.
|
|
246
|
-
console.
|
|
280
|
+
console.error(`herozion: ERROR — could not install binary: ${err.message}`);
|
|
281
|
+
console.error("Try reinstalling with scripts enabled:");
|
|
282
|
+
console.error(" npm install herozion --foreground-scripts");
|
|
283
|
+
console.error(`Or download manually from: ${BASE_URL}/${binaryName}`);
|
|
284
|
+
process.exit(1);
|
|
247
285
|
}
|
|
248
286
|
}
|
|
249
287
|
|
|
250
288
|
main().catch((err) => {
|
|
251
289
|
console.error("herozion install error:", err.message);
|
|
252
|
-
|
|
290
|
+
process.exit(1);
|
|
253
291
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "herozion",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.76",
|
|
4
4
|
"description": "Security audit and performance analysis CLI tool for developers",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"security",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"bin/herozion.js",
|
|
26
|
+
"bin/checksums.json",
|
|
26
27
|
"install.js",
|
|
27
28
|
"README.md"
|
|
28
29
|
],
|