@chitmark/sdk 0.7.0 → 0.9.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/README.md +41 -155
- package/dist/edge.cjs +601 -12
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.d.cts +2 -2
- package/dist/edge.d.ts +2 -2
- package/dist/edge.js +584 -13
- package/dist/edge.js.map +1 -1
- package/dist/index.cjs +634 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +616 -13
- package/dist/index.js.map +1 -1
- package/dist/{trusted-ip-DnCZnqQx.d.cts → trusted-ip-DNO3xzCU.d.cts} +490 -9
- package/dist/{trusted-ip-DnCZnqQx.d.ts → trusted-ip-DNO3xzCU.d.ts} +490 -9
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,122 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/attribution.ts
|
|
4
|
+
function attributionEvidence(options, mode) {
|
|
5
|
+
const { request, agentProof, session, purpose, piiMode = mode } = options;
|
|
6
|
+
const headers = request.headers;
|
|
7
|
+
const header = typeof headers.get === "function" ? headers.get("chitmark-agent-proof") : Object.entries(headers).find(
|
|
8
|
+
([name]) => name.toLowerCase() === "chitmark-agent-proof"
|
|
9
|
+
)?.[1];
|
|
10
|
+
let url;
|
|
11
|
+
if (!options.site && request.url) {
|
|
12
|
+
try {
|
|
13
|
+
url = new URL(request.url);
|
|
14
|
+
} catch {
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const site = options.site ?? (url?.protocol === "https:" ? url.origin : void 0);
|
|
18
|
+
const proof = agentProof ?? (site ? parseProof(header) : void 0);
|
|
19
|
+
return { site, session, piiMode, purpose, agentProof: proof };
|
|
20
|
+
}
|
|
21
|
+
function parseProof(header) {
|
|
22
|
+
if (typeof header !== "string" || header.length > 2048) return;
|
|
23
|
+
try {
|
|
24
|
+
const value = JSON.parse(header);
|
|
25
|
+
if (!value || typeof value.nonce !== "string" || value.nonce.length > 36 || typeof value.issuedAt !== "number" || !Number.isSafeInteger(value.issuedAt) || typeof value.signature !== "string" || value.signature.length > 86)
|
|
26
|
+
return;
|
|
27
|
+
const { nonce, issuedAt, signature } = value;
|
|
28
|
+
if ("iss" in value) {
|
|
29
|
+
const key = value.agentKey;
|
|
30
|
+
if (value.iss === "chitmark-agent-key-v1" && key?.kty === "OKP" && key.crv === "Ed25519" && typeof key.x === "string" && key.x.length === 43 && !("d" in key)) {
|
|
31
|
+
return {
|
|
32
|
+
iss: value.iss,
|
|
33
|
+
agentKey: { kty: key.kty, crv: key.crv, x: key.x },
|
|
34
|
+
nonce,
|
|
35
|
+
issuedAt,
|
|
36
|
+
signature
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (typeof value.linkId === "string" && value.linkId.length <= 36)
|
|
42
|
+
return { linkId: value.linkId, nonce, issuedAt, signature };
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/credentials.ts
|
|
49
|
+
var encode = (bytes) => btoa(String.fromCharCode(...bytes)).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
50
|
+
var json = (value) => encode(new TextEncoder().encode(JSON.stringify(value)));
|
|
51
|
+
async function boundedCredential(work, signal) {
|
|
52
|
+
signal.throwIfAborted();
|
|
53
|
+
let abort;
|
|
54
|
+
const aborted = new Promise((_, reject) => {
|
|
55
|
+
abort = () => reject(new Error("Credential deadline exceeded"));
|
|
56
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
57
|
+
});
|
|
58
|
+
try {
|
|
59
|
+
return await Promise.race([work, aborted]);
|
|
60
|
+
} finally {
|
|
61
|
+
signal.removeEventListener("abort", abort);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function createDPoPCredentialProvider(options) {
|
|
65
|
+
const { privateKey, publicJwk } = options;
|
|
66
|
+
if (publicJwk.d || publicJwk.kty !== "EC" || publicJwk.crv !== "P-256" || !publicJwk.x || !publicJwk.y)
|
|
67
|
+
throw new Error("DPoP requires a public P-256 JWK");
|
|
68
|
+
const jwk = { kty: "EC", crv: "P-256", x: publicJwk.x, y: publicJwk.y };
|
|
69
|
+
let cached;
|
|
70
|
+
let pending;
|
|
71
|
+
const valid = (c) => !!c && typeof c.accessToken === "string" && /^[\w-]+\.[\w-]+\.[\w-]+$/.test(c.accessToken) && [c.expiresAt, c.trustExpiresAt, c.revocationValidUntil].every(
|
|
72
|
+
(v) => Number.isSafeInteger(v) && v > Date.now() / 1e3 + 1
|
|
73
|
+
);
|
|
74
|
+
return {
|
|
75
|
+
async headers({ url, method, signal }) {
|
|
76
|
+
signal.throwIfAborted();
|
|
77
|
+
const target = new URL(url);
|
|
78
|
+
if (target.protocol !== "https:" || target.username || target.password)
|
|
79
|
+
throw new Error("DPoP requires HTTPS");
|
|
80
|
+
if (!valid(cached)) {
|
|
81
|
+
if (!pending) {
|
|
82
|
+
const refreshSignal = AbortSignal.timeout(options.refreshTimeoutMs ?? 500);
|
|
83
|
+
pending = Promise.resolve().then(() => options.load(refreshSignal)).then((c) => {
|
|
84
|
+
if (!valid(c) || refreshSignal.aborted) throw new Error("Stale credential");
|
|
85
|
+
cached = { ...c };
|
|
86
|
+
return cached;
|
|
87
|
+
}).finally(() => {
|
|
88
|
+
pending = void 0;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
await boundedCredential(
|
|
92
|
+
pending,
|
|
93
|
+
AbortSignal.any([signal, AbortSignal.timeout(options.refreshTimeoutMs ?? 500)])
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (!valid(cached)) throw new Error("Stale credential");
|
|
97
|
+
const credential = cached;
|
|
98
|
+
const token = credential.accessToken;
|
|
99
|
+
const ath = encode(
|
|
100
|
+
new Uint8Array(
|
|
101
|
+
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token))
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
const payload = `${json({ typ: "dpop+jwt", alg: "ES256", jwk })}.${json({ jti: crypto.randomUUID(), iat: Math.floor(Date.now() / 1e3), htm: method.toUpperCase(), htu: `${target.origin}${target.pathname}`, ath })}`;
|
|
105
|
+
const signature = await crypto.subtle.sign(
|
|
106
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
107
|
+
privateKey,
|
|
108
|
+
new TextEncoder().encode(payload)
|
|
109
|
+
);
|
|
110
|
+
signal.throwIfAborted();
|
|
111
|
+
if (!valid(credential)) throw new Error("Stale credential");
|
|
112
|
+
return {
|
|
113
|
+
Authorization: `DPoP ${token}`,
|
|
114
|
+
DPoP: `${payload}.${encode(new Uint8Array(signature))}`
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
3
120
|
// src/errors.ts
|
|
4
121
|
var ChitmarkError = class extends Error {
|
|
5
122
|
name = "ChitmarkError";
|
|
@@ -62,7 +179,7 @@ var DEFAULT_BASE_URLS = {
|
|
|
62
179
|
};
|
|
63
180
|
var DEFAULT_TIMEOUT_MS = 800;
|
|
64
181
|
var LOCAL_TIMEOUT_MS = 2e3;
|
|
65
|
-
var SDK_VERSION = "0.
|
|
182
|
+
var SDK_VERSION = "0.9.0";
|
|
66
183
|
function defaultTimeoutMs(baseUrl) {
|
|
67
184
|
try {
|
|
68
185
|
const host = new URL(baseUrl).hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
@@ -125,11 +242,11 @@ function minimizeFormData(formData) {
|
|
|
125
242
|
}
|
|
126
243
|
function bufferToHex(buffer) {
|
|
127
244
|
const bytes = new Uint8Array(buffer);
|
|
128
|
-
let
|
|
245
|
+
let hex2 = "";
|
|
129
246
|
for (const b of bytes) {
|
|
130
|
-
|
|
247
|
+
hex2 += b.toString(16).padStart(2, "0");
|
|
131
248
|
}
|
|
132
|
-
return
|
|
249
|
+
return hex2;
|
|
133
250
|
}
|
|
134
251
|
|
|
135
252
|
// src/internal/prepare.ts
|
|
@@ -205,6 +322,46 @@ var VerdictTokenError = class extends ChitmarkError {
|
|
|
205
322
|
var DEFAULT_JWKS_URL = "https://api.chitmark.com/.well-known/jwks.json";
|
|
206
323
|
var DEFAULT_LEEWAY_SECONDS = 30;
|
|
207
324
|
async function verifyVerdictToken(token, options) {
|
|
325
|
+
return verifyReceipt(token, options, "JWT");
|
|
326
|
+
}
|
|
327
|
+
var SENSITIVE_RECEIPT_ACTIONS = [
|
|
328
|
+
"api_key",
|
|
329
|
+
"data_export",
|
|
330
|
+
"session_establish",
|
|
331
|
+
"privilege_elevate",
|
|
332
|
+
"authenticator_replace",
|
|
333
|
+
"recovery_contact_change",
|
|
334
|
+
"session_use",
|
|
335
|
+
"privilege_change",
|
|
336
|
+
"release_deploy",
|
|
337
|
+
"bulk_mutation",
|
|
338
|
+
"commitment_change",
|
|
339
|
+
"agent_effect",
|
|
340
|
+
"agent_escalation",
|
|
341
|
+
"quote_generate",
|
|
342
|
+
"queue_priority"
|
|
343
|
+
];
|
|
344
|
+
async function verifyActionReceipt(token, options) {
|
|
345
|
+
const claims = await verifyReceipt(
|
|
346
|
+
token,
|
|
347
|
+
{
|
|
348
|
+
...options,
|
|
349
|
+
aud: options.audience,
|
|
350
|
+
issuer: VERDICT_TOKEN_ISSUER,
|
|
351
|
+
leewaySeconds: 0
|
|
352
|
+
},
|
|
353
|
+
"chitmark-action+jwt"
|
|
354
|
+
);
|
|
355
|
+
const now = Math.floor((options.nowMs ?? Date.now()) / 1e3);
|
|
356
|
+
if (!options.audience || !options.session || !options.tenantId || !options.policy || !/^[a-f0-9]{64}$/.test(options.digest) || !(options.action === "trial_activation" ? options.proof === "none" || options.proof === "pow_severe" : SENSITIVE_RECEIPT_ACTIONS.includes(options.action) && options.proof === "tenant_step_up" && typeof options.subject === "string" && /^[A-Za-z0-9_-]{1,128}$/.test(options.subject) && claims.subject === options.subject) || claims.action !== options.action || options.environment !== "test" && options.environment !== "live" || claims.environment !== options.environment || !options.surface || claims.surface !== options.surface || claims.digest !== options.digest || claims.policy !== options.policy || claims.proof !== options.proof || claims.enforcementMode !== "enforce" || claims.decision !== "allow" || claims.degraded !== false || typeof claims.eventId !== "string" || !claims.eventId || !Number.isSafeInteger(claims.iat) || !Number.isSafeInteger(claims.exp) || claims.iat > now || claims.exp <= now || claims.exp - claims.iat !== 60) {
|
|
357
|
+
throw new VerdictTokenError(
|
|
358
|
+
"wrong_action_binding",
|
|
359
|
+
"Receipt cannot authorize this operation"
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
return claims;
|
|
363
|
+
}
|
|
364
|
+
async function verifyReceipt(token, options, expectedType) {
|
|
208
365
|
const nowMs = options.nowMs ?? Date.now();
|
|
209
366
|
const leewaySeconds = options.leewaySeconds ?? DEFAULT_LEEWAY_SECONDS;
|
|
210
367
|
const parts = token.split(".");
|
|
@@ -226,10 +383,10 @@ async function verifyVerdictToken(token, options) {
|
|
|
226
383
|
`verdictToken must use ES256, got ${String(header["alg"])}`
|
|
227
384
|
);
|
|
228
385
|
}
|
|
229
|
-
if (header["typ"] !==
|
|
386
|
+
if (header["typ"] !== expectedType) {
|
|
230
387
|
throw new VerdictTokenError(
|
|
231
388
|
"wrong_type",
|
|
232
|
-
`verdictToken must
|
|
389
|
+
`verdictToken must have type ${expectedType}, got ${String(header["typ"])}`
|
|
233
390
|
);
|
|
234
391
|
}
|
|
235
392
|
const kid = typeof header["kid"] === "string" ? header["kid"] : "";
|
|
@@ -275,6 +432,12 @@ async function verifyVerdictToken(token, options) {
|
|
|
275
432
|
if (!jwk) {
|
|
276
433
|
throw new VerdictTokenError("unknown_kid", `JWKS has no key for kid ${kid}`);
|
|
277
434
|
}
|
|
435
|
+
if (jwk["kty"] !== "EC" || jwk["crv"] !== "P-256" || jwk["alg"] !== void 0 && jwk["alg"] !== "ES256") {
|
|
436
|
+
throw new VerdictTokenError(
|
|
437
|
+
"wrong_algorithm",
|
|
438
|
+
"Verification requires an ES256 P-256 key"
|
|
439
|
+
);
|
|
440
|
+
}
|
|
278
441
|
let publicKey;
|
|
279
442
|
try {
|
|
280
443
|
publicKey = await crypto.subtle.importKey(
|
|
@@ -347,7 +510,27 @@ function decodeBase64UrlBytes(value) {
|
|
|
347
510
|
|
|
348
511
|
// src/client.ts
|
|
349
512
|
var Chitmark = class {
|
|
513
|
+
attribution = {
|
|
514
|
+
resolve: (input) => this.request("/v1/attributions/resolve", {
|
|
515
|
+
method: "POST",
|
|
516
|
+
body: attributionEvidence(input, this.piiMode),
|
|
517
|
+
idempotencyKey: input.idempotencyKey
|
|
518
|
+
}),
|
|
519
|
+
get: (id2) => this.request(`/v1/attributions/${encodeURIComponent(id2)}`, { method: "GET" }),
|
|
520
|
+
createLink: (input, idempotencyKey) => this.request("/v1/identity-links", { method: "POST", body: input, idempotencyKey }),
|
|
521
|
+
revokeLink: (id2) => this.request(`/v1/identity-links/${encodeURIComponent(id2)}`, { method: "DELETE" })
|
|
522
|
+
};
|
|
523
|
+
/** Paid access lifecycle. Transport uncertainty must be resumed, never treated as payment. */
|
|
524
|
+
async charge(request) {
|
|
525
|
+
return this.request("/v1/charge", {
|
|
526
|
+
method: "POST",
|
|
527
|
+
body: request,
|
|
528
|
+
idempotencyKey: request.idempotencyKey,
|
|
529
|
+
timeoutMs: Math.max(this.timeoutMs, 15e3)
|
|
530
|
+
});
|
|
531
|
+
}
|
|
350
532
|
apiKey;
|
|
533
|
+
credentialProvider;
|
|
351
534
|
baseUrl;
|
|
352
535
|
timeoutMs;
|
|
353
536
|
piiMode;
|
|
@@ -355,7 +538,7 @@ var Chitmark = class {
|
|
|
355
538
|
fetchImpl;
|
|
356
539
|
clientName;
|
|
357
540
|
constructor(options) {
|
|
358
|
-
if (
|
|
541
|
+
if (!!options.apiKey === !!options.credentialProvider) {
|
|
359
542
|
throw new ChitmarkError("Chitmark apiKey is required");
|
|
360
543
|
}
|
|
361
544
|
if (options.onDegraded && options.onDegraded !== "challenge") {
|
|
@@ -364,6 +547,7 @@ var Chitmark = class {
|
|
|
364
547
|
);
|
|
365
548
|
}
|
|
366
549
|
this.apiKey = options.apiKey;
|
|
550
|
+
this.credentialProvider = options.credentialProvider;
|
|
367
551
|
this.baseUrl = resolveBaseUrl(options.env, options.baseUrl ?? envBaseUrl());
|
|
368
552
|
this.timeoutMs = options.timeoutMs ?? defaultTimeoutMs(this.baseUrl);
|
|
369
553
|
this.piiMode = options.piiMode ?? "hashed";
|
|
@@ -456,7 +640,8 @@ var Chitmark = class {
|
|
|
456
640
|
/**
|
|
457
641
|
* Complete a challenge by submitting its solved proof. Clears only the bound
|
|
458
642
|
* session, once. Does not authorize the action: re-verify with
|
|
459
|
-
* `context.challengeId`
|
|
643
|
+
* `context.challengeId` for standalone challenges or the original action
|
|
644
|
+
* binding plus the challenge and event IDs for operation-bound challenges.
|
|
460
645
|
*/
|
|
461
646
|
async completeChallenge(request) {
|
|
462
647
|
return this.request("/v1/challenge", {
|
|
@@ -484,15 +669,35 @@ var Chitmark = class {
|
|
|
484
669
|
*/
|
|
485
670
|
async request(path, init) {
|
|
486
671
|
const controller = new AbortController();
|
|
487
|
-
const
|
|
672
|
+
const timeoutMs = init.timeoutMs ?? this.timeoutMs;
|
|
673
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
488
674
|
try {
|
|
489
675
|
const headers = {
|
|
490
|
-
Authorization: `Bearer ${this.apiKey}
|
|
676
|
+
...this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
|
|
491
677
|
"Content-Type": "application/json",
|
|
492
678
|
Accept: "application/json",
|
|
493
679
|
"User-Agent": this.clientName,
|
|
494
680
|
"X-Chitmark-Client": this.clientName
|
|
495
681
|
};
|
|
682
|
+
if (this.credentialProvider) {
|
|
683
|
+
try {
|
|
684
|
+
Object.assign(
|
|
685
|
+
headers,
|
|
686
|
+
await boundedCredential(
|
|
687
|
+
this.credentialProvider.headers({
|
|
688
|
+
url: `${this.baseUrl}${path}`,
|
|
689
|
+
method: init.method,
|
|
690
|
+
signal: controller.signal
|
|
691
|
+
}),
|
|
692
|
+
controller.signal
|
|
693
|
+
)
|
|
694
|
+
);
|
|
695
|
+
} catch {
|
|
696
|
+
throw new ChitmarkError("Credential unavailable", { code: "credential" });
|
|
697
|
+
}
|
|
698
|
+
if (!headers.Authorization?.startsWith("DPoP ") || !headers.DPoP)
|
|
699
|
+
throw new ChitmarkError("Invalid DPoP credentials");
|
|
700
|
+
}
|
|
496
701
|
if (init.idempotencyKey) {
|
|
497
702
|
headers["Idempotency-Key"] = init.idempotencyKey;
|
|
498
703
|
}
|
|
@@ -500,7 +705,8 @@ var Chitmark = class {
|
|
|
500
705
|
method: init.method,
|
|
501
706
|
headers,
|
|
502
707
|
body: init.body !== void 0 ? JSON.stringify(init.body) : void 0,
|
|
503
|
-
signal: controller.signal
|
|
708
|
+
signal: controller.signal,
|
|
709
|
+
redirect: "error"
|
|
504
710
|
});
|
|
505
711
|
const text = await res.text();
|
|
506
712
|
let parsed = void 0;
|
|
@@ -524,7 +730,7 @@ var Chitmark = class {
|
|
|
524
730
|
} catch (err) {
|
|
525
731
|
if (err instanceof ChitmarkApiError) throw err;
|
|
526
732
|
if (err instanceof Error && err.name === "AbortError") {
|
|
527
|
-
throw new ChitmarkError(`Request timed out after ${
|
|
733
|
+
throw new ChitmarkError(`Request timed out after ${timeoutMs}ms`, {
|
|
528
734
|
code: "timeout"
|
|
529
735
|
});
|
|
530
736
|
}
|
|
@@ -550,6 +756,38 @@ function isWellFormedVerdict(value) {
|
|
|
550
756
|
return typeof v.decision === "string" && VERDICT_DECISIONS.has(v.decision) && typeof v.eventId === "string" && v.eventId.length > 0 && typeof v.degraded === "boolean";
|
|
551
757
|
}
|
|
552
758
|
|
|
759
|
+
// src/charge.ts
|
|
760
|
+
function summarizeCharge(p, now = Date.now(), sellerCostCents) {
|
|
761
|
+
if (sellerCostCents !== void 0 && (!Number.isSafeInteger(sellerCostCents) || sellerCostCents < 0))
|
|
762
|
+
throw new Error("Invalid seller cost");
|
|
763
|
+
const deliveredUnits = p.delivery.executions.reduce(
|
|
764
|
+
(n, e) => n + (e.state === "delivered" ? e.usedUnits : 0),
|
|
765
|
+
0
|
|
766
|
+
);
|
|
767
|
+
const unresolvedUnits = p.delivery.executions.reduce(
|
|
768
|
+
(n, e) => n + (e.state === "reserved" || e.state === "unknown" ? e.units : 0),
|
|
769
|
+
0
|
|
770
|
+
);
|
|
771
|
+
const net = p.payment.providerFee === null ? null : p.payment.capturedAmount - p.payment.refundedAmount - p.payment.providerFee;
|
|
772
|
+
return {
|
|
773
|
+
paidCompletion: p.payment.state === "settled" && p.payment.capturedAmount > 0 && p.payment.refundedAmount === 0 && p.payment.disputedAmount === 0 && deliveredUnits === p.quote.quantity,
|
|
774
|
+
billedCents: p.payment.capturedAmount - p.payment.refundedAmount,
|
|
775
|
+
sellerReportedDeliveredCents: deliveredUnits * p.quote.resource.unitAmount,
|
|
776
|
+
deliveredUnits,
|
|
777
|
+
unresolvedUnits,
|
|
778
|
+
unresolvedAgeUpperBoundMs: p.payment.state === "pending" || p.payment.refundState === "pending" || p.payment.refundState === "unknown" || p.payment.state === "unknown" || unresolvedUnits > 0 ? Math.max(0, now - p.createdAt) : null,
|
|
779
|
+
refundedCents: p.payment.refundedAmount,
|
|
780
|
+
disputedCents: p.payment.disputedAmount,
|
|
781
|
+
captureFeeCents: p.payment.providerFee,
|
|
782
|
+
sellerNetAfterCaptureFeeCents: net,
|
|
783
|
+
sellerMarginCents: net === null || sellerCostCents === void 0 ? null : net - sellerCostCents,
|
|
784
|
+
// Provider/application reconciliation must supply duplicate evidence; retries alone do not prove absence.
|
|
785
|
+
duplicateCharges: null,
|
|
786
|
+
duplicateEffects: null,
|
|
787
|
+
observedElapsedMs: Math.max(0, p.updatedAt - p.createdAt)
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
|
|
553
791
|
// src/http-status.ts
|
|
554
792
|
var CHITMARK_HTTP_STATUS = {
|
|
555
793
|
ok: 200,
|
|
@@ -587,6 +825,32 @@ function verdictToHttpStatus(verdict) {
|
|
|
587
825
|
return CHITMARK_HTTP_STATUS.ok;
|
|
588
826
|
}
|
|
589
827
|
|
|
828
|
+
// src/action-binding.ts
|
|
829
|
+
var opaqueId = /^[A-Za-z0-9_.:-]{1,128}$/;
|
|
830
|
+
async function trialCreditOperationDigest(operation) {
|
|
831
|
+
const { operationId, target, quota, recipient } = operation;
|
|
832
|
+
if (Object.keys(operation).some(
|
|
833
|
+
(key) => !["operationId", "target", "quota", "recipient"].includes(key)
|
|
834
|
+
) || typeof operationId !== "string" || !opaqueId.test(operationId) || typeof target !== "string" || !opaqueId.test(target) || !Number.isSafeInteger(quota) || quota < 1 || recipient !== void 0 && (typeof recipient !== "string" || !opaqueId.test(recipient))) {
|
|
835
|
+
throw new TypeError("Invalid trial credit operation");
|
|
836
|
+
}
|
|
837
|
+
const bytes = new TextEncoder().encode(
|
|
838
|
+
JSON.stringify([
|
|
839
|
+
"chitmark-action-v1",
|
|
840
|
+
"trial_activation",
|
|
841
|
+
operationId,
|
|
842
|
+
target,
|
|
843
|
+
quota,
|
|
844
|
+
recipient ?? null
|
|
845
|
+
])
|
|
846
|
+
);
|
|
847
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
848
|
+
return Array.from(
|
|
849
|
+
new Uint8Array(digest),
|
|
850
|
+
(byte) => byte.toString(16).padStart(2, "0")
|
|
851
|
+
).join("");
|
|
852
|
+
}
|
|
853
|
+
|
|
590
854
|
// src/trusted-ip.ts
|
|
591
855
|
function getTrustedClientIp(req) {
|
|
592
856
|
const platform = req.headers.get("cf-connecting-ip")?.trim() || req.headers.get("x-real-ip")?.trim() || req.headers.get("x-vercel-forwarded-for")?.split(",")[0]?.trim() || "";
|
|
@@ -649,22 +913,380 @@ async function verifyNextRequest(client, req, options) {
|
|
|
649
913
|
});
|
|
650
914
|
}
|
|
651
915
|
|
|
916
|
+
// src/evidence.ts
|
|
917
|
+
var EvidenceError = class extends Error {
|
|
918
|
+
constructor(code) {
|
|
919
|
+
super(code);
|
|
920
|
+
this.code = code;
|
|
921
|
+
this.name = "EvidenceError";
|
|
922
|
+
}
|
|
923
|
+
code;
|
|
924
|
+
};
|
|
925
|
+
function evidenceAssert(value, code) {
|
|
926
|
+
if (!value) throw new EvidenceError(code);
|
|
927
|
+
}
|
|
928
|
+
function canonicalEvidence(value) {
|
|
929
|
+
if (value === null || typeof value === "boolean") return JSON.stringify(value);
|
|
930
|
+
if (typeof value === "number") {
|
|
931
|
+
evidenceAssert(
|
|
932
|
+
Number.isSafeInteger(value) && !Object.is(value, -0),
|
|
933
|
+
"noncanonical_number"
|
|
934
|
+
);
|
|
935
|
+
return String(value);
|
|
936
|
+
}
|
|
937
|
+
if (typeof value === "string") {
|
|
938
|
+
evidenceAssert(/^[\x20-\x7e]*$/.test(value), "noncanonical_string");
|
|
939
|
+
return JSON.stringify(value);
|
|
940
|
+
}
|
|
941
|
+
if (Array.isArray(value)) return `[${value.map(canonicalEvidence).join(",")}]`;
|
|
942
|
+
evidenceAssert(
|
|
943
|
+
value && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype,
|
|
944
|
+
"noncanonical_object"
|
|
945
|
+
);
|
|
946
|
+
const obj = value;
|
|
947
|
+
return `{${Object.keys(obj).sort().map((key) => `${canonicalEvidence(key)}:${canonicalEvidence(obj[key])}`).join(",")}}`;
|
|
948
|
+
}
|
|
949
|
+
async function evidenceHash(value) {
|
|
950
|
+
return Array.from(
|
|
951
|
+
new Uint8Array(
|
|
952
|
+
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value))
|
|
953
|
+
),
|
|
954
|
+
(b) => b.toString(16).padStart(2, "0")
|
|
955
|
+
).join("");
|
|
956
|
+
}
|
|
957
|
+
var encode2 = (bytes) => btoa(Array.from(bytes, (b) => String.fromCharCode(b)).join("")).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
958
|
+
var decode = (part) => Uint8Array.from(
|
|
959
|
+
atob(part.replace(/-/g, "+").replace(/_/g, "/")),
|
|
960
|
+
(c) => c.charCodeAt(0)
|
|
961
|
+
);
|
|
962
|
+
function evidenceKeyAt(history, kid, at) {
|
|
963
|
+
const matches = history.filter((key2) => key2.kid === kid);
|
|
964
|
+
evidenceAssert(matches.length === 1, "unknown_trust_root");
|
|
965
|
+
const key = matches[0];
|
|
966
|
+
evidenceAssert(
|
|
967
|
+
key.jwk.kty === "EC" && key.jwk.crv === "P-256" && (!key.jwk.alg || key.jwk.alg === "ES256") && !key.jwk.d,
|
|
968
|
+
"unsupported_key"
|
|
969
|
+
);
|
|
970
|
+
evidenceAssert(
|
|
971
|
+
Number.isSafeInteger(at) && Number.isSafeInteger(key.notBefore) && Number.isSafeInteger(key.notAfter) && key.notBefore <= at && at < key.notAfter,
|
|
972
|
+
"key_outside_validity"
|
|
973
|
+
);
|
|
974
|
+
evidenceAssert(key.revokedAt === void 0, "revoked_key");
|
|
975
|
+
return key;
|
|
976
|
+
}
|
|
977
|
+
async function verifyEvidenceSignature(token, typ, history, at) {
|
|
978
|
+
evidenceAssert(
|
|
979
|
+
typeof token === "string" && token.length <= 8e6 && /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/.test(token),
|
|
980
|
+
"malformed_signature"
|
|
981
|
+
);
|
|
982
|
+
const [h, p, s] = token.split(".");
|
|
983
|
+
let head, payload;
|
|
984
|
+
try {
|
|
985
|
+
head = JSON.parse(
|
|
986
|
+
new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(decode(h))
|
|
987
|
+
);
|
|
988
|
+
payload = JSON.parse(
|
|
989
|
+
new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(decode(p))
|
|
990
|
+
);
|
|
991
|
+
} catch {
|
|
992
|
+
throw new EvidenceError("malformed_signature");
|
|
993
|
+
}
|
|
994
|
+
evidenceAssert(
|
|
995
|
+
head?.alg === "ES256" && head.typ === typ && Object.keys(head).length === 3,
|
|
996
|
+
"unsupported_profile"
|
|
997
|
+
);
|
|
998
|
+
const trusted = evidenceKeyAt(history, head.kid, at);
|
|
999
|
+
const key = await crypto.subtle.importKey(
|
|
1000
|
+
"jwk",
|
|
1001
|
+
trusted.jwk,
|
|
1002
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
1003
|
+
false,
|
|
1004
|
+
["verify"]
|
|
1005
|
+
);
|
|
1006
|
+
evidenceAssert(
|
|
1007
|
+
await crypto.subtle.verify(
|
|
1008
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
1009
|
+
key,
|
|
1010
|
+
decode(s),
|
|
1011
|
+
new TextEncoder().encode(`${h}.${p}`)
|
|
1012
|
+
),
|
|
1013
|
+
"invalid_signature"
|
|
1014
|
+
);
|
|
1015
|
+
evidenceAssert(
|
|
1016
|
+
payload && typeof payload === "object" && !Array.isArray(payload),
|
|
1017
|
+
"malformed_payload"
|
|
1018
|
+
);
|
|
1019
|
+
return payload;
|
|
1020
|
+
}
|
|
1021
|
+
async function signEvidence(payload, typ, kid, jwk) {
|
|
1022
|
+
evidenceAssert(
|
|
1023
|
+
jwk.kty === "EC" && jwk.crv === "P-256" && (!jwk.alg || jwk.alg === "ES256"),
|
|
1024
|
+
"unsupported_key"
|
|
1025
|
+
);
|
|
1026
|
+
const input = `${encode2(new TextEncoder().encode(canonicalEvidence({ alg: "ES256", kid, typ })))}.${encode2(new TextEncoder().encode(canonicalEvidence(payload)))}`;
|
|
1027
|
+
evidenceAssert(input.length + 87 <= 8e6, "bundle_too_large");
|
|
1028
|
+
const key = await crypto.subtle.importKey(
|
|
1029
|
+
"jwk",
|
|
1030
|
+
jwk,
|
|
1031
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
1032
|
+
false,
|
|
1033
|
+
["sign"]
|
|
1034
|
+
);
|
|
1035
|
+
return `${input}.${encode2(new Uint8Array(await crypto.subtle.sign({ name: "ECDSA", hash: "SHA-256" }, key, new TextEncoder().encode(input))))}`;
|
|
1036
|
+
}
|
|
1037
|
+
var id = /^[A-Za-z0-9_.:/-]{1,160}$/;
|
|
1038
|
+
function validateManifest(value, tenantId) {
|
|
1039
|
+
evidenceAssert(
|
|
1040
|
+
Object.keys(value).sort().join(",") === "completeness,createdAt,endAt,gaps,issuer,purpose,records,retention,sourceAsOf,startAt,tenantId,timeBasis,version" && Object.keys(value.retention).sort().join(",") === "deleteAfter,exportedCopies,recipient,redaction",
|
|
1041
|
+
"unminimized_manifest"
|
|
1042
|
+
);
|
|
1043
|
+
canonicalEvidence(value);
|
|
1044
|
+
evidenceAssert(
|
|
1045
|
+
value.version === 1 && value.issuer === "https://portal.chitmark.com" && value.purpose === "historical_evidence" && value.tenantId === tenantId && id.test(tenantId),
|
|
1046
|
+
"wrong_bundle_scope"
|
|
1047
|
+
);
|
|
1048
|
+
evidenceAssert(
|
|
1049
|
+
[
|
|
1050
|
+
value.startAt,
|
|
1051
|
+
value.endAt,
|
|
1052
|
+
value.createdAt,
|
|
1053
|
+
value.sourceAsOf,
|
|
1054
|
+
value.retention.deleteAfter
|
|
1055
|
+
].every(Number.isSafeInteger) && value.startAt < value.endAt && value.endAt <= value.sourceAsOf && value.sourceAsOf <= value.createdAt && value.createdAt < value.retention.deleteAfter,
|
|
1056
|
+
"invalid_window"
|
|
1057
|
+
);
|
|
1058
|
+
evidenceAssert(
|
|
1059
|
+
value.completeness === "unknown" && value.timeBasis === "issuer_and_ingestion_clocks_not_independent_time" && value.retention.redaction === "minimized" && value.retention.exportedCopies === "recipient_controlled" && id.test(value.retention.recipient) && Array.isArray(value.gaps) && value.gaps.every((gap) => id.test(gap)),
|
|
1060
|
+
"invalid_manifest"
|
|
1061
|
+
);
|
|
1062
|
+
evidenceAssert(
|
|
1063
|
+
Array.isArray(value.records) && value.records.length <= 1e4,
|
|
1064
|
+
"record_limit"
|
|
1065
|
+
);
|
|
1066
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1067
|
+
for (const row of value.records) {
|
|
1068
|
+
evidenceAssert(
|
|
1069
|
+
Object.keys(row).sort().join(",") === "eventId,id,kind,occurredAt,policyRevision,receipt,recordedAt,result,source",
|
|
1070
|
+
"unminimized_record"
|
|
1071
|
+
);
|
|
1072
|
+
evidenceAssert(
|
|
1073
|
+
id.test(row.id) && id.test(row.eventId) && ["decision", "execution", "outcome"].includes(row.kind) && id.test(row.result) && (row.policyRevision === null || id.test(row.policyRevision)) && (row.receipt === null || typeof row.receipt === "string" && row.receipt.length <= 8192),
|
|
1074
|
+
"invalid_record"
|
|
1075
|
+
);
|
|
1076
|
+
evidenceAssert(
|
|
1077
|
+
Number.isSafeInteger(row.occurredAt) && Number.isSafeInteger(row.recordedAt) && value.startAt <= row.occurredAt && row.occurredAt < value.endAt && row.recordedAt <= value.sourceAsOf && row.recordedAt >= row.occurredAt && row.source === (row.kind === "decision" ? "decision_service" : "customer_report"),
|
|
1078
|
+
"invalid_provenance"
|
|
1079
|
+
);
|
|
1080
|
+
const identity = `${row.kind}:${row.id}`;
|
|
1081
|
+
evidenceAssert(!seen.has(identity), "duplicate_record");
|
|
1082
|
+
seen.add(identity);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
async function verifyEvidenceBundle(bundle, options) {
|
|
1086
|
+
validateManifest(bundle.manifest, options.tenantId);
|
|
1087
|
+
evidenceAssert(
|
|
1088
|
+
bundle.manifest.retention.recipient === options.recipient,
|
|
1089
|
+
"wrong_recipient"
|
|
1090
|
+
);
|
|
1091
|
+
evidenceAssert(
|
|
1092
|
+
options.now < bundle.manifest.retention.deleteAfter && options.now >= bundle.manifest.createdAt,
|
|
1093
|
+
"retention_expired"
|
|
1094
|
+
);
|
|
1095
|
+
const signed = await verifyEvidenceSignature(
|
|
1096
|
+
bundle.signature,
|
|
1097
|
+
"chitmark-evidence+jwt",
|
|
1098
|
+
options.trustedKeys,
|
|
1099
|
+
bundle.manifest.createdAt
|
|
1100
|
+
);
|
|
1101
|
+
evidenceAssert(
|
|
1102
|
+
canonicalEvidence(signed) === canonicalEvidence(bundle.manifest),
|
|
1103
|
+
"manifest_mismatch"
|
|
1104
|
+
);
|
|
1105
|
+
const head = JSON.parse(
|
|
1106
|
+
new TextDecoder().decode(decode(bundle.signature.split(".")[0]))
|
|
1107
|
+
);
|
|
1108
|
+
evidenceAssert(
|
|
1109
|
+
evidenceKeyAt(options.trustedKeys, head.kid, bundle.manifest.createdAt).compromisedAt === void 0,
|
|
1110
|
+
"compromised_bundle_key"
|
|
1111
|
+
);
|
|
1112
|
+
return {
|
|
1113
|
+
purpose: "historical_evidence",
|
|
1114
|
+
executionAuthorized: false,
|
|
1115
|
+
integrity: "valid",
|
|
1116
|
+
completeness: "unknown",
|
|
1117
|
+
outcomeTruth: "not_established",
|
|
1118
|
+
gaps: bundle.manifest.gaps
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1121
|
+
async function verifyHistoricalReceipt(token, options) {
|
|
1122
|
+
evidenceAssert(
|
|
1123
|
+
typeof token === "string" && token.length <= 8192,
|
|
1124
|
+
"malformed_signature"
|
|
1125
|
+
);
|
|
1126
|
+
let claims, head;
|
|
1127
|
+
try {
|
|
1128
|
+
const parts = token.split(".");
|
|
1129
|
+
head = JSON.parse(new TextDecoder().decode(decode(parts[0])));
|
|
1130
|
+
claims = JSON.parse(new TextDecoder().decode(decode(parts[1])));
|
|
1131
|
+
} catch {
|
|
1132
|
+
throw new EvidenceError("malformed_signature");
|
|
1133
|
+
}
|
|
1134
|
+
evidenceAssert(
|
|
1135
|
+
head.typ === "JWT" || head.typ === "chitmark-action+jwt",
|
|
1136
|
+
"unsupported_profile"
|
|
1137
|
+
);
|
|
1138
|
+
evidenceAssert(
|
|
1139
|
+
Number.isSafeInteger(claims.iat) && Number.isSafeInteger(claims.exp) && Number(claims.iat) < Number(claims.exp) && Number(claims.exp) - Number(claims.iat) <= (head.typ === "JWT" ? 300 : 60),
|
|
1140
|
+
"invalid_receipt_time"
|
|
1141
|
+
);
|
|
1142
|
+
const at = Number(claims.iat);
|
|
1143
|
+
evidenceAssert(
|
|
1144
|
+
typeof claims.eventId === "string" && /^[A-Za-z0-9_-]{1,160}$/.test(claims.eventId),
|
|
1145
|
+
"invalid_receipt_context"
|
|
1146
|
+
);
|
|
1147
|
+
const trusted = evidenceKeyAt(options.trustedKeys, String(head.kid), at);
|
|
1148
|
+
claims = await verifyEvidenceSignature(
|
|
1149
|
+
token,
|
|
1150
|
+
String(head.typ),
|
|
1151
|
+
options.trustedKeys,
|
|
1152
|
+
at
|
|
1153
|
+
);
|
|
1154
|
+
evidenceAssert(
|
|
1155
|
+
claims.tid === options.tenantId && claims.sub === options.session && claims.iss === "https://api.chitmark.com",
|
|
1156
|
+
"wrong_receipt_scope"
|
|
1157
|
+
);
|
|
1158
|
+
const witnessed = options.witness && Number.isSafeInteger(options.witness.observedAt) && options.witness.observedAt >= at && options.witness.tokenHash === await evidenceHash(token);
|
|
1159
|
+
const beforeCompromise = witnessed && (trusted.compromisedAt === void 0 || options.witness.observedAt < trusted.compromisedAt);
|
|
1160
|
+
return {
|
|
1161
|
+
purpose: "historical_evidence",
|
|
1162
|
+
executionAuthorized: false,
|
|
1163
|
+
eventId: String(claims.eventId),
|
|
1164
|
+
policyRevision: typeof claims.policy === "string" ? claims.policy : null,
|
|
1165
|
+
timeIntegrity: beforeCompromise ? "independently_checkpointed" : trusted.compromisedAt !== void 0 ? "uncertain_after_compromise" : "self_asserted"
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
// src/evidence-checkpoint.ts
|
|
1170
|
+
var hex = /^[a-f0-9]{64}$/;
|
|
1171
|
+
function scope(checkpoint, tenantId, now) {
|
|
1172
|
+
evidenceAssert(
|
|
1173
|
+
checkpoint.version === 1 && checkpoint.tenantId === tenantId && /^[A-Za-z0-9_-]{16,128}$/.test(checkpoint.epoch) && Number.isSafeInteger(checkpoint.expiresAt) && now < checkpoint.expiresAt && Number.isSafeInteger(checkpoint.observedAt) && checkpoint.observedAt <= now && checkpoint.observedAt < checkpoint.expiresAt && Number.isSafeInteger(checkpoint.size) && checkpoint.size >= 0 && checkpoint.size <= 1e4 && hex.test(checkpoint.root),
|
|
1174
|
+
"checkpoint_scope_or_expiry"
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
var genesis = (cp) => evidenceHash(
|
|
1178
|
+
canonicalEvidence(["chitmark-private-chain-v1", cp.tenantId, cp.epoch, cp.expiresAt])
|
|
1179
|
+
);
|
|
1180
|
+
var evidenceCommitment = (cp, record, salt) => {
|
|
1181
|
+
evidenceAssert(hex.test(salt), "invalid_commitment_salt");
|
|
1182
|
+
return evidenceHash(
|
|
1183
|
+
canonicalEvidence([
|
|
1184
|
+
"chitmark-record-v1",
|
|
1185
|
+
cp.tenantId,
|
|
1186
|
+
cp.epoch,
|
|
1187
|
+
cp.expiresAt,
|
|
1188
|
+
salt,
|
|
1189
|
+
record
|
|
1190
|
+
])
|
|
1191
|
+
);
|
|
1192
|
+
};
|
|
1193
|
+
var advance = (root, leaf, index) => evidenceHash(canonicalEvidence(["chitmark-append-v1", index, root, leaf]));
|
|
1194
|
+
async function checkpointFromCommitments(input) {
|
|
1195
|
+
evidenceAssert(
|
|
1196
|
+
input.commitments.length <= 1e4 && input.commitments.every((leaf) => hex.test(leaf)),
|
|
1197
|
+
"invalid_commitments"
|
|
1198
|
+
);
|
|
1199
|
+
let root = await genesis(input);
|
|
1200
|
+
for (let index = 0; index < input.commitments.length; index++)
|
|
1201
|
+
root = await advance(root, input.commitments[index], index);
|
|
1202
|
+
const cp = {
|
|
1203
|
+
version: 1,
|
|
1204
|
+
tenantId: input.tenantId,
|
|
1205
|
+
epoch: input.epoch,
|
|
1206
|
+
expiresAt: input.expiresAt,
|
|
1207
|
+
observedAt: input.observedAt,
|
|
1208
|
+
size: input.commitments.length,
|
|
1209
|
+
root
|
|
1210
|
+
};
|
|
1211
|
+
scope(cp, input.tenantId, input.observedAt);
|
|
1212
|
+
return cp;
|
|
1213
|
+
}
|
|
1214
|
+
async function verifyCheckpointAppend(older, newer, appended, options) {
|
|
1215
|
+
scope(older, options.tenantId, options.now);
|
|
1216
|
+
scope(newer, options.tenantId, options.now);
|
|
1217
|
+
if (older.size === 0)
|
|
1218
|
+
evidenceAssert(older.root === await genesis(older), "invalid_empty_checkpoint");
|
|
1219
|
+
evidenceAssert(
|
|
1220
|
+
older.epoch === newer.epoch && older.expiresAt === newer.expiresAt && older.observedAt <= newer.observedAt && older.size <= newer.size,
|
|
1221
|
+
"inconsistent_checkpoint"
|
|
1222
|
+
);
|
|
1223
|
+
if (older.size === newer.size)
|
|
1224
|
+
evidenceAssert(older.root === newer.root, "divergent_history");
|
|
1225
|
+
if (appended === null)
|
|
1226
|
+
return { status: "unavailable", completeness: "unknown" };
|
|
1227
|
+
evidenceAssert(
|
|
1228
|
+
appended.length === newer.size - older.size && appended.every((leaf) => hex.test(leaf)),
|
|
1229
|
+
"invalid_append_proof"
|
|
1230
|
+
);
|
|
1231
|
+
let root = older.root;
|
|
1232
|
+
for (let index = 0; index < appended.length; index++)
|
|
1233
|
+
root = await advance(root, appended[index], older.size + index);
|
|
1234
|
+
evidenceAssert(root === newer.root, "divergent_history");
|
|
1235
|
+
return { status: "consistent", completeness: "unknown" };
|
|
1236
|
+
}
|
|
1237
|
+
async function verifyCheckpointInclusion(checkpoint, proof, options) {
|
|
1238
|
+
scope(checkpoint, options.tenantId, options.now);
|
|
1239
|
+
if (!proof) return { status: "unavailable", completeness: "unknown" };
|
|
1240
|
+
evidenceAssert(
|
|
1241
|
+
Number.isSafeInteger(proof.index) && proof.index >= 0 && proof.index < checkpoint.size && proof.commitments.length === checkpoint.size,
|
|
1242
|
+
"invalid_inclusion_proof"
|
|
1243
|
+
);
|
|
1244
|
+
const rebuilt = await checkpointFromCommitments({
|
|
1245
|
+
...checkpoint,
|
|
1246
|
+
commitments: proof.commitments
|
|
1247
|
+
});
|
|
1248
|
+
evidenceAssert(
|
|
1249
|
+
rebuilt.root === checkpoint.root && await evidenceCommitment(checkpoint, proof.record, proof.salt) === proof.commitments[proof.index],
|
|
1250
|
+
"changed_record"
|
|
1251
|
+
);
|
|
1252
|
+
return { status: "included", completeness: "unknown" };
|
|
1253
|
+
}
|
|
1254
|
+
|
|
652
1255
|
exports.CHITMARK_HTTP_STATUS = CHITMARK_HTTP_STATUS;
|
|
653
1256
|
exports.CHITMARK_HTTP_STATUS_MEANING = CHITMARK_HTTP_STATUS_MEANING;
|
|
654
1257
|
exports.Chitmark = Chitmark;
|
|
655
1258
|
exports.ChitmarkApiError = ChitmarkApiError;
|
|
656
1259
|
exports.ChitmarkError = ChitmarkError;
|
|
1260
|
+
exports.EvidenceError = EvidenceError;
|
|
1261
|
+
exports.SENSITIVE_RECEIPT_ACTIONS = SENSITIVE_RECEIPT_ACTIONS;
|
|
657
1262
|
exports.VERDICT_TOKEN_ISSUER = VERDICT_TOKEN_ISSUER;
|
|
658
1263
|
exports.VerdictTokenError = VerdictTokenError;
|
|
1264
|
+
exports.canonicalEvidence = canonicalEvidence;
|
|
1265
|
+
exports.checkpointFromCommitments = checkpointFromCommitments;
|
|
659
1266
|
exports.chitmarkGate = chitmarkGate;
|
|
1267
|
+
exports.createDPoPCredentialProvider = createDPoPCredentialProvider;
|
|
660
1268
|
exports.degradedChallengeVerdict = degradedChallengeVerdict;
|
|
661
1269
|
exports.enforceDegradedNeverAllow = enforceDegradedNeverAllow;
|
|
1270
|
+
exports.evidenceAssert = evidenceAssert;
|
|
1271
|
+
exports.evidenceCommitment = evidenceCommitment;
|
|
1272
|
+
exports.evidenceHash = evidenceHash;
|
|
1273
|
+
exports.evidenceKeyAt = evidenceKeyAt;
|
|
662
1274
|
exports.getTrustedClientIp = getTrustedClientIp;
|
|
663
1275
|
exports.hashEmailSha256 = hashEmailSha256;
|
|
664
1276
|
exports.isEligibleAllow = isEligibleAllow;
|
|
665
1277
|
exports.minimizeFormData = minimizeFormData;
|
|
1278
|
+
exports.signEvidence = signEvidence;
|
|
1279
|
+
exports.summarizeCharge = summarizeCharge;
|
|
1280
|
+
exports.trialCreditOperationDigest = trialCreditOperationDigest;
|
|
666
1281
|
exports.truncateIp = truncateIp;
|
|
1282
|
+
exports.validateManifest = validateManifest;
|
|
667
1283
|
exports.verdictToHttpStatus = verdictToHttpStatus;
|
|
1284
|
+
exports.verifyActionReceipt = verifyActionReceipt;
|
|
1285
|
+
exports.verifyCheckpointAppend = verifyCheckpointAppend;
|
|
1286
|
+
exports.verifyCheckpointInclusion = verifyCheckpointInclusion;
|
|
1287
|
+
exports.verifyEvidenceBundle = verifyEvidenceBundle;
|
|
1288
|
+
exports.verifyEvidenceSignature = verifyEvidenceSignature;
|
|
1289
|
+
exports.verifyHistoricalReceipt = verifyHistoricalReceipt;
|
|
668
1290
|
exports.verifyNextRequest = verifyNextRequest;
|
|
669
1291
|
exports.verifyVerdictToken = verifyVerdictToken;
|
|
670
1292
|
//# sourceMappingURL=index.cjs.map
|