@reclaimprotocol/client 0.1.26 → 0.1.28
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 +634 -42
- package/lib/api-client.d.ts +31 -0
- package/lib/api-client.js +112 -0
- package/lib/api-consts.d.ts +4 -0
- package/lib/api-consts.js +4 -0
- package/lib/api-errors.d.ts +13 -0
- package/lib/api-errors.js +30 -0
- package/lib/api.d.ts +7 -0
- package/lib/api.js +3 -0
- package/lib/attestor-proof.d.ts +6 -0
- package/lib/attestor-proof.js +45 -18
- package/lib/client.d.ts +1 -6
- package/lib/client.js +12 -33
- package/lib/consts.d.ts +1 -1
- package/lib/consts.js +1 -1
- package/lib/eip191.d.ts +4 -2
- package/lib/eip191.js +17 -1
- package/lib/errors.d.ts +38 -4
- package/lib/errors.js +99 -16
- package/lib/index.d.ts +9 -7
- package/lib/index.js +8 -4
- package/lib/jwks.d.ts +25 -1
- package/lib/jwks.js +69 -4
- package/lib/legacy-proof.d.ts +57 -0
- package/lib/legacy-proof.js +211 -0
- package/lib/proof-hash.d.ts +35 -0
- package/lib/proof-hash.js +216 -0
- package/lib/proof-recipe.d.ts +18 -0
- package/lib/proof-recipe.js +37 -0
- package/lib/proof-trust-constants.d.ts +3 -0
- package/lib/proof-trust-constants.js +43 -0
- package/lib/proof-types.d.ts +62 -0
- package/lib/proof-types.js +1 -0
- package/lib/proof-verification-error.d.ts +13 -0
- package/lib/proof-verification-error.js +11 -0
- package/lib/reclaim.d.ts +27 -5
- package/lib/reclaim.js +140 -14
- package/lib/result.d.ts +58 -6
- package/lib/result.js +252 -61
- package/lib/routes.gen.d.ts +58 -6
- package/lib/routes.gen.js +16 -3
- package/lib/tee-binding.d.ts +82 -0
- package/lib/tee-binding.js +112 -0
- package/lib/types/openapi.gen.d.ts +1412 -193
- package/lib/verification-clients.d.ts +17 -0
- package/lib/verification-clients.js +14 -0
- package/lib/verify-attestor-tee.d.ts +76 -0
- package/lib/verify-attestor-tee.js +243 -0
- package/lib/verify-tee.d.ts +32 -0
- package/lib/verify-tee.js +347 -0
- package/package.json +5 -1
- package/src/api.ts +15 -0
- package/src/attestor-proof.ts +57 -20
- package/src/client.ts +15 -38
- package/src/consts.ts +1 -2
- package/src/eip191.ts +31 -3
- package/src/errors.ts +132 -18
- package/src/index.ts +50 -5
- package/src/jwks.ts +128 -5
- package/src/legacy-proof.ts +367 -0
- package/src/proof-hash.ts +316 -0
- package/src/proof-recipe.ts +75 -0
- package/src/proof-trust-constants.ts +45 -0
- package/src/proof-types.ts +57 -0
- package/src/proof-verification-error.ts +13 -0
- package/src/reclaim.ts +206 -19
- package/src/result.ts +403 -68
- package/src/routes.gen.ts +16 -3
- package/src/tee-binding.ts +192 -0
- package/src/types/openapi.gen.ts +1412 -193
- package/src/verification-clients.ts +22 -0
- package/src/verify-attestor-tee.ts +365 -0
- package/src/verify-tee.ts +507 -0
package/lib/result.js
CHANGED
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
* Consumer-side handling of a delivered callback. Two entry points:
|
|
3
3
|
* - {@link verifyResult}: the offline primitive — decrypt + decode + optional
|
|
4
4
|
* ES256K signature check (caller-supplied key) + `reclaimSessionId` nonce.
|
|
5
|
-
* - {@link verifyResultFull}: the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* - {@link verifyResultFull}: the recommended server-side verification —
|
|
6
|
+
* resolves a registered issuer, discovers the Verification Client's key
|
|
7
|
+
* via JWKS, checks
|
|
8
|
+
* `reclaimSessionId`/`aud` and any legacy `exp`, and passes every exact
|
|
9
|
+
* legacy proof to the in-package, legacy-compatible `verifyProof` verifier.
|
|
9
10
|
*
|
|
10
11
|
* See docs/verification-session.md → "Verification by Consumer".
|
|
11
12
|
*/
|
|
12
13
|
import { sha256 } from '@noble/hashes/sha2.js';
|
|
13
|
-
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
14
14
|
import { decrypt as eciesDecrypt, encrypt as eciesEncrypt } from 'eciesjs';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
15
|
+
import { b64url, base64urlToBytes, hexToBytes } from "./encoding.js";
|
|
16
|
+
import { fetchReclaimJwks, jwkToUncompressedPublicKey, selectVerificationResultKey, } from "./jwks.js";
|
|
17
|
+
import { verifyProof, } from "./legacy-proof.js";
|
|
18
|
+
import { proofHashesFromBuilderRecipe, } from "./proof-recipe.js";
|
|
19
19
|
import { addressFromUncompressedPubkey, secp } from "./secp.js";
|
|
20
20
|
/**
|
|
21
21
|
* ECIES-encrypt `plaintext` for the holder of `publicJwk` (the org's secp256k1
|
|
@@ -134,13 +134,6 @@ export function verifyJwsSignature(jws, signerPublicKey) {
|
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
|
-
/** Content hash binding extracted parameters — MUST mirror the Verification
|
|
138
|
-
* Client's `contentHash` exactly (keccak256 of the RFC 8785 canonical JSON,
|
|
139
|
-
* via the shared `canonicalJson`). */
|
|
140
|
-
function contentHash(params) {
|
|
141
|
-
const canonical = canonicalJson(params);
|
|
142
|
-
return '0x' + bytesToHex(keccak_256(new TextEncoder().encode(canonical)));
|
|
143
|
-
}
|
|
144
137
|
/**
|
|
145
138
|
* Thrown by {@link verifyResult} / {@link verifyResultFull} (and therefore
|
|
146
139
|
* `reclaim.results.verify`/`receive`) when a result fails verification. Carries
|
|
@@ -165,15 +158,17 @@ export class ResultVerificationError extends Error {
|
|
|
165
158
|
}
|
|
166
159
|
}
|
|
167
160
|
/**
|
|
168
|
-
* Full consumer verification:
|
|
169
|
-
*
|
|
170
|
-
* `reclaimSessionId`/`aud
|
|
171
|
-
* proof
|
|
172
|
-
*
|
|
161
|
+
* Full consumer verification: resolves a trusted, registered issuer before
|
|
162
|
+
* using JWKS (header `iss`/`kid`), verifies the top-level JWS, checks
|
|
163
|
+
* `reclaimSessionId`/`aud` and any legacy `exp`, then verifies each exact
|
|
164
|
+
* legacy proof.
|
|
165
|
+
* Network access (JWKS and optional provider resolution) makes this async.
|
|
166
|
+
* Use {@link verifyResult} for the offline primitive.
|
|
173
167
|
*/
|
|
174
168
|
export async function verifyResultFull(jws, opts = {}) {
|
|
175
169
|
const payload = decodeJwsPayload(jws);
|
|
176
170
|
const reclaimSessionId = payload.reclaimSessionId;
|
|
171
|
+
let jwksAttestorAddresses = [];
|
|
177
172
|
/** Throw with the full invalid outcome — verification never *returns* an
|
|
178
173
|
* invalid result. */
|
|
179
174
|
const fail = (reason, extra = {}) => {
|
|
@@ -185,7 +180,8 @@ export async function verifyResultFull(jws, opts = {}) {
|
|
|
185
180
|
...extra,
|
|
186
181
|
});
|
|
187
182
|
};
|
|
188
|
-
// 1. Resolve the VC signer key
|
|
183
|
+
// 1. Resolve the VC signer key. Never use the signed header's `iss` as a
|
|
184
|
+
// network destination until it has matched an explicit or registered issuer.
|
|
189
185
|
let signerPublicKey = opts.signerPublicKey;
|
|
190
186
|
let header = {};
|
|
191
187
|
const sig0 = jws.signatures[0];
|
|
@@ -198,12 +194,37 @@ export async function verifyResultFull(jws, opts = {}) {
|
|
|
198
194
|
}
|
|
199
195
|
}
|
|
200
196
|
if (!signerPublicKey) {
|
|
197
|
+
const verificationClientId = getVerificationClientId(payload) ?? '';
|
|
198
|
+
let configuredIssuers;
|
|
199
|
+
try {
|
|
200
|
+
configuredIssuers = await resolveTrustedIssuers(opts, verificationClientId);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return fail('issuer-resolution-failed');
|
|
204
|
+
}
|
|
205
|
+
if (!configuredIssuers.length) {
|
|
206
|
+
return fail('issuer-not-configured');
|
|
207
|
+
}
|
|
201
208
|
const iss = String(header.iss ?? '');
|
|
202
209
|
if (!iss) {
|
|
203
210
|
return fail('no-issuer');
|
|
204
211
|
}
|
|
205
|
-
const
|
|
206
|
-
|
|
212
|
+
const trustedIssuer = configuredIssuers.find((candidate) => (normalizeIssuer(candidate) === normalizeIssuer(iss)));
|
|
213
|
+
if (!trustedIssuer) {
|
|
214
|
+
return fail('issuer-not-trusted');
|
|
215
|
+
}
|
|
216
|
+
let keys;
|
|
217
|
+
try {
|
|
218
|
+
const jwksUrl = await resolveTrustedJwksUrl(opts, verificationClientId);
|
|
219
|
+
const registry = await fetchReclaimJwks(jwksUrl
|
|
220
|
+
?? `${trustedIssuer.replace(/\/+$/, '')}/.well-known/jwks.json`, opts.fetchImpl);
|
|
221
|
+
keys = registry.keys;
|
|
222
|
+
jwksAttestorAddresses = registry['x-reclaim-attestors'] ?? [];
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
return fail('jwks-fetch-failed');
|
|
226
|
+
}
|
|
227
|
+
const jwk = selectVerificationResultKey(keys, String(header.kid ?? ''), verificationClientId);
|
|
207
228
|
if (!jwk) {
|
|
208
229
|
return fail('signer-key-not-found');
|
|
209
230
|
}
|
|
@@ -212,78 +233,248 @@ export async function verifyResultFull(jws, opts = {}) {
|
|
|
212
233
|
if (!verifyJwsSignature(jws, signerPublicKey)) {
|
|
213
234
|
return fail('bad-signature');
|
|
214
235
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
236
|
+
if (typeof payload.iss === 'string'
|
|
237
|
+
&& typeof header.iss === 'string'
|
|
238
|
+
&& normalizeIssuer(payload.iss) !== normalizeIssuer(header.iss)) {
|
|
239
|
+
return fail('issuer-mismatch');
|
|
240
|
+
}
|
|
241
|
+
// 2. Session binding, audience, and optional legacy result expiry.
|
|
242
|
+
const expectedResultSessionId = opts.sessionId
|
|
243
|
+
?? opts.expectedReclaimSessionId;
|
|
244
|
+
if (expectedResultSessionId && reclaimSessionId !== expectedResultSessionId) {
|
|
218
245
|
return fail('reclaimSessionId-mismatch');
|
|
219
246
|
}
|
|
220
247
|
if (opts.expectedAud && payload.aud !== opts.expectedAud) {
|
|
221
248
|
return fail('aud-mismatch');
|
|
222
249
|
}
|
|
223
250
|
const now = opts.now ?? Math.floor(Date.now() / 1000);
|
|
224
|
-
if (
|
|
251
|
+
if (!opts.ignoreExpiration
|
|
252
|
+
&& typeof payload.exp === 'number'
|
|
253
|
+
&& payload.exp < now) {
|
|
225
254
|
return fail('expired');
|
|
226
255
|
}
|
|
227
|
-
// 3.
|
|
228
|
-
//
|
|
229
|
-
// requests: [...] }]. Every request across every provider must verify.
|
|
256
|
+
// 3. Verify every exact legacy proof carried by the signed result. The outer
|
|
257
|
+
// envelope groups proofs by provider, but it never changes the proof shape.
|
|
230
258
|
const providerResults = Array.isArray(payload.results)
|
|
231
259
|
? payload.results
|
|
232
260
|
: [];
|
|
233
261
|
const proofs = [];
|
|
262
|
+
const proofGroups = [];
|
|
234
263
|
for (const prov of providerResults) {
|
|
235
264
|
const providerId = typeof prov.provider_id === 'string' ? prov.provider_id : undefined;
|
|
265
|
+
const providerVersion = typeof prov.resolved_version === 'string'
|
|
266
|
+
? prov.resolved_version
|
|
267
|
+
: undefined;
|
|
236
268
|
const requests = Array.isArray(prov.requests)
|
|
237
269
|
? prov.requests
|
|
238
270
|
: [];
|
|
239
271
|
for (const r of requests) {
|
|
240
272
|
const requestId = typeof r.request_id === 'string' ? r.request_id : undefined;
|
|
241
|
-
if (
|
|
273
|
+
if (!isLegacyProof(r.proof)) {
|
|
242
274
|
proofs.push({
|
|
243
275
|
providerId, requestId, proofValid: false, reason: 'proof-missing',
|
|
244
276
|
});
|
|
245
277
|
continue;
|
|
246
278
|
}
|
|
247
|
-
const np = verifyNestedProof(r.proof, {
|
|
248
|
-
attestorAddresses: opts.attestorAddresses,
|
|
249
|
-
});
|
|
250
|
-
if (!np.valid) {
|
|
251
|
-
proofs.push({
|
|
252
|
-
providerId,
|
|
253
|
-
requestId,
|
|
254
|
-
proofValid: false,
|
|
255
|
-
reason: np.reason,
|
|
256
|
-
attestorAddress: np.attestorAddress,
|
|
257
|
-
});
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
if (typeof r.content_hash === 'string' &&
|
|
261
|
-
r.extracted_parameters &&
|
|
262
|
-
typeof r.extracted_parameters === 'object') {
|
|
263
|
-
const params = r.extracted_parameters;
|
|
264
|
-
if (contentHash(params).toLowerCase() !== r.content_hash.toLowerCase()) {
|
|
265
|
-
proofs.push({
|
|
266
|
-
providerId,
|
|
267
|
-
requestId,
|
|
268
|
-
proofValid: false,
|
|
269
|
-
reason: 'content-hash-mismatch',
|
|
270
|
-
attestorAddress: np.attestorAddress,
|
|
271
|
-
});
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
279
|
proofs.push({
|
|
276
280
|
providerId,
|
|
277
281
|
requestId,
|
|
278
282
|
proofValid: true,
|
|
279
|
-
attestorAddress:
|
|
283
|
+
attestorAddress: r.proof.witnesses[0]?.id,
|
|
284
|
+
});
|
|
285
|
+
proofGroups.push({
|
|
286
|
+
providerId,
|
|
287
|
+
providerVersion,
|
|
288
|
+
proof: r.proof,
|
|
289
|
+
outcomeIndex: proofs.length - 1,
|
|
280
290
|
});
|
|
281
291
|
}
|
|
282
292
|
}
|
|
293
|
+
const verificationStatus = getVerificationStatus(payload);
|
|
294
|
+
if (verificationStatus === 'success' && !proofGroups.length) {
|
|
295
|
+
return fail('proof-missing', { proofs });
|
|
296
|
+
}
|
|
297
|
+
if (proofGroups.length) {
|
|
298
|
+
const expectedSessionId = expectedResultSessionId;
|
|
299
|
+
const configuredProofValidation = opts.proofValidation
|
|
300
|
+
?? opts.proofVerification;
|
|
301
|
+
const attestorAddresses = [...new Set([
|
|
302
|
+
...(configuredProofValidation?.attestorAddresses ?? []),
|
|
303
|
+
...(opts.attestorAddresses ?? []),
|
|
304
|
+
...jwksAttestorAddresses,
|
|
305
|
+
])];
|
|
306
|
+
const commonValidation = {
|
|
307
|
+
...configuredProofValidation,
|
|
308
|
+
...(opts.hashes ? { hashes: opts.hashes } : {}),
|
|
309
|
+
...(attestorAddresses.length
|
|
310
|
+
? { attestorAddresses }
|
|
311
|
+
: {}),
|
|
312
|
+
...(expectedSessionId
|
|
313
|
+
? { expectedSessionId }
|
|
314
|
+
: {}),
|
|
315
|
+
};
|
|
316
|
+
if (hasContentValidation(commonValidation)) {
|
|
317
|
+
await verifyLegacyProofGroup(proofGroups, commonValidation);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
await verifyByResolvedRecipes(commonValidation, expectedSessionId);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
283
323
|
if (!proofs.every((p) => p.proofValid)) {
|
|
284
324
|
return fail('invalid-proof', { proofs });
|
|
285
325
|
}
|
|
286
326
|
return { valid: true, payload, reclaimSessionId, proofs };
|
|
327
|
+
async function verifyLegacyProofGroup(group, validation) {
|
|
328
|
+
const legacyOutcome = await verifyProof(group.map(({ proof }) => proof), validation);
|
|
329
|
+
if (legacyOutcome.valid) {
|
|
330
|
+
for (const [index, item] of group.entries()) {
|
|
331
|
+
proofs[item.outcomeIndex].data = legacyOutcome.data?.[index];
|
|
332
|
+
proofs[item.outcomeIndex].publicData =
|
|
333
|
+
legacyOutcome.publicData?.[index];
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
for (const { outcomeIndex } of group) {
|
|
338
|
+
proofs[outcomeIndex].proofValid = false;
|
|
339
|
+
proofs[outcomeIndex].reason = legacyOutcome.reason;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function verifyByResolvedRecipes(common, expectedSessionId) {
|
|
343
|
+
let recipes = opts.proofRecipes;
|
|
344
|
+
if (!recipes && expectedSessionId && opts.resolveSession) {
|
|
345
|
+
try {
|
|
346
|
+
const resolved = await opts.resolveSession(expectedSessionId);
|
|
347
|
+
recipes = resolved.recipes;
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return fail('session-resolution-failed', { proofs });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const groups = Map.groupBy(proofGroups, proofGroupKey);
|
|
354
|
+
if (recipes && !recipeGroupsMatch(recipes, groups)) {
|
|
355
|
+
markInvalid(proofGroups, 'recipe-mismatch');
|
|
356
|
+
return fail('invalid-proof', { proofs });
|
|
357
|
+
}
|
|
358
|
+
for (const group of groups.values()) {
|
|
359
|
+
await verifyResolvedGroup(group, recipes, common);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async function verifyResolvedGroup(group, recipes, common) {
|
|
363
|
+
const providerId = group[0]?.providerId;
|
|
364
|
+
const providerVersion = group[0]?.providerVersion;
|
|
365
|
+
const providerValidation = providerId
|
|
366
|
+
? opts.proofValidationByProviderId?.[providerId]
|
|
367
|
+
: undefined;
|
|
368
|
+
const recipe = recipes?.find((candidate) => (candidate.providerId === providerId
|
|
369
|
+
&& candidate.resolvedVersion === providerVersion));
|
|
370
|
+
let hashes;
|
|
371
|
+
if (recipe) {
|
|
372
|
+
try {
|
|
373
|
+
hashes = proofHashesFromBuilderRecipe(recipe, group.map(({ proof }) => proof));
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
markInvalid(group, 'recipe-hash-failed');
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
await verifyLegacyProofGroup(group, {
|
|
381
|
+
...common,
|
|
382
|
+
...(recipe
|
|
383
|
+
? { hashes }
|
|
384
|
+
: providerId
|
|
385
|
+
? { providerId, providerVersion }
|
|
386
|
+
: {}),
|
|
387
|
+
...providerValidation,
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
function markInvalid(group, reason) {
|
|
391
|
+
for (const { outcomeIndex } of group) {
|
|
392
|
+
proofs[outcomeIndex].proofValid = false;
|
|
393
|
+
proofs[outcomeIndex].reason = reason;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
function hasContentValidation(config) {
|
|
398
|
+
return Boolean(config.hashes
|
|
399
|
+
|| config.providerId
|
|
400
|
+
|| config.dangerouslyDisableContentValidation);
|
|
401
|
+
}
|
|
402
|
+
function proofGroupKey(group) {
|
|
403
|
+
return `${group.providerId ?? ''}\u0000${group.providerVersion ?? ''}`;
|
|
404
|
+
}
|
|
405
|
+
function recipeGroupsMatch(recipes, groups) {
|
|
406
|
+
const expected = new Set(recipes.map((recipe) => (`${recipe.providerId}\u0000${recipe.resolvedVersion}`)));
|
|
407
|
+
return expected.size === groups.size
|
|
408
|
+
&& [...groups.keys()].every((key) => expected.has(key));
|
|
409
|
+
}
|
|
410
|
+
function isLegacyProof(value) {
|
|
411
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
const proof = value;
|
|
415
|
+
return typeof proof.identifier === 'string'
|
|
416
|
+
&& !!proof.claimData
|
|
417
|
+
&& typeof proof.claimData === 'object'
|
|
418
|
+
&& Array.isArray(proof.signatures)
|
|
419
|
+
&& Array.isArray(proof.witnesses)
|
|
420
|
+
&& 'extractedParameterValues' in proof;
|
|
421
|
+
}
|
|
422
|
+
function getVerificationStatus(payload) {
|
|
423
|
+
const session = payload.verification_session;
|
|
424
|
+
if (!session || typeof session !== 'object' || Array.isArray(session)) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
const status = session.status;
|
|
428
|
+
return typeof status === 'string' ? status : undefined;
|
|
429
|
+
}
|
|
430
|
+
function normalizeIssuer(issuer) {
|
|
431
|
+
return issuer.trim().replace(/\/+$/, '').toLowerCase();
|
|
432
|
+
}
|
|
433
|
+
function getVerificationClientId(payload) {
|
|
434
|
+
if (typeof payload.verificationClientId === 'string') {
|
|
435
|
+
return payload.verificationClientId;
|
|
436
|
+
}
|
|
437
|
+
if (typeof payload.verification_client_id === 'string') {
|
|
438
|
+
return payload.verification_client_id;
|
|
439
|
+
}
|
|
440
|
+
const session = payload.verification_session;
|
|
441
|
+
if (!session || typeof session !== 'object' || Array.isArray(session)) {
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
const sessionRecord = session;
|
|
445
|
+
const id = sessionRecord.verificationClientId
|
|
446
|
+
?? sessionRecord.verification_client_id;
|
|
447
|
+
return typeof id === 'string' ? id : undefined;
|
|
448
|
+
}
|
|
449
|
+
async function resolveTrustedIssuers(opts, verificationClientId) {
|
|
450
|
+
const explicit = [
|
|
451
|
+
opts.issuer,
|
|
452
|
+
opts.trustedIssuer,
|
|
453
|
+
...(opts.issuers ?? []),
|
|
454
|
+
...(opts.trustedIssuers ?? []),
|
|
455
|
+
].filter((issuer) => typeof issuer === 'string');
|
|
456
|
+
if (explicit.length) {
|
|
457
|
+
return [...new Set(explicit.map(normalizeIssuer))];
|
|
458
|
+
}
|
|
459
|
+
if (!verificationClientId) {
|
|
460
|
+
return [];
|
|
461
|
+
}
|
|
462
|
+
const registered = opts.issuersByVerificationClientId?.[verificationClientId] ?? [];
|
|
463
|
+
const resolve = opts.resolveIssuers ?? opts.issuerResolver;
|
|
464
|
+
const resolved = resolve
|
|
465
|
+
? await resolve(verificationClientId)
|
|
466
|
+
: [];
|
|
467
|
+
return [...new Set([...registered, ...resolved].map(normalizeIssuer))];
|
|
468
|
+
}
|
|
469
|
+
async function resolveTrustedJwksUrl(opts, verificationClientId) {
|
|
470
|
+
if (opts.jwksUrl) {
|
|
471
|
+
return opts.jwksUrl;
|
|
472
|
+
}
|
|
473
|
+
if (!verificationClientId) {
|
|
474
|
+
return undefined;
|
|
475
|
+
}
|
|
476
|
+
const registered = opts.jwksUrlsByVerificationClientId?.[verificationClientId];
|
|
477
|
+
return registered ?? await opts.resolveJwksUrl?.(verificationClientId);
|
|
287
478
|
}
|
|
288
479
|
/** Decrypt-and-verify in one step. */
|
|
289
480
|
export function verifyResult(jws, opts = {}) {
|
package/lib/routes.gen.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export declare const ROUTES: {
|
|
|
11
11
|
readonly method: "post";
|
|
12
12
|
readonly path: "/orgs/{orgId}/members";
|
|
13
13
|
};
|
|
14
|
+
readonly AddProviderContributionComment: {
|
|
15
|
+
readonly method: "post";
|
|
16
|
+
readonly path: "/providers/{providerId}/contributions/{campaignId}/comments";
|
|
17
|
+
};
|
|
14
18
|
readonly AddStaffMember: {
|
|
15
19
|
readonly method: "post";
|
|
16
20
|
readonly path: "/admin/staff";
|
|
@@ -83,6 +87,10 @@ export declare const ROUTES: {
|
|
|
83
87
|
readonly method: "post";
|
|
84
88
|
readonly path: "/admin/orgs/{orgId}/credits/{grantId}/void";
|
|
85
89
|
};
|
|
90
|
+
readonly BindVerificationSessionTeeNonce: {
|
|
91
|
+
readonly method: "put";
|
|
92
|
+
readonly path: "/verifications/sessions/{sessionId}/tee-nonce";
|
|
93
|
+
};
|
|
86
94
|
readonly CancelBillingSubscription: {
|
|
87
95
|
readonly method: "delete";
|
|
88
96
|
readonly path: "/orgs/{orgId}/billing/subscription";
|
|
@@ -143,10 +151,22 @@ export declare const ROUTES: {
|
|
|
143
151
|
readonly method: "post";
|
|
144
152
|
readonly path: "/providers";
|
|
145
153
|
};
|
|
154
|
+
readonly CreateProviderContributionCampaign: {
|
|
155
|
+
readonly method: "post";
|
|
156
|
+
readonly path: "/providers/{providerId}/contributions";
|
|
157
|
+
};
|
|
158
|
+
readonly CreateProviderContributionRequirementRevision: {
|
|
159
|
+
readonly method: "post";
|
|
160
|
+
readonly path: "/providers/{providerId}/contributions/{campaignId}/requirements";
|
|
161
|
+
};
|
|
146
162
|
readonly CreateProviderVersion: {
|
|
147
163
|
readonly method: "post";
|
|
148
164
|
readonly path: "/providers/{providerId}/versions";
|
|
149
165
|
};
|
|
166
|
+
readonly CreatePublicContributionAttempt: {
|
|
167
|
+
readonly method: "post";
|
|
168
|
+
readonly path: "/contribute/{publicId}";
|
|
169
|
+
};
|
|
150
170
|
readonly CreateTheme: {
|
|
151
171
|
readonly method: "post";
|
|
152
172
|
readonly path: "/orgs/{orgId}/themes";
|
|
@@ -279,6 +299,10 @@ export declare const ROUTES: {
|
|
|
279
299
|
readonly method: "get";
|
|
280
300
|
readonly path: "/providers/{providerId}/versions/{version}";
|
|
281
301
|
};
|
|
302
|
+
readonly GetPublicContributionCampaign: {
|
|
303
|
+
readonly method: "get";
|
|
304
|
+
readonly path: "/contribute/{publicId}";
|
|
305
|
+
};
|
|
282
306
|
readonly GetTheme: {
|
|
283
307
|
readonly method: "get";
|
|
284
308
|
readonly path: "/orgs/{orgId}/themes/{themeId}";
|
|
@@ -287,6 +311,10 @@ export declare const ROUTES: {
|
|
|
287
311
|
readonly method: "get";
|
|
288
312
|
readonly path: "/users/{userId}";
|
|
289
313
|
};
|
|
314
|
+
readonly GetVerificationFunnel: {
|
|
315
|
+
readonly method: "get";
|
|
316
|
+
readonly path: "/orgs/{orgId}/verification-funnel";
|
|
317
|
+
};
|
|
290
318
|
readonly GetVerificationRecipe: {
|
|
291
319
|
readonly method: "get";
|
|
292
320
|
readonly path: "/verifications/sessions/{sessionId}/recipe";
|
|
@@ -299,6 +327,10 @@ export declare const ROUTES: {
|
|
|
299
327
|
readonly method: "get";
|
|
300
328
|
readonly path: "/verifications/sessions/{sessionId}";
|
|
301
329
|
};
|
|
330
|
+
readonly ImportDevtoolsProvider: {
|
|
331
|
+
readonly method: "post";
|
|
332
|
+
readonly path: "/providers/import/devtools";
|
|
333
|
+
};
|
|
302
334
|
readonly Index: {
|
|
303
335
|
readonly method: "get";
|
|
304
336
|
readonly path: "/";
|
|
@@ -347,6 +379,10 @@ export declare const ROUTES: {
|
|
|
347
379
|
readonly method: "get";
|
|
348
380
|
readonly path: "/orgs/{orgId}/sessions";
|
|
349
381
|
};
|
|
382
|
+
readonly ListProviderContributionCampaigns: {
|
|
383
|
+
readonly method: "get";
|
|
384
|
+
readonly path: "/providers/{providerId}/contributions";
|
|
385
|
+
};
|
|
350
386
|
readonly ListProviderVersions: {
|
|
351
387
|
readonly method: "get";
|
|
352
388
|
readonly path: "/providers/{providerId}/versions";
|
|
@@ -391,6 +427,10 @@ export declare const ROUTES: {
|
|
|
391
427
|
readonly method: "get";
|
|
392
428
|
readonly path: "/orgs/{orgId}/invite";
|
|
393
429
|
};
|
|
430
|
+
readonly PatchVerificationClaimant: {
|
|
431
|
+
readonly method: "patch";
|
|
432
|
+
readonly path: "/verifications/sessions/{sessionId}/claimant";
|
|
433
|
+
};
|
|
394
434
|
readonly ProviderPreviewImage: {
|
|
395
435
|
readonly method: "get";
|
|
396
436
|
readonly path: "/providers/{providerId}/preview.png";
|
|
@@ -467,18 +507,22 @@ export declare const ROUTES: {
|
|
|
467
507
|
readonly method: "post";
|
|
468
508
|
readonly path: "/admin/billing/plans/{planId}/default";
|
|
469
509
|
};
|
|
470
|
-
readonly
|
|
471
|
-
readonly method: "post";
|
|
472
|
-
readonly path: "/admin/orgs/{orgId}/credits/grace";
|
|
473
|
-
};
|
|
474
|
-
readonly SetOrgGrace: {
|
|
510
|
+
readonly SetOrgCreditAllowance: {
|
|
475
511
|
readonly method: "post";
|
|
476
|
-
readonly path: "/admin/orgs/{orgId}/
|
|
512
|
+
readonly path: "/admin/orgs/{orgId}/credits/allowance";
|
|
477
513
|
};
|
|
478
514
|
readonly SetOrgKeypair: {
|
|
479
515
|
readonly method: "put";
|
|
480
516
|
readonly path: "/orgs/{orgId}/keypair";
|
|
481
517
|
};
|
|
518
|
+
readonly SetOrgPaymentAllowance: {
|
|
519
|
+
readonly method: "post";
|
|
520
|
+
readonly path: "/admin/orgs/{orgId}/billing/allowance";
|
|
521
|
+
};
|
|
522
|
+
readonly SetProviderContributionCampaignStatus: {
|
|
523
|
+
readonly method: "post";
|
|
524
|
+
readonly path: "/providers/{providerId}/contributions/{campaignId}";
|
|
525
|
+
};
|
|
482
526
|
readonly SetupBillingPlan: {
|
|
483
527
|
readonly method: "post";
|
|
484
528
|
readonly path: "/admin/billing/plans/setup";
|
|
@@ -539,6 +583,10 @@ export declare const ROUTES: {
|
|
|
539
583
|
readonly method: "post";
|
|
540
584
|
readonly path: "/providers/{providerId}/versions/{version}/review";
|
|
541
585
|
};
|
|
586
|
+
readonly SubmitPublicContributionFeedback: {
|
|
587
|
+
readonly method: "post";
|
|
588
|
+
readonly path: "/contribute/{publicId}/feedback";
|
|
589
|
+
};
|
|
542
590
|
readonly SubmitVerificationResult: {
|
|
543
591
|
readonly method: "post";
|
|
544
592
|
readonly path: "/verifications/sessions/{sessionId}/result";
|
|
@@ -567,6 +615,10 @@ export declare const ROUTES: {
|
|
|
567
615
|
readonly method: "patch";
|
|
568
616
|
readonly path: "/providers/{providerId}";
|
|
569
617
|
};
|
|
618
|
+
readonly UpdateProviderContributionCampaign: {
|
|
619
|
+
readonly method: "patch";
|
|
620
|
+
readonly path: "/providers/{providerId}/contributions/{campaignId}";
|
|
621
|
+
};
|
|
570
622
|
readonly UpdateProviderVersion: {
|
|
571
623
|
readonly method: "patch";
|
|
572
624
|
readonly path: "/providers/{providerId}/versions/{version}";
|
package/lib/routes.gen.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// AUTO-GENERATED by packages/app/scripts/mcp-tools-gen.ts
|
|
2
2
|
// from packages/app/openapi.yaml.
|
|
3
|
-
// Run `npm run openapi:
|
|
3
|
+
// Run `npm run openapi:gen --workspace=packages/app`
|
|
4
4
|
// to regenerate. Do not edit by hand.
|
|
5
5
|
export const ROUTES = {
|
|
6
6
|
"AcceptOrgInvite": { "method": "post", "path": "/orgs/{orgId}/invite" },
|
|
7
7
|
"ActivateFixWithAiRepair": { "method": "post", "path": "/v/{sessionId}/fix-with-ai/activate" },
|
|
8
8
|
"AddOrgMember": { "method": "post", "path": "/orgs/{orgId}/members" },
|
|
9
|
+
"AddProviderContributionComment": { "method": "post", "path": "/providers/{providerId}/contributions/{campaignId}/comments" },
|
|
9
10
|
"AddStaffMember": { "method": "post", "path": "/admin/staff" },
|
|
10
11
|
"AddVerificationClientKey": { "method": "post", "path": "/admin/verification-clients/{clientId}/keys" },
|
|
11
12
|
"AdminBillingPlans": { "method": "get", "path": "/admin/billing/plans" },
|
|
@@ -24,6 +25,7 @@ export const ROUTES = {
|
|
|
24
25
|
"AdminUsers": { "method": "get", "path": "/admin/users" },
|
|
25
26
|
"AdminVerificationClients": { "method": "get", "path": "/admin/verification-clients" },
|
|
26
27
|
"AdminVoidOrgCredit": { "method": "post", "path": "/admin/orgs/{orgId}/credits/{grantId}/void" },
|
|
28
|
+
"BindVerificationSessionTeeNonce": { "method": "put", "path": "/verifications/sessions/{sessionId}/tee-nonce" },
|
|
27
29
|
"CancelBillingSubscription": { "method": "delete", "path": "/orgs/{orgId}/billing/subscription" },
|
|
28
30
|
"CancelPublicListingRequest": { "method": "post", "path": "/providers/{providerId}/versions/{version}/cancel-review" },
|
|
29
31
|
"ChangeOrgPlan": { "method": "post", "path": "/orgs/{orgId}/billing/change-plan" },
|
|
@@ -39,7 +41,10 @@ export const ROUTES = {
|
|
|
39
41
|
"CreateOrg": { "method": "post", "path": "/orgs" },
|
|
40
42
|
"CreateOrgCallbackSubscription": { "method": "post", "path": "/orgs/{orgId}/callback-subscriptions" },
|
|
41
43
|
"CreateProvider": { "method": "post", "path": "/providers" },
|
|
44
|
+
"CreateProviderContributionCampaign": { "method": "post", "path": "/providers/{providerId}/contributions" },
|
|
45
|
+
"CreateProviderContributionRequirementRevision": { "method": "post", "path": "/providers/{providerId}/contributions/{campaignId}/requirements" },
|
|
42
46
|
"CreateProviderVersion": { "method": "post", "path": "/providers/{providerId}/versions" },
|
|
47
|
+
"CreatePublicContributionAttempt": { "method": "post", "path": "/contribute/{publicId}" },
|
|
43
48
|
"CreateTheme": { "method": "post", "path": "/orgs/{orgId}/themes" },
|
|
44
49
|
"CreateVerificationClient": { "method": "post", "path": "/admin/verification-clients" },
|
|
45
50
|
"CreateVerificationSession": { "method": "post", "path": "/verifications/sessions" },
|
|
@@ -73,11 +78,14 @@ export const ROUTES = {
|
|
|
73
78
|
"GetProvider": { "method": "get", "path": "/providers/{providerId}" },
|
|
74
79
|
"GetProviderBySlug": { "method": "get", "path": "/providers/{providerId}/{slug}" },
|
|
75
80
|
"GetProviderVersion": { "method": "get", "path": "/providers/{providerId}/versions/{version}" },
|
|
81
|
+
"GetPublicContributionCampaign": { "method": "get", "path": "/contribute/{publicId}" },
|
|
76
82
|
"GetTheme": { "method": "get", "path": "/orgs/{orgId}/themes/{themeId}" },
|
|
77
83
|
"GetUser": { "method": "get", "path": "/users/{userId}" },
|
|
84
|
+
"GetVerificationFunnel": { "method": "get", "path": "/orgs/{orgId}/verification-funnel" },
|
|
78
85
|
"GetVerificationRecipe": { "method": "get", "path": "/verifications/sessions/{sessionId}/recipe" },
|
|
79
86
|
"GetVerificationResult": { "method": "get", "path": "/verifications/sessions/{sessionId}/result" },
|
|
80
87
|
"GetVerificationSession": { "method": "get", "path": "/verifications/sessions/{sessionId}" },
|
|
88
|
+
"ImportDevtoolsProvider": { "method": "post", "path": "/providers/import/devtools" },
|
|
81
89
|
"Index": { "method": "get", "path": "/" },
|
|
82
90
|
"IssueOrgToken": { "method": "post", "path": "/orgs/{orgId}/token" },
|
|
83
91
|
"IssueVerificationClientToken": { "method": "post", "path": "/admin/verification-clients/{clientId}/tokens" },
|
|
@@ -90,6 +98,7 @@ export const ROUTES = {
|
|
|
90
98
|
"ListOrgTokens": { "method": "get", "path": "/orgs/{orgId}/token" },
|
|
91
99
|
"ListOrgTransactions": { "method": "get", "path": "/orgs/{orgId}/billing/transactions" },
|
|
92
100
|
"ListOrgVerificationSessions": { "method": "get", "path": "/orgs/{orgId}/sessions" },
|
|
101
|
+
"ListProviderContributionCampaigns": { "method": "get", "path": "/providers/{providerId}/contributions" },
|
|
93
102
|
"ListProviderVersions": { "method": "get", "path": "/providers/{providerId}/versions" },
|
|
94
103
|
"ListSessionCallbackKeys": { "method": "get", "path": "/verifications/sessions/{sessionId}/callback-keys" },
|
|
95
104
|
"ListStaffMembers": { "method": "get", "path": "/admin/staff" },
|
|
@@ -101,6 +110,7 @@ export const ROUTES = {
|
|
|
101
110
|
"MakePrivate": { "method": "post", "path": "/providers/{providerId}/make-private" },
|
|
102
111
|
"OpenApiSpec": { "method": "get", "path": "/openapi.yaml" },
|
|
103
112
|
"OrgInvitePage": { "method": "get", "path": "/orgs/{orgId}/invite" },
|
|
113
|
+
"PatchVerificationClaimant": { "method": "patch", "path": "/verifications/sessions/{sessionId}/claimant" },
|
|
104
114
|
"ProviderPreviewImage": { "method": "get", "path": "/providers/{providerId}/preview.png" },
|
|
105
115
|
"Providers": { "method": "get", "path": "/providers" },
|
|
106
116
|
"PublishProviderVersion": { "method": "post", "path": "/providers/{providerId}/versions/{version}/publish" },
|
|
@@ -120,9 +130,10 @@ export const ROUTES = {
|
|
|
120
130
|
"Robots": { "method": "get", "path": "/robots.txt" },
|
|
121
131
|
"SearchOrgMembers": { "method": "get", "path": "/orgs/{orgId}/members" },
|
|
122
132
|
"SetDefaultBillingPlan": { "method": "post", "path": "/admin/billing/plans/{planId}/default" },
|
|
123
|
-
"
|
|
124
|
-
"SetOrgGrace": { "method": "post", "path": "/admin/orgs/{orgId}/billing/grace" },
|
|
133
|
+
"SetOrgCreditAllowance": { "method": "post", "path": "/admin/orgs/{orgId}/credits/allowance" },
|
|
125
134
|
"SetOrgKeypair": { "method": "put", "path": "/orgs/{orgId}/keypair" },
|
|
135
|
+
"SetOrgPaymentAllowance": { "method": "post", "path": "/admin/orgs/{orgId}/billing/allowance" },
|
|
136
|
+
"SetProviderContributionCampaignStatus": { "method": "post", "path": "/providers/{providerId}/contributions/{campaignId}" },
|
|
126
137
|
"SetupBillingPlan": { "method": "post", "path": "/admin/billing/plans/setup" },
|
|
127
138
|
"SetupProviderCreate": { "method": "post", "path": "/providers/setup" },
|
|
128
139
|
"SiteAiProvider": { "method": "post", "path": "/site/{domain}/ai-provider" },
|
|
@@ -138,6 +149,7 @@ export const ROUTES = {
|
|
|
138
149
|
"StripeWebhook": { "method": "post", "path": "/billing/stripe/webhook" },
|
|
139
150
|
"SubmitConsent": { "method": "post", "path": "/oauth/consent" },
|
|
140
151
|
"SubmitProviderVersionForReview": { "method": "post", "path": "/providers/{providerId}/versions/{version}/review" },
|
|
152
|
+
"SubmitPublicContributionFeedback": { "method": "post", "path": "/contribute/{publicId}/feedback" },
|
|
141
153
|
"SubmitVerificationResult": { "method": "post", "path": "/verifications/sessions/{sessionId}/result" },
|
|
142
154
|
"TransferProvider": { "method": "post", "path": "/providers/{providerId}/transfer" },
|
|
143
155
|
"UpdateBillingPlan": { "method": "put", "path": "/admin/billing/plans/{planId}" },
|
|
@@ -145,6 +157,7 @@ export const ROUTES = {
|
|
|
145
157
|
"UpdateOrgIcon": { "method": "put", "path": "/orgs/{orgId}/icon" },
|
|
146
158
|
"UpdateOrgMember": { "method": "patch", "path": "/orgs/{orgId}/members/{memberId}" },
|
|
147
159
|
"UpdateProvider": { "method": "patch", "path": "/providers/{providerId}" },
|
|
160
|
+
"UpdateProviderContributionCampaign": { "method": "patch", "path": "/providers/{providerId}/contributions/{campaignId}" },
|
|
148
161
|
"UpdateProviderVersion": { "method": "patch", "path": "/providers/{providerId}/versions/{version}" },
|
|
149
162
|
"UpdateTheme": { "method": "patch", "path": "/orgs/{orgId}/themes/{themeId}" },
|
|
150
163
|
"UpdateVerificationClient": { "method": "put", "path": "/admin/verification-clients/{clientId}" },
|