run402 1.54.2 → 1.54.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.
@@ -2,16 +2,64 @@ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, renameSy
2
2
  import { dirname, join } from "node:path";
3
3
  import { randomBytes } from "node:crypto";
4
4
  import { getAllowancePath } from "./config.js";
5
+ // 0x-prefixed 40-hex EVM address.
6
+ const ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
7
+ // 0x-prefixed 64-hex secp256k1 private key (32 bytes).
8
+ const PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
9
+ /**
10
+ * Load the agent allowance from disk.
11
+ *
12
+ * Returns `null` for the two "no allowance configured" cases:
13
+ * - the file does not exist
14
+ * - the file exists but is not parseable JSON (preserve existing UX —
15
+ * consumers print "no_allowance" and tell the user to run init)
16
+ *
17
+ * Throws a structured `Error` (GH-194) when the file parses as JSON but the
18
+ * shape is wrong (missing/wrong-type/wrong-length fields). Without this guard
19
+ * downstream callers crash with raw stack traces:
20
+ * - `cli/lib/status.mjs` reaches for `allowance.address.toLowerCase()`
21
+ * and crashes with `TypeError: Cannot read properties of undefined`.
22
+ * - `core/src/allowance-auth.ts` passes a malformed `privateKey` to
23
+ * `@noble/curves` which throws "expected 32 bytes, got N".
24
+ *
25
+ * The CLI's `cli/lib/config.mjs:readAllowance()` wrapper and the MCP
26
+ * `src/tools/{status,init}.ts` callers translate the throw into their own
27
+ * structured envelopes (`code: BAD_ALLOWANCE_FILE`).
28
+ */
5
29
  export function readAllowance(path) {
6
30
  const p = path ?? getAllowancePath();
7
31
  if (!existsSync(p))
8
32
  return null;
33
+ let raw;
9
34
  try {
10
- return JSON.parse(readFileSync(p, "utf-8"));
35
+ raw = readFileSync(p, "utf-8");
11
36
  }
12
37
  catch {
13
38
  return null;
14
39
  }
40
+ let parsed;
41
+ try {
42
+ parsed = JSON.parse(raw);
43
+ }
44
+ catch {
45
+ // Preserve historical UX — completely unparseable input reads as "no
46
+ // allowance configured" rather than as an error. Consumers already handle
47
+ // null with a friendly "run 'run402 init'" message.
48
+ return null;
49
+ }
50
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
51
+ throw new Error(`allowance.json must contain a JSON object (got ${Array.isArray(parsed) ? "array" : parsed === null ? "null" : typeof parsed}). Back up the file and run 'run402 init' to recreate it.`);
52
+ }
53
+ const data = parsed;
54
+ if (typeof data.address !== "string" || !ADDRESS_RE.test(data.address)) {
55
+ throw new Error("allowance.json missing valid 'address' (expected 0x-prefixed 40-hex string). " +
56
+ "Back up the file and run 'run402 init' to recreate it.");
57
+ }
58
+ if (typeof data.privateKey !== "string" || !PRIVATE_KEY_RE.test(data.privateKey)) {
59
+ throw new Error("allowance.json missing valid 'privateKey' (expected 0x-prefixed 64-hex string). " +
60
+ "Back up the file and run 'run402 init' to recreate it.");
61
+ }
62
+ return data;
15
63
  }
16
64
  export function saveAllowance(data, path) {
17
65
  const p = path ?? getAllowancePath();
@@ -1,8 +1,39 @@
1
1
  import { homedir } from "node:os";
2
2
  import { join } from "node:path";
3
3
  import { existsSync, renameSync, mkdirSync } from "node:fs";
4
+ const DEFAULT_API_BASE = "https://api.run402.com";
5
+ /**
6
+ * Validate a user-supplied API base URL. Throws a clear error message that
7
+ * names the env var when the URL is malformed or uses a scheme other than
8
+ * http(s). Empty string is treated as "set but empty" (almost always a
9
+ * templating mishap) and emits a stderr warning before falling back to
10
+ * `fallback`.
11
+ *
12
+ * Returns the validated URL string (unchanged) or `null` if the env var was
13
+ * unset.
14
+ */
15
+ function validateApiBase(envVar, raw, fallback) {
16
+ if (raw == null)
17
+ return null;
18
+ if (raw === "") {
19
+ process.stderr.write(`warning: ${envVar} is set but empty - using default. Unset the env var to suppress this warning.\n`);
20
+ return fallback;
21
+ }
22
+ let u;
23
+ try {
24
+ u = new URL(raw);
25
+ }
26
+ catch {
27
+ throw new Error(`${envVar} is not a valid URL: ${JSON.stringify(raw)}. Expected an http(s) URL like https://api.run402.com.`);
28
+ }
29
+ if (u.protocol !== "https:" && u.protocol !== "http:") {
30
+ throw new Error(`${envVar} must use http(s):, got ${u.protocol} (full value: ${JSON.stringify(raw)}).`);
31
+ }
32
+ return raw;
33
+ }
4
34
  export function getApiBase() {
5
- return process.env.RUN402_API_BASE || "https://api.run402.com";
35
+ const validated = validateApiBase("RUN402_API_BASE", process.env.RUN402_API_BASE, DEFAULT_API_BASE);
36
+ return validated ?? DEFAULT_API_BASE;
6
37
  }
7
38
  /**
8
39
  * API base for the deploy-v2 routes. Defaults to the same value as
@@ -12,7 +43,9 @@ export function getApiBase() {
12
43
  * should not need this override.
13
44
  */
14
45
  export function getDeployApiBase() {
15
- return process.env.RUN402_DEPLOY_API_BASE || getApiBase();
46
+ const fallback = getApiBase();
47
+ const validated = validateApiBase("RUN402_DEPLOY_API_BASE", process.env.RUN402_DEPLOY_API_BASE, fallback);
48
+ return validated ?? fallback;
16
49
  }
17
50
  export function getConfigDir() {
18
51
  return process.env.RUN402_CONFIG_DIR || join(homedir(), ".config", "run402");
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Wallet auth helper — generates EIP-191 signature headers for Run402 API.
3
+ * Uses @noble/curves (lighter than viem) for signing.
4
+ */
5
+ import { secp256k1 } from "@noble/curves/secp256k1.js";
6
+ import { keccak_256 } from "@noble/hashes/sha3.js";
7
+ import { bytesToHex } from "@noble/hashes/utils.js";
8
+ import { readWallet } from "./wallet.js";
9
+ /**
10
+ * EIP-191 personal_sign: sign a message with the wallet's private key.
11
+ */
12
+ function personalSign(privateKeyHex, address, message) {
13
+ const msgBytes = new TextEncoder().encode(message);
14
+ const prefix = new TextEncoder().encode(`\x19Ethereum Signed Message:\n${msgBytes.length}`);
15
+ const prefixed = new Uint8Array(prefix.length + msgBytes.length);
16
+ prefixed.set(prefix);
17
+ prefixed.set(msgBytes, prefix.length);
18
+ const hash = keccak_256(prefixed);
19
+ const pkHex = privateKeyHex.startsWith("0x")
20
+ ? privateKeyHex.slice(2)
21
+ : privateKeyHex;
22
+ const pkBytes = Uint8Array.from(Buffer.from(pkHex, "hex"));
23
+ const rawSig = secp256k1.sign(hash, pkBytes);
24
+ const sig = secp256k1.Signature.fromBytes(rawSig);
25
+ // Determine recovery bit by trying both and matching the address
26
+ let recovery = 0;
27
+ for (const v of [0, 1]) {
28
+ try {
29
+ const recovered = sig.addRecoveryBit(v).recoverPublicKey(hash);
30
+ const pubBytes = recovered.toBytes(false).slice(1); // uncompressed, drop 04 prefix
31
+ const addrBytes = keccak_256(pubBytes).slice(-20);
32
+ if ("0x" + bytesToHex(addrBytes) === address.toLowerCase()) {
33
+ recovery = v;
34
+ break;
35
+ }
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ }
41
+ const r = sig.r.toString(16).padStart(64, "0");
42
+ const s = sig.s.toString(16).padStart(64, "0");
43
+ const vHex = (recovery + 27).toString(16).padStart(2, "0");
44
+ return "0x" + r + s + vHex;
45
+ }
46
+ /**
47
+ * Get wallet auth headers for the Run402 API.
48
+ * Returns null if no wallet is configured.
49
+ */
50
+ export function getWalletAuthHeaders(walletPath) {
51
+ const wallet = readWallet(walletPath);
52
+ if (!wallet || !wallet.address || !wallet.privateKey)
53
+ return null;
54
+ const timestamp = Math.floor(Date.now() / 1000).toString();
55
+ const signature = personalSign(wallet.privateKey, wallet.address, `run402:${timestamp}`);
56
+ return {
57
+ "X-Run402-Wallet": wallet.address,
58
+ "X-Run402-Signature": signature,
59
+ "X-Run402-Timestamp": timestamp,
60
+ };
61
+ }
62
+ //# sourceMappingURL=wallet-auth.js.map
@@ -0,0 +1,25 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, renameSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { randomBytes } from "node:crypto";
4
+ import { getWalletPath } from "./config.js";
5
+ export function readWallet(path) {
6
+ const p = path ?? getWalletPath();
7
+ if (!existsSync(p))
8
+ return null;
9
+ try {
10
+ return JSON.parse(readFileSync(p, "utf-8"));
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
16
+ export function saveWallet(data, path) {
17
+ const p = path ?? getWalletPath();
18
+ const dir = dirname(p);
19
+ mkdirSync(dir, { recursive: true });
20
+ const tmp = join(dir, `.wallet.${randomBytes(4).toString("hex")}.tmp`);
21
+ writeFileSync(tmp, JSON.stringify(data, null, 2), { mode: 0o600 });
22
+ renameSync(tmp, p);
23
+ chmodSync(p, 0o600);
24
+ }
25
+ //# sourceMappingURL=wallet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"paid-fetch.d.ts","sourceRoot":"","sources":["../../src/node/paid-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,KAAK,OAAO,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AAgCvC,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAyE9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAW7C"}
1
+ {"version":3,"file":"paid-fetch.d.ts","sourceRoot":"","sources":["../../src/node/paid-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,KAAK,OAAO,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AAgCvC,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAmF9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAW7C"}
@@ -37,7 +37,18 @@ async function checkBalance(publicClient, tokenAddress, walletAddress) {
37
37
  }
38
38
  }
39
39
  export async function setupPaidFetch() {
40
- const allowance = readAllowance();
40
+ // GH-194: readAllowance throws on a malformed-shape file. The SDK's
41
+ // contract is graceful degradation here (return null and let the caller
42
+ // fall back to unwrapped fetch), so swallow the error — the CLI's own
43
+ // readAllowance wrapper has already surfaced a structured envelope to
44
+ // the user.
45
+ let allowance;
46
+ try {
47
+ allowance = readAllowance();
48
+ }
49
+ catch {
50
+ return null;
51
+ }
41
52
  if (!allowance)
42
53
  return null;
43
54
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"paid-fetch.js","sourceRoot":"","sources":["../../src/node/paid-fetch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"paid-fetch.js","sourceRoot":"","sources":["../../src/node/paid-fetch.ts"],"names":[],"mappings":"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"}