mppx 0.14.1 → 0.16.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/CHANGELOG.md +42 -0
- package/README.md +1 -1
- package/dist/Expires.js +1 -1
- package/dist/Store.d.ts +2 -2
- package/dist/Store.js +13 -3
- package/dist/cli/cli.js +137 -131
- package/dist/cli/plugins/index.js +11 -11
- package/dist/cli/validate/payment.d.ts +12 -0
- package/dist/cli/validate/payment.js +113 -14
- package/dist/client/Mppx.d.ts +13 -3
- package/dist/client/Mppx.js +47 -22
- package/dist/client/internal/Fetch.d.ts +11 -0
- package/dist/client/internal/Fetch.js +46 -8
- package/dist/client/internal/ProofRealm.d.ts +21 -0
- package/dist/client/internal/ProofRealm.js +55 -0
- package/dist/{attestation → extensions/identity}/Constants.d.ts +2 -2
- package/dist/{attestation → extensions/identity}/Constants.js +2 -2
- package/dist/extensions/identity/Types.d.ts +21 -0
- package/dist/extensions/identity/index.d.ts +7 -0
- package/dist/extensions/identity/index.js +6 -0
- package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.d.ts +3 -3
- package/dist/{attestation → extensions/identity}/internal/HttpMessageSignature.js +12 -10
- package/dist/extensions/identity/internal/SigningContext.d.ts +6 -0
- package/dist/{attestation → extensions/identity}/internal/SigningContext.js +3 -3
- package/dist/extensions/identity/internal/Verification.d.ts +9 -0
- package/dist/extensions/identity/internal/Verification.js +10 -0
- package/dist/{tap → extensions/identity/tap}/Constants.js +1 -1
- package/dist/extensions/identity/tap/client/index.d.ts +32 -0
- package/dist/{tap → extensions/identity/tap}/client/index.js +13 -9
- package/dist/extensions/identity/tap/server/index.d.ts +27 -0
- package/dist/{tap → extensions/identity/tap}/server/index.js +12 -4
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.js +1 -1
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.d.ts +6 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/client/index.js +5 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.d.ts +6 -5
- package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/server/index.js +6 -4
- package/dist/identity/Client.d.ts +34 -0
- package/dist/identity/Client.js +133 -0
- package/dist/identity/Server.d.ts +46 -0
- package/dist/identity/Server.js +145 -0
- package/dist/identity/Types.d.ts +90 -0
- package/dist/identity/Types.js +2 -0
- package/dist/{attestation → identity}/index.d.ts +2 -2
- package/dist/{attestation → identity}/index.js +1 -2
- package/dist/identity/internal/SigningContext.d.ts +6 -0
- package/dist/identity/internal/SigningContext.js +11 -0
- package/dist/integrations/x402/Evm.d.ts +2 -0
- package/dist/internal/version.d.ts +2 -2
- package/dist/internal/version.js +1 -1
- package/dist/mcp/client/McpClient.d.ts +5 -0
- package/dist/mcp/client/McpClient.js +2 -0
- package/dist/middlewares/express.js +18 -6
- package/dist/proxy/Proxy.js +10 -5
- package/dist/proxy/Service.d.ts +42 -4
- package/dist/proxy/Service.js +21 -5
- package/dist/server/Mppx.d.ts +32 -8
- package/dist/server/Mppx.js +144 -54
- package/dist/stripe/server/internal/html.gen.js +1 -1
- package/dist/tempo/Methods.d.ts +5 -0
- package/dist/tempo/Methods.js +1 -0
- package/dist/tempo/client/Subscription.d.ts +5 -0
- package/dist/tempo/internal/charge.js +2 -1
- package/dist/tempo/internal/fee-payer.d.ts +0 -2
- package/dist/tempo/internal/fee-payer.js +0 -4
- package/dist/tempo/server/Charge.js +4 -0
- package/dist/tempo/server/Methods.d.ts +26 -0
- package/dist/tempo/server/Subscription.d.ts +5 -0
- package/dist/tempo/server/Subscription.js +8 -5
- package/dist/tempo/server/internal/html.gen.js +1 -1
- package/dist/tempo/session/client/Runtime.d.ts +2 -0
- package/dist/tempo/session/client/Session.js +1 -1
- package/dist/tempo/session/client/SessionManager.d.ts +6 -0
- package/dist/tempo/session/client/SessionManager.js +14 -7
- package/dist/tempo/session/client/Transports.d.ts +12 -3
- package/dist/tempo/session/client/Transports.js +37 -11
- package/dist/tempo/session/precompile/Chain.js +0 -3
- package/dist/tempo/session/server/Ws.d.ts +5 -2
- package/dist/tempo/session/server/Ws.js +11 -2
- package/dist/tempo/subscription/Store.d.ts +7 -1
- package/dist/tempo/subscription/Store.js +66 -13
- package/dist/tempo/subscription/Types.d.ts +2 -0
- package/package.json +15 -11
- package/dist/attestation/Client.d.ts +0 -17
- package/dist/attestation/Client.js +0 -28
- package/dist/attestation/Server.d.ts +0 -4
- package/dist/attestation/Server.js +0 -8
- package/dist/attestation/Types.d.ts +0 -76
- package/dist/attestation/internal/SigningContext.d.ts +0 -4
- package/dist/tap/client/index.d.ts +0 -26
- package/dist/tap/server/index.d.ts +0 -20
- /package/dist/{attestation → extensions/identity}/Types.js +0 -0
- /package/dist/{tap → extensions/identity/tap}/Constants.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/Types.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/Types.js +0 -0
- /package/dist/{tap → extensions/identity/tap}/index.d.ts +0 -0
- /package/dist/{tap → extensions/identity/tap}/index.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Constants.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/Types.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/index.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/JwkThumbprint.js +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.d.ts +0 -0
- /package/dist/{web-bot-auth → extensions/identity/web-bot-auth}/internal/SignatureAgent.js +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type * as Challenge from '../../Challenge.js';
|
|
2
|
+
/**
|
|
3
|
+
* Pins that let a server origin request zero-amount Tempo proofs for a realm other than its
|
|
4
|
+
* hostname, keyed by origin (`scheme://host[:port]`), such as
|
|
5
|
+
* `{ 'https://api.example.com': 'MPP Payment' }`.
|
|
6
|
+
*/
|
|
7
|
+
export type TrustedRealms = Readonly<Record<string, string>>;
|
|
8
|
+
/**
|
|
9
|
+
* Refuses a zero-amount Tempo proof whose realm the HTTP server that sent the Challenge does not
|
|
10
|
+
* own. A proof authenticates the payer at the Challenge realm, so a foreign origin could otherwise
|
|
11
|
+
* relay another server's Challenge and replay the signed proof there. The server owns the realm
|
|
12
|
+
* when it is the request hostname, or when `trustedRealms` pins it to the request origin. Pass
|
|
13
|
+
* `url` as a function to resolve it only for proof Challenges.
|
|
14
|
+
*/
|
|
15
|
+
export declare function assert(challenge: Challenge.Challenge, url: URL | (() => URL), trustedRealms: TrustedRealms | undefined): void;
|
|
16
|
+
/**
|
|
17
|
+
* Refuses a zero-amount Tempo proof on a transport without an origin, such as MCP, unless
|
|
18
|
+
* `trustedRealms` lists its realm.
|
|
19
|
+
*/
|
|
20
|
+
export declare function assertWithoutOrigin(challenge: Challenge.Challenge, trustedRealms: readonly string[] | undefined): void;
|
|
21
|
+
//# sourceMappingURL=ProofRealm.d.ts.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refuses a zero-amount Tempo proof whose realm the HTTP server that sent the Challenge does not
|
|
3
|
+
* own. A proof authenticates the payer at the Challenge realm, so a foreign origin could otherwise
|
|
4
|
+
* relay another server's Challenge and replay the signed proof there. The server owns the realm
|
|
5
|
+
* when it is the request hostname, or when `trustedRealms` pins it to the request origin. Pass
|
|
6
|
+
* `url` as a function to resolve it only for proof Challenges.
|
|
7
|
+
*/
|
|
8
|
+
export function assert(challenge, url, trustedRealms) {
|
|
9
|
+
if (!isProof(challenge))
|
|
10
|
+
return;
|
|
11
|
+
url = typeof url === 'function' ? url() : url;
|
|
12
|
+
const { realm } = challenge;
|
|
13
|
+
if (realm.toLowerCase() === url.hostname.toLowerCase())
|
|
14
|
+
return;
|
|
15
|
+
const origin = url.origin.toLowerCase();
|
|
16
|
+
for (const [trustedOrigin, trustedRealm] of Object.entries(trustedRealms ?? {}))
|
|
17
|
+
if (trustedRealm === realm && normalizeOrigin(trustedOrigin) === origin)
|
|
18
|
+
return;
|
|
19
|
+
throw new Error(`Refusing to sign Tempo proof for realm ${JSON.stringify(realm)} from ${url.origin}. Pin the realm to this origin with \`trustedTempoProofRealms\` if this server is expected to issue it.`);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Refuses a zero-amount Tempo proof on a transport without an origin, such as MCP, unless
|
|
23
|
+
* `trustedRealms` lists its realm.
|
|
24
|
+
*/
|
|
25
|
+
export function assertWithoutOrigin(challenge, trustedRealms) {
|
|
26
|
+
if (!isProof(challenge))
|
|
27
|
+
return;
|
|
28
|
+
if (trustedRealms?.includes(challenge.realm))
|
|
29
|
+
return;
|
|
30
|
+
throw new Error(`Refusing to sign Tempo proof for untrusted realm ${JSON.stringify(challenge.realm)}. Add it to \`trustedTempoProofRealms\` if this server is expected to issue it.`);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Whether `challenge` is a zero-amount `tempo/charge` Challenge, paid with a signed proof. Uses the
|
|
34
|
+
* same `BigInt` conversion as the Tempo charge client, so every encoding it signs a proof for
|
|
35
|
+
* (such as `"0x0"` or `" 0 "`) is checked.
|
|
36
|
+
*/
|
|
37
|
+
function isProof(challenge) {
|
|
38
|
+
if (challenge.method !== 'tempo' || challenge.intent !== 'charge')
|
|
39
|
+
return false;
|
|
40
|
+
try {
|
|
41
|
+
return BigInt(challenge.request.amount) === 0n;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function normalizeOrigin(origin) {
|
|
48
|
+
try {
|
|
49
|
+
return new URL(origin).origin.toLowerCase();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return origin.toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=ProofRealm.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/** RFC 9421 signature algorithms supported by
|
|
1
|
+
/** RFC 9421 signature algorithms supported by HTTP message signatures. */
|
|
2
2
|
export declare const Algorithms: {
|
|
3
3
|
/** EdDSA using the Ed25519 curve. */
|
|
4
4
|
readonly ed25519: 'ed25519';
|
|
5
5
|
/** RSASSA-PSS using SHA-512 and a 64-byte salt. */
|
|
6
6
|
readonly rsaPssSha512: 'rsa-pss-sha512';
|
|
7
7
|
};
|
|
8
|
-
/** HTTP headers defined by RFC 9421 for
|
|
8
|
+
/** HTTP headers defined by RFC 9421 for identity signatures. */
|
|
9
9
|
export declare const Headers: {
|
|
10
10
|
/** Carries the RFC 9421 signature bytes. */
|
|
11
11
|
readonly signature: 'Signature';
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
/** RFC 9421 signature algorithms supported by
|
|
1
|
+
/** RFC 9421 signature algorithms supported by HTTP message signatures. */
|
|
2
2
|
export const Algorithms = {
|
|
3
3
|
/** EdDSA using the Ed25519 curve. */
|
|
4
4
|
ed25519: 'ed25519',
|
|
5
5
|
/** RSASSA-PSS using SHA-512 and a 64-byte salt. */
|
|
6
6
|
rsaPssSha512: 'rsa-pss-sha512',
|
|
7
7
|
};
|
|
8
|
-
/** HTTP headers defined by RFC 9421 for
|
|
8
|
+
/** HTTP headers defined by RFC 9421 for identity signatures. */
|
|
9
9
|
export const Headers = {
|
|
10
10
|
/** Carries the RFC 9421 signature bytes. */
|
|
11
11
|
signature: 'Signature',
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MaybePromise } from '../../internal/types.js';
|
|
2
|
+
import type { Algorithms } from './Constants.js';
|
|
3
|
+
/** RFC 9421 algorithms implemented by the HTTP message signature signer and verifier. */
|
|
4
|
+
export type SignatureAlgorithm = (typeof Algorithms)[keyof typeof Algorithms];
|
|
5
|
+
/** Resolves a trusted public key for a parsed request signature. */
|
|
6
|
+
export type KeyResolver = (parameters: {
|
|
7
|
+
/** RFC 9421 algorithm declared by the signature. */
|
|
8
|
+
algorithm: SignatureAlgorithm;
|
|
9
|
+
/** Key identifier declared by the signature. */
|
|
10
|
+
keyId: string;
|
|
11
|
+
/** Request carrying the signature. */
|
|
12
|
+
request: Request;
|
|
13
|
+
}) => MaybePromise<CryptoKey | undefined>;
|
|
14
|
+
/** Values shared by every signature on one HTTP attempt. */
|
|
15
|
+
export type SigningContext = {
|
|
16
|
+
/** Unix timestamp, in seconds, at which the attempt was created. */
|
|
17
|
+
readonly created: number;
|
|
18
|
+
/** Base64url-encoded random value identifying the attempt. */
|
|
19
|
+
readonly nonce: string;
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=Types.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Client and server adapters for the TAP agent-recognition signature profile. */
|
|
2
|
+
export * as Tap from './tap/index.js';
|
|
3
|
+
/** Client and server adapters for the Web Bot Auth HTTPS-directory profile. */
|
|
4
|
+
export * as WebBotAuth from './web-bot-auth/index.js';
|
|
5
|
+
export * from './Constants.js';
|
|
6
|
+
export type * from './Types.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Client and server adapters for the TAP agent-recognition signature profile. */
|
|
2
|
+
export * as Tap from './tap/index.js';
|
|
3
|
+
/** Client and server adapters for the Web Bot Auth HTTPS-directory profile. */
|
|
4
|
+
export * as WebBotAuth from './web-bot-auth/index.js';
|
|
5
|
+
export * from './Constants.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { BareItem } from 'structured-headers';
|
|
2
|
-
import type { MaybePromise } from '
|
|
3
|
-
import * as Store from '
|
|
2
|
+
import type { MaybePromise } from '../../../internal/types.js';
|
|
3
|
+
import * as Store from '../../../Store.js';
|
|
4
4
|
import type { KeyResolver, SignatureAlgorithm, SigningContext } from '../Types.js';
|
|
5
|
-
/** RFC 9421 constants used by
|
|
5
|
+
/** RFC 9421 constants used by identity signature profiles. */
|
|
6
6
|
export declare const Constants: {
|
|
7
7
|
/** Derived request components supported by this narrow request profile. */
|
|
8
8
|
readonly components: {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isInnerList, parseDictionary, serializeItem, serializeDictionary, serializeInnerList, serializeParameters, } from 'structured-headers';
|
|
2
|
-
import * as Store from '
|
|
3
|
-
import { Algorithms, Headers as
|
|
2
|
+
import * as Store from '../../../Store.js';
|
|
3
|
+
import { Algorithms, Headers as SignatureHeaders } from '../Constants.js';
|
|
4
4
|
import * as SigningContextInternal from './SigningContext.js';
|
|
5
|
-
/** RFC 9421 constants used by
|
|
5
|
+
/** RFC 9421 constants used by identity signature profiles. */
|
|
6
6
|
export const Constants = {
|
|
7
7
|
/** Derived request components supported by this narrow request profile. */
|
|
8
8
|
components: {
|
|
@@ -55,16 +55,16 @@ export async function sign(request, options) {
|
|
|
55
55
|
};
|
|
56
56
|
const signature = await crypto.subtle.sign(webCryptoAlgorithm(algorithm), options.key, toArrayBuffer(encode(signatureBase(request, input))));
|
|
57
57
|
const headers = new Headers(request.headers);
|
|
58
|
-
const inputs = parseHeaderDictionary(headers,
|
|
59
|
-
const signatures = parseHeaderDictionary(headers,
|
|
58
|
+
const inputs = parseHeaderDictionary(headers, SignatureHeaders.signatureInput);
|
|
59
|
+
const signatures = parseHeaderDictionary(headers, SignatureHeaders.signature);
|
|
60
60
|
if (!haveSameKeys(inputs, signatures))
|
|
61
61
|
throw new Error('Signature-Input and Signature must contain the same labels.');
|
|
62
62
|
if (inputs.has(input.label) || signatures.has(input.label))
|
|
63
63
|
throw new Error(`HTTP message signature label "${input.label}" already exists.`);
|
|
64
64
|
inputs.set(input.label, toInnerList(input));
|
|
65
65
|
signatures.set(input.label, [signature, new Map()]);
|
|
66
|
-
headers.set(
|
|
67
|
-
headers.set(
|
|
66
|
+
headers.set(SignatureHeaders.signatureInput, serializeDictionary(inputs));
|
|
67
|
+
headers.set(SignatureHeaders.signature, serializeDictionary(signatures));
|
|
68
68
|
return new Request(request, { headers });
|
|
69
69
|
}
|
|
70
70
|
/** Verifies a request signature, its lifetime, and optionally its nonce. */
|
|
@@ -132,11 +132,13 @@ export async function verify(request, options) {
|
|
|
132
132
|
catch {
|
|
133
133
|
return { status: 'unverified', reason: 'Replay protection is unavailable.' };
|
|
134
134
|
}
|
|
135
|
+
if (input.expires <= Math.floor(Date.now() / 1000))
|
|
136
|
+
return { status: 'invalid', reason: 'The signature has expired.' };
|
|
135
137
|
return { status: 'verified', input };
|
|
136
138
|
}
|
|
137
139
|
function parse(request, expectedTag) {
|
|
138
|
-
const inputHeader = request.headers.get(
|
|
139
|
-
const signatureHeader = request.headers.get(
|
|
140
|
+
const inputHeader = request.headers.get(SignatureHeaders.signatureInput);
|
|
141
|
+
const signatureHeader = request.headers.get(SignatureHeaders.signature);
|
|
140
142
|
if (!inputHeader && !signatureHeader)
|
|
141
143
|
return undefined;
|
|
142
144
|
if (!inputHeader || !signatureHeader)
|
|
@@ -217,7 +219,7 @@ function algorithmFromKey(key) {
|
|
|
217
219
|
for (const algorithm of Object.values(Algorithms))
|
|
218
220
|
if (keySupportsAlgorithm(key, algorithm))
|
|
219
221
|
return algorithm;
|
|
220
|
-
throw new TypeError('
|
|
222
|
+
throw new TypeError('HTTP message signatures require an Ed25519 or RSA-PSS SHA-512 signing key.');
|
|
221
223
|
}
|
|
222
224
|
function isInteger(value) {
|
|
223
225
|
return typeof value === 'number' && Number.isInteger(value);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Base64 } from 'ox';
|
|
2
|
-
/** Creates the
|
|
2
|
+
/** Creates the attempt values shared by every prover on one HTTP attempt. */
|
|
3
3
|
export function create() {
|
|
4
4
|
const bytes = new Uint8Array(64);
|
|
5
5
|
crypto.getRandomValues(bytes);
|
|
6
|
-
return
|
|
6
|
+
return {
|
|
7
7
|
created: Math.floor(Date.now() / 1_000),
|
|
8
8
|
nonce: Base64.fromBytes(bytes, { pad: false, url: true }),
|
|
9
|
-
}
|
|
9
|
+
};
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=SigningContext.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type * as Identity from '../../../identity/Types.js';
|
|
2
|
+
import type { VerificationResult } from './HttpMessageSignature.js';
|
|
3
|
+
/** Maps a non-verified HTTP message signature result to an identity verification. */
|
|
4
|
+
export declare function fromSignature(result: Exclude<VerificationResult, {
|
|
5
|
+
status: 'verified';
|
|
6
|
+
}>): Exclude<Identity.Verification, {
|
|
7
|
+
status: 'valid';
|
|
8
|
+
}>;
|
|
9
|
+
//# sourceMappingURL=Verification.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Maps a non-verified HTTP message signature result to an identity verification. */
|
|
2
|
+
export function fromSignature(result) {
|
|
3
|
+
if (result.status === 'absent')
|
|
4
|
+
return { status: 'missing' };
|
|
5
|
+
if (result.status === 'invalid')
|
|
6
|
+
return { status: 'invalid', reason: result.reason };
|
|
7
|
+
// The signature was presented but its key is not trusted or available.
|
|
8
|
+
return { status: 'invalid', code: 403, reason: result.reason };
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=Verification.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Constants as HttpMessageSignature } from '../
|
|
1
|
+
import { Constants as HttpMessageSignature } from '../internal/HttpMessageSignature.js';
|
|
2
2
|
/** TAP values required for its RFC 9421 agent-recognition signature profile. */
|
|
3
3
|
export const Constants = {
|
|
4
4
|
/** Stable identifier for Trusted Agent Protocol signers and replay storage. */
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type * as Identity from '../../../../identity/Types.js';
|
|
2
|
+
import { Constants } from '../Constants.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a TAP identity prover.
|
|
5
|
+
*
|
|
6
|
+
* The prover signs each in-scope attempt, including MPP payment retries, with
|
|
7
|
+
* an RFC 9421 HTTP message signature carrying TAP's `agent-browser-auth` or
|
|
8
|
+
* `agent-payer-auth` tag.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* Mppx.create({ identity: [Tap.Client.prover({ intent: 'payment', key, keyId, scope: ['https://shop.example'] })], methods })
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function prover(config: prover.Config): Identity.Prover;
|
|
16
|
+
export declare namespace prover {
|
|
17
|
+
type Config = {
|
|
18
|
+
/** TAP signature type for the request. */
|
|
19
|
+
intent: (typeof Constants.intents)[keyof typeof Constants.intents];
|
|
20
|
+
/** Ed25519 or RSA-PSS SHA-512 private key provisioned to the agent provider. */
|
|
21
|
+
key: CryptoKey;
|
|
22
|
+
/** Identifier the merchant uses to resolve the signing public key. */
|
|
23
|
+
keyId: string;
|
|
24
|
+
/** Origins that receive TAP signatures, or `'*'` for any origin. */
|
|
25
|
+
scope: Identity.Prover['scope'];
|
|
26
|
+
/** Signature lifetime in seconds. TAP permits at most eight minutes. @default 480 */
|
|
27
|
+
expiresIn?: number | undefined;
|
|
28
|
+
/** RFC 9421 dictionary label. @default 'tap' */
|
|
29
|
+
label?: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import * as HttpMessageSignature from '../../
|
|
1
|
+
import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
|
|
2
2
|
import { Constants } from '../Constants.js';
|
|
3
3
|
/**
|
|
4
|
-
* Creates a TAP
|
|
4
|
+
* Creates a TAP identity prover.
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
* `agent-browser-auth` or
|
|
8
|
-
* `
|
|
9
|
-
*
|
|
6
|
+
* The prover signs each in-scope attempt, including MPP payment retries, with
|
|
7
|
+
* an RFC 9421 HTTP message signature carrying TAP's `agent-browser-auth` or
|
|
8
|
+
* `agent-payer-auth` tag.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* Mppx.create({ identity: [Tap.Client.prover({ intent: 'payment', key, keyId, scope: ['https://shop.example'] })], methods })
|
|
13
|
+
* ```
|
|
10
14
|
*/
|
|
11
|
-
export function
|
|
15
|
+
export function prover(config) {
|
|
12
16
|
const tag = config.intent === Constants.intents.payment ? Constants.tags.payment : Constants.tags.browse;
|
|
13
17
|
const expiresIn = config.expiresIn ?? Constants.defaultSignatureLifetime;
|
|
14
18
|
if (!Number.isInteger(expiresIn) ||
|
|
@@ -16,8 +20,8 @@ export function signer(config) {
|
|
|
16
20
|
expiresIn > Constants.maximumSignatureLifetime)
|
|
17
21
|
throw new RangeError(`TAP expiresIn must be an integer from 1 to ${Constants.maximumSignatureLifetime}.`);
|
|
18
22
|
return {
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
scope: config.scope,
|
|
24
|
+
prove(request, context) {
|
|
21
25
|
return HttpMessageSignature.sign(request, {
|
|
22
26
|
components: Constants.requiredComponents,
|
|
23
27
|
context,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type * as Identity from '../../../../identity/Types.js';
|
|
2
|
+
import type * as Store from '../../../../Store.js';
|
|
3
|
+
import type * as SignatureTypes from '../../Types.js';
|
|
4
|
+
import type * as Types from '../Types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates a request-stage identity verifier for TAP agent-recognition signatures.
|
|
7
|
+
*
|
|
8
|
+
* TAP verifies trusted agent participation and request integrity. Consumer
|
|
9
|
+
* recognition and payment-container verification stay protocol-specific and
|
|
10
|
+
* are intentionally not inferred from this header-only verifier.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const tap = Tap.Server.verifier({ keyResolver, nonceStore })
|
|
15
|
+
* mppx.charge({ amount: '1', identity: [tap] })
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function verifier(config: verifier.Config): Identity.Verifier<Types.VerifiedRequest>;
|
|
19
|
+
export declare namespace verifier {
|
|
20
|
+
type Config = {
|
|
21
|
+
/** Resolves a TAP-approved public key by its `keyid` and signature algorithm. */
|
|
22
|
+
keyResolver: SignatureTypes.KeyResolver;
|
|
23
|
+
/** Atomically consumes each nonce in shared storage for multi-instance deployments. */
|
|
24
|
+
nonceStore: Store.AtomicStore;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import * as HttpMessageSignature from '../../
|
|
1
|
+
import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
|
|
2
|
+
import * as Verification from '../../internal/Verification.js';
|
|
2
3
|
import { Constants } from '../Constants.js';
|
|
3
4
|
/**
|
|
4
|
-
* Creates a verifier for TAP agent-recognition signatures.
|
|
5
|
+
* Creates a request-stage identity verifier for TAP agent-recognition signatures.
|
|
5
6
|
*
|
|
6
7
|
* TAP verifies trusted agent participation and request integrity. Consumer
|
|
7
8
|
* recognition and payment-container verification stay protocol-specific and
|
|
8
9
|
* are intentionally not inferred from this header-only verifier.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const tap = Tap.Server.verifier({ keyResolver, nonceStore })
|
|
14
|
+
* mppx.charge({ amount: '1', identity: [tap] })
|
|
15
|
+
* ```
|
|
9
16
|
*/
|
|
10
17
|
export function verifier(config) {
|
|
11
18
|
return {
|
|
19
|
+
stage: 'request',
|
|
12
20
|
async verify(request) {
|
|
13
21
|
const result = await HttpMessageSignature.verify(request, {
|
|
14
22
|
keyResolver: config.keyResolver,
|
|
@@ -19,9 +27,9 @@ export function verifier(config) {
|
|
|
19
27
|
tag: [Constants.tags.browse, Constants.tags.payment],
|
|
20
28
|
});
|
|
21
29
|
if (result.status !== 'verified')
|
|
22
|
-
return result;
|
|
30
|
+
return Verification.fromSignature(result);
|
|
23
31
|
return {
|
|
24
|
-
status: '
|
|
32
|
+
status: 'valid',
|
|
25
33
|
value: {
|
|
26
34
|
keyId: result.input.keyId,
|
|
27
35
|
nonce: result.input.nonce,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Constants as HttpMessageSignature } from '../
|
|
1
|
+
import { Constants as HttpMessageSignature } from '../internal/HttpMessageSignature.js';
|
|
2
2
|
/** Web Bot Auth values for the supported HTTPS-directory signature profile. */
|
|
3
3
|
export const Constants = {
|
|
4
4
|
/** Stable identifier for Web Bot Auth signers and replay storage. */
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type * as
|
|
2
|
-
import { Constants } from '../Constants.js';
|
|
1
|
+
import type * as Identity from '../../../../identity/Types.js';
|
|
3
2
|
/**
|
|
4
|
-
* Creates a Web Bot Auth HTTPS-directory profile
|
|
3
|
+
* Creates a Web Bot Auth HTTPS-directory profile identity prover.
|
|
5
4
|
*
|
|
6
5
|
* The signed `Signature-Agent` header links the request to the HTTPS origin
|
|
7
6
|
* of an HTTP Message Signatures Directory. This adapter does not support
|
|
@@ -9,13 +8,15 @@ import { Constants } from '../Constants.js';
|
|
|
9
8
|
* establishes bot identity only; it does not assert consumer identity or
|
|
10
9
|
* authority to make a payment.
|
|
11
10
|
*/
|
|
12
|
-
export declare function
|
|
13
|
-
export declare namespace
|
|
11
|
+
export declare function prover(config: prover.Config): Identity.Prover;
|
|
12
|
+
export declare namespace prover {
|
|
14
13
|
type Config = {
|
|
15
14
|
/** Ed25519 or RSA-PSS SHA-512 private key registered for the bot. */
|
|
16
15
|
key: CryptoKey;
|
|
17
16
|
/** RFC 7638 JWK thumbprint for the registered public key. */
|
|
18
17
|
keyId: string;
|
|
18
|
+
/** Origins that receive Web Bot Auth signatures, or `'*'` for any origin. */
|
|
19
|
+
scope: Identity.Prover['scope'];
|
|
19
20
|
/** Required HTTPS directory origin, sent with the default `directory` discovery type. */
|
|
20
21
|
signatureAgent: string;
|
|
21
22
|
/** Dictionary member name used for `Signature-Agent`. @default signature label */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { parseDictionary, serializeDictionary } from 'structured-headers';
|
|
2
|
-
import * as HttpMessageSignature from '../../
|
|
2
|
+
import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
|
|
3
3
|
import { Constants } from '../Constants.js';
|
|
4
4
|
import * as JwkThumbprint from '../internal/JwkThumbprint.js';
|
|
5
5
|
import * as SignatureAgent from '../internal/SignatureAgent.js';
|
|
6
6
|
/**
|
|
7
|
-
* Creates a Web Bot Auth HTTPS-directory profile
|
|
7
|
+
* Creates a Web Bot Auth HTTPS-directory profile identity prover.
|
|
8
8
|
*
|
|
9
9
|
* The signed `Signature-Agent` header links the request to the HTTPS origin
|
|
10
10
|
* of an HTTP Message Signatures Directory. This adapter does not support
|
|
@@ -12,7 +12,7 @@ import * as SignatureAgent from '../internal/SignatureAgent.js';
|
|
|
12
12
|
* establishes bot identity only; it does not assert consumer identity or
|
|
13
13
|
* authority to make a payment.
|
|
14
14
|
*/
|
|
15
|
-
export function
|
|
15
|
+
export function prover(config) {
|
|
16
16
|
const label = config.label ?? Constants.label;
|
|
17
17
|
const signatureAgentKey = config.signatureAgentKey ?? label;
|
|
18
18
|
const expiresIn = config.expiresIn ?? Constants.defaultSignatureLifetime;
|
|
@@ -24,8 +24,8 @@ export function signer(config) {
|
|
|
24
24
|
if (!Number.isInteger(expiresIn) || expiresIn <= 0)
|
|
25
25
|
throw new RangeError('Web Bot Auth expiresIn must be a positive integer.');
|
|
26
26
|
return {
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
scope: config.scope,
|
|
28
|
+
prove(request, context) {
|
|
29
29
|
const headers = new Headers(request.headers);
|
|
30
30
|
const signatureAgents = parseSignatureAgents(headers);
|
|
31
31
|
if (signatureAgents.has(signatureAgentKey))
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type * as
|
|
2
|
-
import type * as Store from '
|
|
1
|
+
import type * as Identity from '../../../../identity/Types.js';
|
|
2
|
+
import type * as Store from '../../../../Store.js';
|
|
3
|
+
import type * as SignatureTypes from '../../Types.js';
|
|
3
4
|
import type * as Types from '../Types.js';
|
|
4
5
|
/**
|
|
5
|
-
* Creates a verifier for the Web Bot Auth HTTPS-directory profile.
|
|
6
|
+
* Creates a request-stage identity verifier for the Web Bot Auth HTTPS-directory profile.
|
|
6
7
|
*
|
|
7
8
|
* It requires an `@authority` and signed `Signature-Agent` directory member;
|
|
8
9
|
* direct key configuration and other Web Bot Auth discovery types are outside
|
|
@@ -10,7 +11,7 @@ import type * as Types from '../Types.js';
|
|
|
10
11
|
* automated HTTP client. It must not be used on its own as user or payment
|
|
11
12
|
* authorization.
|
|
12
13
|
*/
|
|
13
|
-
export declare function verifier(config: verifier.Config):
|
|
14
|
+
export declare function verifier(config: verifier.Config): Identity.Verifier<Types.VerifiedRequest>;
|
|
14
15
|
export declare namespace verifier {
|
|
15
16
|
type Config = {
|
|
16
17
|
/**
|
|
@@ -21,7 +22,7 @@ export declare namespace verifier {
|
|
|
21
22
|
* must be extractable so their RFC 7638 thumbprints can be verified.
|
|
22
23
|
*/
|
|
23
24
|
keyResolver: (parameters: {
|
|
24
|
-
algorithm:
|
|
25
|
+
algorithm: SignatureTypes.SignatureAlgorithm;
|
|
25
26
|
keyId: string;
|
|
26
27
|
request: Request;
|
|
27
28
|
signatureAgent: string;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { isInnerList, parseDictionary, Token } from 'structured-headers';
|
|
2
|
-
import * as HttpMessageSignature from '../../
|
|
2
|
+
import * as HttpMessageSignature from '../../internal/HttpMessageSignature.js';
|
|
3
|
+
import * as Verification from '../../internal/Verification.js';
|
|
3
4
|
import { Constants } from '../Constants.js';
|
|
4
5
|
import * as JwkThumbprint from '../internal/JwkThumbprint.js';
|
|
5
6
|
import * as SignatureAgent from '../internal/SignatureAgent.js';
|
|
6
7
|
/**
|
|
7
|
-
* Creates a verifier for the Web Bot Auth HTTPS-directory profile.
|
|
8
|
+
* Creates a request-stage identity verifier for the Web Bot Auth HTTPS-directory profile.
|
|
8
9
|
*
|
|
9
10
|
* It requires an `@authority` and signed `Signature-Agent` directory member;
|
|
10
11
|
* direct key configuration and other Web Bot Auth discovery types are outside
|
|
@@ -17,6 +18,7 @@ export function verifier(config) {
|
|
|
17
18
|
if (!Number.isInteger(maxAge) || maxAge <= 0)
|
|
18
19
|
throw new RangeError('Web Bot Auth maxAge must be a positive integer.');
|
|
19
20
|
return {
|
|
21
|
+
stage: 'request',
|
|
20
22
|
async verify(request) {
|
|
21
23
|
let signatureAgent;
|
|
22
24
|
const result = await HttpMessageSignature.verify(request, {
|
|
@@ -73,9 +75,9 @@ export function verifier(config) {
|
|
|
73
75
|
},
|
|
74
76
|
});
|
|
75
77
|
if (result.status !== 'verified')
|
|
76
|
-
return result;
|
|
78
|
+
return Verification.fromSignature(result);
|
|
77
79
|
return {
|
|
78
|
-
status: '
|
|
80
|
+
status: 'valid',
|
|
79
81
|
value: {
|
|
80
82
|
keyId: result.input.keyId,
|
|
81
83
|
nonce: result.input.nonce,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type * as Types from './Types.js';
|
|
2
|
+
/** Sends HTTP attempts with every in-scope prover applied. */
|
|
3
|
+
export type Client = {
|
|
4
|
+
/**
|
|
5
|
+
* Proves and sends one request.
|
|
6
|
+
*
|
|
7
|
+
* Requests that carry proofs do not follow redirects: a redirect rejects
|
|
8
|
+
* (`redirect: 'error'`), so proofs never reach another URL. Requests with no
|
|
9
|
+
* prover in scope are sent unchanged. If a prover asks to retry a rejected
|
|
10
|
+
* (non-402) response, the request is proved again and resent once, except for
|
|
11
|
+
* paid attempts, which are never resent.
|
|
12
|
+
*/
|
|
13
|
+
send: (fetch: typeof globalThis.fetch, request: Request, context?: Types.Context) => Promise<{
|
|
14
|
+
request: Request;
|
|
15
|
+
response: Response;
|
|
16
|
+
}>;
|
|
17
|
+
/** Lets in-scope provers prepare proofs for a 402 challenge from `url` before the payment retry. */
|
|
18
|
+
challenge: (response: Response, context: Types.Context, url: string) => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Creates the client runner for a list of provers.
|
|
22
|
+
*
|
|
23
|
+
* Provers run in list order on every attempt, sharing one attempt context.
|
|
24
|
+
* List request signers last so their signatures cover headers added by
|
|
25
|
+
* earlier provers.
|
|
26
|
+
*/
|
|
27
|
+
export declare function from(provers: readonly Types.Prover[]): Client;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a fetch implementation so every request is proved.
|
|
30
|
+
*
|
|
31
|
+
* Prefer `Mppx.create({ identity })`, which also passes the payment challenge to provers.
|
|
32
|
+
*/
|
|
33
|
+
export declare function wrapFetch(fetch: typeof globalThis.fetch, client: Client, context?: Types.Context): typeof globalThis.fetch;
|
|
34
|
+
//# sourceMappingURL=Client.d.ts.map
|