@vibecook/truffle 0.4.6 → 0.4.8
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/dist/create-mesh-node.d.ts +1 -1
- package/dist/create-mesh-node.d.ts.map +1 -1
- package/dist/create-mesh-node.js +35 -16
- package/dist/create-mesh-node.js.map +1 -1
- package/dist/sidecar.d.ts.map +1 -1
- package/dist/sidecar.js +49 -3
- package/dist/sidecar.js.map +1 -1
- package/package.json +6 -6
- package/scripts/postinstall.cjs +129 -21
- package/sidecar-checksums.json +12 -0
|
@@ -36,7 +36,7 @@ export interface CreateMeshNodeOptions {
|
|
|
36
36
|
authKey?: string;
|
|
37
37
|
/** Whether this node is ephemeral (removed from tailnet on stop). */
|
|
38
38
|
ephemeral?: boolean;
|
|
39
|
-
/** WebSocket listener port
|
|
39
|
+
/** WebSocket listener port. Defaults to 9417 when omitted. */
|
|
40
40
|
wsPort?: number;
|
|
41
41
|
/**
|
|
42
42
|
* Auto-open the Tailscale auth URL in the default browser.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-mesh-node.d.ts","sourceRoot":"","sources":["../src/create-mesh-node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAuB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG7F;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,
|
|
1
|
+
{"version":3,"file":"create-mesh-node.d.ts","sourceRoot":"","sources":["../src/create-mesh-node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAuB,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAG7F;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,qEAAqE;IACrE,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/C;AAsBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA2EtF"}
|
package/dist/create-mesh-node.js
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
2
|
import { NapiNode } from '@vibecook/truffle-native';
|
|
3
3
|
import { resolveSidecarPath } from './sidecar.js';
|
|
4
4
|
/**
|
|
5
5
|
* Open a URL in the system's default browser.
|
|
6
6
|
*/
|
|
7
7
|
function defaultOpenUrl(url) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
//
|
|
21
|
-
}
|
|
8
|
+
// Only ever open http(s) URLs, and pass the URL as an argv element (never
|
|
9
|
+
// through a shell) so it cannot be interpreted as a command. The previous
|
|
10
|
+
// `execSync(`open "${url}"`)` form let shell metacharacters ($(), backticks)
|
|
11
|
+
// in the URL execute arbitrary commands.
|
|
12
|
+
if (!/^https?:\/\//i.test(url))
|
|
13
|
+
return;
|
|
14
|
+
const [cmd, args] = process.platform === 'darwin'
|
|
15
|
+
? ['open', [url]]
|
|
16
|
+
: process.platform === 'win32'
|
|
17
|
+
? ['explorer', [url]]
|
|
18
|
+
: ['xdg-open', [url]];
|
|
19
|
+
execFile(cmd, args, () => {
|
|
20
|
+
// Best-effort; ignore failures (no browser, headless environment, etc.).
|
|
21
|
+
});
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Create and start a Truffle node with sensible defaults.
|
|
@@ -41,6 +41,12 @@ function defaultOpenUrl(url) {
|
|
|
41
41
|
*/
|
|
42
42
|
export async function createMeshNode(options) {
|
|
43
43
|
const { appId, deviceName, deviceId, autoAuth = true, openUrl: customOpenUrl, onAuthRequired, onPeerChange, sidecarPath, stateDir, authKey, ephemeral, wsPort, } = options;
|
|
44
|
+
// Validate appId synchronously (mirrors the Rust-side rule) so a bad value
|
|
45
|
+
// fails here with a clear error instead of asynchronously across the FFI.
|
|
46
|
+
if (!/^[a-z][a-z0-9-]{1,31}$/.test(appId)) {
|
|
47
|
+
throw new Error(`[truffle] Invalid appId ${JSON.stringify(appId)}: must match ^[a-z][a-z0-9-]{1,31}$ ` +
|
|
48
|
+
`(2–32 chars; lowercase letters, digits, hyphens; must start with a letter).`);
|
|
49
|
+
}
|
|
44
50
|
const resolvedSidecarPath = sidecarPath ?? resolveSidecarPath();
|
|
45
51
|
const node = new NapiNode();
|
|
46
52
|
// IMPORTANT: install the auth-required callback BEFORE calling `start()`.
|
|
@@ -68,7 +74,20 @@ export async function createMeshNode(options) {
|
|
|
68
74
|
ephemeral,
|
|
69
75
|
wsPort,
|
|
70
76
|
};
|
|
71
|
-
|
|
77
|
+
try {
|
|
78
|
+
await node.start(config);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
// Best-effort cleanup so a failed start doesn't leak the spawned sidecar
|
|
82
|
+
// process. `stop()` is safe to call even if start() failed early.
|
|
83
|
+
try {
|
|
84
|
+
await node.stop();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// ignore — nothing to clean up, or already torn down
|
|
88
|
+
}
|
|
89
|
+
throw err;
|
|
90
|
+
}
|
|
72
91
|
// Post-start: forward ongoing peer lifecycle events to the user callback.
|
|
73
92
|
if (onPeerChange) {
|
|
74
93
|
node.onPeerChange(onPeerChange);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-mesh-node.js","sourceRoot":"","sources":["../src/create-mesh-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAA2C,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAyDlD;;GAEG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"create-mesh-node.js","sourceRoot":"","sources":["../src/create-mesh-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAA2C,MAAM,0BAA0B,CAAC;AAC7F,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAyDlD;;GAEG;AACH,SAAS,cAAc,CAAC,GAAW;IACjC,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,yCAAyC;IACzC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO;IACvC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GACf,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC3B,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;YACrB,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE;QACvB,yEAAyE;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAA8B;IACjE,MAAM,EACJ,KAAK,EACL,UAAU,EACV,QAAQ,EACR,QAAQ,GAAG,IAAI,EACf,OAAO,EAAE,aAAa,EACtB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,OAAO,EACP,SAAS,EACT,MAAM,GACP,GAAG,OAAO,CAAC;IAEZ,2EAA2E;IAC3E,0EAA0E;IAC1E,IAAI,CAAC,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CACb,2BAA2B,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,sCAAsC;YACpF,6EAA6E,CAChF,CAAC;IACJ,CAAC;IAED,MAAM,mBAAmB,GAAG,WAAW,IAAI,kBAAkB,EAAE,CAAC;IAEhE,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAE5B,0EAA0E;IAC1E,wEAAwE;IACxE,iEAAiE;IACjE,wEAAwE;IACxE,gEAAgE;IAChE,EAAE;IACF,0EAA0E;IAC1E,4DAA4D;IAC5D,IAAI,CAAC,cAAc,CAAC,CAAC,GAAW,EAAE,EAAE;QAClC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,aAAa,IAAI,cAAc,CAAC;YAC/C,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC;QACD,cAAc,EAAE,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAmB;QAC7B,KAAK;QACL,UAAU;QACV,QAAQ;QACR,WAAW,EAAE,mBAAmB;QAChC,QAAQ;QACR,OAAO;QACP,SAAS;QACT,MAAM;KACP,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,kEAAkE;QAClE,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,0EAA0E;IAC1E,IAAI,YAAY,EAAE,CAAC;QACjB,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/sidecar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAyDH;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CA+B3C"}
|
package/dist/sidecar.js
CHANGED
|
@@ -8,11 +8,56 @@
|
|
|
8
8
|
*
|
|
9
9
|
* Follows the esbuild pattern for distributing platform-specific binaries.
|
|
10
10
|
*/
|
|
11
|
-
import { existsSync } from 'node:fs';
|
|
11
|
+
import { closeSync, existsSync, openSync, readSync } from 'node:fs';
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
13
13
|
import { dirname, join } from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
const require = createRequire(import.meta.url);
|
|
16
|
+
/**
|
|
17
|
+
* Best-effort check that a local binary's architecture matches this process.
|
|
18
|
+
*
|
|
19
|
+
* The `bin/` fallback is populated by postinstall for the *current* platform,
|
|
20
|
+
* but a stray/leftover binary of the wrong arch would otherwise be returned and
|
|
21
|
+
* fail later with a cryptic `ENOEXEC`. We sniff the executable's magic bytes and
|
|
22
|
+
* only reject on a *positive* mismatch; when we can't tell, we allow it.
|
|
23
|
+
*/
|
|
24
|
+
function binaryMatchesPlatform(path) {
|
|
25
|
+
let fd;
|
|
26
|
+
try {
|
|
27
|
+
fd = openSync(path, 'r');
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const buf = Buffer.alloc(20);
|
|
34
|
+
if (readSync(fd, buf, 0, 20, 0) < 20)
|
|
35
|
+
return true; // too small to judge
|
|
36
|
+
// Mach-O 64-bit (macOS): LE magic 0xFEEDFACF, cputype at offset 4.
|
|
37
|
+
if (buf[0] === 0xcf && buf[1] === 0xfa && buf[2] === 0xed && buf[3] === 0xfe) {
|
|
38
|
+
const cpuType = buf.readUInt32LE(4);
|
|
39
|
+
if (process.arch === 'arm64')
|
|
40
|
+
return cpuType === 0x0100000c; // CPU_TYPE_ARM64
|
|
41
|
+
if (process.arch === 'x64')
|
|
42
|
+
return cpuType === 0x01000007; // CPU_TYPE_X86_64
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
// ELF (Linux): magic 0x7F 'E' 'L' 'F', e_machine at offset 18 (LE).
|
|
46
|
+
if (buf[0] === 0x7f && buf[1] === 0x45 && buf[2] === 0x4c && buf[3] === 0x46) {
|
|
47
|
+
const machine = buf.readUInt16LE(18);
|
|
48
|
+
if (process.arch === 'x64')
|
|
49
|
+
return machine === 0x3e; // EM_X86_64
|
|
50
|
+
if (process.arch === 'arm64')
|
|
51
|
+
return machine === 0xb7; // EM_AARCH64
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
// PE (Windows) / unknown format — don't block.
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
closeSync(fd);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
16
61
|
const PLATFORM_PACKAGES = {
|
|
17
62
|
'darwin-arm64': '@vibecook/truffle-sidecar-darwin-arm64',
|
|
18
63
|
'darwin-x64': '@vibecook/truffle-sidecar-darwin-x64',
|
|
@@ -46,10 +91,11 @@ export function resolveSidecarPath() {
|
|
|
46
91
|
// Package not installed — fall through
|
|
47
92
|
}
|
|
48
93
|
}
|
|
49
|
-
// 2. Try postinstall-downloaded binary (fallback)
|
|
94
|
+
// 2. Try postinstall-downloaded binary (fallback), but only if its arch
|
|
95
|
+
// matches this process — a wrong-arch leftover would fail with ENOEXEC.
|
|
50
96
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
51
97
|
const localBin = join(__dirname, '..', 'bin', binName);
|
|
52
|
-
if (existsSync(localBin))
|
|
98
|
+
if (existsSync(localBin) && binaryMatchesPlatform(localBin))
|
|
53
99
|
return localBin;
|
|
54
100
|
// 3. Nothing found
|
|
55
101
|
const supported = Object.keys(PLATFORM_PACKAGES).join(', ');
|
package/dist/sidecar.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibecook/truffle",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Mesh networking for local-first apps, built on Tailscale",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "James Yong",
|
|
@@ -40,15 +40,15 @@
|
|
|
40
40
|
},
|
|
41
41
|
"files": [
|
|
42
42
|
"dist",
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"scripts",
|
|
44
|
+
"sidecar-checksums.json"
|
|
45
45
|
],
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@vibecook/truffle-native": "0.4.
|
|
47
|
+
"@vibecook/truffle-native": "0.4.8"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"@vibecook/truffle-sidecar-darwin-arm64": "^0.
|
|
51
|
-
"@vibecook/truffle-sidecar-darwin-x64": "^0.4.
|
|
50
|
+
"@vibecook/truffle-sidecar-darwin-arm64": "^0.4.6",
|
|
51
|
+
"@vibecook/truffle-sidecar-darwin-x64": "^0.4.6",
|
|
52
52
|
"@vibecook/truffle-sidecar-linux-x64": "^0.4.5",
|
|
53
53
|
"@vibecook/truffle-sidecar-linux-arm64": "^0.4.5",
|
|
54
54
|
"@vibecook/truffle-sidecar-win32-x64": "^0.4.5"
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -3,19 +3,34 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Postinstall script for @vibecook/truffle.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Primary path: the platform-specific sidecar arrives via optionalDependencies
|
|
7
|
+
* (npm integrity-protected). Fallback (e.g. `--no-optional`): download the
|
|
8
|
+
* binary from GitHub Releases over HTTPS, then verify its SHA-256 against the
|
|
9
|
+
* checksums shipped *inside this package* (`sidecar-checksums.json`). When a
|
|
10
|
+
* checksum is present we fail closed on mismatch; when absent we warn loudly
|
|
11
|
+
* that integrity could not be verified.
|
|
8
12
|
*
|
|
9
|
-
* This
|
|
13
|
+
* This replaces the previous unverified `curl | chmod +x` fallback.
|
|
10
14
|
*/
|
|
11
15
|
|
|
12
16
|
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
13
17
|
|
|
14
|
-
const {
|
|
18
|
+
const {
|
|
19
|
+
existsSync,
|
|
20
|
+
mkdirSync,
|
|
21
|
+
chmodSync,
|
|
22
|
+
createWriteStream,
|
|
23
|
+
createReadStream,
|
|
24
|
+
readFileSync,
|
|
25
|
+
unlinkSync,
|
|
26
|
+
} = require('fs');
|
|
15
27
|
const { join, dirname } = require('path');
|
|
16
|
-
const
|
|
28
|
+
const https = require('https');
|
|
29
|
+
const crypto = require('crypto');
|
|
17
30
|
|
|
18
31
|
const GITHUB_REPO = 'jamesyong-42/truffle';
|
|
32
|
+
const DOWNLOAD_TIMEOUT_MS = 60_000;
|
|
33
|
+
const MAX_ATTEMPTS = 3;
|
|
19
34
|
|
|
20
35
|
const PLATFORM_PACKAGES = {
|
|
21
36
|
'darwin-arm64': '@vibecook/truffle-sidecar-darwin-arm64',
|
|
@@ -34,18 +49,74 @@ const GITHUB_ASSETS = {
|
|
|
34
49
|
'win32-x64': 'tsnet-sidecar-windows-amd64.exe',
|
|
35
50
|
};
|
|
36
51
|
|
|
37
|
-
|
|
52
|
+
/** Download `url` to `dest` over HTTPS, following redirects, with a hard timeout. */
|
|
53
|
+
function httpsDownload(url, dest, timeoutMs) {
|
|
54
|
+
return new Promise((resolve, reject) => {
|
|
55
|
+
const req = https.get(url, { headers: { 'User-Agent': 'truffle-postinstall' } }, (res) => {
|
|
56
|
+
// GitHub release downloads redirect to a CDN — follow 3xx.
|
|
57
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
58
|
+
res.resume();
|
|
59
|
+
httpsDownload(res.headers.location, dest, timeoutMs).then(resolve, reject);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (res.statusCode !== 200) {
|
|
63
|
+
res.resume();
|
|
64
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const file = createWriteStream(dest);
|
|
68
|
+
res.pipe(file);
|
|
69
|
+
file.on('finish', () => file.close((err) => (err ? reject(err) : resolve())));
|
|
70
|
+
file.on('error', (err) => {
|
|
71
|
+
try {
|
|
72
|
+
unlinkSync(dest);
|
|
73
|
+
} catch {
|
|
74
|
+
/* ignore */
|
|
75
|
+
}
|
|
76
|
+
reject(err);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
req.setTimeout(timeoutMs, () => req.destroy(new Error(`timed out after ${timeoutMs}ms`)));
|
|
80
|
+
req.on('error', reject);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Compute the hex SHA-256 of a file. */
|
|
85
|
+
function sha256File(path) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const hash = crypto.createHash('sha256');
|
|
88
|
+
const s = createReadStream(path);
|
|
89
|
+
s.on('data', (d) => hash.update(d));
|
|
90
|
+
s.on('end', () => resolve(hash.digest('hex')));
|
|
91
|
+
s.on('error', reject);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/** Look up the expected SHA-256 for a given version/asset from the shipped checksum map. */
|
|
96
|
+
function loadExpectedChecksum(version, asset) {
|
|
97
|
+
try {
|
|
98
|
+
const map = JSON.parse(readFileSync(join(__dirname, '..', 'sidecar-checksums.json'), 'utf8'));
|
|
99
|
+
const byVersion = map[version] || map[`v${version}`];
|
|
100
|
+
return byVersion ? byVersion[asset] : undefined;
|
|
101
|
+
} catch {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function main() {
|
|
38
107
|
const key = `${process.platform}-${process.arch}`;
|
|
39
108
|
const pkg = PLATFORM_PACKAGES[key];
|
|
40
109
|
const ext = process.platform === 'win32' ? '.exe' : '';
|
|
41
110
|
const binName = `sidecar-slim${ext}`;
|
|
42
111
|
|
|
43
112
|
if (!pkg) {
|
|
44
|
-
console.warn(
|
|
113
|
+
console.warn(
|
|
114
|
+
`[truffle] No prebuilt sidecar for ${key}. Build from source: cd packages/sidecar-slim && go build`,
|
|
115
|
+
);
|
|
45
116
|
return;
|
|
46
117
|
}
|
|
47
118
|
|
|
48
|
-
//
|
|
119
|
+
// Primary: was the platform optionalDependency installed?
|
|
49
120
|
try {
|
|
50
121
|
const pkgJson = require.resolve(`${pkg}/package.json`);
|
|
51
122
|
const binPath = join(dirname(pkgJson), 'bin', binName);
|
|
@@ -66,32 +137,69 @@ function main() {
|
|
|
66
137
|
// Not installed — fall through to download
|
|
67
138
|
}
|
|
68
139
|
|
|
69
|
-
// Fallback: download from GitHub Releases
|
|
140
|
+
// Fallback: download from GitHub Releases (verified).
|
|
70
141
|
const asset = GITHUB_ASSETS[key];
|
|
71
142
|
if (!asset) return;
|
|
72
143
|
|
|
73
144
|
const version = require('../package.json').version;
|
|
74
145
|
const url = `https://github.com/${GITHUB_REPO}/releases/download/v${version}/${asset}`;
|
|
146
|
+
const expected = loadExpectedChecksum(version, asset);
|
|
75
147
|
|
|
76
148
|
console.log(`[truffle] Sidecar not found via npm. Downloading from GitHub Releases...`);
|
|
77
149
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
150
|
+
const binDir = join(__dirname, '..', 'bin');
|
|
151
|
+
const dest = join(binDir, binName);
|
|
152
|
+
|
|
153
|
+
// Retry only the network download; a checksum mismatch is deterministic and
|
|
154
|
+
// must NOT be retried (it would just re-download the same bad bytes).
|
|
155
|
+
let downloaded = false;
|
|
156
|
+
for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
|
|
157
|
+
try {
|
|
158
|
+
mkdirSync(binDir, { recursive: true });
|
|
159
|
+
await httpsDownload(url, dest, DOWNLOAD_TIMEOUT_MS);
|
|
160
|
+
downloaded = true;
|
|
161
|
+
break;
|
|
162
|
+
} catch (err) {
|
|
163
|
+
console.warn(`[truffle] Download attempt ${attempt}/${MAX_ATTEMPTS} failed: ${err.message}`);
|
|
87
164
|
}
|
|
165
|
+
}
|
|
88
166
|
|
|
89
|
-
|
|
90
|
-
} catch {
|
|
167
|
+
if (!downloaded) {
|
|
91
168
|
console.warn(`[truffle] Could not download sidecar binary.`);
|
|
92
169
|
console.warn(`[truffle] Download manually: ${url}`);
|
|
93
|
-
console.warn(
|
|
170
|
+
console.warn(
|
|
171
|
+
`[truffle] Or build from source: cd packages/sidecar-slim && go build -o bin/sidecar-slim`,
|
|
172
|
+
);
|
|
173
|
+
return;
|
|
94
174
|
}
|
|
175
|
+
|
|
176
|
+
// Integrity check.
|
|
177
|
+
if (expected) {
|
|
178
|
+
const actual = await sha256File(dest);
|
|
179
|
+
if (actual.toLowerCase() !== expected.toLowerCase()) {
|
|
180
|
+
try {
|
|
181
|
+
unlinkSync(dest);
|
|
182
|
+
} catch {
|
|
183
|
+
/* ignore */
|
|
184
|
+
}
|
|
185
|
+
console.error(
|
|
186
|
+
`[truffle] SECURITY: sidecar checksum mismatch for v${version}/${asset}. ` +
|
|
187
|
+
`Deleted the download and refusing to install it. Expected ${expected}, got ${actual}.`,
|
|
188
|
+
);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
console.warn(
|
|
193
|
+
`[truffle] WARNING: no pinned checksum for v${version}/${asset}; integrity NOT verified. ` +
|
|
194
|
+
`Prefer installing with optionalDependencies enabled.`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (process.platform !== 'win32') {
|
|
199
|
+
chmodSync(dest, 0o755);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
console.log(`[truffle] Sidecar downloaded${expected ? ' and verified' : ''}.`);
|
|
95
203
|
}
|
|
96
204
|
|
|
97
205
|
main();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "SHA-256 of each GitHub Release sidecar asset, keyed by release version then by asset filename. This file ships inside the npm package (which npm integrity-protects), so it is the trust anchor for the postinstall HTTPS download fallback. When an entry for the installing version/asset is present, postinstall FAILS CLOSED on a checksum mismatch; when absent it warns that integrity was not verified. Populate this at release time, e.g. `shasum -a 256 tsnet-sidecar-*` over the built assets. Keys must match GITHUB_ASSETS in scripts/postinstall.cjs.",
|
|
3
|
+
"_example": {
|
|
4
|
+
"0.4.7": {
|
|
5
|
+
"tsnet-sidecar-darwin-arm64": "<sha256-hex>",
|
|
6
|
+
"tsnet-sidecar-darwin-amd64": "<sha256-hex>",
|
|
7
|
+
"tsnet-sidecar-linux-amd64": "<sha256-hex>",
|
|
8
|
+
"tsnet-sidecar-linux-arm64": "<sha256-hex>",
|
|
9
|
+
"tsnet-sidecar-windows-amd64.exe": "<sha256-hex>"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|