run402 1.54.2 → 1.54.4

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/lib/webhooks.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { resolveProjectId } from "./config.mjs";
2
2
  import { getSdk } from "./sdk.mjs";
3
3
  import { reportSdkError, fail } from "./sdk-errors.mjs";
4
+ import { validateWebhookUrl } from "./argparse.mjs";
4
5
 
5
6
  const HELP = `run402 email webhooks — Manage mailbox webhooks
6
7
 
@@ -121,6 +122,11 @@ async function update(args) {
121
122
  if (!url && !eventsRaw) {
122
123
  fail({ code: "BAD_USAGE", message: "Provide at least --url or --events" });
123
124
  }
125
+ // GH-192: scheme-only local validation. Server-side SSRF defenses are out
126
+ // of scope for the CLI (private-IP / DNS rebinding / IMDS belongs on the
127
+ // gateway). `validateWebhookUrl` is a no-op when `url` is null/undefined,
128
+ // so partial updates that change only `--events` still work.
129
+ validateWebhookUrl(url, "--url");
124
130
 
125
131
  try {
126
132
  const data = await getSdk().email.webhooks.update(projectId, webhookId, {
@@ -146,6 +152,10 @@ async function register(args) {
146
152
  hint: "run402 email webhooks register --url <url> --events <e1,e2>",
147
153
  });
148
154
  }
155
+ // GH-192: validate scheme locally before any network call. Catches
156
+ // javascript:/file:/http:/data: schemes that the gateway would reject
157
+ // anyway, but with a friendlier round-trip-free error.
158
+ validateWebhookUrl(url, "--url");
149
159
  if (!eventsRaw) {
150
160
  fail({
151
161
  code: "BAD_USAGE",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "run402",
3
- "version": "1.54.2",
3
+ "version": "1.54.4",
4
4
  "description": "CLI for Run402 — provision Postgres databases, deploy static sites, generate images, and manage wallets via x402 and MPP micropayments.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -87,6 +87,11 @@ export function formatSIWEMessage(opts, address) {
87
87
  * @param path - API path (e.g. "/projects/v1") used to build the SIWE uri field.
88
88
  */
89
89
  export function getAllowanceAuthHeaders(path, allowancePath) {
90
+ // GH-194: readAllowance throws on a malformed-shape allowance file. The
91
+ // CLI's higher-level readAllowance wrapper surfaces this as a structured
92
+ // BAD_ALLOWANCE_FILE envelope; here we preserve the public contract that
93
+ // this helper returns SIWxAuthHeaders | null. Re-throw so callers above
94
+ // the CLI's wrapper (e.g. SDK paid-fetch) can decide whether to swallow it.
90
95
  const allowance = readAllowance(allowancePath);
91
96
  if (!allowance || !allowance.address || !allowance.privateKey)
92
97
  return null;
@@ -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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"}