@node9/proxy 1.0.19 → 1.1.1
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 +3 -1
- package/dist/cli.js +523 -251
- package/dist/cli.mjs +529 -257
- package/dist/index.js +178 -59
- package/dist/index.mjs +178 -59
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -37,13 +37,14 @@ module.exports = __toCommonJS(src_exports);
|
|
|
37
37
|
// src/core.ts
|
|
38
38
|
var import_chalk2 = __toESM(require("chalk"));
|
|
39
39
|
var import_prompts = require("@inquirer/prompts");
|
|
40
|
-
var
|
|
41
|
-
var
|
|
40
|
+
var import_fs3 = __toESM(require("fs"));
|
|
41
|
+
var import_path5 = __toESM(require("path"));
|
|
42
42
|
var import_os2 = __toESM(require("os"));
|
|
43
43
|
var import_net = __toESM(require("net"));
|
|
44
44
|
var import_crypto = require("crypto");
|
|
45
45
|
var import_child_process2 = require("child_process");
|
|
46
46
|
var import_picomatch = __toESM(require("picomatch"));
|
|
47
|
+
var import_safe_regex2 = __toESM(require("safe-regex2"));
|
|
47
48
|
var import_sh_syntax = require("sh-syntax");
|
|
48
49
|
|
|
49
50
|
// src/ui/native.ts
|
|
@@ -465,8 +466,8 @@ function sanitizeConfig(raw) {
|
|
|
465
466
|
}
|
|
466
467
|
}
|
|
467
468
|
const lines = result.error.issues.map((issue) => {
|
|
468
|
-
const
|
|
469
|
-
return ` \u2022 ${
|
|
469
|
+
const path6 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
470
|
+
return ` \u2022 ${path6}: ${issue.message}`;
|
|
470
471
|
});
|
|
471
472
|
return {
|
|
472
473
|
sanitized,
|
|
@@ -679,10 +680,14 @@ function readActiveShields() {
|
|
|
679
680
|
}
|
|
680
681
|
|
|
681
682
|
// src/dlp.ts
|
|
683
|
+
var import_fs2 = __toESM(require("fs"));
|
|
684
|
+
var import_path4 = __toESM(require("path"));
|
|
682
685
|
var DLP_PATTERNS = [
|
|
683
686
|
{ name: "AWS Access Key ID", regex: /\bAKIA[0-9A-Z]{16}\b/, severity: "block" },
|
|
684
687
|
{ name: "GitHub Token", regex: /\bgh[pous]_[A-Za-z0-9]{36}\b/, severity: "block" },
|
|
685
|
-
|
|
688
|
+
// Slack bot tokens: xoxb- + variable segment. Real tokens are ~50–80 chars;
|
|
689
|
+
// lower bound 20 avoids false negatives on partial tokens, upper 100 caps scan cost.
|
|
690
|
+
{ name: "Slack Bot Token", regex: /\bxoxb-[0-9A-Za-z-]{20,100}\b/, severity: "block" },
|
|
686
691
|
{ name: "OpenAI API Key", regex: /\bsk-[a-zA-Z0-9_-]{20,}\b/, severity: "block" },
|
|
687
692
|
{ name: "Stripe Secret Key", regex: /\bsk_(?:live|test)_[0-9a-zA-Z]{24}\b/, severity: "block" },
|
|
688
693
|
{
|
|
@@ -690,8 +695,76 @@ var DLP_PATTERNS = [
|
|
|
690
695
|
regex: /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/,
|
|
691
696
|
severity: "block"
|
|
692
697
|
},
|
|
698
|
+
// GCP service account JSON (detects the type field that uniquely identifies it)
|
|
699
|
+
{
|
|
700
|
+
name: "GCP Service Account",
|
|
701
|
+
regex: /"type"\s*:\s*"service_account"/,
|
|
702
|
+
severity: "block"
|
|
703
|
+
},
|
|
704
|
+
// NPM auth token in .npmrc format
|
|
705
|
+
{
|
|
706
|
+
name: "NPM Auth Token",
|
|
707
|
+
regex: /_authToken\s*=\s*[A-Za-z0-9_\-]{20,}/,
|
|
708
|
+
severity: "block"
|
|
709
|
+
},
|
|
693
710
|
{ name: "Bearer Token", regex: /Bearer\s+[a-zA-Z0-9\-._~+/]+=*/i, severity: "review" }
|
|
694
711
|
];
|
|
712
|
+
var SENSITIVE_PATH_PATTERNS = [
|
|
713
|
+
/[/\\]\.ssh[/\\]/i,
|
|
714
|
+
/[/\\]\.aws[/\\]/i,
|
|
715
|
+
/[/\\]\.config[/\\]gcloud[/\\]/i,
|
|
716
|
+
/[/\\]\.azure[/\\]/i,
|
|
717
|
+
/[/\\]\.kube[/\\]config$/i,
|
|
718
|
+
/[/\\]\.env($|\.)/i,
|
|
719
|
+
// .env, .env.local, .env.production — not .envoy
|
|
720
|
+
/[/\\]\.git-credentials$/i,
|
|
721
|
+
/[/\\]\.npmrc$/i,
|
|
722
|
+
/[/\\]\.docker[/\\]config\.json$/i,
|
|
723
|
+
/[/\\][^/\\]+\.pem$/i,
|
|
724
|
+
/[/\\][^/\\]+\.key$/i,
|
|
725
|
+
/[/\\][^/\\]+\.p12$/i,
|
|
726
|
+
/[/\\][^/\\]+\.pfx$/i,
|
|
727
|
+
/^\/etc\/passwd$/,
|
|
728
|
+
/^\/etc\/shadow$/,
|
|
729
|
+
/^\/etc\/sudoers$/,
|
|
730
|
+
/[/\\]credentials\.json$/i,
|
|
731
|
+
/[/\\]id_rsa$/i,
|
|
732
|
+
/[/\\]id_ed25519$/i,
|
|
733
|
+
/[/\\]id_ecdsa$/i
|
|
734
|
+
];
|
|
735
|
+
function scanFilePath(filePath, cwd = process.cwd()) {
|
|
736
|
+
if (!filePath) return null;
|
|
737
|
+
let resolved;
|
|
738
|
+
try {
|
|
739
|
+
const absolute = import_path4.default.resolve(cwd, filePath);
|
|
740
|
+
resolved = import_fs2.default.realpathSync.native(absolute);
|
|
741
|
+
} catch (err) {
|
|
742
|
+
const code = err.code;
|
|
743
|
+
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
744
|
+
resolved = import_path4.default.resolve(cwd, filePath);
|
|
745
|
+
} else {
|
|
746
|
+
return {
|
|
747
|
+
patternName: "Sensitive File Path",
|
|
748
|
+
fieldPath: "file_path",
|
|
749
|
+
redactedSample: filePath,
|
|
750
|
+
severity: "block"
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
const normalised = resolved.replace(/\\/g, "/");
|
|
755
|
+
for (const pattern of SENSITIVE_PATH_PATTERNS) {
|
|
756
|
+
if (pattern.test(normalised)) {
|
|
757
|
+
return {
|
|
758
|
+
patternName: "Sensitive File Path",
|
|
759
|
+
fieldPath: "file_path",
|
|
760
|
+
redactedSample: filePath,
|
|
761
|
+
// show original path in alert, not resolved
|
|
762
|
+
severity: "block"
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
return null;
|
|
767
|
+
}
|
|
695
768
|
function maskSecret(raw, pattern) {
|
|
696
769
|
const match = raw.match(pattern);
|
|
697
770
|
if (!match) return "****";
|
|
@@ -749,17 +822,17 @@ function scanArgs(args, depth = 0, fieldPath = "args") {
|
|
|
749
822
|
}
|
|
750
823
|
|
|
751
824
|
// src/core.ts
|
|
752
|
-
var PAUSED_FILE =
|
|
753
|
-
var TRUST_FILE =
|
|
754
|
-
var LOCAL_AUDIT_LOG =
|
|
755
|
-
var HOOK_DEBUG_LOG =
|
|
825
|
+
var PAUSED_FILE = import_path5.default.join(import_os2.default.homedir(), ".node9", "PAUSED");
|
|
826
|
+
var TRUST_FILE = import_path5.default.join(import_os2.default.homedir(), ".node9", "trust.json");
|
|
827
|
+
var LOCAL_AUDIT_LOG = import_path5.default.join(import_os2.default.homedir(), ".node9", "audit.log");
|
|
828
|
+
var HOOK_DEBUG_LOG = import_path5.default.join(import_os2.default.homedir(), ".node9", "hook-debug.log");
|
|
756
829
|
function checkPause() {
|
|
757
830
|
try {
|
|
758
|
-
if (!
|
|
759
|
-
const state = JSON.parse(
|
|
831
|
+
if (!import_fs3.default.existsSync(PAUSED_FILE)) return { paused: false };
|
|
832
|
+
const state = JSON.parse(import_fs3.default.readFileSync(PAUSED_FILE, "utf-8"));
|
|
760
833
|
if (state.expiry > 0 && Date.now() >= state.expiry) {
|
|
761
834
|
try {
|
|
762
|
-
|
|
835
|
+
import_fs3.default.unlinkSync(PAUSED_FILE);
|
|
763
836
|
} catch {
|
|
764
837
|
}
|
|
765
838
|
return { paused: false };
|
|
@@ -770,20 +843,66 @@ function checkPause() {
|
|
|
770
843
|
}
|
|
771
844
|
}
|
|
772
845
|
function atomicWriteSync(filePath, data, options) {
|
|
773
|
-
const dir =
|
|
774
|
-
if (!
|
|
846
|
+
const dir = import_path5.default.dirname(filePath);
|
|
847
|
+
if (!import_fs3.default.existsSync(dir)) import_fs3.default.mkdirSync(dir, { recursive: true });
|
|
775
848
|
const tmpPath = `${filePath}.${import_os2.default.hostname()}.${process.pid}.tmp`;
|
|
776
|
-
|
|
777
|
-
|
|
849
|
+
import_fs3.default.writeFileSync(tmpPath, data, options);
|
|
850
|
+
import_fs3.default.renameSync(tmpPath, filePath);
|
|
851
|
+
}
|
|
852
|
+
var MAX_REGEX_LENGTH = 100;
|
|
853
|
+
var REGEX_CACHE_MAX = 500;
|
|
854
|
+
var regexCache = /* @__PURE__ */ new Map();
|
|
855
|
+
function validateRegex(pattern) {
|
|
856
|
+
if (!pattern) return "Pattern is required";
|
|
857
|
+
if (pattern.length > MAX_REGEX_LENGTH) return `Pattern exceeds max length of ${MAX_REGEX_LENGTH}`;
|
|
858
|
+
try {
|
|
859
|
+
new RegExp(pattern);
|
|
860
|
+
} catch (e) {
|
|
861
|
+
return `Invalid regex syntax: ${e.message}`;
|
|
862
|
+
}
|
|
863
|
+
if (/\\\d+[*+{]/.test(pattern)) return "Quantified backreferences are forbidden (ReDoS risk)";
|
|
864
|
+
if (!(0, import_safe_regex2.default)(pattern)) return "Pattern rejected: potential ReDoS vulnerability detected";
|
|
865
|
+
return null;
|
|
866
|
+
}
|
|
867
|
+
function getCompiledRegex(pattern, flags = "") {
|
|
868
|
+
if (flags && !/^[gimsuy]+$/.test(flags)) {
|
|
869
|
+
if (process.env.NODE9_DEBUG === "1") console.error(`[Node9] Invalid regex flags: "${flags}"`);
|
|
870
|
+
return null;
|
|
871
|
+
}
|
|
872
|
+
const key = `${pattern}\0${flags}`;
|
|
873
|
+
if (regexCache.has(key)) {
|
|
874
|
+
const cached = regexCache.get(key);
|
|
875
|
+
regexCache.delete(key);
|
|
876
|
+
regexCache.set(key, cached);
|
|
877
|
+
return cached;
|
|
878
|
+
}
|
|
879
|
+
const err = validateRegex(pattern);
|
|
880
|
+
if (err) {
|
|
881
|
+
if (process.env.NODE9_DEBUG === "1")
|
|
882
|
+
console.error(`[Node9] Regex blocked: ${err} \u2014 pattern: "${pattern}"`);
|
|
883
|
+
return null;
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
const re = new RegExp(pattern, flags);
|
|
887
|
+
if (regexCache.size >= REGEX_CACHE_MAX) {
|
|
888
|
+
const oldest = regexCache.keys().next().value;
|
|
889
|
+
if (oldest) regexCache.delete(oldest);
|
|
890
|
+
}
|
|
891
|
+
regexCache.set(key, re);
|
|
892
|
+
return re;
|
|
893
|
+
} catch (e) {
|
|
894
|
+
if (process.env.NODE9_DEBUG === "1") console.error(`[Node9] Regex compile failed:`, e);
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
778
897
|
}
|
|
779
898
|
function getActiveTrustSession(toolName) {
|
|
780
899
|
try {
|
|
781
|
-
if (!
|
|
782
|
-
const trust = JSON.parse(
|
|
900
|
+
if (!import_fs3.default.existsSync(TRUST_FILE)) return false;
|
|
901
|
+
const trust = JSON.parse(import_fs3.default.readFileSync(TRUST_FILE, "utf-8"));
|
|
783
902
|
const now = Date.now();
|
|
784
903
|
const active = trust.entries.filter((e) => e.expiry > now);
|
|
785
904
|
if (active.length !== trust.entries.length) {
|
|
786
|
-
|
|
905
|
+
import_fs3.default.writeFileSync(TRUST_FILE, JSON.stringify({ entries: active }, null, 2));
|
|
787
906
|
}
|
|
788
907
|
return active.some((e) => e.tool === toolName || matchesPattern(toolName, e.tool));
|
|
789
908
|
} catch {
|
|
@@ -794,8 +913,8 @@ function writeTrustSession(toolName, durationMs) {
|
|
|
794
913
|
try {
|
|
795
914
|
let trust = { entries: [] };
|
|
796
915
|
try {
|
|
797
|
-
if (
|
|
798
|
-
trust = JSON.parse(
|
|
916
|
+
if (import_fs3.default.existsSync(TRUST_FILE)) {
|
|
917
|
+
trust = JSON.parse(import_fs3.default.readFileSync(TRUST_FILE, "utf-8"));
|
|
799
918
|
}
|
|
800
919
|
} catch {
|
|
801
920
|
}
|
|
@@ -811,9 +930,9 @@ function writeTrustSession(toolName, durationMs) {
|
|
|
811
930
|
}
|
|
812
931
|
function appendToLog(logPath, entry) {
|
|
813
932
|
try {
|
|
814
|
-
const dir =
|
|
815
|
-
if (!
|
|
816
|
-
|
|
933
|
+
const dir = import_path5.default.dirname(logPath);
|
|
934
|
+
if (!import_fs3.default.existsSync(dir)) import_fs3.default.mkdirSync(dir, { recursive: true });
|
|
935
|
+
import_fs3.default.appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
817
936
|
} catch {
|
|
818
937
|
}
|
|
819
938
|
}
|
|
@@ -855,9 +974,9 @@ function matchesPattern(text, patterns) {
|
|
|
855
974
|
const withoutDotSlash = text.replace(/^\.\//, "");
|
|
856
975
|
return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
|
|
857
976
|
}
|
|
858
|
-
function getNestedValue(obj,
|
|
977
|
+
function getNestedValue(obj, path6) {
|
|
859
978
|
if (!obj || typeof obj !== "object") return null;
|
|
860
|
-
return
|
|
979
|
+
return path6.split(".").reduce((prev, curr) => prev?.[curr], obj);
|
|
861
980
|
}
|
|
862
981
|
function evaluateSmartConditions(args, rule) {
|
|
863
982
|
if (!rule.conditions || rule.conditions.length === 0) return true;
|
|
@@ -876,19 +995,16 @@ function evaluateSmartConditions(args, rule) {
|
|
|
876
995
|
return val !== null && cond.value ? !val.includes(cond.value) : true;
|
|
877
996
|
case "matches": {
|
|
878
997
|
if (val === null || !cond.value) return false;
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
return false;
|
|
883
|
-
}
|
|
998
|
+
const reM = getCompiledRegex(cond.value, cond.flags ?? "");
|
|
999
|
+
if (!reM) return false;
|
|
1000
|
+
return reM.test(val);
|
|
884
1001
|
}
|
|
885
1002
|
case "notMatches": {
|
|
886
|
-
if (
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
}
|
|
1003
|
+
if (!cond.value) return false;
|
|
1004
|
+
if (val === null) return true;
|
|
1005
|
+
const reN = getCompiledRegex(cond.value, cond.flags ?? "");
|
|
1006
|
+
if (!reN) return false;
|
|
1007
|
+
return !reN.test(val);
|
|
892
1008
|
}
|
|
893
1009
|
case "matchesGlob":
|
|
894
1010
|
return val !== null && cond.value ? import_picomatch.default.isMatch(val, cond.value) : false;
|
|
@@ -1210,9 +1326,9 @@ var ADVISORY_SMART_RULES = [
|
|
|
1210
1326
|
var cachedConfig = null;
|
|
1211
1327
|
function getInternalToken() {
|
|
1212
1328
|
try {
|
|
1213
|
-
const pidFile =
|
|
1214
|
-
if (!
|
|
1215
|
-
const data = JSON.parse(
|
|
1329
|
+
const pidFile = import_path5.default.join(import_os2.default.homedir(), ".node9", "daemon.pid");
|
|
1330
|
+
if (!import_fs3.default.existsSync(pidFile)) return null;
|
|
1331
|
+
const data = JSON.parse(import_fs3.default.readFileSync(pidFile, "utf-8"));
|
|
1216
1332
|
process.kill(data.pid, 0);
|
|
1217
1333
|
return data.internalToken ?? null;
|
|
1218
1334
|
} catch {
|
|
@@ -1332,10 +1448,10 @@ function isIgnoredTool(toolName) {
|
|
|
1332
1448
|
var DAEMON_PORT = 7391;
|
|
1333
1449
|
var DAEMON_HOST = "127.0.0.1";
|
|
1334
1450
|
function isDaemonRunning() {
|
|
1335
|
-
const pidFile =
|
|
1336
|
-
if (
|
|
1451
|
+
const pidFile = import_path5.default.join(import_os2.default.homedir(), ".node9", "daemon.pid");
|
|
1452
|
+
if (import_fs3.default.existsSync(pidFile)) {
|
|
1337
1453
|
try {
|
|
1338
|
-
const { pid, port } = JSON.parse(
|
|
1454
|
+
const { pid, port } = JSON.parse(import_fs3.default.readFileSync(pidFile, "utf-8"));
|
|
1339
1455
|
if (port !== DAEMON_PORT) return false;
|
|
1340
1456
|
process.kill(pid, 0);
|
|
1341
1457
|
return true;
|
|
@@ -1355,9 +1471,9 @@ function isDaemonRunning() {
|
|
|
1355
1471
|
}
|
|
1356
1472
|
function getPersistentDecision(toolName) {
|
|
1357
1473
|
try {
|
|
1358
|
-
const file =
|
|
1359
|
-
if (!
|
|
1360
|
-
const decisions = JSON.parse(
|
|
1474
|
+
const file = import_path5.default.join(import_os2.default.homedir(), ".node9", "decisions.json");
|
|
1475
|
+
if (!import_fs3.default.existsSync(file)) return null;
|
|
1476
|
+
const decisions = JSON.parse(import_fs3.default.readFileSync(file, "utf-8"));
|
|
1361
1477
|
const d = decisions[toolName];
|
|
1362
1478
|
if (d === "allow" || d === "deny") return d;
|
|
1363
1479
|
} catch {
|
|
@@ -1439,7 +1555,7 @@ async function resolveViaDaemon(id, decision, internalToken) {
|
|
|
1439
1555
|
signal: AbortSignal.timeout(3e3)
|
|
1440
1556
|
});
|
|
1441
1557
|
}
|
|
1442
|
-
var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" :
|
|
1558
|
+
var ACTIVITY_SOCKET_PATH = process.platform === "win32" ? "\\\\.\\pipe\\node9-activity" : import_path5.default.join(import_os2.default.tmpdir(), "node9-activity.sock");
|
|
1443
1559
|
function notifyActivity(data) {
|
|
1444
1560
|
return new Promise((resolve) => {
|
|
1445
1561
|
try {
|
|
@@ -1501,7 +1617,9 @@ async function _authorizeHeadlessCore(toolName, args, allowTerminalFallback = fa
|
|
|
1501
1617
|
let policyMatchedWord;
|
|
1502
1618
|
let riskMetadata;
|
|
1503
1619
|
if (config.policy.dlp.enabled && (!isIgnoredTool(toolName) || config.policy.dlp.scanIgnoredTools)) {
|
|
1504
|
-
const
|
|
1620
|
+
const argsObj = args && typeof args === "object" && !Array.isArray(args) ? args : {};
|
|
1621
|
+
const filePath = String(argsObj.file_path ?? argsObj.path ?? argsObj.filename ?? "");
|
|
1622
|
+
const dlpMatch = (filePath ? scanFilePath(filePath) : null) ?? scanArgs(args);
|
|
1505
1623
|
if (dlpMatch) {
|
|
1506
1624
|
const dlpReason = `\u{1F6A8} DATA LOSS PREVENTION: ${dlpMatch.patternName} detected in field "${dlpMatch.fieldPath}" (${dlpMatch.redactedSample})`;
|
|
1507
1625
|
if (dlpMatch.severity === "block") {
|
|
@@ -1873,10 +1991,10 @@ REASON: Action blocked because no approval channels are available. (Native/Brows
|
|
|
1873
1991
|
}
|
|
1874
1992
|
return finalResult;
|
|
1875
1993
|
}
|
|
1876
|
-
function getConfig() {
|
|
1877
|
-
if (cachedConfig) return cachedConfig;
|
|
1878
|
-
const globalPath =
|
|
1879
|
-
const projectPath =
|
|
1994
|
+
function getConfig(cwd) {
|
|
1995
|
+
if (!cwd && cachedConfig) return cachedConfig;
|
|
1996
|
+
const globalPath = import_path5.default.join(import_os2.default.homedir(), ".node9", "config.json");
|
|
1997
|
+
const projectPath = import_path5.default.join(cwd ?? process.cwd(), "node9.config.json");
|
|
1880
1998
|
const globalConfig = tryLoadConfig(globalPath);
|
|
1881
1999
|
const projectConfig = tryLoadConfig(projectPath);
|
|
1882
2000
|
const mergedSettings = {
|
|
@@ -1963,18 +2081,19 @@ function getConfig() {
|
|
|
1963
2081
|
mergedPolicy.snapshot.tools = [...new Set(mergedPolicy.snapshot.tools)];
|
|
1964
2082
|
mergedPolicy.snapshot.onlyPaths = [...new Set(mergedPolicy.snapshot.onlyPaths)];
|
|
1965
2083
|
mergedPolicy.snapshot.ignorePaths = [...new Set(mergedPolicy.snapshot.ignorePaths)];
|
|
1966
|
-
|
|
2084
|
+
const result = {
|
|
1967
2085
|
settings: mergedSettings,
|
|
1968
2086
|
policy: mergedPolicy,
|
|
1969
2087
|
environments: mergedEnvironments
|
|
1970
2088
|
};
|
|
1971
|
-
|
|
2089
|
+
if (!cwd) cachedConfig = result;
|
|
2090
|
+
return result;
|
|
1972
2091
|
}
|
|
1973
2092
|
function tryLoadConfig(filePath) {
|
|
1974
|
-
if (!
|
|
2093
|
+
if (!import_fs3.default.existsSync(filePath)) return null;
|
|
1975
2094
|
let raw;
|
|
1976
2095
|
try {
|
|
1977
|
-
raw = JSON.parse(
|
|
2096
|
+
raw = JSON.parse(import_fs3.default.readFileSync(filePath, "utf-8"));
|
|
1978
2097
|
} catch (err) {
|
|
1979
2098
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1980
2099
|
process.stderr.write(
|
|
@@ -2036,9 +2155,9 @@ function getCredentials() {
|
|
|
2036
2155
|
};
|
|
2037
2156
|
}
|
|
2038
2157
|
try {
|
|
2039
|
-
const credPath =
|
|
2040
|
-
if (
|
|
2041
|
-
const creds = JSON.parse(
|
|
2158
|
+
const credPath = import_path5.default.join(import_os2.default.homedir(), ".node9", "credentials.json");
|
|
2159
|
+
if (import_fs3.default.existsSync(credPath)) {
|
|
2160
|
+
const creds = JSON.parse(import_fs3.default.readFileSync(credPath, "utf-8"));
|
|
2042
2161
|
const profileName = process.env.NODE9_PROFILE || "default";
|
|
2043
2162
|
const profile = creds[profileName];
|
|
2044
2163
|
if (profile?.apiKey) {
|