infynon 0.2.4 → 0.2.6
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/package.json +3 -2
- package/postinstall.js +100 -4
- package/preuninstall.js +3 -48
- package/run-pkg.js +5 -0
- package/run.js +22 -4
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infynon",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"description": "Thin npm installer for the proprietary INFYNON CLI binary releases.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"infynon": "run.js",
|
|
7
|
-
"infynon-pkg": "run.js"
|
|
7
|
+
"infynon-pkg": "run-pkg.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"postinstall": "node postinstall.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"LICENSE",
|
|
15
15
|
"run.js",
|
|
16
|
+
"run-pkg.js",
|
|
16
17
|
"postinstall.js",
|
|
17
18
|
"preuninstall.js"
|
|
18
19
|
],
|
package/postinstall.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
|
+
const crypto = require("crypto");
|
|
4
5
|
const https = require("https");
|
|
5
6
|
const fs = require("fs");
|
|
6
7
|
const path = require("path");
|
|
8
|
+
const { spawnSync } = require("child_process");
|
|
7
9
|
|
|
8
10
|
const REPO = "d4rkNinja/infynon-cli";
|
|
9
11
|
const VERSION = require("./package.json").version;
|
|
10
12
|
const BIN_DIR = path.join(__dirname, "bin");
|
|
11
13
|
const BIN_PATH = path.join(BIN_DIR, process.platform === "win32" ? "infynon.exe" : "infynon");
|
|
14
|
+
const TEMP_BIN_PATH = BIN_PATH + ".download-" + process.pid;
|
|
15
|
+
const TEMP_CHECKSUMS_PATH = BIN_PATH + ".checksums-" + process.pid + ".txt";
|
|
12
16
|
|
|
13
17
|
function getTarget() {
|
|
14
18
|
if (process.platform === "win32" && process.arch === "x64") return { target: "x86_64-pc-windows-msvc", ext: ".exe" };
|
|
@@ -22,14 +26,24 @@ function getTarget() {
|
|
|
22
26
|
function downloadFile(url, dest, redirects) {
|
|
23
27
|
redirects = redirects === undefined ? 0 : redirects;
|
|
24
28
|
if (redirects > 5) {
|
|
25
|
-
|
|
29
|
+
return Promise.reject(new Error("Too many redirects while downloading binary"));
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
return new Promise(function (resolve, reject) {
|
|
29
33
|
https
|
|
30
34
|
.get(url, { headers: { "User-Agent": "infynon-npm-installer" } }, function (res) {
|
|
31
|
-
if (res.statusCode
|
|
32
|
-
|
|
35
|
+
if (res.statusCode >= 300 && res.statusCode < 400) {
|
|
36
|
+
res.resume();
|
|
37
|
+
if (!res.headers.location) {
|
|
38
|
+
return reject(new Error("Redirect response did not include a Location header"));
|
|
39
|
+
}
|
|
40
|
+
let nextUrl;
|
|
41
|
+
try {
|
|
42
|
+
nextUrl = new URL(res.headers.location, url).toString();
|
|
43
|
+
} catch (err) {
|
|
44
|
+
return reject(err);
|
|
45
|
+
}
|
|
46
|
+
return downloadFile(nextUrl, dest, redirects + 1)
|
|
33
47
|
.then(resolve)
|
|
34
48
|
.catch(reject);
|
|
35
49
|
}
|
|
@@ -47,6 +61,12 @@ function downloadFile(url, dest, redirects) {
|
|
|
47
61
|
file.on("finish", function () {
|
|
48
62
|
file.close(resolve);
|
|
49
63
|
});
|
|
64
|
+
res.on("error", function (err) {
|
|
65
|
+
file.close(function () {
|
|
66
|
+
fs.unlink(dest, function () {});
|
|
67
|
+
reject(err);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
50
70
|
res.pipe(file);
|
|
51
71
|
})
|
|
52
72
|
.on("error", function (err) {
|
|
@@ -56,6 +76,62 @@ function downloadFile(url, dest, redirects) {
|
|
|
56
76
|
});
|
|
57
77
|
}
|
|
58
78
|
|
|
79
|
+
function removeQuietly(filePath) {
|
|
80
|
+
try {
|
|
81
|
+
fs.rmSync(filePath, { force: true });
|
|
82
|
+
} catch (_) {}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function checksumForAsset(checksumsText, assetName) {
|
|
86
|
+
const lines = checksumsText.split(/\r?\n/);
|
|
87
|
+
for (const line of lines) {
|
|
88
|
+
const match = line.match(/^([a-fA-F0-9]{64})\s+[* ]?(.+)$/);
|
|
89
|
+
if (!match) continue;
|
|
90
|
+
if (path.basename(match[2].trim()) === assetName) {
|
|
91
|
+
return match[1].toLowerCase();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
throw new Error("checksums.txt does not include " + assetName);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function sha256File(filePath) {
|
|
98
|
+
return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function verifyChecksum(checksumsPath, filePath, assetName) {
|
|
102
|
+
const expected = checksumForAsset(fs.readFileSync(checksumsPath, "utf8"), assetName);
|
|
103
|
+
const actual = sha256File(filePath);
|
|
104
|
+
if (actual !== expected) {
|
|
105
|
+
throw new Error("SHA-256 mismatch for " + assetName);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function verifyBinary() {
|
|
110
|
+
const result = spawnSync(BIN_PATH, ["--version"], {
|
|
111
|
+
encoding: "utf8",
|
|
112
|
+
windowsHide: true,
|
|
113
|
+
});
|
|
114
|
+
if (result.error) {
|
|
115
|
+
throw new Error("Downloaded binary is not executable: " + result.error.message);
|
|
116
|
+
}
|
|
117
|
+
if (result.status !== 0) {
|
|
118
|
+
const detail = (result.stderr || result.stdout || "").trim();
|
|
119
|
+
throw new Error(
|
|
120
|
+
"Downloaded binary failed verification" +
|
|
121
|
+
(detail ? ": " + detail : " with exit code " + result.status)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
const versionFields = String((result.stdout || "") + " " + (result.stderr || ""))
|
|
125
|
+
.trim()
|
|
126
|
+
.split(/\s+/)
|
|
127
|
+
.map(function (field) {
|
|
128
|
+
return field.replace(/^v/, "");
|
|
129
|
+
});
|
|
130
|
+
if (versionFields.indexOf(VERSION) === -1) {
|
|
131
|
+
throw new Error("Downloaded binary did not report version " + VERSION);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
59
135
|
async function main() {
|
|
60
136
|
const info = getTarget();
|
|
61
137
|
|
|
@@ -70,6 +146,7 @@ async function main() {
|
|
|
70
146
|
const tag = "v" + VERSION;
|
|
71
147
|
const assetName = "infynon-" + info.target + info.ext;
|
|
72
148
|
const url = "https://github.com/" + REPO + "/releases/download/" + tag + "/" + assetName;
|
|
149
|
+
const checksumsUrl = "https://github.com/" + REPO + "/releases/download/" + tag + "/checksums.txt";
|
|
73
150
|
|
|
74
151
|
if (!fs.existsSync(BIN_DIR)) {
|
|
75
152
|
fs.mkdirSync(BIN_DIR, { recursive: true });
|
|
@@ -78,17 +155,36 @@ async function main() {
|
|
|
78
155
|
console.log("[infynon] Downloading " + assetName + " from " + tag + " release...");
|
|
79
156
|
|
|
80
157
|
try {
|
|
81
|
-
|
|
158
|
+
removeQuietly(TEMP_BIN_PATH);
|
|
159
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
160
|
+
await downloadFile(url, TEMP_BIN_PATH);
|
|
161
|
+
await downloadFile(checksumsUrl, TEMP_CHECKSUMS_PATH);
|
|
162
|
+
verifyChecksum(TEMP_CHECKSUMS_PATH, TEMP_BIN_PATH, assetName);
|
|
163
|
+
removeQuietly(BIN_PATH);
|
|
164
|
+
fs.renameSync(TEMP_BIN_PATH, BIN_PATH);
|
|
82
165
|
} catch (err) {
|
|
166
|
+
removeQuietly(TEMP_BIN_PATH);
|
|
167
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
83
168
|
console.error("[infynon] Download failed: " + err.message);
|
|
84
169
|
console.error("[infynon] Manual install: https://github.com/" + REPO + "/releases/tag/" + tag);
|
|
85
170
|
process.exit(1);
|
|
171
|
+
} finally {
|
|
172
|
+
removeQuietly(TEMP_CHECKSUMS_PATH);
|
|
86
173
|
}
|
|
87
174
|
|
|
88
175
|
if (process.platform !== "win32") {
|
|
89
176
|
fs.chmodSync(BIN_PATH, 0o755);
|
|
90
177
|
}
|
|
91
178
|
|
|
179
|
+
try {
|
|
180
|
+
verifyBinary();
|
|
181
|
+
} catch (err) {
|
|
182
|
+
removeQuietly(BIN_PATH);
|
|
183
|
+
console.error("[infynon] Binary verification failed: " + err.message);
|
|
184
|
+
console.error("[infynon] Reinstall after the release asset is corrected: npm install -g infynon");
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
|
|
92
188
|
console.log("[infynon] Installed successfully. Run: infynon --help");
|
|
93
189
|
}
|
|
94
190
|
|
package/preuninstall.js
CHANGED
|
@@ -3,54 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
|
-
const os = require("os");
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
const INFYNON_DIR = path.join(os.homedir(), ".infynon");
|
|
7
|
+
const BIN_DIR = path.join(__dirname, "bin");
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
{ p: path.join(INFYNON_DIR, "infynon.toml"), label: "firewall config" },
|
|
14
|
-
{ p: path.join(INFYNON_DIR, "eagle-eye.toml"), label: "eagle eye config" },
|
|
15
|
-
{ p: path.join(INFYNON_DIR, "access.jsonl"), label: "access log" },
|
|
16
|
-
{ p: path.join(INFYNON_DIR, "blocked.jsonl"), label: "blocked log" },
|
|
17
|
-
{ p: path.join(INFYNON_DIR, "sbom.json"), label: "SBOM" },
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
console.log("\n[infynon] Cleaning up...\n");
|
|
21
|
-
|
|
22
|
-
let removed = 0;
|
|
23
|
-
|
|
24
|
-
for (const { p, label } of MANAGED_PATHS) {
|
|
25
|
-
if (fs.existsSync(p)) {
|
|
26
|
-
try {
|
|
27
|
-
fs.rmSync(p, { force: true });
|
|
28
|
-
console.log(" removed " + label + " (" + p + ")");
|
|
29
|
-
removed++;
|
|
30
|
-
} catch (err) {
|
|
31
|
-
console.warn(" skipped " + label + " — " + err.message);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Remove ~/.infynon/ itself if it is now empty
|
|
37
|
-
if (fs.existsSync(INFYNON_DIR)) {
|
|
38
|
-
try {
|
|
39
|
-
const remaining = fs.readdirSync(INFYNON_DIR);
|
|
40
|
-
if (remaining.length === 0) {
|
|
41
|
-
fs.rmdirSync(INFYNON_DIR);
|
|
42
|
-
console.log(" removed ~/.infynon/ directory");
|
|
43
|
-
} else {
|
|
44
|
-
console.log(
|
|
45
|
-
" kept ~/.infynon/ — " + remaining.length +
|
|
46
|
-
" user file(s) remain: " + remaining.join(", ")
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
} catch (_) {}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (removed === 0) {
|
|
53
|
-
console.log(" nothing to clean up.\n");
|
|
54
|
-
} else {
|
|
55
|
-
console.log("\n[infynon] Clean uninstall complete.\n");
|
|
9
|
+
if (fs.existsSync(BIN_DIR)) {
|
|
10
|
+
fs.rmSync(BIN_DIR, { recursive: true, force: true });
|
|
56
11
|
}
|
package/run-pkg.js
ADDED
package/run.js
CHANGED
|
@@ -20,13 +20,31 @@ if (!fs.existsSync(BIN_PATH)) {
|
|
|
20
20
|
process.exit(1);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
function runBinary(args) {
|
|
24
|
+
if (process.platform === "win32") {
|
|
25
|
+
const estimatedLength = BIN_PATH.length + args.reduce(function (total, arg) {
|
|
26
|
+
return total + String(arg).length + 3;
|
|
27
|
+
}, 0);
|
|
28
|
+
if (estimatedLength > 30000) {
|
|
29
|
+
return {
|
|
30
|
+
error: new Error("command line is too long for Windows process creation; reduce arguments or use file-based package-manager input"),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return spawnSync(BIN_PATH, args, {
|
|
35
|
+
stdio: "inherit",
|
|
36
|
+
windowsHide: false,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = runBinary(process.argv.slice(2));
|
|
27
41
|
|
|
28
42
|
if (result.error) {
|
|
29
43
|
console.error("[infynon] Failed to run binary:", result.error.message);
|
|
44
|
+
if (process.platform === "win32" && result.error.code === "UNKNOWN") {
|
|
45
|
+
console.error("[infynon] The installed Windows binary could not be executed.");
|
|
46
|
+
console.error("[infynon] Reinstall to download and verify a fresh release asset: npm install -g infynon");
|
|
47
|
+
}
|
|
30
48
|
process.exit(1);
|
|
31
49
|
}
|
|
32
50
|
|