@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.
Files changed (73) hide show
  1. package/README.md +634 -42
  2. package/lib/api-client.d.ts +31 -0
  3. package/lib/api-client.js +112 -0
  4. package/lib/api-consts.d.ts +4 -0
  5. package/lib/api-consts.js +4 -0
  6. package/lib/api-errors.d.ts +13 -0
  7. package/lib/api-errors.js +30 -0
  8. package/lib/api.d.ts +7 -0
  9. package/lib/api.js +3 -0
  10. package/lib/attestor-proof.d.ts +6 -0
  11. package/lib/attestor-proof.js +45 -18
  12. package/lib/client.d.ts +1 -6
  13. package/lib/client.js +12 -33
  14. package/lib/consts.d.ts +1 -1
  15. package/lib/consts.js +1 -1
  16. package/lib/eip191.d.ts +4 -2
  17. package/lib/eip191.js +17 -1
  18. package/lib/errors.d.ts +38 -4
  19. package/lib/errors.js +99 -16
  20. package/lib/index.d.ts +9 -7
  21. package/lib/index.js +8 -4
  22. package/lib/jwks.d.ts +25 -1
  23. package/lib/jwks.js +69 -4
  24. package/lib/legacy-proof.d.ts +57 -0
  25. package/lib/legacy-proof.js +211 -0
  26. package/lib/proof-hash.d.ts +35 -0
  27. package/lib/proof-hash.js +216 -0
  28. package/lib/proof-recipe.d.ts +18 -0
  29. package/lib/proof-recipe.js +37 -0
  30. package/lib/proof-trust-constants.d.ts +3 -0
  31. package/lib/proof-trust-constants.js +43 -0
  32. package/lib/proof-types.d.ts +62 -0
  33. package/lib/proof-types.js +1 -0
  34. package/lib/proof-verification-error.d.ts +13 -0
  35. package/lib/proof-verification-error.js +11 -0
  36. package/lib/reclaim.d.ts +27 -5
  37. package/lib/reclaim.js +140 -14
  38. package/lib/result.d.ts +58 -6
  39. package/lib/result.js +252 -61
  40. package/lib/routes.gen.d.ts +54 -6
  41. package/lib/routes.gen.js +15 -3
  42. package/lib/tee-binding.d.ts +82 -0
  43. package/lib/tee-binding.js +112 -0
  44. package/lib/types/openapi.gen.d.ts +1343 -206
  45. package/lib/verification-clients.d.ts +17 -0
  46. package/lib/verification-clients.js +14 -0
  47. package/lib/verify-attestor-tee.d.ts +76 -0
  48. package/lib/verify-attestor-tee.js +243 -0
  49. package/lib/verify-tee.d.ts +32 -0
  50. package/lib/verify-tee.js +347 -0
  51. package/package.json +5 -1
  52. package/src/api.ts +15 -0
  53. package/src/attestor-proof.ts +57 -20
  54. package/src/client.ts +15 -38
  55. package/src/consts.ts +1 -2
  56. package/src/eip191.ts +31 -3
  57. package/src/errors.ts +132 -18
  58. package/src/index.ts +50 -5
  59. package/src/jwks.ts +128 -5
  60. package/src/legacy-proof.ts +367 -0
  61. package/src/proof-hash.ts +316 -0
  62. package/src/proof-recipe.ts +75 -0
  63. package/src/proof-trust-constants.ts +45 -0
  64. package/src/proof-types.ts +57 -0
  65. package/src/proof-verification-error.ts +13 -0
  66. package/src/reclaim.ts +206 -19
  67. package/src/result.ts +403 -68
  68. package/src/routes.gen.ts +15 -3
  69. package/src/tee-binding.ts +192 -0
  70. package/src/types/openapi.gen.ts +1343 -206
  71. package/src/verification-clients.ts +22 -0
  72. package/src/verify-attestor-tee.ts +365 -0
  73. package/src/verify-tee.ts +507 -0
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Stateless helpers for registering an organization-owned, legacy-compatible
3
+ * TEE nonce with Builder after a verification session exists. The organization
4
+ * verification private key is used only locally: it derives the legacy app ID,
5
+ * produces the nonce, and signs the Builder registration payload.
6
+ */
7
+ import { keccak_256 } from '@noble/hashes/sha3.js'
8
+ import { signEip191 } from './eip191.ts'
9
+ import { bytesToHex } from './encoding.ts'
10
+ import { deriveFromPrivateKey } from './keypair.ts'
11
+
12
+ /** The exact domain used by the legacy JS SDK's hash-based TEE nonce. */
13
+ export const LEGACY_TEE_NONCE_DOMAIN = 'RECLAIM_TEE_NONCE_V1'
14
+ /** The version that legacy SDK clients put in `attestationNonceData`. */
15
+ export const LEGACY_TEE_ATTESTATION_VERSION = 'v3'
16
+ /** Domain for the authenticated, Builder-specific nonce registration. */
17
+ export const BUILDER_TEE_BINDING_DOMAIN = 'RECLAIM_BUILDER_TEE_BINDING_V1'
18
+
19
+ /** The exact nonce context shape preserved into an emitted legacy proof. */
20
+ export interface LegacyTeeNonceData {
21
+ applicationId: string
22
+ sessionId: string
23
+ /** Decimal Unix milliseconds. Do not convert to Unix seconds. */
24
+ timestamp: string
25
+ attestationVersion: typeof LEGACY_TEE_ATTESTATION_VERSION
26
+ }
27
+
28
+ /** A legacy nonce and its context, forwarded unchanged by a VC. */
29
+ export interface LegacyTeeNonceContext {
30
+ attestationNonce: string
31
+ attestationNonceData: LegacyTeeNonceData
32
+ }
33
+
34
+ export type LegacyTeeNonceMode = 'hash' | 'signature'
35
+
36
+ /** Fields authenticated when registering a TEE binding with Builder. */
37
+ export interface BuilderTeeBindingPayload extends LegacyTeeNonceContext {
38
+ organizationId: string
39
+ }
40
+
41
+ /** Builder registration data. `signature` is EIP-191 / `personal_sign`. */
42
+ export interface BuilderTeeBinding extends BuilderTeeBindingPayload {
43
+ payload: string
44
+ signature: string
45
+ }
46
+
47
+ /**
48
+ * Return the EIP-55 application ID a legacy verifier derives from an app
49
+ * secret. This is intentionally checksummed rather than the SDK's usual
50
+ * lowercase org address: the original SDK uses `ethers.Wallet(secret).address`.
51
+ */
52
+ export function legacyApplicationIdFromPrivateKey(privateKey: string): string {
53
+ const address = deriveFromPrivateKey(privateKey).address.slice(2)
54
+ const addressHash = bytesToHex(keccak_256(new TextEncoder().encode(address)))
55
+ const checksummed = [...address].map((char, index) => (
56
+ Number.parseInt(addressHash[index], 16) >= 8
57
+ ? char.toUpperCase()
58
+ : char
59
+ )).join('')
60
+
61
+ return '0x' + checksummed
62
+ }
63
+
64
+ /**
65
+ * Derive the exact 64-character lowercase nonce generated by the legacy SDK.
66
+ * `applicationId` is serialized byte-for-byte; it is deliberately not
67
+ * normalized here because legacy `generateAttestationNonce` does not normalize
68
+ * it either.
69
+ */
70
+ export function deriveLegacyTeeNonce(
71
+ appSecret: string,
72
+ data: Pick<LegacyTeeNonceData, 'applicationId' | 'sessionId' | 'timestamp'>,
73
+ ): string {
74
+ const payload = [
75
+ LEGACY_TEE_NONCE_DOMAIN,
76
+ data.applicationId,
77
+ data.sessionId,
78
+ data.timestamp,
79
+ appSecret,
80
+ ].join(':')
81
+ return bytesToHex(keccak_256(new TextEncoder().encode(payload)))
82
+ }
83
+
84
+ /**
85
+ * Produce the older legacy nonce: an EIP-191 signature over
86
+ * `keccak256(applicationId:sessionId:timestamp)`. This is a nonce encoding,
87
+ * not a TEE attestation-version number; v2 and v3 attestations can carry it.
88
+ */
89
+ export function deriveLegacySignatureTeeNonce(
90
+ appSecret: string,
91
+ data: Pick<LegacyTeeNonceData, 'applicationId' | 'sessionId' | 'timestamp'>,
92
+ ): string {
93
+ const message = [data.applicationId, data.sessionId, data.timestamp].join(':')
94
+ return signEip191(
95
+ keccak_256(new TextEncoder().encode(message)),
96
+ appSecret,
97
+ )
98
+ }
99
+
100
+ /**
101
+ * Create the legacy TEE context after Builder returns a session ID. Its
102
+ * application ID is derived from the same private key that later verifies the
103
+ * proof, so legacy TEE application binding succeeds without sending that key
104
+ * to Builder.
105
+ */
106
+ export function createLegacyTeeNonceContext(input: {
107
+ organizationVerificationPrivateKey: string
108
+ sessionId: string
109
+ /** Decimal Unix milliseconds, typically `Date.now().toString()`. */
110
+ timestamp: string
111
+ /** Defaults to the current hash nonce. Use `signature` for old clients. */
112
+ nonceMode?: LegacyTeeNonceMode
113
+ }): LegacyTeeNonceContext {
114
+ const attestationNonceData: LegacyTeeNonceData = {
115
+ applicationId: legacyApplicationIdFromPrivateKey(
116
+ input.organizationVerificationPrivateKey,
117
+ ),
118
+ sessionId: input.sessionId,
119
+ timestamp: input.timestamp,
120
+ attestationVersion: LEGACY_TEE_ATTESTATION_VERSION,
121
+ }
122
+ return {
123
+ attestationNonce: input.nonceMode === 'signature'
124
+ ? deriveLegacySignatureTeeNonce(
125
+ input.organizationVerificationPrivateKey,
126
+ attestationNonceData,
127
+ )
128
+ : deriveLegacyTeeNonce(
129
+ input.organizationVerificationPrivateKey,
130
+ attestationNonceData,
131
+ ),
132
+ attestationNonceData,
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Canonical payload for Builder TEE-binding registration. Every field is a
138
+ * string and the fixed field order avoids JSON canonicalization differences.
139
+ */
140
+ export function builderTeeBindingPayload(
141
+ payload: BuilderTeeBindingPayload,
142
+ ): string {
143
+ const { organizationId, attestationNonce, attestationNonceData } = payload
144
+ return [
145
+ BUILDER_TEE_BINDING_DOMAIN,
146
+ organizationId,
147
+ attestationNonceData.sessionId,
148
+ attestationNonceData.applicationId,
149
+ attestationNonceData.timestamp,
150
+ attestationNonceData.attestationVersion,
151
+ attestationNonce,
152
+ ].join(':')
153
+ }
154
+
155
+ /** Sign a canonical Builder TEE-binding payload using EIP-191.
156
+ * `personal_sign` callers can use the returned signature directly. */
157
+ export function signBuilderTeeBinding(
158
+ payload: BuilderTeeBindingPayload,
159
+ organizationVerificationPrivateKey: string,
160
+ ): string {
161
+ return signEip191(
162
+ builderTeeBindingPayload(payload),
163
+ organizationVerificationPrivateKey,
164
+ )
165
+ }
166
+
167
+ /**
168
+ * Create a nonce context and its signed Builder registration in one local,
169
+ * stateless operation. The private key appears only as a function input and is
170
+ * never included in the returned object.
171
+ */
172
+ export function createBuilderTeeBinding(input: {
173
+ organizationId: string
174
+ organizationVerificationPrivateKey: string
175
+ sessionId: string
176
+ timestamp: string
177
+ nonceMode?: LegacyTeeNonceMode
178
+ }): BuilderTeeBinding {
179
+ const context = createLegacyTeeNonceContext(input)
180
+ const payload: BuilderTeeBindingPayload = {
181
+ organizationId: input.organizationId,
182
+ ...context,
183
+ }
184
+ return {
185
+ ...payload,
186
+ payload: builderTeeBindingPayload(payload),
187
+ signature: signBuilderTeeBinding(
188
+ payload,
189
+ input.organizationVerificationPrivateKey,
190
+ ),
191
+ }
192
+ }