@reclaimprotocol/client 0.1.28 → 0.1.31
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 +255 -234
- package/lib/api.d.ts +2 -0
- package/lib/api.js +2 -0
- package/lib/client.js +2 -0
- package/lib/enckeys.d.ts +1 -1
- package/lib/enckeys.js +2 -2
- package/lib/encoding.d.ts +4 -0
- package/lib/encoding.js +10 -0
- package/lib/feature-flags.d.ts +9 -0
- package/lib/feature-flags.js +19 -0
- package/lib/index.d.ts +4 -4
- package/lib/index.js +4 -4
- package/lib/jwks.d.ts +8 -8
- package/lib/jwks.js +38 -17
- package/lib/launch/destination.d.ts +14 -0
- package/lib/launch/destination.js +89 -0
- package/lib/launch/device.d.ts +30 -0
- package/lib/launch/device.js +168 -0
- package/lib/launch/environment.d.ts +224 -0
- package/lib/launch/environment.js +98 -0
- package/lib/launch/errors.d.ts +20 -0
- package/lib/launch/errors.js +25 -0
- package/lib/launch/extension.d.ts +42 -0
- package/lib/launch/extension.js +72 -0
- package/lib/launch/flow.d.ts +82 -0
- package/lib/launch/flow.js +222 -0
- package/lib/launch/index.d.ts +16 -0
- package/lib/launch/index.js +12 -0
- package/lib/launch/mobile.d.ts +77 -0
- package/lib/launch/mobile.js +124 -0
- package/lib/launch/modal.d.ts +50 -0
- package/lib/launch/modal.js +258 -0
- package/lib/launch/options.d.ts +74 -0
- package/lib/launch/options.js +20 -0
- package/lib/launch/portal.d.ts +28 -0
- package/lib/launch/portal.js +68 -0
- package/lib/launch/qr.d.ts +5 -0
- package/lib/launch/qr.js +28 -0
- package/lib/launch/target.d.ts +46 -0
- package/lib/launch/target.js +128 -0
- package/lib/launch/vendor/qrcodegen.d.ts +134 -0
- package/lib/launch/vendor/qrcodegen.js +822 -0
- package/lib/legacy-proof.d.ts +2 -0
- package/lib/legacy-proof.js +37 -7
- package/lib/proof-hash.d.ts +5 -5
- package/lib/proof-hash.js +1 -1
- package/lib/proof-recipe.d.ts +3 -3
- package/lib/proof-recipe.js +1 -1
- package/lib/proof-types.d.ts +35 -8
- package/lib/reclaim.d.ts +81 -70
- package/lib/reclaim.js +79 -130
- package/lib/request-proof.d.ts +60 -0
- package/lib/request-proof.js +241 -0
- package/lib/result.d.ts +46 -38
- package/lib/result.js +160 -100
- package/lib/routes.gen.d.ts +76 -28
- package/lib/routes.gen.js +24 -11
- package/lib/tee-binding.d.ts +1 -1
- package/lib/types/openapi.d.ts +1 -0
- package/lib/types/openapi.gen.d.ts +1594 -488
- package/lib/types/openapi.gen.js +5 -0
- package/lib/verification-clients.d.ts +28 -14
- package/lib/verification-clients.js +31 -11
- package/lib/verify-attestor-tee.d.ts +19 -2
- package/lib/verify-attestor-tee.js +40 -4
- package/lib/verify-tee.d.ts +10 -1
- package/lib/verify-tee.js +34 -10
- package/package.json +5 -1
- package/src/api.ts +9 -0
- package/src/client.ts +2 -0
- package/src/enckeys.ts +2 -2
- package/src/encoding.ts +12 -0
- package/src/feature-flags.ts +39 -0
- package/src/index.ts +13 -14
- package/src/jwks.ts +52 -30
- package/src/launch/destination.ts +111 -0
- package/src/launch/device.ts +242 -0
- package/src/launch/environment.ts +337 -0
- package/src/launch/errors.ts +49 -0
- package/src/launch/extension.ts +124 -0
- package/src/launch/flow.ts +369 -0
- package/src/launch/index.ts +42 -0
- package/src/launch/mobile.ts +184 -0
- package/src/launch/modal.ts +378 -0
- package/src/launch/options.ts +99 -0
- package/src/launch/portal.ts +104 -0
- package/src/launch/qr.ts +37 -0
- package/src/launch/target.ts +150 -0
- package/src/launch/vendor/qrcodegen.ts +1034 -0
- package/src/proof-hash.ts +6 -6
- package/src/proof-recipe.ts +3 -3
- package/src/proof-types.ts +36 -8
- package/src/reclaim.ts +185 -218
- package/src/{legacy-proof.ts → request-proof.ts} +81 -36
- package/src/result.ts +238 -172
- package/src/routes.gen.ts +24 -11
- package/src/tee-binding.ts +1 -1
- package/src/types/openapi.gen.ts +1599 -488
- package/src/types/openapi.ts +3 -1
- package/src/verification-clients.ts +33 -19
- package/src/verify-attestor-tee.ts +66 -8
- package/src/verify-tee.ts +44 -13
- package/lib/api-client.d.ts +0 -31
- package/lib/api-client.js +0 -112
- package/lib/api-consts.d.ts +0 -4
- package/lib/api-consts.js +0 -4
- package/lib/api-errors.d.ts +0 -13
- package/lib/api-errors.js +0 -30
- package/lib/eip712.d.ts +0 -20
- package/lib/eip712.js +0 -108
|
@@ -4,7 +4,7 @@ import { fetchReclaimJwks, trustedAttestorAddresses } from './jwks.ts'
|
|
|
4
4
|
import { assertValidProofHashes, getHashFromProof } from './proof-hash.ts'
|
|
5
5
|
import type {
|
|
6
6
|
HashRequirement,
|
|
7
|
-
|
|
7
|
+
ReclaimRequestProof,
|
|
8
8
|
TrustedData,
|
|
9
9
|
} from './proof-types.ts'
|
|
10
10
|
import {
|
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
} from './verify-attestor-tee.ts'
|
|
14
14
|
import { runTeeVerification, type TeeAttestationConfig } from './verify-tee.ts'
|
|
15
15
|
|
|
16
|
-
export type {
|
|
16
|
+
export type { ReclaimRequestProof } from './proof-types.ts'
|
|
17
17
|
|
|
18
|
-
/** A proof hash requirement accepted by
|
|
18
|
+
/** A proof hash requirement accepted by `verifyRequestProof`. */
|
|
19
19
|
export type ProofHashRequirement = string | HashRequirement
|
|
20
20
|
|
|
21
21
|
export interface ResolvedSessionProofValidation {
|
|
@@ -30,8 +30,9 @@ export interface ResolvedProviderProofValidation {
|
|
|
30
30
|
hashes: ProofHashRequirement[]
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/** Field names match the request spec a provider recipe declares, so a
|
|
34
|
+
* caller configuring verification reads the same vocabulary it authored. */
|
|
35
|
+
export interface VerifyRequestProofOptions {
|
|
35
36
|
hashes?: ProofHashRequirement[]
|
|
36
37
|
providerId?: string
|
|
37
38
|
providerVersion?: string
|
|
@@ -50,7 +51,7 @@ export interface LegacyVerifyProofOptions {
|
|
|
50
51
|
sessionId?: string
|
|
51
52
|
resolveSession?: (
|
|
52
53
|
sessionId: string,
|
|
53
|
-
proofs:
|
|
54
|
+
proofs: ReclaimRequestProof[],
|
|
54
55
|
) => Promise<ResolvedSessionProofValidation>
|
|
55
56
|
| ResolvedSessionProofValidation
|
|
56
57
|
/** Resolve an exact provider without coupling this verifier to HTTP. */
|
|
@@ -58,7 +59,7 @@ export interface LegacyVerifyProofOptions {
|
|
|
58
59
|
providerId: string,
|
|
59
60
|
providerVersion: string | undefined,
|
|
60
61
|
allowedTags: string[] | undefined,
|
|
61
|
-
proofs:
|
|
62
|
+
proofs: ReclaimRequestProof[],
|
|
62
63
|
) => Promise<ResolvedProviderProofValidation[]>
|
|
63
64
|
| ResolvedProviderProofValidation[]
|
|
64
65
|
expectedSessionId?: string
|
|
@@ -66,29 +67,31 @@ export interface LegacyVerifyProofOptions {
|
|
|
66
67
|
expectedContext?: Record<string, unknown>
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
export interface
|
|
70
|
+
export interface ReclaimRequestProofOutcome {
|
|
70
71
|
valid: boolean
|
|
71
72
|
reason?: string
|
|
72
73
|
proofHashes?: string[]
|
|
73
74
|
isTeeAttestationVerified?: boolean
|
|
75
|
+
/** True when at least one witness's `attestation_report` verified; false
|
|
76
|
+
* when the check ran and no witness carried one. */
|
|
74
77
|
isAttestorTeeAttestationVerified?: boolean
|
|
75
78
|
data?: TrustedData[]
|
|
76
79
|
publicData?: unknown[]
|
|
77
80
|
}
|
|
78
81
|
|
|
79
|
-
/** Return the provider hashes encoded in an exact
|
|
80
|
-
export function proofHashes(proof:
|
|
82
|
+
/** Return the provider hashes encoded in an exact request proof. */
|
|
83
|
+
export function proofHashes(proof: ReclaimRequestProof): string[] {
|
|
81
84
|
return getHashFromProof(proof)
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/**
|
|
85
|
-
* Verify exact
|
|
88
|
+
* Verify exact request proofs without depending on `@reclaimprotocol/js-sdk`.
|
|
86
89
|
* The signed claim is never renamed or reconstructed.
|
|
87
90
|
*/
|
|
88
|
-
export async function
|
|
89
|
-
proofOrProofs:
|
|
90
|
-
config:
|
|
91
|
-
): Promise<
|
|
91
|
+
export async function verifyRequestProof(
|
|
92
|
+
proofOrProofs: ReclaimRequestProof | ReclaimRequestProof[],
|
|
93
|
+
config: VerifyRequestProofOptions,
|
|
94
|
+
): Promise<ReclaimRequestProofOutcome> {
|
|
92
95
|
const proofs = Array.isArray(proofOrProofs) ? proofOrProofs : [proofOrProofs]
|
|
93
96
|
if(!proofs.length) {
|
|
94
97
|
return { valid: false, reason: 'no-proofs' }
|
|
@@ -97,8 +100,8 @@ export async function verifyProof(
|
|
|
97
100
|
try {
|
|
98
101
|
const effective = await resolveValidation(config, proofs)
|
|
99
102
|
assertSessionAndContext(proofs, effective)
|
|
100
|
-
const
|
|
101
|
-
assertVerifiedSignatures(proofs,
|
|
103
|
+
const trust = await resolveAttestorTrust(effective)
|
|
104
|
+
assertVerifiedSignatures(proofs, trust.addresses)
|
|
102
105
|
await assertContent(proofs, effective)
|
|
103
106
|
|
|
104
107
|
let isTeeAttestationVerified: boolean | undefined
|
|
@@ -108,12 +111,20 @@ export async function verifyProof(
|
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
let isAttestorTeeAttestationVerified: boolean | undefined
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
const attestorTeeAttestation = resolveAttestorTeeAttestation(
|
|
115
|
+
effective.attestorTeeAttestation,
|
|
116
|
+
trust.imageDigests,
|
|
117
|
+
)
|
|
118
|
+
if(attestorTeeAttestation) {
|
|
119
|
+
// `verified` counts witnesses whose attestation report was checked.
|
|
120
|
+
// A proof whose witnesses carry no report still passes the address
|
|
121
|
+
// and signature bindings, but nothing was attested — say so rather
|
|
122
|
+
// than reporting a TEE attestation that never happened.
|
|
123
|
+
const summary = await runAttestorTeeVerification(
|
|
113
124
|
proofs,
|
|
114
|
-
|
|
125
|
+
attestorTeeAttestation,
|
|
115
126
|
)
|
|
116
|
-
isAttestorTeeAttestationVerified =
|
|
127
|
+
isAttestorTeeAttestationVerified = summary.verified > 0
|
|
117
128
|
}
|
|
118
129
|
|
|
119
130
|
return {
|
|
@@ -133,8 +144,8 @@ export async function verifyProof(
|
|
|
133
144
|
}
|
|
134
145
|
|
|
135
146
|
async function resolveValidation(
|
|
136
|
-
config:
|
|
137
|
-
proofs:
|
|
147
|
+
config: VerifyRequestProofOptions,
|
|
148
|
+
proofs: ReclaimRequestProof[],
|
|
138
149
|
) {
|
|
139
150
|
let effective = config
|
|
140
151
|
if(config.sessionId && !hasContentValidation(config)) {
|
|
@@ -151,8 +162,9 @@ async function resolveValidation(
|
|
|
151
162
|
return effective
|
|
152
163
|
}
|
|
153
164
|
|
|
154
|
-
async function
|
|
165
|
+
async function resolveAttestorTrust(config: VerifyRequestProofOptions) {
|
|
155
166
|
const addresses = config.attestorAddresses?.map(normalized) ?? []
|
|
167
|
+
const imageDigests: string[] = []
|
|
156
168
|
if(config.attestorJwksUrl) {
|
|
157
169
|
const registry = await fetchReclaimJwks(
|
|
158
170
|
config.attestorJwksUrl,
|
|
@@ -162,6 +174,9 @@ async function resolveTrustedAttestors(config: LegacyVerifyProofOptions) {
|
|
|
162
174
|
...(registry['x-reclaim-attestors'] ?? []),
|
|
163
175
|
...trustedAttestorAddresses(registry.keys),
|
|
164
176
|
)
|
|
177
|
+
imageDigests.push(
|
|
178
|
+
...(registry['x-reclaim-attestor-image-digests'] ?? []),
|
|
179
|
+
)
|
|
165
180
|
}
|
|
166
181
|
|
|
167
182
|
const unique = [...new Set(addresses)]
|
|
@@ -169,11 +184,41 @@ async function resolveTrustedAttestors(config: LegacyVerifyProofOptions) {
|
|
|
169
184
|
throw new Error('attestor-trust-required')
|
|
170
185
|
}
|
|
171
186
|
|
|
172
|
-
return
|
|
187
|
+
return {
|
|
188
|
+
addresses: unique,
|
|
189
|
+
imageDigests: [...new Set(imageDigests)],
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function resolveAttestorTeeAttestation(
|
|
194
|
+
configured: AttestorTeeAttestationConfig | undefined,
|
|
195
|
+
registryImageDigests: string[],
|
|
196
|
+
): AttestorTeeAttestationConfig | undefined {
|
|
197
|
+
if(!registryImageDigests.length) {
|
|
198
|
+
return configured
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const configuredDigests = configured?.expectedImageDigests
|
|
202
|
+
if(configuredDigests?.length) {
|
|
203
|
+
const registry = new Set(registryImageDigests)
|
|
204
|
+
const expectedImageDigests = [...new Set(configuredDigests
|
|
205
|
+
.map((digest) => digest.trim().toLowerCase())
|
|
206
|
+
.filter((digest) => registry.has(digest)))]
|
|
207
|
+
if(!expectedImageDigests.length) {
|
|
208
|
+
throw new Error('attestor-image-trust-mismatch')
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return { ...configured, expectedImageDigests }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
...configured,
|
|
216
|
+
expectedImageDigests: registryImageDigests,
|
|
217
|
+
}
|
|
173
218
|
}
|
|
174
219
|
|
|
175
220
|
function assertVerifiedSignatures(
|
|
176
|
-
proofs:
|
|
221
|
+
proofs: ReclaimRequestProof[],
|
|
177
222
|
trustedAttestors: string[],
|
|
178
223
|
) {
|
|
179
224
|
for(const proof of proofs) {
|
|
@@ -201,8 +246,8 @@ function assertVerifiedSignatures(
|
|
|
201
246
|
}
|
|
202
247
|
|
|
203
248
|
async function assertContent(
|
|
204
|
-
proofs:
|
|
205
|
-
config:
|
|
249
|
+
proofs: ReclaimRequestProof[],
|
|
250
|
+
config: VerifyRequestProofOptions,
|
|
206
251
|
) {
|
|
207
252
|
if(config.dangerouslyDisableContentValidation) {
|
|
208
253
|
return
|
|
@@ -245,8 +290,8 @@ async function assertContent(
|
|
|
245
290
|
}
|
|
246
291
|
|
|
247
292
|
function assertSessionAndContext(
|
|
248
|
-
proofs:
|
|
249
|
-
config:
|
|
293
|
+
proofs: ReclaimRequestProof[],
|
|
294
|
+
config: VerifyRequestProofOptions,
|
|
250
295
|
) {
|
|
251
296
|
const expectedSessionId = config.sessionId ?? config.expectedSessionId
|
|
252
297
|
for(const proof of proofs) {
|
|
@@ -267,7 +312,7 @@ function assertSessionAndContext(
|
|
|
267
312
|
}
|
|
268
313
|
}
|
|
269
314
|
|
|
270
|
-
function trustedData(proof:
|
|
315
|
+
function trustedData(proof: ReclaimRequestProof): TrustedData {
|
|
271
316
|
const context = contextFrom(proof)
|
|
272
317
|
const extractedParameters = isRecord(context.extractedParameters)
|
|
273
318
|
? Object.fromEntries(Object.entries(context.extractedParameters).map(
|
|
@@ -279,7 +324,7 @@ function trustedData(proof: LegacyProof): TrustedData {
|
|
|
279
324
|
}
|
|
280
325
|
|
|
281
326
|
function collectProofHashes(
|
|
282
|
-
proofs:
|
|
327
|
+
proofs: ReclaimRequestProof[],
|
|
283
328
|
hasNoPii: true | undefined,
|
|
284
329
|
): string[] | undefined {
|
|
285
330
|
try {
|
|
@@ -289,7 +334,7 @@ function collectProofHashes(
|
|
|
289
334
|
}
|
|
290
335
|
}
|
|
291
336
|
|
|
292
|
-
function hasContentValidation(config:
|
|
337
|
+
function hasContentValidation(config: VerifyRequestProofOptions): boolean {
|
|
293
338
|
return Boolean(
|
|
294
339
|
config.hashes
|
|
295
340
|
|| config.providerId
|
|
@@ -315,7 +360,7 @@ function normalized(value: string): string {
|
|
|
315
360
|
return value.trim().toLowerCase()
|
|
316
361
|
}
|
|
317
362
|
|
|
318
|
-
function contextFrom(proof:
|
|
363
|
+
function contextFrom(proof: ReclaimRequestProof): Record<string, unknown> {
|
|
319
364
|
const raw = proof.claimData.context
|
|
320
365
|
if(!raw) {
|
|
321
366
|
return {}
|
|
@@ -329,7 +374,7 @@ function contextFrom(proof: LegacyProof): Record<string, unknown> {
|
|
|
329
374
|
}
|
|
330
375
|
}
|
|
331
376
|
|
|
332
|
-
function sessionIds(proof:
|
|
377
|
+
function sessionIds(proof: ReclaimRequestProof): string[] {
|
|
333
378
|
const context = contextFrom(proof)
|
|
334
379
|
const ids = [context.reclaimSessionId]
|
|
335
380
|
try {
|
|
@@ -349,7 +394,7 @@ function sessionIds(proof: LegacyProof): string[] {
|
|
|
349
394
|
}
|
|
350
395
|
|
|
351
396
|
function contextMatches(
|
|
352
|
-
proof:
|
|
397
|
+
proof: ReclaimRequestProof,
|
|
353
398
|
expected?: Record<string, unknown>,
|
|
354
399
|
): boolean {
|
|
355
400
|
if(!expected) {
|