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 CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "infynon",
3
- "version": "0.2.4",
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
- throw new Error("Too many redirects while downloading binary");
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 === 301 || res.statusCode === 302) {
32
- return downloadFile(res.headers.location, dest, redirects + 1)
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
- await downloadFile(url, BIN_PATH);
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
- // Mirror the same path logic as src/firewall/config.rs → config_dir()
9
- const INFYNON_DIR = path.join(os.homedir(), ".infynon");
7
+ const BIN_DIR = path.join(__dirname, "bin");
10
8
 
11
- // Files/dirs managed by infynon that live outside the npm package
12
- const MANAGED_PATHS = [
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
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ process.argv.splice(2, 0, "pkg");
5
+ require("./run.js");
package/run.js CHANGED
@@ -20,13 +20,31 @@ if (!fs.existsSync(BIN_PATH)) {
20
20
  process.exit(1);
21
21
  }
22
22
 
23
- const result = spawnSync(BIN_PATH, process.argv.slice(2), {
24
- stdio: "inherit",
25
- windowsHide: false,
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