run402 4.120.0 → 4.121.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/core-dist/wallet-auth.js +77 -38
- package/core-dist/wallet.js +21 -0
- package/lib/ci.mjs +1 -1
- package/lib/config.mjs +8 -0
- package/lib/contacts.mjs +3 -3
- package/lib/session-proofs.mjs +8 -4
- package/lib/subscriptions.mjs +2 -2
- package/lib/wallets.mjs +41 -1
- package/lib/webhook-secret.mjs +1 -1
- package/package.json +2 -1
- package/sdk/core-dist/wallet-auth.js +77 -38
- package/sdk/core-dist/wallet.js +21 -0
- package/sdk/dist/credentials.d.ts +15 -1
- package/sdk/dist/credentials.d.ts.map +1 -1
- package/sdk/dist/errors.d.ts +14 -0
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +22 -0
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/index.d.ts +1 -1
- package/sdk/dist/index.d.ts.map +1 -1
- package/sdk/dist/index.js +1 -1
- package/sdk/dist/index.js.map +1 -1
- package/sdk/dist/node/_paid-stack.d.ts +18 -0
- package/sdk/dist/node/_paid-stack.d.ts.map +1 -1
- package/sdk/dist/node/_paid-stack.js +19 -0
- package/sdk/dist/node/_paid-stack.js.map +1 -1
- package/sdk/dist/node/ci.d.ts +1 -1
- package/sdk/dist/node/ci.d.ts.map +1 -1
- package/sdk/dist/node/ci.js +8 -6
- package/sdk/dist/node/ci.js.map +1 -1
- package/sdk/dist/node/credentials.d.ts.map +1 -1
- package/sdk/dist/node/credentials.js +5 -4
- package/sdk/dist/node/credentials.js.map +1 -1
- package/sdk/dist/node/index.d.ts +2 -1
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +2 -1
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/org-adopt.d.ts +1 -1
- package/sdk/dist/node/org-adopt.d.ts.map +1 -1
- package/sdk/dist/node/org-adopt.js +9 -7
- package/sdk/dist/node/org-adopt.js.map +1 -1
- package/sdk/dist/node/paid-fetch.d.ts.map +1 -1
- package/sdk/dist/node/paid-fetch.js +6 -4
- package/sdk/dist/node/paid-fetch.js.map +1 -1
- package/sdk/dist/node/signers/index.d.ts +26 -0
- package/sdk/dist/node/signers/index.d.ts.map +1 -0
- package/sdk/dist/node/signers/index.js +35 -0
- package/sdk/dist/node/signers/index.js.map +1 -0
- package/sdk/dist/node/signers/kms.d.ts +54 -0
- package/sdk/dist/node/signers/kms.d.ts.map +1 -0
- package/sdk/dist/node/signers/kms.js +236 -0
- package/sdk/dist/node/signers/kms.js.map +1 -0
- package/sdk/dist/node/wallets-send.d.ts +62 -0
- package/sdk/dist/node/wallets-send.d.ts.map +1 -0
- package/sdk/dist/node/wallets-send.js +149 -0
- package/sdk/dist/node/wallets-send.js.map +1 -0
- package/sdk/dist/node/wallets.d.ts +33 -5
- package/sdk/dist/node/wallets.d.ts.map +1 -1
- package/sdk/dist/node/wallets.js +78 -12
- package/sdk/dist/node/wallets.js.map +1 -1
- package/sdk/dist/secret-gate.d.ts +1 -1
- package/sdk/dist/secret-gate.d.ts.map +1 -1
- package/sdk/dist/secret-gate.js +7 -2
- package/sdk/dist/secret-gate.js.map +1 -1
- package/vault-surface.json +1 -1
package/core-dist/wallet-auth.js
CHANGED
|
@@ -6,7 +6,7 @@ import { randomBytes } from "node:crypto";
|
|
|
6
6
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
7
7
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
8
8
|
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
9
|
-
import { readWallet } from "./wallet.js";
|
|
9
|
+
import { isSignerWallet, readWallet } from "./wallet.js";
|
|
10
10
|
import { getApiBase } from "./config.js";
|
|
11
11
|
/**
|
|
12
12
|
* EIP-55 mixed-case checksum encoding.
|
|
@@ -57,6 +57,33 @@ function personalSign(privateKeyHex, address, message) {
|
|
|
57
57
|
const vHex = (recovery + 27).toString(16).padStart(2, "0");
|
|
58
58
|
return "0x" + r + s + vHex;
|
|
59
59
|
}
|
|
60
|
+
export function prepareSIWx(opts) {
|
|
61
|
+
const message = formatSIWEMessage(opts, opts.address);
|
|
62
|
+
return {
|
|
63
|
+
message,
|
|
64
|
+
finish(signature) {
|
|
65
|
+
const payload = {
|
|
66
|
+
domain: opts.domain,
|
|
67
|
+
address: toChecksumAddress(opts.address),
|
|
68
|
+
statement: opts.statement,
|
|
69
|
+
uri: opts.uri,
|
|
70
|
+
version: opts.version ?? "1",
|
|
71
|
+
chainId: payloadChainId(opts.chainId),
|
|
72
|
+
type: opts.type ?? "eip191",
|
|
73
|
+
nonce: opts.nonce,
|
|
74
|
+
issuedAt: opts.issuedAt,
|
|
75
|
+
expirationTime: opts.expirationTime,
|
|
76
|
+
signature,
|
|
77
|
+
};
|
|
78
|
+
if (opts.resources !== undefined) {
|
|
79
|
+
payload.resources = opts.resources;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
"SIGN-IN-WITH-X": Buffer.from(JSON.stringify(payload)).toString("base64"),
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
60
87
|
/**
|
|
61
88
|
* Format an EIP-4361 (SIWE) message. Must be byte-for-byte compatible
|
|
62
89
|
* with the `siwe` library's message format used server-side for verification.
|
|
@@ -85,29 +112,54 @@ export function formatSIWEMessage(opts, address) {
|
|
|
85
112
|
}
|
|
86
113
|
return lines.join("\n");
|
|
87
114
|
}
|
|
115
|
+
/** SIWX headers signed with a local private key (synchronous). */
|
|
88
116
|
export function buildSIWxAuthHeaders(opts) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const payload = {
|
|
92
|
-
domain: opts.domain,
|
|
93
|
-
address: toChecksumAddress(opts.wallet.address),
|
|
94
|
-
statement: opts.statement,
|
|
95
|
-
uri: opts.uri,
|
|
96
|
-
version: opts.version ?? "1",
|
|
97
|
-
chainId: payloadChainId(opts.chainId),
|
|
98
|
-
type: opts.type ?? "eip191",
|
|
99
|
-
nonce: opts.nonce,
|
|
100
|
-
issuedAt: opts.issuedAt,
|
|
101
|
-
expirationTime: opts.expirationTime,
|
|
102
|
-
signature,
|
|
103
|
-
};
|
|
104
|
-
if (opts.resources !== undefined) {
|
|
105
|
-
payload.resources = opts.resources;
|
|
117
|
+
if (!opts.wallet.privateKey) {
|
|
118
|
+
throw new SignerWalletError();
|
|
106
119
|
}
|
|
120
|
+
const prepared = prepareSIWx({ ...opts, address: opts.wallet.address });
|
|
121
|
+
return prepared.finish(personalSign(opts.wallet.privateKey, opts.wallet.address, prepared.message));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Thrown where a synchronous signature is required but the wallet signs
|
|
125
|
+
* through a signer (`wallet.json` `signer`). Callers that can wait use
|
|
126
|
+
* `getWalletAuthHeadersAsync` with the SDK's signer instead.
|
|
127
|
+
*/
|
|
128
|
+
export class SignerWalletError extends Error {
|
|
129
|
+
code = "SIGNER_WALLET_ASYNC";
|
|
130
|
+
constructor() {
|
|
131
|
+
super("This wallet signs through a signer (wallet.json 'signer'), which this synchronous path cannot use.");
|
|
132
|
+
this.name = "SignerWalletError";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function walletSIWxOptions(path) {
|
|
136
|
+
const apiBase = getApiBase();
|
|
137
|
+
const url = new URL(apiBase);
|
|
138
|
+
const now = new Date();
|
|
107
139
|
return {
|
|
108
|
-
|
|
140
|
+
domain: url.hostname,
|
|
141
|
+
uri: `${apiBase}${path}`,
|
|
142
|
+
statement: "Sign in to Run402",
|
|
143
|
+
chainId: "eip155:84532",
|
|
144
|
+
nonce: randomBytes(16).toString("hex"),
|
|
145
|
+
issuedAt: now.toISOString(),
|
|
146
|
+
expirationTime: new Date(now.getTime() + 5 * 60 * 1000).toISOString(),
|
|
109
147
|
};
|
|
110
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* SIWX headers for any wallet: a key-backed wallet signs locally; a
|
|
151
|
+
* signer-backed one through `signerFor(wallet)`. Null when no wallet exists.
|
|
152
|
+
*/
|
|
153
|
+
export async function getWalletAuthHeadersAsync(path, walletPath, signerFor) {
|
|
154
|
+
const localWallet = readWallet(walletPath);
|
|
155
|
+
if (!localWallet || !localWallet.address)
|
|
156
|
+
return null;
|
|
157
|
+
if (!isSignerWallet(localWallet))
|
|
158
|
+
return getWalletAuthHeaders(path, walletPath);
|
|
159
|
+
const prepared = prepareSIWx({ ...walletSIWxOptions(path), address: localWallet.address });
|
|
160
|
+
const sign = await signerFor(localWallet);
|
|
161
|
+
return prepared.finish(await sign(prepared.message));
|
|
162
|
+
}
|
|
111
163
|
/**
|
|
112
164
|
* Get SIWX auth headers for the Run402 API.
|
|
113
165
|
* Returns null if no local wallet is configured.
|
|
@@ -121,26 +173,13 @@ export function getWalletAuthHeaders(path, walletPath) {
|
|
|
121
173
|
// this helper returns SIWxAuthHeaders | null. Re-throw so callers above
|
|
122
174
|
// the CLI's wrapper (e.g. SDK paid-fetch) can decide whether to swallow it.
|
|
123
175
|
const localWallet = readWallet(walletPath);
|
|
124
|
-
if (!localWallet || !localWallet.address
|
|
176
|
+
if (!localWallet || !localWallet.address)
|
|
125
177
|
return null;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const now = new Date();
|
|
132
|
-
const issuedAt = now.toISOString();
|
|
133
|
-
const expirationTime = new Date(now.getTime() + 5 * 60 * 1000).toISOString();
|
|
134
|
-
return buildSIWxAuthHeaders({
|
|
135
|
-
wallet: localWallet,
|
|
136
|
-
domain,
|
|
137
|
-
uri,
|
|
138
|
-
statement: "Sign in to Run402",
|
|
139
|
-
chainId: "eip155:84532",
|
|
140
|
-
nonce,
|
|
141
|
-
issuedAt,
|
|
142
|
-
expirationTime,
|
|
143
|
-
});
|
|
178
|
+
if (isSignerWallet(localWallet))
|
|
179
|
+
throw new SignerWalletError();
|
|
180
|
+
if (!localWallet.privateKey)
|
|
181
|
+
return null;
|
|
182
|
+
return buildSIWxAuthHeaders({ wallet: localWallet, ...walletSIWxOptions(path) });
|
|
144
183
|
}
|
|
145
184
|
function messageChainId(chainId) {
|
|
146
185
|
if (typeof chainId === "number")
|
package/core-dist/wallet.js
CHANGED
|
@@ -6,6 +6,12 @@ import { getWalletPath } from "./config.js";
|
|
|
6
6
|
const ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
7
7
|
// 0x-prefixed 64-hex secp256k1 private key (32 bytes).
|
|
8
8
|
const PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
9
|
+
// arn:aws:kms:<region>:<account>:key/<id>
|
|
10
|
+
export const KMS_KEY_ARN_RE = /^arn:aws[a-z-]*:kms:([a-z0-9-]+):\d{12}:key\/[A-Za-z0-9-]+$/;
|
|
11
|
+
/** True when the wallet signs through a signer instead of a local key. */
|
|
12
|
+
export function isSignerWallet(wallet) {
|
|
13
|
+
return wallet.signer !== undefined;
|
|
14
|
+
}
|
|
9
15
|
/**
|
|
10
16
|
* Load the agent wallet from disk.
|
|
11
17
|
*
|
|
@@ -78,6 +84,21 @@ export function readWallet(path) {
|
|
|
78
84
|
throw new Error("wallet.json missing valid 'address' (expected 0x-prefixed 40-hex string). " +
|
|
79
85
|
"Back up the file and run 'run402 init' to recreate it.");
|
|
80
86
|
}
|
|
87
|
+
if (data.privateKey !== undefined && data.signer !== undefined) {
|
|
88
|
+
throw new Error(`${p} has both 'privateKey' and 'signer'; a wallet is backed by exactly one. ` +
|
|
89
|
+
"Remove the one that does not belong to this wallet.");
|
|
90
|
+
}
|
|
91
|
+
if (data.signer !== undefined) {
|
|
92
|
+
const signer = data.signer;
|
|
93
|
+
if (!signer || typeof signer !== "object" || signer.kind !== "aws_kms" ||
|
|
94
|
+
typeof signer.key_arn !== "string" || !KMS_KEY_ARN_RE.test(signer.key_arn) ||
|
|
95
|
+
typeof signer.region !== "string" || signer.region.length === 0 ||
|
|
96
|
+
(signer.aws_profile !== undefined && (typeof signer.aws_profile !== "string" || signer.aws_profile.length === 0))) {
|
|
97
|
+
throw new Error(`${p} has a malformed 'signer' (expected { kind: "aws_kms", key_arn, region, aws_profile? }). ` +
|
|
98
|
+
"Re-import the wallet with 'run402 wallets import <name> --kms <key-arn>'.");
|
|
99
|
+
}
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
81
102
|
if (typeof data.privateKey !== "string" || !PRIVATE_KEY_RE.test(data.privateKey)) {
|
|
82
103
|
throw new Error("wallet.json missing valid 'privateKey' (expected 0x-prefixed 64-hex string). " +
|
|
83
104
|
"Back up the file and run 'run402 init' to recreate it.");
|
package/lib/ci.mjs
CHANGED
|
@@ -325,7 +325,7 @@ async function linkGithub(args) {
|
|
|
325
325
|
|
|
326
326
|
let signedDelegation;
|
|
327
327
|
try {
|
|
328
|
-
signedDelegation = signCiDelegation(values, { apiBase: API });
|
|
328
|
+
signedDelegation = await signCiDelegation(values, { apiBase: API });
|
|
329
329
|
} catch (err) {
|
|
330
330
|
fail({
|
|
331
331
|
code: "NO_WALLET",
|
package/lib/config.mjs
CHANGED
|
@@ -81,7 +81,15 @@ export function saveWallet(data) {
|
|
|
81
81
|
coreSaveWallet(data);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
/**
|
|
85
|
+
* The wallet's SIWX headers for `path`, or the NO_WALLET failure. Most
|
|
86
|
+
* callers use this only as a "a wallet is configured" check before handing
|
|
87
|
+
* the request to the SDK. A signer-backed wallet (KMS) signs asynchronously
|
|
88
|
+
* inside the SDK, so here it only proves the wallet exists and returns no
|
|
89
|
+
* headers; callers that need its signature use the SDK.
|
|
90
|
+
*/
|
|
84
91
|
export function walletAuthHeaders(path) {
|
|
92
|
+
if (readWallet()?.signer) return {};
|
|
85
93
|
const headers = coreGetWalletAuthHeaders(path);
|
|
86
94
|
if (!headers) {
|
|
87
95
|
fail({
|
package/lib/contacts.mjs
CHANGED
|
@@ -104,7 +104,7 @@ async function preferences(args) {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
try {
|
|
107
|
-
const data = await getSdk().admin.setNotificationPreferences(patch, sessionProofs("/agent/v1/notifications/preferences"));
|
|
107
|
+
const data = await getSdk().admin.setNotificationPreferences(patch, await sessionProofs("/agent/v1/notifications/preferences"));
|
|
108
108
|
console.log(JSON.stringify(data, null, 2));
|
|
109
109
|
} catch (err) {
|
|
110
110
|
reportSdkError(err);
|
|
@@ -185,7 +185,7 @@ async function channelsConnect(args) {
|
|
|
185
185
|
fail({ code: "BAD_USAGE", message: `Unexpected argument for notifications channels connect: ${positionals[1]}` });
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
const proofs = sessionProofs("/agent/v1/notifications/channels/telegram");
|
|
188
|
+
const proofs = await sessionProofs("/agent/v1/notifications/channels/telegram");
|
|
189
189
|
let pending;
|
|
190
190
|
try {
|
|
191
191
|
pending = await getSdk().admin.channels.connectTelegram(label ? { label } : {}, proofs);
|
|
@@ -234,7 +234,7 @@ async function channelsRevoke(args) {
|
|
|
234
234
|
});
|
|
235
235
|
walletAuthHeaders("/agent/v1/notifications/channels/telegram");
|
|
236
236
|
try {
|
|
237
|
-
console.log(JSON.stringify(await getSdk().admin.channels.revokeTelegram(bindingId, sessionProofs("/agent/v1/notifications/channels/telegram")), null, 2));
|
|
237
|
+
console.log(JSON.stringify(await getSdk().admin.channels.revokeTelegram(bindingId, await sessionProofs("/agent/v1/notifications/channels/telegram")), null, 2));
|
|
238
238
|
} catch (err) {
|
|
239
239
|
reportSdkError(err);
|
|
240
240
|
}
|
package/lib/session-proofs.mjs
CHANGED
|
@@ -9,13 +9,17 @@
|
|
|
9
9
|
* signed in once is never asked to enroll a second passkey. With no live cached
|
|
10
10
|
* session this returns `undefined` and the verb uses wallet auth alone.
|
|
11
11
|
*/
|
|
12
|
-
import { walletAuthHeaders } from "./config.mjs";
|
|
12
|
+
import { walletAuthHeaders, walletFile } from "./config.mjs";
|
|
13
13
|
import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.js";
|
|
14
|
+
import { getWalletAuthHeadersAsync } from "../core-dist/wallet-auth.js";
|
|
15
|
+
import { personalMessageSignerFor } from "#sdk/node";
|
|
14
16
|
|
|
15
17
|
/** `{ siwx, token }` for `path`, or `undefined` when no live sign-in session is cached. */
|
|
16
|
-
export function sessionProofs(path) {
|
|
17
|
-
|
|
18
|
+
export async function sessionProofs(path) {
|
|
19
|
+
walletAuthHeaders(path); // NO_WALLET when none is configured
|
|
18
20
|
const live = loadLiveControlPlaneSession();
|
|
19
21
|
if (!live || !live.control_plane_session_token) return undefined;
|
|
20
|
-
|
|
22
|
+
// A key-backed wallet signs locally; a signer-backed one (KMS) through its signer.
|
|
23
|
+
const headers = await getWalletAuthHeadersAsync(path, walletFile(), (w) => personalMessageSignerFor(w));
|
|
24
|
+
return { siwx: headers["SIGN-IN-WITH-X"], token: live.control_plane_session_token };
|
|
21
25
|
}
|
package/lib/subscriptions.mjs
CHANGED
|
@@ -136,7 +136,7 @@ async function rulesAdd(args) {
|
|
|
136
136
|
|
|
137
137
|
walletAuthHeaders("/agent/v1/notifications/rules");
|
|
138
138
|
try {
|
|
139
|
-
console.log(JSON.stringify(await getSdk().admin.rules.create(input, sessionProofs("/agent/v1/notifications/rules")), null, 2));
|
|
139
|
+
console.log(JSON.stringify(await getSdk().admin.rules.create(input, await sessionProofs("/agent/v1/notifications/rules")), null, 2));
|
|
140
140
|
} catch (err) {
|
|
141
141
|
reportSdkError(err);
|
|
142
142
|
}
|
|
@@ -162,7 +162,7 @@ async function rulesRm(args) {
|
|
|
162
162
|
});
|
|
163
163
|
walletAuthHeaders("/agent/v1/notifications/rules");
|
|
164
164
|
try {
|
|
165
|
-
console.log(JSON.stringify(await getSdk().admin.rules.delete(ruleId, sessionProofs("/agent/v1/notifications/rules")), null, 2));
|
|
165
|
+
console.log(JSON.stringify(await getSdk().admin.rules.delete(ruleId, await sessionProofs("/agent/v1/notifications/rules")), null, 2));
|
|
166
166
|
} catch (err) {
|
|
167
167
|
reportSdkError(err);
|
|
168
168
|
}
|
package/lib/wallets.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import { ALL_ON_CHAIN_BALANCE_KEYS, readOnChainBalances, TEMPO_MODERATO } from "
|
|
|
20
20
|
const HELP = `run402 wallets — manage named wallets (profiles)
|
|
21
21
|
|
|
22
22
|
Usage:
|
|
23
|
-
run402 wallets list List all wallets (local_label, server_label, address, rail, active)
|
|
23
|
+
run402 wallets list List all wallets (local_label, server_label, address, rail, signer, active)
|
|
24
24
|
run402 wallets current Show the active wallet: how it was selected, address, rail, file path, faucet use
|
|
25
25
|
run402 wallets fund Request testnet funds from the faucet into the active wallet (Base Sepolia or Tempo)
|
|
26
26
|
run402 wallets balance The active wallet's on-chain balances, plus its organization's allowance
|
|
@@ -30,6 +30,11 @@ Usage:
|
|
|
30
30
|
run402 wallets bind [<name>] Write ./.run402.json binding this directory to a wallet
|
|
31
31
|
run402 wallets unbind Remove ./.run402.json
|
|
32
32
|
run402 wallets import <name> --key <path|-> Adopt an existing private key as a named wallet
|
|
33
|
+
run402 wallets import <name> --kms <key-arn> [--aws-profile <p>]
|
|
34
|
+
Adopt an AWS KMS key by reference (no secret on disk)
|
|
35
|
+
run402 wallets send <amount> --to <address> [--from <smart-account>] [--network <n>] [--confirm]
|
|
36
|
+
Send USDC (base, base-sepolia) or pathUSD (tempo, tempo-moderato)
|
|
37
|
+
from the active wallet; previews without --confirm
|
|
33
38
|
run402 wallets rm <name> --yes Delete a wallet and its keys (requires --yes)
|
|
34
39
|
run402 wallets lightning status The active wallet's Lightning wallet (balance, budget, custody)
|
|
35
40
|
run402 wallets lightning mint Mint the Lightning wallet for the active wallet (same as init lightning)
|
|
@@ -43,6 +48,12 @@ Options:
|
|
|
43
48
|
--rail <rail> (new) x402 (default), mpp, or lightning; a lightning wallet
|
|
44
49
|
is minted on the platform by: run402 --wallet <name> init lightning
|
|
45
50
|
--key <path|-> (import) read the private key from a file, or '-' for stdin
|
|
51
|
+
--kms <arn> (import) a KMS key ARN (ECC_SECG_P256K1, SIGN_VERIFY); the key never leaves KMS
|
|
52
|
+
--aws-profile <p> (import) the AWS profile the key is reached through (e.g. an SSO profile)
|
|
53
|
+
--to <address> (send) the recipient
|
|
54
|
+
--from <addr> (send) a CoinbaseSmartWallet the wallet owns, to send from (Base only)
|
|
55
|
+
--network <n> (send) base (default), base-sepolia, tempo, or tempo-moderato
|
|
56
|
+
--confirm (send) sign and send; without it, print the checked preview only
|
|
46
57
|
--yes (rm) confirm deletion
|
|
47
58
|
|
|
48
59
|
Notes:
|
|
@@ -97,6 +108,14 @@ const cmdBind = (args) => call((w) => w.bind(firstPositional(args)));
|
|
|
97
108
|
const cmdUnbind = () => call((w) => w.unbind());
|
|
98
109
|
|
|
99
110
|
function cmdImport(args) {
|
|
111
|
+
const kms = flagVal(args, "--kms");
|
|
112
|
+
if (kms) {
|
|
113
|
+
if (args.includes("--key")) {
|
|
114
|
+
fail({ code: "BAD_USAGE", message: "Pass either --key or --kms, not both." });
|
|
115
|
+
}
|
|
116
|
+
const awsProfile = flagVal(args, "--aws-profile") ?? undefined;
|
|
117
|
+
return call((w) => w.import(firstPositional(args), { kms: { keyId: kms, awsProfile } }));
|
|
118
|
+
}
|
|
100
119
|
// The key is read only after the SDK has accepted the name.
|
|
101
120
|
return call((w) => w.import(firstPositional(args), () => {
|
|
102
121
|
const keyArg = flagVal(args, "--key");
|
|
@@ -113,6 +132,26 @@ function cmdImport(args) {
|
|
|
113
132
|
|
|
114
133
|
const cmdRm = (args) => call((w) => w.remove(firstPositional(args), { confirm: args.includes("--yes") }));
|
|
115
134
|
|
|
135
|
+
function cmdSend(args) {
|
|
136
|
+
const valueFlags = new Set(["--to", "--from", "--network"]);
|
|
137
|
+
const amount = args.find((a, i) => a && !a.startsWith("-") && !valueFlags.has(args[i - 1]));
|
|
138
|
+
const to = flagVal(args, "--to");
|
|
139
|
+
if (!amount || !to) {
|
|
140
|
+
fail({ code: "BAD_USAGE", message: "Usage: run402 wallets send <amount> --to <address> [--from <smart-account>] [--network <n>] [--confirm]" });
|
|
141
|
+
}
|
|
142
|
+
const opts = {
|
|
143
|
+
amount,
|
|
144
|
+
to,
|
|
145
|
+
from: flagVal(args, "--from") ?? undefined,
|
|
146
|
+
network: flagVal(args, "--network") ?? undefined,
|
|
147
|
+
confirm: args.includes("--confirm"),
|
|
148
|
+
};
|
|
149
|
+
return call(async (w) => {
|
|
150
|
+
const result = await w.send(opts);
|
|
151
|
+
return result.preview ? { ...result, hint: "Nothing was signed. Re-run with --confirm to sign and send." } : result;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
116
155
|
export async function run(sub, args = []) {
|
|
117
156
|
const rest = Array.isArray(args) ? args : [];
|
|
118
157
|
if (!sub || sub === "--help" || sub === "-h" || rest.includes("--help") || rest.includes("-h")) {
|
|
@@ -129,6 +168,7 @@ export async function run(sub, args = []) {
|
|
|
129
168
|
case "unbind": return cmdUnbind();
|
|
130
169
|
case "import": return cmdImport(rest);
|
|
131
170
|
case "rm": return cmdRm(rest);
|
|
171
|
+
case "send": return cmdSend(rest);
|
|
132
172
|
case "fund": return cmdFund();
|
|
133
173
|
case "balance": return cmdBalance();
|
|
134
174
|
case "lightning": return cmdLightning(rest);
|
package/lib/webhook-secret.mjs
CHANGED
|
@@ -39,7 +39,7 @@ export async function run(sub, args = []) {
|
|
|
39
39
|
}
|
|
40
40
|
const parsedArgs = normalizeArgv(args);
|
|
41
41
|
assertKnownFlags(parsedArgs, ["--help", "-h"]);
|
|
42
|
-
const proofs = sessionProofs("/agent/v1/webhook-secret/rotate");
|
|
42
|
+
const proofs = await sessionProofs("/agent/v1/webhook-secret/rotate");
|
|
43
43
|
try {
|
|
44
44
|
const data = await getSdk().admin.rotateWebhookSecret(proofs);
|
|
45
45
|
console.log(JSON.stringify(data, null, 2));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "run402",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.121.0",
|
|
4
4
|
"description": "CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"vault-surface.json"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
+
"@aws-sdk/client-kms": "^3.1147.0",
|
|
26
27
|
"@hpke/chacha20poly1305": "^1.8.0",
|
|
27
28
|
"@hpke/core": "^1.9.0",
|
|
28
29
|
"@humanwhocodes/momoa": "3.3.10",
|
|
@@ -6,7 +6,7 @@ import { randomBytes } from "node:crypto";
|
|
|
6
6
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
7
7
|
import { keccak_256 } from "@noble/hashes/sha3.js";
|
|
8
8
|
import { bytesToHex } from "@noble/hashes/utils.js";
|
|
9
|
-
import { readWallet } from "./wallet.js";
|
|
9
|
+
import { isSignerWallet, readWallet } from "./wallet.js";
|
|
10
10
|
import { getApiBase } from "./config.js";
|
|
11
11
|
/**
|
|
12
12
|
* EIP-55 mixed-case checksum encoding.
|
|
@@ -57,6 +57,33 @@ function personalSign(privateKeyHex, address, message) {
|
|
|
57
57
|
const vHex = (recovery + 27).toString(16).padStart(2, "0");
|
|
58
58
|
return "0x" + r + s + vHex;
|
|
59
59
|
}
|
|
60
|
+
export function prepareSIWx(opts) {
|
|
61
|
+
const message = formatSIWEMessage(opts, opts.address);
|
|
62
|
+
return {
|
|
63
|
+
message,
|
|
64
|
+
finish(signature) {
|
|
65
|
+
const payload = {
|
|
66
|
+
domain: opts.domain,
|
|
67
|
+
address: toChecksumAddress(opts.address),
|
|
68
|
+
statement: opts.statement,
|
|
69
|
+
uri: opts.uri,
|
|
70
|
+
version: opts.version ?? "1",
|
|
71
|
+
chainId: payloadChainId(opts.chainId),
|
|
72
|
+
type: opts.type ?? "eip191",
|
|
73
|
+
nonce: opts.nonce,
|
|
74
|
+
issuedAt: opts.issuedAt,
|
|
75
|
+
expirationTime: opts.expirationTime,
|
|
76
|
+
signature,
|
|
77
|
+
};
|
|
78
|
+
if (opts.resources !== undefined) {
|
|
79
|
+
payload.resources = opts.resources;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
"SIGN-IN-WITH-X": Buffer.from(JSON.stringify(payload)).toString("base64"),
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
60
87
|
/**
|
|
61
88
|
* Format an EIP-4361 (SIWE) message. Must be byte-for-byte compatible
|
|
62
89
|
* with the `siwe` library's message format used server-side for verification.
|
|
@@ -85,29 +112,54 @@ export function formatSIWEMessage(opts, address) {
|
|
|
85
112
|
}
|
|
86
113
|
return lines.join("\n");
|
|
87
114
|
}
|
|
115
|
+
/** SIWX headers signed with a local private key (synchronous). */
|
|
88
116
|
export function buildSIWxAuthHeaders(opts) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const payload = {
|
|
92
|
-
domain: opts.domain,
|
|
93
|
-
address: toChecksumAddress(opts.wallet.address),
|
|
94
|
-
statement: opts.statement,
|
|
95
|
-
uri: opts.uri,
|
|
96
|
-
version: opts.version ?? "1",
|
|
97
|
-
chainId: payloadChainId(opts.chainId),
|
|
98
|
-
type: opts.type ?? "eip191",
|
|
99
|
-
nonce: opts.nonce,
|
|
100
|
-
issuedAt: opts.issuedAt,
|
|
101
|
-
expirationTime: opts.expirationTime,
|
|
102
|
-
signature,
|
|
103
|
-
};
|
|
104
|
-
if (opts.resources !== undefined) {
|
|
105
|
-
payload.resources = opts.resources;
|
|
117
|
+
if (!opts.wallet.privateKey) {
|
|
118
|
+
throw new SignerWalletError();
|
|
106
119
|
}
|
|
120
|
+
const prepared = prepareSIWx({ ...opts, address: opts.wallet.address });
|
|
121
|
+
return prepared.finish(personalSign(opts.wallet.privateKey, opts.wallet.address, prepared.message));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Thrown where a synchronous signature is required but the wallet signs
|
|
125
|
+
* through a signer (`wallet.json` `signer`). Callers that can wait use
|
|
126
|
+
* `getWalletAuthHeadersAsync` with the SDK's signer instead.
|
|
127
|
+
*/
|
|
128
|
+
export class SignerWalletError extends Error {
|
|
129
|
+
code = "SIGNER_WALLET_ASYNC";
|
|
130
|
+
constructor() {
|
|
131
|
+
super("This wallet signs through a signer (wallet.json 'signer'), which this synchronous path cannot use.");
|
|
132
|
+
this.name = "SignerWalletError";
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function walletSIWxOptions(path) {
|
|
136
|
+
const apiBase = getApiBase();
|
|
137
|
+
const url = new URL(apiBase);
|
|
138
|
+
const now = new Date();
|
|
107
139
|
return {
|
|
108
|
-
|
|
140
|
+
domain: url.hostname,
|
|
141
|
+
uri: `${apiBase}${path}`,
|
|
142
|
+
statement: "Sign in to Run402",
|
|
143
|
+
chainId: "eip155:84532",
|
|
144
|
+
nonce: randomBytes(16).toString("hex"),
|
|
145
|
+
issuedAt: now.toISOString(),
|
|
146
|
+
expirationTime: new Date(now.getTime() + 5 * 60 * 1000).toISOString(),
|
|
109
147
|
};
|
|
110
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* SIWX headers for any wallet: a key-backed wallet signs locally; a
|
|
151
|
+
* signer-backed one through `signerFor(wallet)`. Null when no wallet exists.
|
|
152
|
+
*/
|
|
153
|
+
export async function getWalletAuthHeadersAsync(path, walletPath, signerFor) {
|
|
154
|
+
const localWallet = readWallet(walletPath);
|
|
155
|
+
if (!localWallet || !localWallet.address)
|
|
156
|
+
return null;
|
|
157
|
+
if (!isSignerWallet(localWallet))
|
|
158
|
+
return getWalletAuthHeaders(path, walletPath);
|
|
159
|
+
const prepared = prepareSIWx({ ...walletSIWxOptions(path), address: localWallet.address });
|
|
160
|
+
const sign = await signerFor(localWallet);
|
|
161
|
+
return prepared.finish(await sign(prepared.message));
|
|
162
|
+
}
|
|
111
163
|
/**
|
|
112
164
|
* Get SIWX auth headers for the Run402 API.
|
|
113
165
|
* Returns null if no local wallet is configured.
|
|
@@ -121,26 +173,13 @@ export function getWalletAuthHeaders(path, walletPath) {
|
|
|
121
173
|
// this helper returns SIWxAuthHeaders | null. Re-throw so callers above
|
|
122
174
|
// the CLI's wrapper (e.g. SDK paid-fetch) can decide whether to swallow it.
|
|
123
175
|
const localWallet = readWallet(walletPath);
|
|
124
|
-
if (!localWallet || !localWallet.address
|
|
176
|
+
if (!localWallet || !localWallet.address)
|
|
125
177
|
return null;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const now = new Date();
|
|
132
|
-
const issuedAt = now.toISOString();
|
|
133
|
-
const expirationTime = new Date(now.getTime() + 5 * 60 * 1000).toISOString();
|
|
134
|
-
return buildSIWxAuthHeaders({
|
|
135
|
-
wallet: localWallet,
|
|
136
|
-
domain,
|
|
137
|
-
uri,
|
|
138
|
-
statement: "Sign in to Run402",
|
|
139
|
-
chainId: "eip155:84532",
|
|
140
|
-
nonce,
|
|
141
|
-
issuedAt,
|
|
142
|
-
expirationTime,
|
|
143
|
-
});
|
|
178
|
+
if (isSignerWallet(localWallet))
|
|
179
|
+
throw new SignerWalletError();
|
|
180
|
+
if (!localWallet.privateKey)
|
|
181
|
+
return null;
|
|
182
|
+
return buildSIWxAuthHeaders({ wallet: localWallet, ...walletSIWxOptions(path) });
|
|
144
183
|
}
|
|
145
184
|
function messageChainId(chainId) {
|
|
146
185
|
if (typeof chainId === "number")
|
package/sdk/core-dist/wallet.js
CHANGED
|
@@ -6,6 +6,12 @@ import { getWalletPath } from "./config.js";
|
|
|
6
6
|
const ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
7
7
|
// 0x-prefixed 64-hex secp256k1 private key (32 bytes).
|
|
8
8
|
const PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
9
|
+
// arn:aws:kms:<region>:<account>:key/<id>
|
|
10
|
+
export const KMS_KEY_ARN_RE = /^arn:aws[a-z-]*:kms:([a-z0-9-]+):\d{12}:key\/[A-Za-z0-9-]+$/;
|
|
11
|
+
/** True when the wallet signs through a signer instead of a local key. */
|
|
12
|
+
export function isSignerWallet(wallet) {
|
|
13
|
+
return wallet.signer !== undefined;
|
|
14
|
+
}
|
|
9
15
|
/**
|
|
10
16
|
* Load the agent wallet from disk.
|
|
11
17
|
*
|
|
@@ -78,6 +84,21 @@ export function readWallet(path) {
|
|
|
78
84
|
throw new Error("wallet.json missing valid 'address' (expected 0x-prefixed 40-hex string). " +
|
|
79
85
|
"Back up the file and run 'run402 init' to recreate it.");
|
|
80
86
|
}
|
|
87
|
+
if (data.privateKey !== undefined && data.signer !== undefined) {
|
|
88
|
+
throw new Error(`${p} has both 'privateKey' and 'signer'; a wallet is backed by exactly one. ` +
|
|
89
|
+
"Remove the one that does not belong to this wallet.");
|
|
90
|
+
}
|
|
91
|
+
if (data.signer !== undefined) {
|
|
92
|
+
const signer = data.signer;
|
|
93
|
+
if (!signer || typeof signer !== "object" || signer.kind !== "aws_kms" ||
|
|
94
|
+
typeof signer.key_arn !== "string" || !KMS_KEY_ARN_RE.test(signer.key_arn) ||
|
|
95
|
+
typeof signer.region !== "string" || signer.region.length === 0 ||
|
|
96
|
+
(signer.aws_profile !== undefined && (typeof signer.aws_profile !== "string" || signer.aws_profile.length === 0))) {
|
|
97
|
+
throw new Error(`${p} has a malformed 'signer' (expected { kind: "aws_kms", key_arn, region, aws_profile? }). ` +
|
|
98
|
+
"Re-import the wallet with 'run402 wallets import <name> --kms <key-arn>'.");
|
|
99
|
+
}
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
81
102
|
if (typeof data.privateKey !== "string" || !PRIVATE_KEY_RE.test(data.privateKey)) {
|
|
82
103
|
throw new Error("wallet.json missing valid 'privateKey' (expected 0x-prefixed 64-hex string). " +
|
|
83
104
|
"Back up the file and run 'run402 init' to recreate it.");
|
|
@@ -31,9 +31,23 @@ export interface ProjectCredentialCacheInfo {
|
|
|
31
31
|
wallet?: string;
|
|
32
32
|
profile?: string;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* A wallet is backed by exactly one of: a local private key (`privateKey`),
|
|
36
|
+
* or a signer reference (`signer`) naming where the key lives (an AWS KMS
|
|
37
|
+
* key). A signer reference holds no secret.
|
|
38
|
+
*/
|
|
34
39
|
export interface WalletData {
|
|
35
40
|
address: string;
|
|
36
|
-
|
|
41
|
+
/** Local signing key. Absent on a signer-backed wallet. */
|
|
42
|
+
privateKey?: string;
|
|
43
|
+
/** Where a signer-backed wallet's key lives. Absent on a key-backed wallet. */
|
|
44
|
+
signer?: {
|
|
45
|
+
kind: "aws_kms";
|
|
46
|
+
key_arn: string;
|
|
47
|
+
region: string;
|
|
48
|
+
/** The AWS profile the key is reached through; the default credential chain when absent. */
|
|
49
|
+
aws_profile?: string;
|
|
50
|
+
};
|
|
37
51
|
created?: string;
|
|
38
52
|
funded?: boolean;
|
|
39
53
|
lastFaucet?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|
package/sdk/dist/errors.d.ts
CHANGED
|
@@ -266,6 +266,20 @@ export declare class ProjectCredentialNotFound extends LocalError {
|
|
|
266
266
|
* `run_cli_command` next action naming the CLI command that performs the
|
|
267
267
|
* same operation, where the secret prints once to a person's terminal.
|
|
268
268
|
*/
|
|
269
|
+
/**
|
|
270
|
+
* `VALUE_TRANSFER_REQUIRES_CLI` — a method that moves money out of a wallet
|
|
271
|
+
* (`wallets.send`) was called on a client whose `capabilities.returnSecrets`
|
|
272
|
+
* is false: the `sandbox` surface an MCP `run` snippet executes on. Thrown
|
|
273
|
+
* before any signature is requested. Paying a priced route from the sandbox is
|
|
274
|
+
* unaffected (it is bounded by the client's spend controls); a transfer to an
|
|
275
|
+
* arbitrary address is not, so it belongs to a person at the CLI. Carries one
|
|
276
|
+
* `run_cli_command` next action naming the equivalent command.
|
|
277
|
+
*/
|
|
278
|
+
export declare class ValueTransferRequiresCliError extends LocalError {
|
|
279
|
+
/** The exact CLI command line for the same transfer. */
|
|
280
|
+
readonly command: string;
|
|
281
|
+
constructor(command: string);
|
|
282
|
+
}
|
|
269
283
|
export declare class SecretRequiresCliError extends LocalError {
|
|
270
284
|
/** The exact CLI command line for the same operation. */
|
|
271
285
|
readonly command: string;
|