@node9/proxy 2.14.2 → 2.15.0
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/README.md +1 -1
- package/dist/cli.js +1476 -1337
- package/dist/cli.mjs +1406 -1269
- package/dist/dashboard.mjs +82 -7
- package/dist/index.js +223 -88
- package/dist/index.mjs +223 -88
- package/package.json +5 -4
package/dist/dashboard.mjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __esm = (fn, res) => function __init() {
|
|
4
|
-
|
|
3
|
+
var __esm = (fn, res, err) => function __init() {
|
|
4
|
+
if (err) throw err[0];
|
|
5
|
+
try {
|
|
6
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
7
|
+
} catch (e) {
|
|
8
|
+
throw err = [e], e;
|
|
9
|
+
}
|
|
5
10
|
};
|
|
6
11
|
var __export = (target, all) => {
|
|
7
12
|
for (var name in all)
|
|
@@ -4660,6 +4665,51 @@ var init_trusted_hosts = __esm({
|
|
|
4660
4665
|
}
|
|
4661
4666
|
});
|
|
4662
4667
|
|
|
4668
|
+
// src/auth/api-url.ts
|
|
4669
|
+
function defaultHostSuffixes() {
|
|
4670
|
+
const host = new URL(DEFAULT_API_URL).hostname.toLowerCase();
|
|
4671
|
+
const parent = host.split(".").slice(1).join(".");
|
|
4672
|
+
return parent.includes(".") ? [host, parent] : [host];
|
|
4673
|
+
}
|
|
4674
|
+
function allowedSuffixes() {
|
|
4675
|
+
const extra = (process.env[HOST_ALLOW_ENV] ?? "").split(",").map(
|
|
4676
|
+
(s) => s.trim().toLowerCase().replace(/^\*?\./, "")
|
|
4677
|
+
).filter(Boolean);
|
|
4678
|
+
return [...defaultHostSuffixes(), ...extra];
|
|
4679
|
+
}
|
|
4680
|
+
function validateApiUrl(raw) {
|
|
4681
|
+
if (typeof raw !== "string" || raw.length === 0 || raw.length > 2048) return null;
|
|
4682
|
+
let u;
|
|
4683
|
+
try {
|
|
4684
|
+
u = new URL(raw);
|
|
4685
|
+
} catch {
|
|
4686
|
+
return null;
|
|
4687
|
+
}
|
|
4688
|
+
if (u.username || u.password) return null;
|
|
4689
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return null;
|
|
4690
|
+
const host = u.hostname.toLowerCase();
|
|
4691
|
+
if (LOOPBACK.has(host)) return u;
|
|
4692
|
+
if (u.protocol !== "https:") return null;
|
|
4693
|
+
const suffixes = allowedSuffixes();
|
|
4694
|
+
const ok = suffixes.some((s) => host === s || host.endsWith("." + s));
|
|
4695
|
+
return ok ? u : null;
|
|
4696
|
+
}
|
|
4697
|
+
function safeApiUrl(raw, onReject) {
|
|
4698
|
+
const ok = validateApiUrl(raw);
|
|
4699
|
+
if (ok) return typeof raw === "string" ? raw : ok.toString();
|
|
4700
|
+
onReject?.(raw);
|
|
4701
|
+
return DEFAULT_API_URL;
|
|
4702
|
+
}
|
|
4703
|
+
var DEFAULT_API_URL, LOOPBACK, HOST_ALLOW_ENV;
|
|
4704
|
+
var init_api_url = __esm({
|
|
4705
|
+
"src/auth/api-url.ts"() {
|
|
4706
|
+
"use strict";
|
|
4707
|
+
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
|
|
4708
|
+
LOOPBACK = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"]);
|
|
4709
|
+
HOST_ALLOW_ENV = "NODE9_API_HOST_ALLOW";
|
|
4710
|
+
}
|
|
4711
|
+
});
|
|
4712
|
+
|
|
4663
4713
|
// src/config/index.ts
|
|
4664
4714
|
import fs6 from "fs";
|
|
4665
4715
|
import path7 from "path";
|
|
@@ -4678,12 +4728,26 @@ function sanitizeSsrfAllow(entries, source) {
|
|
|
4678
4728
|
}
|
|
4679
4729
|
return kept;
|
|
4680
4730
|
}
|
|
4731
|
+
function noteRejectedApiUrl(raw) {
|
|
4732
|
+
const key = String(raw).slice(0, 200);
|
|
4733
|
+
if (rejectedApiUrlsSeen.has(key)) return;
|
|
4734
|
+
rejectedApiUrlsSeen.add(key);
|
|
4735
|
+
try {
|
|
4736
|
+
fs6.appendFileSync(
|
|
4737
|
+
path7.join(os7.homedir(), ".node9", "hook-debug.log"),
|
|
4738
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] REFUSED apiUrl, using the default instead: ${String(raw).slice(0, 200).replace(/[\r\n]+/g, " ")}
|
|
4739
|
+
`
|
|
4740
|
+
);
|
|
4741
|
+
} catch {
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4681
4744
|
function getCredentials() {
|
|
4682
|
-
const DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
|
|
4683
4745
|
if (process.env.NODE9_API_KEY) {
|
|
4684
4746
|
return {
|
|
4685
4747
|
apiKey: process.env.NODE9_API_KEY,
|
|
4686
|
-
|
|
4748
|
+
// NODE9_API_URL is env, and a hook inherits the agent's env, so it is
|
|
4749
|
+
// no more trusted than the file below.
|
|
4750
|
+
apiUrl: safeApiUrl(process.env.NODE9_API_URL || DEFAULT_API_URL, noteRejectedApiUrl)
|
|
4687
4751
|
};
|
|
4688
4752
|
}
|
|
4689
4753
|
try {
|
|
@@ -4695,14 +4759,14 @@ function getCredentials() {
|
|
|
4695
4759
|
if (profile?.apiKey) {
|
|
4696
4760
|
return {
|
|
4697
4761
|
apiKey: profile.apiKey,
|
|
4698
|
-
apiUrl: profile.apiUrl || DEFAULT_API_URL,
|
|
4762
|
+
apiUrl: safeApiUrl(profile.apiUrl || DEFAULT_API_URL, noteRejectedApiUrl),
|
|
4699
4763
|
localOnly: profile.localOnly === true || profileName !== "default"
|
|
4700
4764
|
};
|
|
4701
4765
|
}
|
|
4702
4766
|
if (creds.apiKey) {
|
|
4703
4767
|
return {
|
|
4704
4768
|
apiKey: creds.apiKey,
|
|
4705
|
-
apiUrl: creds.apiUrl || DEFAULT_API_URL,
|
|
4769
|
+
apiUrl: safeApiUrl(creds.apiUrl || DEFAULT_API_URL, noteRejectedApiUrl),
|
|
4706
4770
|
localOnly: creds.localOnly === true
|
|
4707
4771
|
};
|
|
4708
4772
|
}
|
|
@@ -5332,7 +5396,7 @@ ${error.replace("Invalid config:\n", "")}
|
|
|
5332
5396
|
}
|
|
5333
5397
|
return sanitized;
|
|
5334
5398
|
}
|
|
5335
|
-
var DANGEROUS_WORDS, DEFAULT_CONFIG, RM_SAFE_PATH_PATTERN, VERDICT_ORDER, ADVISORY_SMART_RULES, cachedConfig, lastParsedRulesCache, CACHE_LOG_REARM_MS, cacheReadLastLoggedAt;
|
|
5399
|
+
var DANGEROUS_WORDS, DEFAULT_CONFIG, RM_SAFE_PATH_PATTERN, VERDICT_ORDER, ADVISORY_SMART_RULES, cachedConfig, rejectedApiUrlsSeen, lastParsedRulesCache, CACHE_LOG_REARM_MS, cacheReadLastLoggedAt;
|
|
5336
5400
|
var init_config = __esm({
|
|
5337
5401
|
"src/config/index.ts"() {
|
|
5338
5402
|
"use strict";
|
|
@@ -5343,6 +5407,7 @@ var init_config = __esm({
|
|
|
5343
5407
|
init_trusted_hosts();
|
|
5344
5408
|
init_dist();
|
|
5345
5409
|
init_dist();
|
|
5410
|
+
init_api_url();
|
|
5346
5411
|
DANGEROUS_WORDS = [
|
|
5347
5412
|
"mkfs",
|
|
5348
5413
|
// formats/wipes a filesystem partition
|
|
@@ -5616,6 +5681,7 @@ var init_config = __esm({
|
|
|
5616
5681
|
}
|
|
5617
5682
|
];
|
|
5618
5683
|
cachedConfig = null;
|
|
5684
|
+
rejectedApiUrlsSeen = /* @__PURE__ */ new Set();
|
|
5619
5685
|
lastParsedRulesCache = null;
|
|
5620
5686
|
CACHE_LOG_REARM_MS = 5 * 60 * 1e3;
|
|
5621
5687
|
cacheReadLastLoggedAt = 0;
|
|
@@ -6615,6 +6681,13 @@ var init_setup_pi_shim = __esm({
|
|
|
6615
6681
|
}
|
|
6616
6682
|
});
|
|
6617
6683
|
|
|
6684
|
+
// src/utils/atomic-write.ts
|
|
6685
|
+
var init_atomic_write = __esm({
|
|
6686
|
+
"src/utils/atomic-write.ts"() {
|
|
6687
|
+
"use strict";
|
|
6688
|
+
}
|
|
6689
|
+
});
|
|
6690
|
+
|
|
6618
6691
|
// src/setup.ts
|
|
6619
6692
|
import chalk3 from "chalk";
|
|
6620
6693
|
import { confirm as rawConfirm } from "@inquirer/prompts";
|
|
@@ -6627,6 +6700,7 @@ var init_setup = __esm({
|
|
|
6627
6700
|
init_hook_baseline();
|
|
6628
6701
|
init_setup_opencode_shim();
|
|
6629
6702
|
init_setup_pi_shim();
|
|
6703
|
+
init_atomic_write();
|
|
6630
6704
|
}
|
|
6631
6705
|
});
|
|
6632
6706
|
|
|
@@ -6651,6 +6725,7 @@ var init_scan_json = __esm({
|
|
|
6651
6725
|
var init_scan_history = __esm({
|
|
6652
6726
|
"src/cli/render/scan-history.ts"() {
|
|
6653
6727
|
"use strict";
|
|
6728
|
+
init_atomic_write();
|
|
6654
6729
|
}
|
|
6655
6730
|
});
|
|
6656
6731
|
|