x402-payguard / tree / test/publicbase.test.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// Reverse-proxy public base URL (api.youraitools.co/<prefix>): see src/publicbase.js.
import test from 'node:test';
import assert from 'node:assert/strict';
import { wrapFetchWithPaymentFromConfig } from '@x402/fetch';
import { ExactEvmScheme } from '@x402/evm';
import { privateKeyToAccount, generatePrivateKey } from 'viem/accounts';
import { forwardedBase, publicBaseHandler, rewriteHtml } from '../src/publicbase.js';
import { createApp } from '../src/app.js';
const WORKERS_DEV = 'https://payguard.agentgate.workers.dev'; const PREFIX = '/payguard';
const PAID_PATH = '/v1/address'; const PAID = '/v1/address?address=0x098B716B8Aaf21512996dC57EB0615e2383E2f96'; const AMOUNT = '1000';
const appOpts = async () => ({ payTo: '0x3c1A1E01e790Cd326495631B3b38Bd7068F08d6F', network: 'eip155:8453' });

const NETWORK = 'eip155:8453';
const ENV = { PUBLIC_URL: WORKERS_DEV, PROXY_HOSTS: 'api.youraitools.co', PROXY_PREFIX: PREFIX };
const PROXY_BASE = `https://api.youraitools.co${PREFIX}`;
const FWD = { 'x-forwarded-host': 'api.youraitools.co', 'x-forwarded-prefix': PREFIX, 'x-forwarded-proto': 'https' };
const decode = (h) => JSON.parse(Buffer.from(h, 'base64').toString('utf8'));
const req = (path, headers = {}, init = {}) => new Request(`${WORKERS_DEV}${path}`, { ...init, headers: { ...headers, ...(init.headers || {}) } });

function facilitator() {
  const f = { verified: [], settled: [],
    async getSupported() { return { kinds: [{ x402Version: 2, scheme: 'exact', network: NETWORK }], extensions: ['bazaar'], signers: {} }; },
    async verify(payload, r) { f.verified.push({ payload, r }); const a = payload?.payload?.authorization; return a && a.to.toLowerCase() === r.payTo.toLowerCase() && String(a.value) === String(r.amount) ? { isValid: true, payer: a.from } : { isValid: false, invalidReason: 'fake_invalid' }; },
    async settle(payload, r) { f.settled.push({ payload, r }); return { success: true, transaction: '0x' + 'ab'.repeat(32), network: r.network, payer: payload.payload.authorization.from }; },
  };
  return f;
}
async function handler() {
  const fac = facilitator(); const opts = await appOpts(); const made = [];
  const h = publicBaseHandler(ENV, (publicUrl) => { made.push(publicUrl); return createApp({ ...opts, facilitatorClient: fac, publicUrl }); });
  return { h, fac, made };
}

test('forwardedBase: only the allowlisted host with this Worker\'s prefix is honoured', () => {
  const r = (h) => new Request(`${WORKERS_DEV}/`, { headers: h });
  assert.deepEqual(forwardedBase(r(FWD), ENV), { host: 'api.youraitools.co', prefix: PREFIX, base: PROXY_BASE });
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-host': 'API.YourAITools.co' }), ENV).base, PROXY_BASE);
  assert.equal(forwardedBase(r({}), ENV), null);
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-host': 'evil.example' }), ENV), null);
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-host': 'api.youraitools.co.evil.example' }), ENV), null);
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-prefix': '/other' }), ENV), null);
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-prefix': '' }), ENV), null);
  assert.equal(forwardedBase(r({ ...FWD, 'x-forwarded-prefix': '/x/../../evil' }), ENV), null);
  assert.equal(forwardedBase(r(FWD), { ...ENV, PROXY_PREFIX: undefined }), null);
});

test('rewriteHtml: root-relative links and sister-tool links get the proxy prefix, absolute links stay', () => {
  const out = rewriteHtml('<a href="/health">h</a><a href="//cdn.x/y">c</a><a href="https://x.example/">x</a><script>fetch(\'/v1/x\')</script><a href="https://webread.agentgate.workers.dev">w</a>', { host: 'api.youraitools.co', prefix: '/p' });
  assert.match(out, /href="\/p\/health"/); assert.match(out, /href="\/\/cdn\.x\/y"/); assert.match(out, /href="https:\/\/x\.example\/"/);
  assert.match(out, /fetch\('\/p\/v1\/x'\)/); assert.match(out, /href="https:\/\/api\.youraitools\.co\/webread"/);
});

test('direct workers.dev request is unchanged: 402 resource (v2 header and v1 body) on workers.dev', async () => {
  const { h } = await handler();
  const r = await h(req(PAID), ENV);
  assert.equal(r.status, 402);
  assert.equal(decode(r.headers.get('PAYMENT-REQUIRED')).resource.url, `${WORKERS_DEV}${PAID_PATH}`);
  assert.equal((await r.json()).accepts[0].resource, `${WORKERS_DEV}${PAID_PATH}`);
});

test('spoofed X-Forwarded-Host is ignored (workers.dev URLs)', async () => {
  const { h } = await handler();
  const r = await h(req(PAID, { ...FWD, 'x-forwarded-host': 'evil.example' }), ENV);
  assert.equal(decode(r.headers.get('PAYMENT-REQUIRED')).resource.url, `${WORKERS_DEV}${PAID_PATH}`);
});

test('proxied request: 402 resource, openapi servers, .well-known and landing use api.youraitools.co/<prefix>', async () => {
  const { h, made } = await handler();
  const r = await h(req(PAID, FWD), ENV);
  assert.equal(r.status, 402);
  const pr = decode(r.headers.get('PAYMENT-REQUIRED'));
  assert.equal(pr.resource.url, `${PROXY_BASE}${PAID_PATH}`);
  assert.equal(pr.accepts[0].amount, AMOUNT);
  assert.equal((await r.json()).accepts[0].resource, `${PROXY_BASE}${PAID_PATH}`);
  const oa = await (await h(req('/openapi.json', FWD), ENV)).json();
  assert.equal(oa.servers[0].url, PROXY_BASE);
  assert.ok(!JSON.stringify(oa).includes('agentgate.workers.dev'), 'no workers.dev URL in proxied openapi');
  const wk = await (await h(req('/.well-known/x402', FWD), ENV)).json();
  assert.ok(wk.resources.length && wk.resources.every((u) => u.startsWith(`${PROXY_BASE}/`)), JSON.stringify(wk.resources));
  const html = await (await h(req('/', { ...FWD, accept: 'text/html' }), ENV)).text();
  assert.ok(!new RegExp(`(href|src)="/(?!/)(?!${PREFIX.slice(1)}/)`).test(html), 'every root-relative link carries the prefix');
  assert.ok(html.includes(PROXY_BASE));
  // workers.dev answers are untouched by a proxied request in the same isolate
  const oa2 = await (await h(req('/openapi.json'), ENV)).json();
  assert.equal(oa2.servers[0].url, WORKERS_DEV);
  assert.deepEqual(made.sort(), [PROXY_BASE, WORKERS_DEV].sort(), 'exactly one app per public base');
});

test('proxied paid call (official @x402/fetch v2 client): the signed resource is the proxied URL, verified and settled', async () => {
  const { h, fac } = await handler();
  const viaProxy = (input, init) => { const r0 = input instanceof Request ? input : new Request(input, init); const r1 = new Request(r0); for (const [k, v] of Object.entries(FWD)) r1.headers.set(k, v); return h(r1, ENV); };
  const pay = wrapFetchWithPaymentFromConfig(viaProxy, { schemes: [{ network: NETWORK, client: new ExactEvmScheme(privateKeyToAccount(generatePrivateKey())) }] });
  const r = await pay(`${WORKERS_DEV}${PAID}`);
  assert.equal(r.status, 200, await r.clone().text());
  assert.equal((await r.clone().json()).sanctioned, true);
  assert.ok(r.headers.get('PAYMENT-RESPONSE'));
  assert.equal(fac.verified.length, 1); assert.equal(fac.settled.length, 1);
  assert.equal(fac.verified[0].payload.resource.url, `${PROXY_BASE}${PAID_PATH}`);
  assert.equal(fac.settled[0].payload.resource.url, `${PROXY_BASE}${PAID_PATH}`);
});

test('proxied MCP tools/list works', async () => {
  const { h } = await handler();
  const r = await h(req('/mcp', { ...FWD, 'content-type': 'application/json', accept: 'application/json, text/event-stream' }, { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} }) }), ENV);
  assert.equal(r.status, 200);
  const t = await r.text();
  const body = JSON.parse(t.startsWith('{') ? t : t.split('\n').find((l) => l.startsWith('data:')).slice(5));
  assert.ok(body.result.tools.length >= 1);
});

agentgate-source: code mirror on Cloudflare Pages. All repos