mppx 0.8.14 → 0.8.17
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/CHANGELOG.md +57 -0
- package/dist/Challenge.d.ts.map +1 -1
- package/dist/Challenge.js +40 -35
- package/dist/Challenge.js.map +1 -1
- package/dist/Constants.d.ts +17 -17
- package/dist/Constants.d.ts.map +1 -1
- package/dist/Credential.d.ts.map +1 -1
- package/dist/Errors.d.ts +3 -3
- package/dist/Errors.d.ts.map +1 -1
- package/dist/Errors.js.map +1 -1
- package/dist/Method.d.ts +35 -5
- package/dist/Method.d.ts.map +1 -1
- package/dist/Method.js +7 -22
- package/dist/Method.js.map +1 -1
- package/dist/Store.d.ts +19 -0
- package/dist/Store.d.ts.map +1 -1
- package/dist/Store.js +43 -0
- package/dist/Store.js.map +1 -1
- package/dist/attestation/Client.d.ts +17 -0
- package/dist/attestation/Client.d.ts.map +1 -0
- package/dist/attestation/Client.js +28 -0
- package/dist/attestation/Client.js.map +1 -0
- package/dist/attestation/Constants.d.ts +15 -0
- package/dist/attestation/Constants.d.ts.map +1 -0
- package/dist/attestation/Constants.js +15 -0
- package/dist/attestation/Constants.js.map +1 -0
- package/dist/attestation/Server.d.ts +4 -0
- package/dist/attestation/Server.d.ts.map +1 -0
- package/dist/attestation/Server.js +8 -0
- package/dist/attestation/Server.js.map +1 -0
- package/dist/attestation/Types.d.ts +76 -0
- package/dist/attestation/Types.d.ts.map +1 -0
- package/dist/attestation/Types.js +2 -0
- package/dist/attestation/Types.js.map +1 -0
- package/dist/attestation/index.d.ts +6 -0
- package/dist/attestation/index.d.ts.map +1 -0
- package/dist/attestation/index.js +6 -0
- package/dist/attestation/index.js.map +1 -0
- package/dist/attestation/internal/HttpMessageSignature.d.ts +73 -0
- package/dist/attestation/internal/HttpMessageSignature.d.ts.map +1 -0
- package/dist/attestation/internal/HttpMessageSignature.js +320 -0
- package/dist/attestation/internal/HttpMessageSignature.js.map +1 -0
- package/dist/attestation/internal/SigningContext.d.ts +4 -0
- package/dist/attestation/internal/SigningContext.d.ts.map +1 -0
- package/dist/attestation/internal/SigningContext.js +11 -0
- package/dist/attestation/internal/SigningContext.js.map +1 -0
- package/dist/cli/account.d.ts +14 -14
- package/dist/cli/account.d.ts.map +1 -1
- package/dist/cli/cli.d.ts +6 -6
- package/dist/cli/cli.d.ts.map +1 -1
- package/dist/cli/cli.js +1 -0
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/plugins/tempo.js.map +1 -1
- package/dist/cli/sessions/commands.d.ts +4 -4
- package/dist/cli/sessions/commands.d.ts.map +1 -1
- package/dist/cli/sessions/commands.js.map +1 -1
- package/dist/cli/sessions/store.d.ts.map +1 -1
- package/dist/cli/sessions/store.js.map +1 -1
- package/dist/cli/utils.d.ts +1 -1
- package/dist/cli/utils.d.ts.map +1 -1
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/validate/discovery.js.map +1 -1
- package/dist/cli/validate/index.d.ts +3 -3
- package/dist/cli/validate/index.d.ts.map +1 -1
- package/dist/cli/validate/payment.d.ts.map +1 -1
- package/dist/cli/validate/payment.js +18 -4
- package/dist/cli/validate/payment.js.map +1 -1
- package/dist/client/Mppx.d.ts +3 -0
- package/dist/client/Mppx.d.ts.map +1 -1
- package/dist/client/Mppx.js +13 -5
- package/dist/client/Mppx.js.map +1 -1
- package/dist/client/Transport.d.ts +3 -5
- package/dist/client/Transport.d.ts.map +1 -1
- package/dist/client/Transport.js +1 -17
- package/dist/client/Transport.js.map +1 -1
- package/dist/client/internal/Fetch.d.ts.map +1 -1
- package/dist/client/internal/Fetch.js +92 -13
- package/dist/client/internal/Fetch.js.map +1 -1
- package/dist/client/internal/MethodChallenge.d.ts +2 -0
- package/dist/client/internal/MethodChallenge.d.ts.map +1 -1
- package/dist/client/internal/MethodChallenge.js +4 -0
- package/dist/client/internal/MethodChallenge.js.map +1 -1
- package/dist/client/internal/MethodResponse.d.ts +15 -0
- package/dist/client/internal/MethodResponse.d.ts.map +1 -1
- package/dist/client/internal/MethodResponse.js +10 -0
- package/dist/client/internal/MethodResponse.js.map +1 -1
- package/dist/client/node.js.map +1 -1
- package/dist/discovery/OpenApi.d.ts +3 -5
- package/dist/discovery/OpenApi.d.ts.map +1 -1
- package/dist/discovery/OpenApi.js +13 -34
- package/dist/discovery/OpenApi.js.map +1 -1
- package/dist/discovery/internal/Metadata.d.ts +20 -0
- package/dist/discovery/internal/Metadata.d.ts.map +1 -0
- package/dist/discovery/internal/Metadata.js +36 -0
- package/dist/discovery/internal/Metadata.js.map +1 -0
- package/dist/evm/Methods.d.ts +11 -11
- package/dist/evm/Methods.d.ts.map +1 -1
- package/dist/evm/Types.d.ts +17 -17
- package/dist/evm/Types.d.ts.map +1 -1
- package/dist/evm/client/Charge.d.ts +11 -11
- package/dist/evm/client/Methods.d.ts +11 -11
- package/dist/evm/server/Charge.d.ts +1 -1
- package/dist/evm/server/Charge.d.ts.map +1 -1
- package/dist/evm/server/Charge.js +2 -0
- package/dist/evm/server/Charge.js.map +1 -1
- package/dist/evm/server/Methods.d.ts +11 -11
- package/dist/internal/HeaderCodec.d.ts +2 -2
- package/dist/internal/HeaderCodec.d.ts.map +1 -1
- package/dist/internal/types.d.ts +6 -0
- package/dist/internal/types.d.ts.map +1 -1
- package/dist/middlewares/elysia.js.map +1 -1
- package/dist/middlewares/express.js.map +1 -1
- package/dist/middlewares/hono.js.map +1 -1
- package/dist/middlewares/nextjs.js.map +1 -1
- package/dist/proxy/Proxy.d.ts +2 -0
- package/dist/proxy/Proxy.d.ts.map +1 -1
- package/dist/proxy/Proxy.js +117 -9
- package/dist/proxy/Proxy.js.map +1 -1
- package/dist/proxy/Service.d.ts +36 -1
- package/dist/proxy/Service.d.ts.map +1 -1
- package/dist/proxy/Service.js +9 -8
- package/dist/proxy/Service.js.map +1 -1
- package/dist/proxy/services/anthropic.d.ts.map +1 -1
- package/dist/proxy/services/anthropic.js +1 -0
- package/dist/proxy/services/anthropic.js.map +1 -1
- package/dist/proxy/services/openai.d.ts.map +1 -1
- package/dist/proxy/services/openai.js +1 -0
- package/dist/proxy/services/openai.js.map +1 -1
- package/dist/proxy/services/stripe.d.ts.map +1 -1
- package/dist/proxy/services/stripe.js +1 -0
- package/dist/proxy/services/stripe.js.map +1 -1
- package/dist/server/Mppx.d.ts +75 -13
- package/dist/server/Mppx.d.ts.map +1 -1
- package/dist/server/Mppx.js +201 -23
- package/dist/server/Mppx.js.map +1 -1
- package/dist/server/internal/html/config.d.ts +9 -9
- package/dist/server/internal/html/config.d.ts.map +1 -1
- package/dist/server/internal/html/constants.d.ts +17 -17
- package/dist/server/internal/html/constants.d.ts.map +1 -1
- package/dist/stripe/Methods.d.ts +10 -10
- package/dist/stripe/Methods.d.ts.map +1 -1
- package/dist/stripe/client/Charge.d.ts +10 -10
- package/dist/stripe/client/Methods.d.ts +10 -10
- package/dist/stripe/internal/constants.d.ts +1 -1
- package/dist/stripe/internal/constants.js +1 -1
- package/dist/stripe/internal/types.d.ts +1 -0
- package/dist/stripe/internal/types.d.ts.map +1 -1
- package/dist/stripe/server/Charge.d.ts +11 -11
- package/dist/stripe/server/Charge.d.ts.map +1 -1
- package/dist/stripe/server/Charge.js +49 -1
- package/dist/stripe/server/Charge.js.map +1 -1
- package/dist/stripe/server/Methods.d.ts +137 -48
- package/dist/stripe/server/Methods.d.ts.map +1 -1
- package/dist/stripe/server/Methods.js +259 -4
- package/dist/stripe/server/Methods.js.map +1 -1
- package/dist/stripe/server/internal/deposit-address.d.ts +13 -0
- package/dist/stripe/server/internal/deposit-address.d.ts.map +1 -0
- package/dist/stripe/server/internal/deposit-address.js +28 -0
- package/dist/stripe/server/internal/deposit-address.js.map +1 -0
- package/dist/stripe/server/internal/html.gen.d.ts +1 -1
- package/dist/stripe/server/internal/html.gen.d.ts.map +1 -1
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/stripe/server/internal/html.gen.js.map +1 -1
- package/dist/stripe/server/internal/record-payment.d.ts +15 -0
- package/dist/stripe/server/internal/record-payment.d.ts.map +1 -0
- package/dist/stripe/server/internal/record-payment.js +42 -0
- package/dist/stripe/server/internal/record-payment.js.map +1 -0
- package/dist/stripe/server/internal/request.d.ts +25 -0
- package/dist/stripe/server/internal/request.d.ts.map +1 -0
- package/dist/stripe/server/internal/request.js +29 -0
- package/dist/stripe/server/internal/request.js.map +1 -0
- package/dist/tap/Constants.d.ts +28 -0
- package/dist/tap/Constants.d.ts.map +1 -0
- package/dist/tap/Constants.js +32 -0
- package/dist/tap/Constants.js.map +1 -0
- package/dist/tap/Types.d.ts +11 -0
- package/dist/tap/Types.d.ts.map +1 -0
- package/dist/tap/Types.js +2 -0
- package/dist/tap/Types.js.map +1 -0
- package/dist/tap/client/index.d.ts +26 -0
- package/dist/tap/client/index.d.ts.map +1 -0
- package/dist/tap/client/index.js +33 -0
- package/dist/tap/client/index.js.map +1 -0
- package/dist/tap/index.d.ts +5 -0
- package/dist/tap/index.d.ts.map +1 -0
- package/dist/tap/index.js +5 -0
- package/dist/tap/index.js.map +1 -0
- package/dist/tap/server/index.d.ts +20 -0
- package/dist/tap/server/index.d.ts.map +1 -0
- package/dist/tap/server/index.js +36 -0
- package/dist/tap/server/index.js.map +1 -0
- package/dist/tempo/Attribution.d.ts +1 -1
- package/dist/tempo/Methods.d.ts +60 -60
- package/dist/tempo/Methods.d.ts.map +1 -1
- package/dist/tempo/Proof.d.ts +16 -16
- package/dist/tempo/client/Charge.d.ts +19 -19
- package/dist/tempo/client/Charge.d.ts.map +1 -1
- package/dist/tempo/client/Charge.js +1 -7
- package/dist/tempo/client/Charge.js.map +1 -1
- package/dist/tempo/client/Methods.d.ts +38 -38
- package/dist/tempo/client/Methods.js.map +1 -1
- package/dist/tempo/client/Subscription.d.ts +23 -23
- package/dist/tempo/client/Subscription.js.map +1 -1
- package/dist/tempo/internal/address.d.ts +2 -1
- package/dist/tempo/internal/address.d.ts.map +1 -1
- package/dist/tempo/internal/address.js +3 -1
- package/dist/tempo/internal/address.js.map +1 -1
- package/dist/tempo/internal/auto-swap.d.ts.map +1 -1
- package/dist/tempo/internal/auto-swap.js +4 -19
- package/dist/tempo/internal/auto-swap.js.map +1 -1
- package/dist/tempo/internal/defaults.d.ts +6 -6
- package/dist/tempo/internal/defaults.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.d.ts +12 -12
- package/dist/tempo/internal/fee-payer.d.ts.map +1 -1
- package/dist/tempo/internal/fee-payer.js.map +1 -1
- package/dist/tempo/internal/proof.d.ts +17 -17
- package/dist/tempo/internal/proof.d.ts.map +1 -1
- package/dist/tempo/legacy/client/Session.d.ts +20 -20
- package/dist/tempo/legacy/client/Session.js.map +1 -1
- package/dist/tempo/legacy/client/SessionManager.js.map +1 -1
- package/dist/tempo/legacy/index.d.ts +1 -3
- package/dist/tempo/legacy/index.d.ts.map +1 -1
- package/dist/tempo/legacy/index.js +1 -3
- package/dist/tempo/legacy/index.js.map +1 -1
- package/dist/tempo/legacy/session/escrow.abi.d.ts +374 -374
- package/dist/tempo/legacy/session/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/server/Charge.d.ts +34 -12
- package/dist/tempo/server/Charge.d.ts.map +1 -1
- package/dist/tempo/server/Charge.js +44 -39
- package/dist/tempo/server/Charge.js.map +1 -1
- package/dist/tempo/server/Methods.d.ts +37 -52
- package/dist/tempo/server/Methods.d.ts.map +1 -1
- package/dist/tempo/server/Methods.js +0 -14
- package/dist/tempo/server/Methods.js.map +1 -1
- package/dist/tempo/server/Relay.d.ts +14 -5
- package/dist/tempo/server/Relay.d.ts.map +1 -1
- package/dist/tempo/server/Relay.js +6 -4
- package/dist/tempo/server/Relay.js.map +1 -1
- package/dist/tempo/server/SponsorBudget.d.ts.map +1 -1
- package/dist/tempo/server/SponsorBudget.js +7 -1
- package/dist/tempo/server/SponsorBudget.js.map +1 -1
- package/dist/tempo/server/Subscription.d.ts +25 -25
- package/dist/tempo/server/Subscription.d.ts.map +1 -1
- package/dist/tempo/server/Subscription.js +2 -0
- package/dist/tempo/server/Subscription.js.map +1 -1
- package/dist/tempo/server/index.d.ts +1 -1
- package/dist/tempo/server/index.d.ts.map +1 -1
- package/dist/tempo/server/index.js +1 -1
- package/dist/tempo/server/index.js.map +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts +1 -1
- package/dist/tempo/server/internal/html.gen.d.ts.map +1 -1
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/server/internal/html.gen.js.map +1 -1
- package/dist/tempo/server/internal/transport.d.ts +2 -0
- package/dist/tempo/server/internal/transport.d.ts.map +1 -1
- package/dist/tempo/server/internal/transport.js +9 -2
- package/dist/tempo/server/internal/transport.js.map +1 -1
- package/dist/tempo/session/client/ChannelOps.js.map +1 -1
- package/dist/tempo/session/client/CredentialState.d.ts +1 -1
- package/dist/tempo/session/client/CredentialState.js.map +1 -1
- package/dist/tempo/session/client/ReceiptCoordinator.js.map +1 -1
- package/dist/tempo/session/client/Runtime.js.map +1 -1
- package/dist/tempo/session/client/Session.d.ts +19 -19
- package/dist/tempo/session/client/Session.d.ts.map +1 -1
- package/dist/tempo/session/client/Session.js +128 -14
- package/dist/tempo/session/client/Session.js.map +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts.map +1 -1
- package/dist/tempo/session/client/SessionManager.js +62 -20
- package/dist/tempo/session/client/SessionManager.js.map +1 -1
- package/dist/tempo/session/client/Transports.d.ts +9 -1
- package/dist/tempo/session/client/Transports.d.ts.map +1 -1
- package/dist/tempo/session/client/Transports.js +36 -13
- package/dist/tempo/session/client/Transports.js.map +1 -1
- package/dist/tempo/session/precompile/Chain.d.ts +27 -0
- package/dist/tempo/session/precompile/Chain.d.ts.map +1 -1
- package/dist/tempo/session/precompile/Chain.js +68 -7
- package/dist/tempo/session/precompile/Chain.js.map +1 -1
- package/dist/tempo/session/precompile/Protocol.js.map +1 -1
- package/dist/tempo/session/precompile/Voucher.d.ts +4 -4
- package/dist/tempo/session/precompile/Voucher.d.ts.map +1 -1
- package/dist/tempo/session/precompile/escrow.abi.d.ts +306 -306
- package/dist/tempo/session/precompile/escrow.abi.d.ts.map +1 -1
- package/dist/tempo/session/server/ChannelStore.d.ts +9 -0
- package/dist/tempo/session/server/ChannelStore.d.ts.map +1 -1
- package/dist/tempo/session/server/ChannelStore.js +16 -8
- package/dist/tempo/session/server/ChannelStore.js.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.d.ts +30 -13
- package/dist/tempo/session/server/CredentialVerification.d.ts.map +1 -1
- package/dist/tempo/session/server/CredentialVerification.js +207 -13
- package/dist/tempo/session/server/CredentialVerification.js.map +1 -1
- package/dist/tempo/session/server/MeteredStream.d.ts +3 -0
- package/dist/tempo/session/server/MeteredStream.d.ts.map +1 -1
- package/dist/tempo/session/server/MeteredStream.js +3 -1
- package/dist/tempo/session/server/MeteredStream.js.map +1 -1
- package/dist/tempo/session/server/Session.d.ts +32 -21
- package/dist/tempo/session/server/Session.d.ts.map +1 -1
- package/dist/tempo/session/server/Session.js +116 -53
- package/dist/tempo/session/server/Session.js.map +1 -1
- package/dist/tempo/session/server/Sse.d.ts +3 -1
- package/dist/tempo/session/server/Sse.d.ts.map +1 -1
- package/dist/tempo/session/server/Sse.js +2 -1
- package/dist/tempo/session/server/Sse.js.map +1 -1
- package/dist/tempo/session/server/Transports.d.ts +1 -1
- package/dist/tempo/session/server/Transports.d.ts.map +1 -1
- package/dist/tempo/session/server/Transports.js +1 -0
- package/dist/tempo/session/server/Transports.js.map +1 -1
- package/dist/tempo/session/server/Ws.d.ts +6 -1
- package/dist/tempo/session/server/Ws.d.ts.map +1 -1
- package/dist/tempo/session/server/Ws.js +4 -0
- package/dist/tempo/session/server/Ws.js.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.d.ts +38 -866
- package/dist/tempo/subscription/KeyAuthorization.d.ts.map +1 -1
- package/dist/tempo/subscription/KeyAuthorization.js +14 -3
- package/dist/tempo/subscription/KeyAuthorization.js.map +1 -1
- package/dist/viem/Account.d.ts.map +1 -1
- package/dist/viem/Account.js.map +1 -1
- package/dist/viem/Client.d.ts.map +1 -1
- package/dist/viem/Client.js +6 -1
- package/dist/viem/Client.js.map +1 -1
- package/dist/web-bot-auth/Constants.d.ts +20 -0
- package/dist/web-bot-auth/Constants.d.ts.map +1 -0
- package/dist/web-bot-auth/Constants.js +24 -0
- package/dist/web-bot-auth/Constants.js.map +1 -0
- package/dist/web-bot-auth/Types.d.ts +10 -0
- package/dist/web-bot-auth/Types.d.ts.map +1 -0
- package/dist/web-bot-auth/Types.js +2 -0
- package/dist/web-bot-auth/Types.js.map +1 -0
- package/dist/web-bot-auth/client/index.d.ts +29 -0
- package/dist/web-bot-auth/client/index.d.ts.map +1 -0
- package/dist/web-bot-auth/client/index.js +64 -0
- package/dist/web-bot-auth/client/index.js.map +1 -0
- package/dist/web-bot-auth/index.d.ts +7 -0
- package/dist/web-bot-auth/index.d.ts.map +1 -0
- package/dist/web-bot-auth/index.js +7 -0
- package/dist/web-bot-auth/index.js.map +1 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.d.ts +5 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.d.ts.map +1 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.js +20 -0
- package/dist/web-bot-auth/internal/JwkThumbprint.js.map +1 -0
- package/dist/web-bot-auth/internal/SignatureAgent.d.ts +3 -0
- package/dist/web-bot-auth/internal/SignatureAgent.d.ts.map +1 -0
- package/dist/web-bot-auth/internal/SignatureAgent.js +18 -0
- package/dist/web-bot-auth/internal/SignatureAgent.js.map +1 -0
- package/dist/web-bot-auth/server/index.d.ts +35 -0
- package/dist/web-bot-auth/server/index.d.ts.map +1 -0
- package/dist/web-bot-auth/server/index.js +88 -0
- package/dist/web-bot-auth/server/index.js.map +1 -0
- package/dist/x402/Assets.d.ts.map +1 -1
- package/dist/x402/Types.d.ts +6 -6
- package/dist/x402/Types.d.ts.map +1 -1
- package/dist/x402/server/EvmCharge.d.ts.map +1 -1
- package/dist/x402/server/EvmCharge.js +32 -20
- package/dist/x402/server/EvmCharge.js.map +1 -1
- package/package.json +20 -4
- package/src/Challenge.fuzz.test.ts +80 -47
- package/src/Challenge.test.ts +65 -0
- package/src/Challenge.ts +39 -35
- package/src/Method.ts +82 -68
- package/src/Store.test-d.ts +16 -0
- package/src/Store.test.ts +50 -0
- package/src/Store.ts +68 -0
- package/src/attestation/Attestation.integration.test.ts +208 -0
- package/src/attestation/Client.test.ts +83 -0
- package/src/attestation/Client.ts +34 -0
- package/src/attestation/Constants.ts +15 -0
- package/src/attestation/Server.test.ts +60 -0
- package/src/attestation/Server.ts +12 -0
- package/src/attestation/Types.test-d.ts +54 -0
- package/src/attestation/Types.ts +77 -0
- package/src/attestation/index.ts +5 -0
- package/src/attestation/internal/HttpMessageSignature.test.ts +101 -0
- package/src/attestation/internal/HttpMessageSignature.ts +429 -0
- package/src/attestation/internal/SigningContext.ts +13 -0
- package/src/bin.js +2 -0
- package/src/cli/cli.ts +1 -0
- package/src/cli/validate/payment.ts +18 -4
- package/src/cli/validate.test.ts +16 -0
- package/src/client/Mppx.test-d.ts +17 -0
- package/src/client/Mppx.test.ts +14 -14
- package/src/client/Mppx.ts +25 -4
- package/src/client/Transport.test.ts +12 -45
- package/src/client/Transport.ts +3 -24
- package/src/client/internal/Fetch.test.ts +77 -0
- package/src/client/internal/Fetch.ts +112 -14
- package/src/client/internal/MethodChallenge.ts +5 -0
- package/src/client/internal/MethodResponse.ts +28 -0
- package/src/discovery/OpenApi.test.ts +170 -0
- package/src/discovery/OpenApi.ts +16 -48
- package/src/discovery/internal/Metadata.ts +51 -0
- package/src/evm/server/Charge.ts +6 -1
- package/src/internal/AcceptPayment.test.ts +12 -8
- package/src/internal/types.ts +9 -0
- package/src/mcp/client/McpClient.integration.test.ts +19 -32
- package/src/middlewares/elysia.test.ts +2 -12
- package/src/middlewares/express.test.ts +2 -12
- package/src/middlewares/hono.test.ts +6 -9
- package/src/middlewares/nextjs.test.ts +2 -12
- package/src/proxy/Proxy.test.ts +26 -19
- package/src/proxy/Proxy.ts +147 -9
- package/src/proxy/Proxy.upstreamError.test.ts +364 -0
- package/src/proxy/Service.test.ts +73 -3
- package/src/proxy/Service.ts +50 -23
- package/src/proxy/services/anthropic.ts +1 -0
- package/src/proxy/services/hooks.test-d.ts +14 -0
- package/src/proxy/services/hooks.test.ts +44 -0
- package/src/proxy/services/openai.ts +1 -0
- package/src/proxy/services/stripe.ts +1 -0
- package/src/server/Methods.test-d.ts +88 -0
- package/src/server/Methods.test.ts +69 -0
- package/src/server/Mppx.test-d.ts +141 -7
- package/src/server/Mppx.test.ts +1017 -119
- package/src/server/Mppx.ts +350 -54
- package/src/stripe/internal/constants.ts +1 -1
- package/src/stripe/internal/types.ts +1 -0
- package/src/stripe/server/Charge.test-d.ts +16 -1
- package/src/stripe/server/Charge.test.ts +79 -0
- package/src/stripe/server/Charge.ts +54 -1
- package/src/stripe/server/Methods.test-d.ts +157 -0
- package/src/stripe/server/Methods.test.ts +403 -0
- package/src/stripe/server/Methods.ts +423 -6
- package/src/stripe/server/internal/deposit-address.ts +57 -0
- package/src/stripe/server/internal/html/node_modules/.bin/mppx +3 -3
- package/src/stripe/server/internal/html/package.json +1 -1
- package/src/stripe/server/internal/html.gen.ts +1 -1
- package/src/stripe/server/internal/record-payment.ts +66 -0
- package/src/stripe/server/internal/request.ts +49 -0
- package/src/tap/Constants.ts +32 -0
- package/src/tap/Tap.test.ts +125 -0
- package/src/tap/Types.ts +11 -0
- package/src/tap/client/index.ts +54 -0
- package/src/tap/index.ts +4 -0
- package/src/tap/server/index.ts +48 -0
- package/src/tempo/PublicExports.test-d.ts +3 -3
- package/src/tempo/client/Charge.ts +1 -19
- package/src/tempo/internal/address.test.ts +42 -0
- package/src/tempo/internal/address.ts +3 -3
- package/src/tempo/internal/auto-swap.test.ts +4 -4
- package/src/tempo/internal/auto-swap.ts +7 -50
- package/src/tempo/legacy/README.md +5 -5
- package/src/tempo/legacy/index.ts +1 -3
- package/src/tempo/server/AtomicStore.test-d.ts +13 -0
- package/src/tempo/server/Charge.test.ts +19 -84
- package/src/tempo/server/Charge.ts +92 -56
- package/src/tempo/server/Methods.ts +0 -20
- package/src/tempo/server/Relay.test.ts +161 -7
- package/src/tempo/server/Relay.ts +15 -6
- package/src/tempo/server/SponsorBudget.test.ts +29 -0
- package/src/tempo/server/SponsorBudget.ts +7 -1
- package/src/tempo/server/Subscription.ts +4 -1
- package/src/tempo/server/index.ts +1 -1
- package/src/tempo/server/internal/html/node_modules/.bin/mppx +3 -3
- package/src/tempo/server/internal/html/package.json +1 -1
- package/src/tempo/server/internal/html.gen.ts +1 -1
- package/src/tempo/server/internal/transport.test.ts +22 -3
- package/src/tempo/server/internal/transport.ts +15 -3
- package/src/tempo/session/README.md +119 -0
- package/src/tempo/session/client/Session.test.ts +299 -33
- package/src/tempo/session/client/Session.ts +152 -16
- package/src/tempo/session/client/SessionManager.test.ts +216 -9
- package/src/tempo/session/client/SessionManager.ts +63 -17
- package/src/tempo/session/client/Transports.test.ts +22 -0
- package/src/tempo/session/client/Transports.ts +58 -22
- package/src/tempo/session/precompile/Chain.ts +131 -11
- package/src/tempo/session/server/ChannelStore.ts +33 -12
- package/src/tempo/session/server/CredentialVerification.test.ts +4 -4
- package/src/tempo/session/server/CredentialVerification.ts +340 -28
- package/src/tempo/session/server/MeteredStream.ts +5 -1
- package/src/tempo/session/server/Session.test.ts +483 -36
- package/src/tempo/session/server/Session.ts +159 -60
- package/src/tempo/session/server/Sse.test.ts +77 -0
- package/src/tempo/session/server/Sse.ts +8 -1
- package/src/tempo/session/server/Transports.ts +2 -1
- package/src/tempo/session/server/Ws.test.ts +171 -0
- package/src/tempo/session/server/Ws.ts +10 -1
- package/src/tempo/subscription/KeyAuthorization.test.ts +70 -1
- package/src/tempo/subscription/KeyAuthorization.ts +14 -3
- package/src/viem/Client.test.ts +18 -1
- package/src/viem/Client.ts +7 -1
- package/src/web-bot-auth/Constants.ts +24 -0
- package/src/web-bot-auth/Types.ts +9 -0
- package/src/web-bot-auth/WebBotAuth.test.ts +182 -0
- package/src/web-bot-auth/client/index.ts +84 -0
- package/src/web-bot-auth/index.ts +6 -0
- package/src/web-bot-auth/internal/JwkThumbprint.ts +21 -0
- package/src/web-bot-auth/internal/SignatureAgent.ts +18 -0
- package/src/web-bot-auth/server/index.ts +113 -0
- package/src/x402/Exact.e2e.test.ts +121 -81
- package/src/x402/Exact.localnet.test.ts +1 -1
- package/src/x402/server/EvmCharge.ts +35 -19
- package/dist/tempo/legacy/server/Session.d.ts +0 -208
- package/dist/tempo/legacy/server/Session.d.ts.map +0 -1
- package/dist/tempo/legacy/server/Session.js +0 -698
- package/dist/tempo/legacy/server/Session.js.map +0 -1
- package/dist/tempo/legacy/server/index.d.ts +0 -5
- package/dist/tempo/legacy/server/index.d.ts.map +0 -1
- package/dist/tempo/legacy/server/index.js +0 -5
- package/dist/tempo/legacy/server/index.js.map +0 -1
- package/dist/tempo/legacy/session/ChannelStore.d.ts +0 -22
- package/dist/tempo/legacy/session/ChannelStore.d.ts.map +0 -1
- package/dist/tempo/legacy/session/ChannelStore.js +0 -6
- package/dist/tempo/legacy/session/ChannelStore.js.map +0 -1
- package/src/tempo/legacy/server/Defaults.test-d.ts +0 -9
- package/src/tempo/legacy/server/Session.test.ts +0 -6370
- package/src/tempo/legacy/server/Session.ts +0 -1024
- package/src/tempo/legacy/server/index.ts +0 -4
- package/src/tempo/legacy/session/ChannelStore.test.ts +0 -58
- package/src/tempo/legacy/session/ChannelStore.ts +0 -39
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Rlp } from 'ox'
|
|
2
|
+
import { KeyAuthorization, SignatureEnvelope } from 'ox/tempo'
|
|
2
3
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
3
4
|
import { describe, expect, test } from 'vp/test'
|
|
4
5
|
|
|
@@ -69,6 +70,25 @@ async function createPayload(request = parseRequest()) {
|
|
|
69
70
|
} as const
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
function serializeCompositeSignature(
|
|
74
|
+
type: 'keychain' | 'multisig',
|
|
75
|
+
inner: SignatureEnvelope.Primitive,
|
|
76
|
+
) {
|
|
77
|
+
return SignatureEnvelope.serialize(
|
|
78
|
+
type === 'keychain'
|
|
79
|
+
? {
|
|
80
|
+
inner,
|
|
81
|
+
type,
|
|
82
|
+
userAddress: rootAccount.address,
|
|
83
|
+
}
|
|
84
|
+
: {
|
|
85
|
+
account: rootAccount.address,
|
|
86
|
+
signatures: [inner],
|
|
87
|
+
type,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
72
92
|
describe('tempo subscription key authorization', () => {
|
|
73
93
|
test('signs and verifies a scoped key authorization', async () => {
|
|
74
94
|
const request = parseRequest()
|
|
@@ -87,6 +107,55 @@ describe('tempo subscription key authorization', () => {
|
|
|
87
107
|
)
|
|
88
108
|
})
|
|
89
109
|
|
|
110
|
+
test.each(['keychain', 'multisig'] as const)(
|
|
111
|
+
'rejects %s authorization signatures',
|
|
112
|
+
async (type) => {
|
|
113
|
+
const request = parseRequest()
|
|
114
|
+
|
|
115
|
+
await expect(
|
|
116
|
+
signSubscriptionKeyAuthorization({
|
|
117
|
+
accessKey,
|
|
118
|
+
account: {
|
|
119
|
+
async sign({ hash }) {
|
|
120
|
+
const inner = SignatureEnvelope.from(await rootAccount.sign({ hash }))
|
|
121
|
+
if (inner.type === 'keychain' || inner.type === 'multisig') {
|
|
122
|
+
throw new Error('expected primitive signature')
|
|
123
|
+
}
|
|
124
|
+
return serializeCompositeSignature(type, inner)
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
chainId: 4217,
|
|
128
|
+
request,
|
|
129
|
+
}),
|
|
130
|
+
).rejects.toThrow('keyAuthorization must use a primitive signature')
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
test.each(['keychain', 'multisig'] as const)(
|
|
135
|
+
'rejects serialized %s authorization signatures',
|
|
136
|
+
async (type) => {
|
|
137
|
+
const request = parseRequest()
|
|
138
|
+
const payload = await createPayload(request)
|
|
139
|
+
const authorization = KeyAuthorization.deserialize(payload.signature)
|
|
140
|
+
const [authorizationTuple] = KeyAuthorization.toTuple(authorization)
|
|
141
|
+
|
|
142
|
+
expect(() =>
|
|
143
|
+
verifySubscriptionKeyAuthorization({
|
|
144
|
+
accessKey,
|
|
145
|
+
chainId: 4217,
|
|
146
|
+
payload: {
|
|
147
|
+
...payload,
|
|
148
|
+
signature: Rlp.fromHex([
|
|
149
|
+
authorizationTuple,
|
|
150
|
+
serializeCompositeSignature(type, authorization.signature!),
|
|
151
|
+
]),
|
|
152
|
+
},
|
|
153
|
+
request,
|
|
154
|
+
}),
|
|
155
|
+
).toThrow('keyAuthorization must use a primitive signature')
|
|
156
|
+
},
|
|
157
|
+
)
|
|
158
|
+
|
|
90
159
|
test('builds wallet allowed calls from the subscription request', () => {
|
|
91
160
|
const request = parseRequest()
|
|
92
161
|
|
|
@@ -168,8 +168,14 @@ export async function signSubscriptionKeyAuthorization(parameters: {
|
|
|
168
168
|
const signature = await account.sign({
|
|
169
169
|
hash: KeyAuthorization.getSignPayload(authorization),
|
|
170
170
|
})
|
|
171
|
+
const signatureEnvelope = SignatureEnvelope.from(signature)
|
|
172
|
+
if (signatureEnvelope.type === 'keychain' || signatureEnvelope.type === 'multisig') {
|
|
173
|
+
throw new VerificationFailedError({
|
|
174
|
+
reason: 'keyAuthorization must use a primitive signature',
|
|
175
|
+
})
|
|
176
|
+
}
|
|
171
177
|
return KeyAuthorization.from(authorization, {
|
|
172
|
-
signature
|
|
178
|
+
signature,
|
|
173
179
|
})
|
|
174
180
|
}
|
|
175
181
|
|
|
@@ -238,14 +244,19 @@ function createUnsignedAuthorization(parameters: {
|
|
|
238
244
|
function deserializeAuthorization(signature: `0x${string}`) {
|
|
239
245
|
try {
|
|
240
246
|
return KeyAuthorization.deserialize(signature)
|
|
241
|
-
} catch {
|
|
247
|
+
} catch (error) {
|
|
248
|
+
if (error instanceof KeyAuthorization.InvalidSignatureTypeError) {
|
|
249
|
+
throw new VerificationFailedError({
|
|
250
|
+
reason: 'keyAuthorization must use a primitive signature',
|
|
251
|
+
})
|
|
252
|
+
}
|
|
242
253
|
throw new VerificationFailedError({ reason: 'invalid keyAuthorization payload' })
|
|
243
254
|
}
|
|
244
255
|
}
|
|
245
256
|
|
|
246
257
|
function getPrimitiveSignature(authorization: Authorization) {
|
|
247
258
|
const signature = authorization.signature
|
|
248
|
-
if (!signature
|
|
259
|
+
if (!signature) {
|
|
249
260
|
throw new VerificationFailedError({
|
|
250
261
|
reason: 'keyAuthorization must use a primitive signature',
|
|
251
262
|
})
|
package/src/viem/Client.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { createClient, custom, defineChain, type Hex } from 'viem'
|
|
|
2
2
|
import { privateKeyToAccount } from 'viem/accounts'
|
|
3
3
|
import { signTransaction } from 'viem/actions'
|
|
4
4
|
import { Account as TempoAccount, Transaction } from 'viem/tempo'
|
|
5
|
-
import { tempoLocalnet } from 'viem/tempo/chains'
|
|
5
|
+
import { tempo as tempoMainnetChain, tempoLocalnet, tempoModerato } from 'viem/tempo/chains'
|
|
6
6
|
import { afterEach, describe, expect, test, vi } from 'vp/test'
|
|
7
7
|
|
|
8
8
|
import * as Client from './Client.js'
|
|
@@ -48,6 +48,23 @@ describe('getResolver', () => {
|
|
|
48
48
|
expect(client.chain?.name).toBe('test')
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
+
test('behavior: resolves the correct named Tempo chain even when the default chain differs', async () => {
|
|
52
|
+
const getClient = Client.getResolver({
|
|
53
|
+
// Default chain is mainnet, but the resolved chain ID below is testnet.
|
|
54
|
+
chain: tempoMainnetChain as never,
|
|
55
|
+
rpcUrl: {
|
|
56
|
+
[tempoMainnetChain.id]: 'https://rpc.example.com',
|
|
57
|
+
[tempoModerato.id]: 'https://rpc2.example.com',
|
|
58
|
+
},
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const client = await getClient({ chainId: tempoModerato.id })
|
|
62
|
+
|
|
63
|
+
expect(client.chain?.id).toBe(tempoModerato.id)
|
|
64
|
+
expect(client.chain?.name).toBe(tempoModerato.name)
|
|
65
|
+
expect(client.chain?.name).not.toBe(tempoMainnetChain.name)
|
|
66
|
+
})
|
|
67
|
+
|
|
51
68
|
test('error: throws when no rpcUrl provided', () => {
|
|
52
69
|
const getClient = Client.getResolver({})
|
|
53
70
|
|
package/src/viem/Client.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { type Chain, type Client, createClient, createTransport, custom, http } from 'viem'
|
|
2
2
|
import { withFeePayer } from 'viem/tempo'
|
|
3
|
+
import { tempo as tempoMainnetChain, tempoModerato } from 'viem/tempo/chains'
|
|
3
4
|
|
|
4
5
|
import type { MaybePromise } from '../internal/types.js'
|
|
5
6
|
|
|
7
|
+
const knownTempoChains: Record<number, Chain> = {
|
|
8
|
+
[tempoMainnetChain.id]: tempoMainnetChain,
|
|
9
|
+
[tempoModerato.id]: tempoModerato,
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
export function getResolver(
|
|
7
13
|
parameters: getResolver.Parameters & {
|
|
8
14
|
/** Default chain to use if not provided. */
|
|
@@ -73,7 +79,7 @@ export function getResolver(
|
|
|
73
79
|
if (!url) throw new Error(`No \`rpcUrl\` configured for \`chainId\` (${resolvedChainId}).`)
|
|
74
80
|
const transport = feePayerUrl ? withFeePayer(http(url), http(feePayerUrl)) : http(url)
|
|
75
81
|
return createClient({
|
|
76
|
-
chain: { ...chain, id: resolvedChainId } as never,
|
|
82
|
+
chain: (knownTempoChains[resolvedChainId] ?? { ...chain, id: resolvedChainId }) as never,
|
|
77
83
|
transport,
|
|
78
84
|
})
|
|
79
85
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Constants as HttpMessageSignature } from '../attestation/internal/HttpMessageSignature.js'
|
|
2
|
+
|
|
3
|
+
/** Web Bot Auth values for the supported HTTPS-directory signature profile. */
|
|
4
|
+
export const Constants = {
|
|
5
|
+
/** Stable identifier for Web Bot Auth signers and replay storage. */
|
|
6
|
+
protocol: 'web-bot-auth',
|
|
7
|
+
/** Web Bot Auth discovery type supported by this adapter. */
|
|
8
|
+
discoveryType: 'directory',
|
|
9
|
+
/** RFC 9421 signature label used when no label is configured. */
|
|
10
|
+
label: 'webbot',
|
|
11
|
+
/** Tag identifying a Web Bot Auth request signature. */
|
|
12
|
+
tag: 'web-bot-auth',
|
|
13
|
+
/** Structured HTTP header linking a bot signature to its HTTPS directory origin. */
|
|
14
|
+
signatureAgentHeader: 'Signature-Agent',
|
|
15
|
+
/** Default lifetime, in seconds, for a bot request signature. */
|
|
16
|
+
defaultSignatureLifetime: 60,
|
|
17
|
+
/** Default verifier limit, following the draft's recommended 24-hour maximum. */
|
|
18
|
+
defaultMaximumSignatureLifetime: 24 * 60 * 60,
|
|
19
|
+
/** HTTP components required by this directory profile. */
|
|
20
|
+
requiredComponents: [
|
|
21
|
+
HttpMessageSignature.components.authority,
|
|
22
|
+
HttpMessageSignature.components.signatureAgent,
|
|
23
|
+
],
|
|
24
|
+
} as const
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Verified Web Bot Auth HTTPS-directory profile request signature. */
|
|
2
|
+
export type VerifiedRequest = {
|
|
3
|
+
/** Public-key thumbprint advertised by the bot. */
|
|
4
|
+
keyId: string
|
|
5
|
+
/** HTTPS directory origin carried in the signed `Signature-Agent` header. */
|
|
6
|
+
signatureAgent: string
|
|
7
|
+
/** Signature nonce supplied by the bot. */
|
|
8
|
+
nonce: string
|
|
9
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import * as Attestation from 'mppx/attestation'
|
|
2
|
+
import * as WebBotAuth from 'mppx/attestation/web-bot-auth'
|
|
3
|
+
import { expect, test } from 'vp/test'
|
|
4
|
+
import { jwkThumbprint, keyPair, rsaKeyPair } from '~test/Attestation.js'
|
|
5
|
+
|
|
6
|
+
import * as HttpMessageSignature from '../attestation/internal/HttpMessageSignature.js'
|
|
7
|
+
|
|
8
|
+
test('emits and verifies a signed Signature-Agent member', async () => {
|
|
9
|
+
const keys = await keyPair()
|
|
10
|
+
const keyId = await jwkThumbprint(keys.publicKey)
|
|
11
|
+
const signatureAgent = 'https://agent.example'
|
|
12
|
+
const signed = await WebBotAuth.Client.signer({
|
|
13
|
+
expiresIn: WebBotAuth.Constants.defaultSignatureLifetime + 1,
|
|
14
|
+
key: keys.privateKey,
|
|
15
|
+
keyId,
|
|
16
|
+
signatureAgent: `${signatureAgent}/`,
|
|
17
|
+
}).sign(new Request('https://merchant.example/resource'))
|
|
18
|
+
|
|
19
|
+
expect(signed.headers.get(WebBotAuth.Constants.signatureAgentHeader)).toBe(
|
|
20
|
+
`${WebBotAuth.Constants.label}="${signatureAgent}"`,
|
|
21
|
+
)
|
|
22
|
+
expect(signed.headers.get(Attestation.Headers.signatureInput)).toContain(
|
|
23
|
+
`"signature-agent";key="${WebBotAuth.Constants.label}"`,
|
|
24
|
+
)
|
|
25
|
+
expect(
|
|
26
|
+
await WebBotAuth.Server.verifier({
|
|
27
|
+
keyResolver: () => keys.publicKey,
|
|
28
|
+
maxAge: WebBotAuth.Constants.defaultSignatureLifetime,
|
|
29
|
+
nonceStore: Attestation.Store.memory(),
|
|
30
|
+
}).verify(signed),
|
|
31
|
+
).toMatchObject({ status: 'invalid' })
|
|
32
|
+
expect(
|
|
33
|
+
await WebBotAuth.Server.verifier({
|
|
34
|
+
keyResolver: () => keys.publicKey,
|
|
35
|
+
nonceStore: Attestation.Store.memory(),
|
|
36
|
+
}).verify(signed),
|
|
37
|
+
).toMatchObject({
|
|
38
|
+
status: 'verified',
|
|
39
|
+
value: { keyId, signatureAgent },
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('signs and verifies RSA-PSS SHA-512', async () => {
|
|
44
|
+
const keys = await rsaKeyPair()
|
|
45
|
+
const keyId = await jwkThumbprint(keys.publicKey)
|
|
46
|
+
const algorithms: Attestation.SignatureAlgorithm[] = []
|
|
47
|
+
const signed = await WebBotAuth.Client.signer({
|
|
48
|
+
key: keys.privateKey,
|
|
49
|
+
keyId,
|
|
50
|
+
signatureAgent: 'https://agent.example',
|
|
51
|
+
}).sign(new Request('https://merchant.example/resource'))
|
|
52
|
+
const result = await WebBotAuth.Server.verifier({
|
|
53
|
+
keyResolver({ algorithm, keyId: candidate }) {
|
|
54
|
+
algorithms.push(algorithm)
|
|
55
|
+
return candidate === keyId ? keys.publicKey : undefined
|
|
56
|
+
},
|
|
57
|
+
nonceStore: Attestation.Store.memory(),
|
|
58
|
+
}).verify(signed)
|
|
59
|
+
|
|
60
|
+
expect(signed.headers.get(Attestation.Headers.signatureInput)).toContain(
|
|
61
|
+
`alg="${Attestation.Algorithms.rsaPssSha512}"`,
|
|
62
|
+
)
|
|
63
|
+
expect(algorithms).toEqual([Attestation.Algorithms.rsaPssSha512])
|
|
64
|
+
expect(result).toMatchObject({ status: 'verified' })
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('preserves directory lookup failures as unverified outcomes', async () => {
|
|
68
|
+
const keys = await keyPair()
|
|
69
|
+
const keyId = await jwkThumbprint(keys.publicKey)
|
|
70
|
+
const signed = await WebBotAuth.Client.signer({
|
|
71
|
+
key: keys.privateKey,
|
|
72
|
+
keyId,
|
|
73
|
+
signatureAgent: 'https://agent.example',
|
|
74
|
+
}).sign(new Request('https://merchant.example/resource'))
|
|
75
|
+
|
|
76
|
+
expect(
|
|
77
|
+
await WebBotAuth.Server.verifier({
|
|
78
|
+
keyResolver: () => undefined,
|
|
79
|
+
nonceStore: Attestation.Store.memory(),
|
|
80
|
+
}).verify(signed),
|
|
81
|
+
).toEqual({
|
|
82
|
+
reason: 'No public key is available for the signature key ID.',
|
|
83
|
+
status: 'unverified',
|
|
84
|
+
})
|
|
85
|
+
expect(
|
|
86
|
+
await WebBotAuth.Server.verifier({
|
|
87
|
+
keyResolver() {
|
|
88
|
+
throw new Error('directory unavailable')
|
|
89
|
+
},
|
|
90
|
+
nonceStore: Attestation.Store.memory(),
|
|
91
|
+
}).verify(signed),
|
|
92
|
+
).toEqual({
|
|
93
|
+
reason: 'The public key could not be resolved.',
|
|
94
|
+
status: 'unverified',
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('rejects mismatched keys, non-directory discovery, and header tampering', async () => {
|
|
99
|
+
const advertisedKeys = await keyPair()
|
|
100
|
+
const signingKeys = await keyPair()
|
|
101
|
+
const advertisedKeyId = await jwkThumbprint(advertisedKeys.publicKey)
|
|
102
|
+
const signatureAgent = 'https://agent.example'
|
|
103
|
+
const signed = await WebBotAuth.Client.signer({
|
|
104
|
+
key: signingKeys.privateKey,
|
|
105
|
+
keyId: advertisedKeyId,
|
|
106
|
+
signatureAgent,
|
|
107
|
+
}).sign(new Request('https://merchant.example/resource'))
|
|
108
|
+
const verifier = WebBotAuth.Server.verifier({
|
|
109
|
+
keyResolver: () => signingKeys.publicKey,
|
|
110
|
+
nonceStore: Attestation.Store.memory(),
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
expect(await verifier.verify(signed)).toMatchObject({ status: 'invalid' })
|
|
114
|
+
|
|
115
|
+
const alteredHeaders = new Headers(signed.headers)
|
|
116
|
+
alteredHeaders.set(
|
|
117
|
+
WebBotAuth.Constants.signatureAgentHeader,
|
|
118
|
+
`${WebBotAuth.Constants.label}="https://attacker.example"`,
|
|
119
|
+
)
|
|
120
|
+
expect(
|
|
121
|
+
await WebBotAuth.Server.verifier({
|
|
122
|
+
keyResolver: () => signingKeys.publicKey,
|
|
123
|
+
nonceStore: Attestation.Store.memory(),
|
|
124
|
+
}).verify(new Request(signed, { headers: alteredHeaders })),
|
|
125
|
+
).toMatchObject({ status: 'invalid' })
|
|
126
|
+
|
|
127
|
+
const discoveryHeaders = new Headers({
|
|
128
|
+
[WebBotAuth.Constants.signatureAgentHeader]:
|
|
129
|
+
'webbot="https://agent.example/keys";type=jwks_uri',
|
|
130
|
+
})
|
|
131
|
+
const unsupportedDiscovery = await HttpMessageSignature.sign(
|
|
132
|
+
new Request('https://merchant.example/resource', { headers: discoveryHeaders }),
|
|
133
|
+
{
|
|
134
|
+
components: [
|
|
135
|
+
HttpMessageSignature.Constants.components.authority,
|
|
136
|
+
{
|
|
137
|
+
id: HttpMessageSignature.Constants.components.signatureAgent,
|
|
138
|
+
parameters: new Map([['key', WebBotAuth.Constants.label]]),
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
key: advertisedKeys.privateKey,
|
|
142
|
+
keyId: advertisedKeyId,
|
|
143
|
+
label: WebBotAuth.Constants.label,
|
|
144
|
+
tag: WebBotAuth.Constants.tag,
|
|
145
|
+
},
|
|
146
|
+
)
|
|
147
|
+
expect(
|
|
148
|
+
await WebBotAuth.Server.verifier({
|
|
149
|
+
keyResolver: () => advertisedKeys.publicKey,
|
|
150
|
+
nonceStore: Attestation.Store.memory(),
|
|
151
|
+
}).verify(unsupportedDiscovery),
|
|
152
|
+
).toMatchObject({
|
|
153
|
+
reason: 'The Signature-Agent discovery type is not supported by this directory profile.',
|
|
154
|
+
status: 'invalid',
|
|
155
|
+
})
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
test('validates signer and verifier configuration', async () => {
|
|
159
|
+
const keys = await keyPair()
|
|
160
|
+
const keyId = await jwkThumbprint(keys.publicKey)
|
|
161
|
+
const config = { key: keys.privateKey, keyId, signatureAgent: 'https://agent.example' }
|
|
162
|
+
|
|
163
|
+
expect(() => WebBotAuth.Client.signer({ ...config, keyId: 'not-a-thumbprint' })).toThrow(
|
|
164
|
+
'Web Bot Auth keyId must be an RFC 7638 SHA-256 JWK thumbprint.',
|
|
165
|
+
)
|
|
166
|
+
expect(() => WebBotAuth.Client.signer({ ...config, signatureAgent: 'https://' })).toThrow(
|
|
167
|
+
'Signature-Agent must identify a valid HTTPS origin.',
|
|
168
|
+
)
|
|
169
|
+
expect(() =>
|
|
170
|
+
WebBotAuth.Client.signer({ ...config, signatureAgent: 'https://agent.example/keys' }),
|
|
171
|
+
).toThrow('Signature-Agent must identify a valid HTTPS origin.')
|
|
172
|
+
expect(() => WebBotAuth.Client.signer({ ...config, expiresIn: 0 })).toThrow(
|
|
173
|
+
'Web Bot Auth expiresIn must be a positive integer.',
|
|
174
|
+
)
|
|
175
|
+
expect(() =>
|
|
176
|
+
WebBotAuth.Server.verifier({
|
|
177
|
+
keyResolver: () => keys.publicKey,
|
|
178
|
+
maxAge: 0,
|
|
179
|
+
nonceStore: Attestation.Store.memory(),
|
|
180
|
+
}),
|
|
181
|
+
).toThrow('Web Bot Auth maxAge must be a positive integer.')
|
|
182
|
+
})
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { parseDictionary, serializeDictionary } from 'structured-headers'
|
|
2
|
+
import type { Dictionary } from 'structured-headers'
|
|
3
|
+
|
|
4
|
+
import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js'
|
|
5
|
+
import type * as AttestationTypes from '../../attestation/Types.js'
|
|
6
|
+
import { Constants } from '../Constants.js'
|
|
7
|
+
import * as JwkThumbprint from '../internal/JwkThumbprint.js'
|
|
8
|
+
import * as SignatureAgent from '../internal/SignatureAgent.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a Web Bot Auth HTTPS-directory profile request signer.
|
|
12
|
+
*
|
|
13
|
+
* The signed `Signature-Agent` header links the request to the HTTPS origin
|
|
14
|
+
* of an HTTP Message Signatures Directory. This adapter does not support
|
|
15
|
+
* direct key configuration or other Web Bot Auth discovery types. It
|
|
16
|
+
* establishes bot identity only; it does not assert consumer identity or
|
|
17
|
+
* authority to make a payment.
|
|
18
|
+
*/
|
|
19
|
+
export function signer(config: signer.Config): AttestationTypes.Signer<typeof Constants.protocol> {
|
|
20
|
+
const label = config.label ?? Constants.label
|
|
21
|
+
const signatureAgentKey = config.signatureAgentKey ?? label
|
|
22
|
+
const expiresIn = config.expiresIn ?? Constants.defaultSignatureLifetime
|
|
23
|
+
const signatureAgent = SignatureAgent.directoryOrigin(config.signatureAgent)
|
|
24
|
+
if (!JwkThumbprint.is(config.keyId))
|
|
25
|
+
throw new TypeError('Web Bot Auth keyId must be an RFC 7638 SHA-256 JWK thumbprint.')
|
|
26
|
+
if (!signatureAgent) throw new TypeError('Signature-Agent must identify a valid HTTPS origin.')
|
|
27
|
+
if (!Number.isInteger(expiresIn) || expiresIn <= 0)
|
|
28
|
+
throw new RangeError('Web Bot Auth expiresIn must be a positive integer.')
|
|
29
|
+
return {
|
|
30
|
+
protocol: Constants.protocol,
|
|
31
|
+
sign(request, context) {
|
|
32
|
+
const headers = new Headers(request.headers)
|
|
33
|
+
const signatureAgents = parseSignatureAgents(headers)
|
|
34
|
+
if (signatureAgents.has(signatureAgentKey))
|
|
35
|
+
throw new Error(`Signature-Agent member "${signatureAgentKey}" already exists.`)
|
|
36
|
+
signatureAgents.set(signatureAgentKey, [signatureAgent, new Map()])
|
|
37
|
+
headers.set(Constants.signatureAgentHeader, serializeDictionary(signatureAgents))
|
|
38
|
+
return HttpMessageSignature.sign(new Request(request, { headers }), {
|
|
39
|
+
components: [
|
|
40
|
+
HttpMessageSignature.Constants.components.authority,
|
|
41
|
+
{
|
|
42
|
+
id: HttpMessageSignature.Constants.components.signatureAgent,
|
|
43
|
+
parameters: new Map([['key', signatureAgentKey]]),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
context,
|
|
47
|
+
expiresIn,
|
|
48
|
+
key: config.key,
|
|
49
|
+
keyId: config.keyId,
|
|
50
|
+
label,
|
|
51
|
+
tag: Constants.tag,
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export declare namespace signer {
|
|
58
|
+
type Config = {
|
|
59
|
+
/** Ed25519 or RSA-PSS SHA-512 private key registered for the bot. */
|
|
60
|
+
key: CryptoKey
|
|
61
|
+
/** RFC 7638 JWK thumbprint for the registered public key. */
|
|
62
|
+
keyId: string
|
|
63
|
+
/** Required HTTPS directory origin, sent with the default `directory` discovery type. */
|
|
64
|
+
signatureAgent: string
|
|
65
|
+
/** Dictionary member name used for `Signature-Agent`. @default signature label */
|
|
66
|
+
signatureAgentKey?: string | undefined
|
|
67
|
+
/** Signature lifetime in seconds. @default 60 */
|
|
68
|
+
expiresIn?: number | undefined
|
|
69
|
+
/** RFC 9421 dictionary label. @default 'webbot' */
|
|
70
|
+
label?: string | undefined
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parseSignatureAgents(headers: Headers): Dictionary {
|
|
75
|
+
const value = headers.get(Constants.signatureAgentHeader)
|
|
76
|
+
if (!value) return new Map()
|
|
77
|
+
try {
|
|
78
|
+
return parseDictionary(value)
|
|
79
|
+
} catch {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`HTTP header "${Constants.signatureAgentHeader}" is not a structured dictionary.`,
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Client helpers for the Web Bot Auth HTTPS-directory profile. */
|
|
2
|
+
export * as Client from './client/index.js'
|
|
3
|
+
/** Server helpers for the Web Bot Auth HTTPS-directory profile. */
|
|
4
|
+
export * as Server from './server/index.js'
|
|
5
|
+
export * from './Constants.js'
|
|
6
|
+
export * from './Types.js'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Base64 } from 'ox'
|
|
2
|
+
|
|
3
|
+
const pattern = /^[A-Za-z0-9_-]{43}$/
|
|
4
|
+
|
|
5
|
+
/** Returns whether a value has the RFC 7638 SHA-256 thumbprint encoding. */
|
|
6
|
+
export function is(value: string): boolean {
|
|
7
|
+
return pattern.test(value)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Derives an RFC 7638 thumbprint from an extractable Ed25519 or RSA public key. */
|
|
11
|
+
export async function fromKey(key: CryptoKey): Promise<string> {
|
|
12
|
+
const jwk = await crypto.subtle.exportKey('jwk', key)
|
|
13
|
+
let canonical: string
|
|
14
|
+
if (jwk.kty === 'OKP' && jwk.crv === 'Ed25519' && jwk.x)
|
|
15
|
+
canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x })
|
|
16
|
+
else if (jwk.kty === 'RSA' && jwk.e && jwk.n)
|
|
17
|
+
canonical = JSON.stringify({ e: jwk.e, kty: jwk.kty, n: jwk.n })
|
|
18
|
+
else throw new TypeError('Web Bot Auth requires an Ed25519 or RSA public key.')
|
|
19
|
+
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(canonical))
|
|
20
|
+
return Base64.fromBytes(new Uint8Array(digest), { pad: false, url: true })
|
|
21
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Returns the canonical origin for a Web Bot Auth directory identifier. */
|
|
2
|
+
export function directoryOrigin(value: string): string | undefined {
|
|
3
|
+
try {
|
|
4
|
+
const url = new URL(value)
|
|
5
|
+
if (
|
|
6
|
+
url.protocol !== 'https:' ||
|
|
7
|
+
url.username ||
|
|
8
|
+
url.password ||
|
|
9
|
+
url.pathname !== '/' ||
|
|
10
|
+
url.search ||
|
|
11
|
+
url.hash
|
|
12
|
+
)
|
|
13
|
+
return undefined
|
|
14
|
+
return url.origin
|
|
15
|
+
} catch {
|
|
16
|
+
return undefined
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { isInnerList, parseDictionary, Token } from 'structured-headers'
|
|
2
|
+
|
|
3
|
+
import * as HttpMessageSignature from '../../attestation/internal/HttpMessageSignature.js'
|
|
4
|
+
import type * as Attestation from '../../attestation/Types.js'
|
|
5
|
+
import type * as Store from '../../Store.js'
|
|
6
|
+
import { Constants } from '../Constants.js'
|
|
7
|
+
import * as JwkThumbprint from '../internal/JwkThumbprint.js'
|
|
8
|
+
import * as SignatureAgent from '../internal/SignatureAgent.js'
|
|
9
|
+
import type * as Types from '../Types.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Creates a verifier for the Web Bot Auth HTTPS-directory profile.
|
|
13
|
+
*
|
|
14
|
+
* It requires an `@authority` and signed `Signature-Agent` directory member;
|
|
15
|
+
* direct key configuration and other Web Bot Auth discovery types are outside
|
|
16
|
+
* this adapter's scope. Verification confirms the cryptographic identity of an
|
|
17
|
+
* automated HTTP client. It must not be used on its own as user or payment
|
|
18
|
+
* authorization.
|
|
19
|
+
*/
|
|
20
|
+
export function verifier(config: verifier.Config): Attestation.Verifier<Types.VerifiedRequest> {
|
|
21
|
+
const maxAge = config.maxAge ?? Constants.defaultMaximumSignatureLifetime
|
|
22
|
+
if (!Number.isInteger(maxAge) || maxAge <= 0)
|
|
23
|
+
throw new RangeError('Web Bot Auth maxAge must be a positive integer.')
|
|
24
|
+
return {
|
|
25
|
+
async verify(request) {
|
|
26
|
+
let signatureAgent: string | undefined
|
|
27
|
+
const result = await HttpMessageSignature.verify(request, {
|
|
28
|
+
async keyResolver(parameters) {
|
|
29
|
+
return config.keyResolver({
|
|
30
|
+
...parameters,
|
|
31
|
+
signatureAgent: signatureAgent!,
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
async validateKey(key, input) {
|
|
35
|
+
try {
|
|
36
|
+
return (await JwkThumbprint.fromKey(key)) === input.keyId
|
|
37
|
+
? undefined
|
|
38
|
+
: 'The Web Bot Auth key does not match its RFC 7638 keyid.'
|
|
39
|
+
} catch {
|
|
40
|
+
return 'The Web Bot Auth key must be an extractable Ed25519 or RSA public key.'
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
maxAge,
|
|
44
|
+
nonceNamespace: Constants.protocol,
|
|
45
|
+
nonceStore: config.nonceStore,
|
|
46
|
+
requiredComponents: Constants.requiredComponents,
|
|
47
|
+
tag: Constants.tag,
|
|
48
|
+
validate(signature, request) {
|
|
49
|
+
if (!JwkThumbprint.is(signature.keyId))
|
|
50
|
+
return 'The Web Bot Auth keyid must be an RFC 7638 SHA-256 JWK thumbprint.'
|
|
51
|
+
const component = signature.components.find(
|
|
52
|
+
(entry) => entry.id === HttpMessageSignature.Constants.components.signatureAgent,
|
|
53
|
+
)
|
|
54
|
+
const key = component?.parameters?.get('key')
|
|
55
|
+
if (typeof key !== 'string')
|
|
56
|
+
return 'The signed Signature-Agent component must identify a dictionary member.'
|
|
57
|
+
const value = request.headers.get(Constants.signatureAgentHeader)
|
|
58
|
+
if (!value) return 'The Signature-Agent header is required.'
|
|
59
|
+
let agents
|
|
60
|
+
try {
|
|
61
|
+
agents = parseDictionary(value)
|
|
62
|
+
} catch {
|
|
63
|
+
return 'The Signature-Agent header must be a structured dictionary.'
|
|
64
|
+
}
|
|
65
|
+
const agent = agents.get(key)
|
|
66
|
+
if (!agent || isInnerList(agent) || typeof agent[0] !== 'string')
|
|
67
|
+
return 'The signed Signature-Agent member must be an HTTPS URL.'
|
|
68
|
+
const type = agent[1].get('type')
|
|
69
|
+
if (
|
|
70
|
+
type !== undefined &&
|
|
71
|
+
(!(type instanceof Token) || type.toString() !== Constants.discoveryType)
|
|
72
|
+
)
|
|
73
|
+
return 'The Signature-Agent discovery type is not supported by this directory profile.'
|
|
74
|
+
const origin = SignatureAgent.directoryOrigin(agent[0])
|
|
75
|
+
if (!origin) return 'The Signature-Agent header must identify a valid HTTPS origin.'
|
|
76
|
+
signatureAgent = origin
|
|
77
|
+
return undefined
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
if (result.status !== 'verified') return result
|
|
81
|
+
return {
|
|
82
|
+
status: 'verified',
|
|
83
|
+
value: {
|
|
84
|
+
keyId: result.input.keyId,
|
|
85
|
+
nonce: result.input.nonce,
|
|
86
|
+
signatureAgent: signatureAgent!,
|
|
87
|
+
},
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export declare namespace verifier {
|
|
94
|
+
type Config = {
|
|
95
|
+
/**
|
|
96
|
+
* Resolves a public key for the advertised directory.
|
|
97
|
+
*
|
|
98
|
+
* Apply the origin's trust policy before any network lookup; do not fetch an
|
|
99
|
+
* arbitrary caller-provided `signatureAgent` URL. Returned public keys
|
|
100
|
+
* must be extractable so their RFC 7638 thumbprints can be verified.
|
|
101
|
+
*/
|
|
102
|
+
keyResolver: (parameters: {
|
|
103
|
+
algorithm: Attestation.SignatureAlgorithm
|
|
104
|
+
keyId: string
|
|
105
|
+
request: Request
|
|
106
|
+
signatureAgent: string
|
|
107
|
+
}) => Promise<CryptoKey | undefined> | CryptoKey | undefined
|
|
108
|
+
/** Maximum accepted signature lifetime in seconds. @default 86400 */
|
|
109
|
+
maxAge?: number | undefined
|
|
110
|
+
/** Atomically consumes each nonce in shared storage for multi-instance deployments. */
|
|
111
|
+
nonceStore: Store.AtomicStore
|
|
112
|
+
}
|
|
113
|
+
}
|