run402-mcp
Version:
MCP server 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.
236 lines • 11 kB
JavaScript
import { LocalError } from "../../errors.js";
import { PaidStackUnavailable, loadKmsStack } from "../_paid-stack.js";
const SECP256K1_N = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n;
const SECP256K1_HALF_N = SECP256K1_N >> 1n;
/** KMS answered with something that is not an ECDSA signature. */
function malformed(message) {
return new LocalError(message, "signing with a KMS wallet", {
code: "KMS_SIGNATURE_MALFORMED",
next_actions: [{ type: "retry", why: "Retry once; if it persists, check the key is ECC_SECG_P256K1 / SIGN_VERIFY." }],
});
}
function bytesToHex(bytes) {
return Buffer.from(bytes).toString("hex");
}
/** DER length at `i`: returns [length, next index]. Supports short and long form. */
function derLength(der, i) {
const first = der[i];
if (first === undefined)
throw malformed("malformed DER: truncated length");
if ((first & 0x80) === 0)
return [first, i + 1];
const count = first & 0x7f;
if (count === 0 || count > 2 || i + 1 + count > der.length)
throw malformed("malformed DER: bad length");
let len = 0;
for (let j = 0; j < count; j++)
len = (len << 8) | der[i + 1 + j];
return [len, i + 1 + count];
}
/** Parse an ECDSA DER signature (SEQUENCE { INTEGER r, INTEGER s }). */
export function parseDerSignature(der) {
if (der[0] !== 0x30)
throw malformed("malformed DER signature: not a SEQUENCE");
let [, i] = derLength(der, 1);
const readInt = () => {
if (der[i] !== 0x02)
throw malformed("malformed DER signature: expected INTEGER");
const [len, start] = derLength(der, i + 1);
if (len === 0 || start + len > der.length)
throw malformed("malformed DER signature: bad INTEGER");
const value = BigInt("0x" + bytesToHex(der.slice(start, start + len)));
i = start + len;
return value;
};
const r = readInt();
const s = readInt();
if (r === 0n || s === 0n || r >= SECP256K1_N || s >= SECP256K1_N)
throw malformed("malformed DER signature: out of range");
return { r, s };
}
/**
* KMS's DER signature over `hash` → a 65-byte Ethereum signature that recovers
* to `address`, or `SIGNER_ADDRESS_MISMATCH`.
*/
export async function derToEthereumSignature(viem, der, hash, address) {
const { r, s } = parseDerSignature(der);
const lowS = s > SECP256K1_HALF_N ? SECP256K1_N - s : s;
const rHex = viem.numberToHex(r, { size: 32 });
const sHex = viem.numberToHex(lowS, { size: 32 });
const recovered = [];
for (const yParity of [0, 1]) {
const signature = viem.serializeSignature({ r: rHex, s: sHex, yParity });
try {
const candidate = await viem.recoverAddress({ hash, signature });
if (candidate.toLowerCase() === address.toLowerCase())
return signature;
recovered.push(candidate);
}
catch {
// the other recovery id
}
}
throw new LocalError(`The KMS key signed as ${recovered.join(" or ") || "no recoverable address"}, not as this wallet's address ${address}.`, "signing with a KMS wallet", {
code: "SIGNER_ADDRESS_MISMATCH",
details: { expected_address: address, recovered_addresses: recovered },
next_actions: [{
type: "edit_request",
why: "The key behind this wallet's ARN is not the key it was imported from. Re-import the right key, or check wallet.json's key_arn.",
}],
});
}
function errorName(err) {
return err?.name === undefined ? "" : String(err.name);
}
/** A KMS/AWS failure as a named local error with its remedy; never renders a credential. */
export function kmsError(err, signer, context) {
if (err instanceof LocalError)
return err;
if (err instanceof PaidStackUnavailable) {
return new LocalError(`A KMS wallet needs ${err.missingPackages.join(", ")}, which is not installed.`, context, {
code: "KMS_SIGNER_UNAVAILABLE",
details: { missing_packages: err.missingPackages },
next_actions: [{ type: "upgrade_client", command: `npm install ${err.missingPackages.join(" ")}`, why: "Install the KMS client, then retry." }],
});
}
const name = errorName(err);
const message = err instanceof Error ? err.message : String(err);
if (name === "AccessDeniedException") {
const caller = /User: (arn:[^\s]+)/.exec(message)?.[1] ?? null;
return new LocalError(`${caller ?? "This AWS identity"} may not use KMS key ${signer.key_arn}.`, context, {
code: "KMS_ACCESS_DENIED",
details: { key_arn: signer.key_arn, caller_arn: caller },
next_actions: [{
type: "authenticate",
...(signer.aws_profile ? { command: `aws sso login --profile ${signer.aws_profile}` } : {}),
why: "Sign in as the identity the key's policy names (for a seller key, that person's SellerSigner session).",
}],
});
}
const credentials = /CredentialsProviderError|ExpiredToken|UnrecognizedClient|InvalidSignature|TokenProviderError|SSO/i.test(name) ||
/token (?:has )?expired|sso session|could not load credentials|unable to load credentials|security token included in the request is expired/i.test(message);
return new LocalError(credentials
? `The AWS session for KMS key ${signer.key_arn} is missing or expired.`
: `KMS key ${signer.key_arn} could not be reached (${name || "error"}).`, context, {
code: "KMS_SIGNER_UNAVAILABLE",
details: { key_arn: signer.key_arn, region: signer.region, aws_error: name || null },
next_actions: credentials
? [{
type: "authenticate",
command: signer.aws_profile ? `aws sso login --profile ${signer.aws_profile}` : "aws sso login",
why: "Refresh the AWS session the key is reached through, then retry.",
}]
: [{ type: "retry", why: "Retry once KMS is reachable." }],
});
}
const clients = new Map();
/** One KMS client per (region, profile) per process. */
function kmsClient(stack, signer) {
const key = `${signer.region}|${signer.aws_profile ?? ""}`;
let client = clients.get(key);
if (!client) {
client = new stack.KMSClient({ region: signer.region, ...(signer.aws_profile ? { profile: signer.aws_profile } : {}) });
clients.set(key, client);
}
return client;
}
/** A viem account that signs through `signer` as `address`. */
export async function kmsAccount(signer, address, opts = {}) {
let stack;
try {
stack = opts.stack ?? await loadKmsStack();
}
catch (err) {
throw kmsError(err, signer, "loading the KMS signer");
}
const client = opts.client ?? kmsClient(stack, signer);
const { viem } = stack;
const signHash = async (hash) => {
let der;
try {
const out = await client.send(new stack.SignCommand({
KeyId: signer.key_arn,
Message: viem.hexToBytes(hash),
MessageType: "DIGEST",
SigningAlgorithm: "ECDSA_SHA_256",
}));
if (!out.Signature)
throw malformed("KMS returned no signature");
der = out.Signature;
}
catch (err) {
throw kmsError(err, signer, "signing with a KMS wallet");
}
return derToEthereumSignature(viem, der, hash, address);
};
const account = stack.toAccount({
address: viem.getAddress(address),
async sign({ hash }) {
return signHash(hash);
},
async signMessage({ message }) {
return signHash(viem.hashMessage(message));
},
async signTypedData(typedData) {
return signHash(viem.hashTypedData(typedData));
},
async signTransaction(transaction, options) {
const serializer = (options?.serializer ?? viem.serializeTransaction);
// As viem's own local account does: an EIP-4844 transaction is signed without its sidecars.
const signable = transaction.type === "eip4844"
? { ...transaction, sidecars: false }
: transaction;
const signature = await signHash(viem.keccak256(await serializer(signable)));
return await serializer(transaction, viem.parseSignature(signature));
},
});
return account;
}
/**
* Read a KMS key's public key and metadata (read-only: `GetPublicKey` only)
* and derive its address; `KMS_KEY_UNSUITABLE` unless it is a secp256k1
* signing key.
*/
export async function adoptKmsKey(signer, opts = {}) {
let stack;
try {
stack = opts.stack ?? await loadKmsStack();
}
catch (err) {
throw kmsError(err, signer, "importing a KMS wallet");
}
const client = opts.client ?? kmsClient(stack, signer);
let out;
try {
out = await client.send(new stack.GetPublicKeyCommand({ KeyId: signer.key_arn }));
}
catch (err) {
throw kmsError(err, signer, "importing a KMS wallet");
}
if (out.KeySpec !== "ECC_SECG_P256K1" || out.KeyUsage !== "SIGN_VERIFY" || !out.PublicKey) {
throw new LocalError(`KMS key ${signer.key_arn} is ${out.KeySpec ?? "unknown"} / ${out.KeyUsage ?? "unknown"}; a wallet needs ECC_SECG_P256K1 / SIGN_VERIFY.`, "importing a KMS wallet", {
code: "KMS_KEY_UNSUITABLE",
details: { key_arn: signer.key_arn, key_spec: out.KeySpec ?? null, key_usage: out.KeyUsage ?? null },
next_actions: [{ type: "edit_request", why: "Import an asymmetric secp256k1 signing key (ECC_SECG_P256K1, SIGN_VERIFY)." }],
});
}
return { address: addressFromSpki(stack.viem, out.PublicKey), key_spec: out.KeySpec, key_usage: out.KeyUsage };
}
const SECP256K1_SPKI_PREFIX = "3056301006072a8648ce3d020106052b8104000a034200";
/** The EVM address of a secp256k1 SubjectPublicKeyInfo (what KMS GetPublicKey returns). */
export function addressFromSpki(viem, der) {
const hex = bytesToHex(der);
if (!hex.startsWith(SECP256K1_SPKI_PREFIX) || hex.length !== SECP256K1_SPKI_PREFIX.length + 130 || hex.slice(SECP256K1_SPKI_PREFIX.length, SECP256K1_SPKI_PREFIX.length + 2) !== "04") {
throw new LocalError("The KMS public key is not a secp256k1 SubjectPublicKeyInfo with an uncompressed point.", "importing a KMS wallet", {
code: "KMS_KEY_UNSUITABLE",
next_actions: [{ type: "edit_request", why: "Import an asymmetric secp256k1 signing key (ECC_SECG_P256K1, SIGN_VERIFY)." }],
});
}
const hash = viem.keccak256(`0x${hex.slice(SECP256K1_SPKI_PREFIX.length + 2)}`);
return viem.getAddress(`0x${hash.slice(-40)}`);
}
/** Test seam: forget cached clients. */
export function resetKmsClientsForTests() {
clients.clear();
}
//# sourceMappingURL=kms.js.map