@node9/proxy 2.14.2 → 2.14.3
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/cli.js +1464 -1334
- package/dist/cli.mjs +1394 -1266
- package/dist/dashboard.mjs +75 -5
- package/dist/index.js +216 -86
- package/dist/index.mjs +216 -86
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -4660,6 +4660,51 @@ var init_trusted_hosts = __esm({
|
|
|
4660
4660
|
}
|
|
4661
4661
|
});
|
|
4662
4662
|
|
|
4663
|
+
// src/auth/api-url.ts
|
|
4664
|
+
function defaultHostSuffixes() {
|
|
4665
|
+
const host = new URL(DEFAULT_API_URL).hostname.toLowerCase();
|
|
4666
|
+
const parent = host.split(".").slice(1).join(".");
|
|
4667
|
+
return parent.includes(".") ? [host, parent] : [host];
|
|
4668
|
+
}
|
|
4669
|
+
function allowedSuffixes() {
|
|
4670
|
+
const extra = (process.env[HOST_ALLOW_ENV] ?? "").split(",").map(
|
|
4671
|
+
(s) => s.trim().toLowerCase().replace(/^\*?\./, "")
|
|
4672
|
+
).filter(Boolean);
|
|
4673
|
+
return [...defaultHostSuffixes(), ...extra];
|
|
4674
|
+
}
|
|
4675
|
+
function validateApiUrl(raw) {
|
|
4676
|
+
if (typeof raw !== "string" || raw.length === 0 || raw.length > 2048) return null;
|
|
4677
|
+
let u;
|
|
4678
|
+
try {
|
|
4679
|
+
u = new URL(raw);
|
|
4680
|
+
} catch {
|
|
4681
|
+
return null;
|
|
4682
|
+
}
|
|
4683
|
+
if (u.username || u.password) return null;
|
|
4684
|
+
if (u.protocol !== "https:" && u.protocol !== "http:") return null;
|
|
4685
|
+
const host = u.hostname.toLowerCase();
|
|
4686
|
+
if (LOOPBACK.has(host)) return u;
|
|
4687
|
+
if (u.protocol !== "https:") return null;
|
|
4688
|
+
const suffixes = allowedSuffixes();
|
|
4689
|
+
const ok = suffixes.some((s) => host === s || host.endsWith("." + s));
|
|
4690
|
+
return ok ? u : null;
|
|
4691
|
+
}
|
|
4692
|
+
function safeApiUrl(raw, onReject) {
|
|
4693
|
+
const ok = validateApiUrl(raw);
|
|
4694
|
+
if (ok) return typeof raw === "string" ? raw : ok.toString();
|
|
4695
|
+
onReject?.(raw);
|
|
4696
|
+
return DEFAULT_API_URL;
|
|
4697
|
+
}
|
|
4698
|
+
var DEFAULT_API_URL, LOOPBACK, HOST_ALLOW_ENV;
|
|
4699
|
+
var init_api_url = __esm({
|
|
4700
|
+
"src/auth/api-url.ts"() {
|
|
4701
|
+
"use strict";
|
|
4702
|
+
DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
|
|
4703
|
+
LOOPBACK = /* @__PURE__ */ new Set(["127.0.0.1", "localhost", "::1", "[::1]", "0.0.0.0"]);
|
|
4704
|
+
HOST_ALLOW_ENV = "NODE9_API_HOST_ALLOW";
|
|
4705
|
+
}
|
|
4706
|
+
});
|
|
4707
|
+
|
|
4663
4708
|
// src/config/index.ts
|
|
4664
4709
|
import fs6 from "fs";
|
|
4665
4710
|
import path7 from "path";
|
|
@@ -4678,12 +4723,26 @@ function sanitizeSsrfAllow(entries, source) {
|
|
|
4678
4723
|
}
|
|
4679
4724
|
return kept;
|
|
4680
4725
|
}
|
|
4726
|
+
function noteRejectedApiUrl(raw) {
|
|
4727
|
+
const key = String(raw).slice(0, 200);
|
|
4728
|
+
if (rejectedApiUrlsSeen.has(key)) return;
|
|
4729
|
+
rejectedApiUrlsSeen.add(key);
|
|
4730
|
+
try {
|
|
4731
|
+
fs6.appendFileSync(
|
|
4732
|
+
path7.join(os7.homedir(), ".node9", "hook-debug.log"),
|
|
4733
|
+
`[${(/* @__PURE__ */ new Date()).toISOString()}] REFUSED apiUrl, using the default instead: ${String(raw).slice(0, 200).replace(/[\r\n]+/g, " ")}
|
|
4734
|
+
`
|
|
4735
|
+
);
|
|
4736
|
+
} catch {
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4681
4739
|
function getCredentials() {
|
|
4682
|
-
const DEFAULT_API_URL = "https://api.node9.ai/api/v1/intercept";
|
|
4683
4740
|
if (process.env.NODE9_API_KEY) {
|
|
4684
4741
|
return {
|
|
4685
4742
|
apiKey: process.env.NODE9_API_KEY,
|
|
4686
|
-
|
|
4743
|
+
// NODE9_API_URL is env, and a hook inherits the agent's env, so it is
|
|
4744
|
+
// no more trusted than the file below.
|
|
4745
|
+
apiUrl: safeApiUrl(process.env.NODE9_API_URL || DEFAULT_API_URL, noteRejectedApiUrl)
|
|
4687
4746
|
};
|
|
4688
4747
|
}
|
|
4689
4748
|
try {
|
|
@@ -4695,14 +4754,14 @@ function getCredentials() {
|
|
|
4695
4754
|
if (profile?.apiKey) {
|
|
4696
4755
|
return {
|
|
4697
4756
|
apiKey: profile.apiKey,
|
|
4698
|
-
apiUrl: profile.apiUrl || DEFAULT_API_URL,
|
|
4757
|
+
apiUrl: safeApiUrl(profile.apiUrl || DEFAULT_API_URL, noteRejectedApiUrl),
|
|
4699
4758
|
localOnly: profile.localOnly === true || profileName !== "default"
|
|
4700
4759
|
};
|
|
4701
4760
|
}
|
|
4702
4761
|
if (creds.apiKey) {
|
|
4703
4762
|
return {
|
|
4704
4763
|
apiKey: creds.apiKey,
|
|
4705
|
-
apiUrl: creds.apiUrl || DEFAULT_API_URL,
|
|
4764
|
+
apiUrl: safeApiUrl(creds.apiUrl || DEFAULT_API_URL, noteRejectedApiUrl),
|
|
4706
4765
|
localOnly: creds.localOnly === true
|
|
4707
4766
|
};
|
|
4708
4767
|
}
|
|
@@ -5332,7 +5391,7 @@ ${error.replace("Invalid config:\n", "")}
|
|
|
5332
5391
|
}
|
|
5333
5392
|
return sanitized;
|
|
5334
5393
|
}
|
|
5335
|
-
var DANGEROUS_WORDS, DEFAULT_CONFIG, RM_SAFE_PATH_PATTERN, VERDICT_ORDER, ADVISORY_SMART_RULES, cachedConfig, lastParsedRulesCache, CACHE_LOG_REARM_MS, cacheReadLastLoggedAt;
|
|
5394
|
+
var DANGEROUS_WORDS, DEFAULT_CONFIG, RM_SAFE_PATH_PATTERN, VERDICT_ORDER, ADVISORY_SMART_RULES, cachedConfig, rejectedApiUrlsSeen, lastParsedRulesCache, CACHE_LOG_REARM_MS, cacheReadLastLoggedAt;
|
|
5336
5395
|
var init_config = __esm({
|
|
5337
5396
|
"src/config/index.ts"() {
|
|
5338
5397
|
"use strict";
|
|
@@ -5343,6 +5402,7 @@ var init_config = __esm({
|
|
|
5343
5402
|
init_trusted_hosts();
|
|
5344
5403
|
init_dist();
|
|
5345
5404
|
init_dist();
|
|
5405
|
+
init_api_url();
|
|
5346
5406
|
DANGEROUS_WORDS = [
|
|
5347
5407
|
"mkfs",
|
|
5348
5408
|
// formats/wipes a filesystem partition
|
|
@@ -5616,6 +5676,7 @@ var init_config = __esm({
|
|
|
5616
5676
|
}
|
|
5617
5677
|
];
|
|
5618
5678
|
cachedConfig = null;
|
|
5679
|
+
rejectedApiUrlsSeen = /* @__PURE__ */ new Set();
|
|
5619
5680
|
lastParsedRulesCache = null;
|
|
5620
5681
|
CACHE_LOG_REARM_MS = 5 * 60 * 1e3;
|
|
5621
5682
|
cacheReadLastLoggedAt = 0;
|
|
@@ -6615,6 +6676,13 @@ var init_setup_pi_shim = __esm({
|
|
|
6615
6676
|
}
|
|
6616
6677
|
});
|
|
6617
6678
|
|
|
6679
|
+
// src/utils/atomic-write.ts
|
|
6680
|
+
var init_atomic_write = __esm({
|
|
6681
|
+
"src/utils/atomic-write.ts"() {
|
|
6682
|
+
"use strict";
|
|
6683
|
+
}
|
|
6684
|
+
});
|
|
6685
|
+
|
|
6618
6686
|
// src/setup.ts
|
|
6619
6687
|
import chalk3 from "chalk";
|
|
6620
6688
|
import { confirm as rawConfirm } from "@inquirer/prompts";
|
|
@@ -6627,6 +6695,7 @@ var init_setup = __esm({
|
|
|
6627
6695
|
init_hook_baseline();
|
|
6628
6696
|
init_setup_opencode_shim();
|
|
6629
6697
|
init_setup_pi_shim();
|
|
6698
|
+
init_atomic_write();
|
|
6630
6699
|
}
|
|
6631
6700
|
});
|
|
6632
6701
|
|
|
@@ -6651,6 +6720,7 @@ var init_scan_json = __esm({
|
|
|
6651
6720
|
var init_scan_history = __esm({
|
|
6652
6721
|
"src/cli/render/scan-history.ts"() {
|
|
6653
6722
|
"use strict";
|
|
6723
|
+
init_atomic_write();
|
|
6654
6724
|
}
|
|
6655
6725
|
});
|
|
6656
6726
|
|