@reclaimprotocol/client 0.1.27 → 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 +54 -6
- package/lib/routes.gen.js +15 -3
- package/lib/tee-binding.d.ts +82 -0
- package/lib/tee-binding.js +112 -0
- package/lib/types/openapi.gen.d.ts +1343 -206
- 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 +15 -3
- package/src/tee-binding.ts +192 -0
- package/src/types/openapi.gen.ts +1343 -206
- 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";
|
|
@@ -351,6 +379,10 @@ export declare const ROUTES: {
|
|
|
351
379
|
readonly method: "get";
|
|
352
380
|
readonly path: "/orgs/{orgId}/sessions";
|
|
353
381
|
};
|
|
382
|
+
readonly ListProviderContributionCampaigns: {
|
|
383
|
+
readonly method: "get";
|
|
384
|
+
readonly path: "/providers/{providerId}/contributions";
|
|
385
|
+
};
|
|
354
386
|
readonly ListProviderVersions: {
|
|
355
387
|
readonly method: "get";
|
|
356
388
|
readonly path: "/providers/{providerId}/versions";
|
|
@@ -395,6 +427,10 @@ export declare const ROUTES: {
|
|
|
395
427
|
readonly method: "get";
|
|
396
428
|
readonly path: "/orgs/{orgId}/invite";
|
|
397
429
|
};
|
|
430
|
+
readonly PatchVerificationClaimant: {
|
|
431
|
+
readonly method: "patch";
|
|
432
|
+
readonly path: "/verifications/sessions/{sessionId}/claimant";
|
|
433
|
+
};
|
|
398
434
|
readonly ProviderPreviewImage: {
|
|
399
435
|
readonly method: "get";
|
|
400
436
|
readonly path: "/providers/{providerId}/preview.png";
|
|
@@ -471,18 +507,22 @@ export declare const ROUTES: {
|
|
|
471
507
|
readonly method: "post";
|
|
472
508
|
readonly path: "/admin/billing/plans/{planId}/default";
|
|
473
509
|
};
|
|
474
|
-
readonly
|
|
510
|
+
readonly SetOrgCreditAllowance: {
|
|
475
511
|
readonly method: "post";
|
|
476
|
-
readonly path: "/admin/orgs/{orgId}/credits/
|
|
477
|
-
};
|
|
478
|
-
readonly SetOrgGrace: {
|
|
479
|
-
readonly method: "post";
|
|
480
|
-
readonly path: "/admin/orgs/{orgId}/billing/grace";
|
|
512
|
+
readonly path: "/admin/orgs/{orgId}/credits/allowance";
|
|
481
513
|
};
|
|
482
514
|
readonly SetOrgKeypair: {
|
|
483
515
|
readonly method: "put";
|
|
484
516
|
readonly path: "/orgs/{orgId}/keypair";
|
|
485
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
|
+
};
|
|
486
526
|
readonly SetupBillingPlan: {
|
|
487
527
|
readonly method: "post";
|
|
488
528
|
readonly path: "/admin/billing/plans/setup";
|
|
@@ -543,6 +583,10 @@ export declare const ROUTES: {
|
|
|
543
583
|
readonly method: "post";
|
|
544
584
|
readonly path: "/providers/{providerId}/versions/{version}/review";
|
|
545
585
|
};
|
|
586
|
+
readonly SubmitPublicContributionFeedback: {
|
|
587
|
+
readonly method: "post";
|
|
588
|
+
readonly path: "/contribute/{publicId}/feedback";
|
|
589
|
+
};
|
|
546
590
|
readonly SubmitVerificationResult: {
|
|
547
591
|
readonly method: "post";
|
|
548
592
|
readonly path: "/verifications/sessions/{sessionId}/result";
|
|
@@ -571,6 +615,10 @@ export declare const ROUTES: {
|
|
|
571
615
|
readonly method: "patch";
|
|
572
616
|
readonly path: "/providers/{providerId}";
|
|
573
617
|
};
|
|
618
|
+
readonly UpdateProviderContributionCampaign: {
|
|
619
|
+
readonly method: "patch";
|
|
620
|
+
readonly path: "/providers/{providerId}/contributions/{campaignId}";
|
|
621
|
+
};
|
|
574
622
|
readonly UpdateProviderVersion: {
|
|
575
623
|
readonly method: "patch";
|
|
576
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,8 +78,10 @@ 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}" },
|
|
@@ -91,6 +98,7 @@ export const ROUTES = {
|
|
|
91
98
|
"ListOrgTokens": { "method": "get", "path": "/orgs/{orgId}/token" },
|
|
92
99
|
"ListOrgTransactions": { "method": "get", "path": "/orgs/{orgId}/billing/transactions" },
|
|
93
100
|
"ListOrgVerificationSessions": { "method": "get", "path": "/orgs/{orgId}/sessions" },
|
|
101
|
+
"ListProviderContributionCampaigns": { "method": "get", "path": "/providers/{providerId}/contributions" },
|
|
94
102
|
"ListProviderVersions": { "method": "get", "path": "/providers/{providerId}/versions" },
|
|
95
103
|
"ListSessionCallbackKeys": { "method": "get", "path": "/verifications/sessions/{sessionId}/callback-keys" },
|
|
96
104
|
"ListStaffMembers": { "method": "get", "path": "/admin/staff" },
|
|
@@ -102,6 +110,7 @@ export const ROUTES = {
|
|
|
102
110
|
"MakePrivate": { "method": "post", "path": "/providers/{providerId}/make-private" },
|
|
103
111
|
"OpenApiSpec": { "method": "get", "path": "/openapi.yaml" },
|
|
104
112
|
"OrgInvitePage": { "method": "get", "path": "/orgs/{orgId}/invite" },
|
|
113
|
+
"PatchVerificationClaimant": { "method": "patch", "path": "/verifications/sessions/{sessionId}/claimant" },
|
|
105
114
|
"ProviderPreviewImage": { "method": "get", "path": "/providers/{providerId}/preview.png" },
|
|
106
115
|
"Providers": { "method": "get", "path": "/providers" },
|
|
107
116
|
"PublishProviderVersion": { "method": "post", "path": "/providers/{providerId}/versions/{version}/publish" },
|
|
@@ -121,9 +130,10 @@ export const ROUTES = {
|
|
|
121
130
|
"Robots": { "method": "get", "path": "/robots.txt" },
|
|
122
131
|
"SearchOrgMembers": { "method": "get", "path": "/orgs/{orgId}/members" },
|
|
123
132
|
"SetDefaultBillingPlan": { "method": "post", "path": "/admin/billing/plans/{planId}/default" },
|
|
124
|
-
"
|
|
125
|
-
"SetOrgGrace": { "method": "post", "path": "/admin/orgs/{orgId}/billing/grace" },
|
|
133
|
+
"SetOrgCreditAllowance": { "method": "post", "path": "/admin/orgs/{orgId}/credits/allowance" },
|
|
126
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}" },
|
|
127
137
|
"SetupBillingPlan": { "method": "post", "path": "/admin/billing/plans/setup" },
|
|
128
138
|
"SetupProviderCreate": { "method": "post", "path": "/providers/setup" },
|
|
129
139
|
"SiteAiProvider": { "method": "post", "path": "/site/{domain}/ai-provider" },
|
|
@@ -139,6 +149,7 @@ export const ROUTES = {
|
|
|
139
149
|
"StripeWebhook": { "method": "post", "path": "/billing/stripe/webhook" },
|
|
140
150
|
"SubmitConsent": { "method": "post", "path": "/oauth/consent" },
|
|
141
151
|
"SubmitProviderVersionForReview": { "method": "post", "path": "/providers/{providerId}/versions/{version}/review" },
|
|
152
|
+
"SubmitPublicContributionFeedback": { "method": "post", "path": "/contribute/{publicId}/feedback" },
|
|
142
153
|
"SubmitVerificationResult": { "method": "post", "path": "/verifications/sessions/{sessionId}/result" },
|
|
143
154
|
"TransferProvider": { "method": "post", "path": "/providers/{providerId}/transfer" },
|
|
144
155
|
"UpdateBillingPlan": { "method": "put", "path": "/admin/billing/plans/{planId}" },
|
|
@@ -146,6 +157,7 @@ export const ROUTES = {
|
|
|
146
157
|
"UpdateOrgIcon": { "method": "put", "path": "/orgs/{orgId}/icon" },
|
|
147
158
|
"UpdateOrgMember": { "method": "patch", "path": "/orgs/{orgId}/members/{memberId}" },
|
|
148
159
|
"UpdateProvider": { "method": "patch", "path": "/providers/{providerId}" },
|
|
160
|
+
"UpdateProviderContributionCampaign": { "method": "patch", "path": "/providers/{providerId}/contributions/{campaignId}" },
|
|
149
161
|
"UpdateProviderVersion": { "method": "patch", "path": "/providers/{providerId}/versions/{version}" },
|
|
150
162
|
"UpdateTheme": { "method": "patch", "path": "/orgs/{orgId}/themes/{themeId}" },
|
|
151
163
|
"UpdateVerificationClient": { "method": "put", "path": "/admin/verification-clients/{clientId}" },
|