@reclaimprotocol/js-sdk 5.3.0-dev.1 → 5.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -701,6 +701,52 @@ const { isVerified } = await verifyProof(proof, {
701
701
  });
702
702
  ```
703
703
 
704
+ ### Replay Protection
705
+
706
+ Proofs are submitted by the user, so the server must not trust any field on the proof in isolation. `verifyProof` (and `verifyTeeAttestation`) cryptographically bind a proof to a specific session, but **the SDK is stateless** — it cannot tell whether the same valid proof has already been verified. Preventing replay is the caller's responsibility.
707
+
708
+ **What the SDK guarantees**
709
+
710
+ The `attestationNonce` baked into the proof context is computed as `keccak256("RECLAIM_TEE_NONCE_V1" : applicationId : sessionId : timestamp : appSecret)`. When you call `verifyProof` with `teeAttestation: { appSecret }`, the SDK:
711
+
712
+ - Recomputes the nonce from `(applicationId, sessionId, timestamp)` in the proof context using **your** `appSecret` and asserts it matches — only the holder of the app secret can mint a valid nonce, so the user cannot rebind a proof to a different `sessionId` or `applicationId`.
713
+ - Confirms the recomputed nonce appears in the TEE attestation token's `eat_nonce` (signed by Google's Confidential Computing OIDC issuer), so the TEE-signed binding cannot be forged either.
714
+ - Asserts the `applicationId` in the nonce data matches the address derived from `appSecret`, and that `sessionId` in the nonce data agrees with `reclaimSessionId` in `claimData.context` and `proxySessionId`/`sessionId` in `claimData.parameters`.
715
+ - Asserts `claimData.timestampS` is within 10 minutes of the nonce timestamp.
716
+
717
+ In short: the user cannot mutate `sessionId`, `applicationId`, or `timestamp` on a proof without invalidating it. They *can*, however, resubmit the same valid proof.
718
+
719
+ **What you must do on your server**
720
+
721
+ 1. **Use a session you initiated.** Call `ReclaimProofRequest.init(...)` and `getSessionId()` server-side (or record the `sessionId` returned to your callback). When verifying, reject any proof whose `sessionId` you did not issue.
722
+ 2. **Dedupe by `sessionId`.** Persist accepted `sessionId`s (e.g., a unique index in your DB or a TTL cache) and reject a `sessionId` that has already been verified. This is the primary replay defense.
723
+ 3. **Require `teeAttestation`** in `verifyProof` for any flow where replay or tampering matters — without it, the cryptographic binding to `appSecret` is not checked.
724
+ 4. **Enforce a freshness window.** Reject proofs whose `claimData.timestampS` is older than your business policy allows (the SDK only enforces a 10-minute skew between the nonce timestamp and claim timestamp, not absolute freshness).
725
+
726
+ ```javascript
727
+ // Pseudocode for a server-side verification handler
728
+ const expectedSessionId = await loadSessionForUser(req.user); // session you created
729
+ const sessionId = JSON.parse(proof.claimData.context).reclaimSessionId;
730
+
731
+ if (sessionId !== expectedSessionId) {
732
+ throw new Error("session mismatch");
733
+ }
734
+ if (await db.consumedSessions.has(sessionId)) {
735
+ throw new Error("proof already used"); // replay
736
+ }
737
+
738
+ const { isVerified, error } = await verifyProof(proof, {
739
+ ...providerVersion,
740
+ teeAttestation: { appSecret: process.env.APP_SECRET },
741
+ });
742
+ if (!isVerified) throw error;
743
+
744
+ await db.consumedSessions.add(sessionId); // mark consumed atomically
745
+ ```
746
+
747
+ > [!WARNING]
748
+ > Without server-side session tracking and dedup, a malicious user can submit the same valid proof repeatedly. The cryptographic checks in `verifyProof` are necessary but not sufficient for replay protection.
749
+
704
750
  ## TEE Attestation Verification
705
751
 
706
752
  The SDK supports verifying TEE (Trusted Execution Environment) attestations included in proofs. The attestation flow verifies the Google Confidential Computing OIDC token returned by Popcorn's GCP attestor and checks that it is bound to the proof nonce, application identity, and image digests.
package/dist/index.d.ts CHANGED
@@ -772,6 +772,13 @@ type ProviderHashRequirementsResponse = {
772
772
  * * `getProviderHashRequirementsFromSpec()` - To get the expected proof hash requirements from a provider spec.
773
773
  * * All 3 functions above are alternatives of each other and result from these functions can be directly used as `config` parameter in this function for proof validation.
774
774
  *
775
+ * Replay protection: this function is stateless. It verifies that a proof is cryptographically
776
+ * bound to a specific `sessionId`/`applicationId` (via the `appSecret`-keyed attestation nonce
777
+ * when `teeAttestation` is provided) but does not track which proofs have already been
778
+ * verified. Callers must (a) verify the proof's `sessionId` matches a session they initiated
779
+ * and (b) persist accepted `sessionId`s and reject duplicates. See the README's
780
+ * "Replay Protection" section for details.
781
+ *
775
782
  * @param proofOrProofs - A single proof object or an array of proof objects to be verified.
776
783
  * @param config - Verification configuration that specifies required hashes, allowed extra hashes, or disables content validation. Optionally includes `teeAttestation` to require TEE attestation verification.
777
784
  * @returns Verification result with `isVerified`, `isTeeAttestationVerified` (always boolean), extracted `data` from each proof, and optional `error` on failure. The application ID is derived from `appSecret` automatically.
@@ -892,6 +899,47 @@ declare class ReclaimProofRequest {
892
899
  * ```
893
900
  */
894
901
  static init(applicationId: string, appSecret: string, providerId: string, options?: ProofRequestOptions): Promise<ReclaimProofRequest>;
902
+ /**
903
+ * Initializes a new Reclaim proof request using a signature computed externally
904
+ * (e.g. on a trusted backend), so `appSecret` never has to live on the client.
905
+ *
906
+ * The signature must be produced over `canonicalize({ providerId, timestamp })`
907
+ * using the application's `appSecret` — see `generateInitSignature()` for the
908
+ * exact algorithm. The same `timestamp` used at signing time must be passed here.
909
+ *
910
+ * TEE attestation: the attestation nonce depends on `sessionId`, which is only
911
+ * known after the backend init call. To use TEE without exposing `appSecret`,
912
+ * pass an async `getAttestationNonce` callback that derives the nonce on your
913
+ * server using `generateAttestationNonce(appSecret, applicationId, sessionId, timestamp)`.
914
+ * If `acceptTeeAttestation` is left enabled but no callback is provided, init throws.
915
+ *
916
+ * @param applicationId - Your Reclaim application ID
917
+ * @param providerId - The ID of the provider to use for proof generation
918
+ * @param sessionAuth - Pre-computed signature, the timestamp it was signed over,
919
+ * and an optional async callback to compute the attestation nonce.
920
+ * @param options - Optional configuration options for the proof request
921
+ *
922
+ * @example
923
+ * ```typescript
924
+ * // Backend (Node):
925
+ * const timestamp = Date.now().toString();
926
+ * const signature = await generateInitSignature(APP_SECRET, providerId, timestamp);
927
+ * // ...return { signature, timestamp } to the client...
928
+ *
929
+ * // Client:
930
+ * const proofRequest = await ReclaimProofRequest.initWithSignature(
931
+ * applicationId,
932
+ * providerId,
933
+ * { signature, timestamp },
934
+ * { acceptTeeAttestation: false }
935
+ * );
936
+ * ```
937
+ */
938
+ static initWithSignature(applicationId: string, providerId: string, sessionAuth: {
939
+ signature: string;
940
+ timestamp: string;
941
+ getAttestationNonce?: (sessionId: string) => Promise<string> | string;
942
+ }, options?: ProofRequestOptions): Promise<ReclaimProofRequest>;
895
943
  /**
896
944
  * Creates a ReclaimProofRequest instance from a JSON string representation
897
945
  *
@@ -1171,6 +1219,7 @@ declare class ReclaimProofRequest {
1171
1219
  * ```
1172
1220
  */
1173
1221
  getSessionId(): string;
1222
+ private static validateInitOptions;
1174
1223
  private setSignature;
1175
1224
  private generateSignature;
1176
1225
  private clearInterval;
@@ -1456,6 +1505,22 @@ declare function updateSession(sessionId: string, status: SessionStatus): Promis
1456
1505
  declare function fetchStatusUrl(sessionId: string): Promise<StatusUrlResponse>;
1457
1506
  declare function fetchProviderConfigs(providerId: string, exactProviderVersionString: string | null | undefined, allowedTags: string[] | null | undefined): Promise<ProviderConfigResponse>;
1458
1507
 
1508
+ /**
1509
+ * Computes the signature required by `initSession` over `{providerId, timestamp}`.
1510
+ *
1511
+ * Use this on a trusted server (where `appSecret` lives) to produce a signature
1512
+ * that can then be passed to `ReclaimProofRequest.initWithSignature(...)` from a
1513
+ * client that never sees the secret.
1514
+ *
1515
+ * @param appSecret - The application secret (private key). Must remain server-side.
1516
+ * @param providerId - The provider id the session will be initialized against.
1517
+ * @param timestamp - The timestamp (ms epoch as string) that will be sent with init.
1518
+ * The same value MUST be passed to `initWithSignature`.
1519
+ */
1520
+ declare function generateInitSignature(appSecret: string, providerId: string, timestamp: string): Promise<string>;
1521
+
1522
+ declare function generateAttestationNonce(appSecret: string, applicationId: string, sessionId: string, timestamp: string): string;
1523
+
1459
1524
  declare function createSignDataForClaim(data: CompleteClaimData): string;
1460
1525
  declare function getIdentifierFromClaimInfo(info: ClaimInfo): ClaimID;
1461
1526
  /**
@@ -1509,6 +1574,10 @@ type TeeVerificationResult = {
1509
1574
  * was generated for your application.
1510
1575
  * Returns a result object with `isVerified` and an optional `error` message.
1511
1576
  *
1577
+ * This check is stateless and does not protect against replay of a previously
1578
+ * valid proof. Callers must enforce session matching and dedup `sessionId` on
1579
+ * their server. See the README's "Replay Protection" section.
1580
+ *
1512
1581
  * @param proof - The proof containing TEE attestation data
1513
1582
  * @param appSecret - Your application secret (Ethereum private key). Used to
1514
1583
  * derive the application ID and recompute the attestation nonce.
@@ -1565,4 +1634,4 @@ declare function isDesktopDevice(): boolean;
1565
1634
  */
1566
1635
  declare function clearDeviceCache(): void;
1567
1636
 
1568
- export { type Beacon, type BeaconState, type BodySniff, ClaimCreationType, type ClaimID, type ClaimInfo, type CompleteClaimData, type Context, type CreateVerificationRequest, DeviceType, type EmbeddedFlowHandle, type ExtensionMessage, type FlowHandle, type HashRequirement, type HashableHttpProviderClaimParams, type HttpFormEntry, type HttpProviderClaimParams, type HttpRedirectionMethod, type HttpRedirectionOptions, type InitSessionResponse, type InjectedRequestSpec, type InterceptorRequestSpec, type ModalOptions, type OnError, type OnSuccess, type Proof, type ProofPropertiesJSON, type ProofRequestOptions, type ProviderClaimData, type ProviderConfigResponse, type ProviderHashRequirementSpec, type ProviderHashRequirementsConfig, type ProviderHashRequirementsResponse, type ProviderVersionConfig, type ProviderVersionInfo, RECLAIM_EXTENSION_ACTIONS, type ReclaimFlowInitOptions, type ReclaimFlowLaunchOptions, ReclaimProofRequest, type ReclaimProviderConfig, type ReclaimProviderConfigWithRequestSpec, type RequestSpec, type ResponseMatchSpec, type ResponseRedactionSpec, SUPPORTED_TEE_ATTESTATION_VERSIONS, type SerializableModalOptions, SessionStatus, type SignedClaim, type StartSessionParams, type StatusUrlResponse, type TeeAttestation, type TeeAttestationConfig, type TeeAttestationVersion, TeeVerificationError, type TeeVerificationResult, type TemplateData, type TrustedData, type UpdateSessionResponse, type ValidationConfig, type ValidationConfigWithDisabledValidation, type ValidationConfigWithHash, type ValidationConfigWithProviderInformation, type VerificationConfig, type VerifyProofResult, type VerifyProofResultFailure, type VerifyProofResultSuccess, type WitnessData, assertValidProofsByHash, assertValidateProof, assertVerifiedProof, clearDeviceCache, createLinkWithTemplateData, createSignDataForClaim, fetchProviderConfigs, fetchProviderHashRequirementsBy, fetchStatusUrl, generateSpecsFromRequestSpecTemplate, getAttestors, getDeviceType, getHttpProviderClaimParamsFromProof, getIdentifierFromClaimInfo, getMobileDeviceType, getProviderHashRequirementSpecFromProviderConfig, getProviderHashRequirementsFromSpec, getProviderParamsAsCanonicalizedString, getShortenedUrl, hashProofClaimParams, hashRequestSpec, initSession, isDesktopDevice, isHttpProviderClaimParams, isMobileDevice, recoverSignersOfSignedClaim, runTeeVerification, takePairsWhereValueIsArray, takeTemplateParametersFromProofs, transformForOnchain, updateSession, verifyProof, verifyTeeAttestation };
1637
+ export { type Beacon, type BeaconState, type BodySniff, ClaimCreationType, type ClaimID, type ClaimInfo, type CompleteClaimData, type Context, type CreateVerificationRequest, DeviceType, type EmbeddedFlowHandle, type ExtensionMessage, type FlowHandle, type HashRequirement, type HashableHttpProviderClaimParams, type HttpFormEntry, type HttpProviderClaimParams, type HttpRedirectionMethod, type HttpRedirectionOptions, type InitSessionResponse, type InjectedRequestSpec, type InterceptorRequestSpec, type ModalOptions, type OnError, type OnSuccess, type Proof, type ProofPropertiesJSON, type ProofRequestOptions, type ProviderClaimData, type ProviderConfigResponse, type ProviderHashRequirementSpec, type ProviderHashRequirementsConfig, type ProviderHashRequirementsResponse, type ProviderVersionConfig, type ProviderVersionInfo, RECLAIM_EXTENSION_ACTIONS, type ReclaimFlowInitOptions, type ReclaimFlowLaunchOptions, ReclaimProofRequest, type ReclaimProviderConfig, type ReclaimProviderConfigWithRequestSpec, type RequestSpec, type ResponseMatchSpec, type ResponseRedactionSpec, SUPPORTED_TEE_ATTESTATION_VERSIONS, type SerializableModalOptions, SessionStatus, type SignedClaim, type StartSessionParams, type StatusUrlResponse, type TeeAttestation, type TeeAttestationConfig, type TeeAttestationVersion, TeeVerificationError, type TeeVerificationResult, type TemplateData, type TrustedData, type UpdateSessionResponse, type ValidationConfig, type ValidationConfigWithDisabledValidation, type ValidationConfigWithHash, type ValidationConfigWithProviderInformation, type VerificationConfig, type VerifyProofResult, type VerifyProofResultFailure, type VerifyProofResultSuccess, type WitnessData, assertValidProofsByHash, assertValidateProof, assertVerifiedProof, clearDeviceCache, createLinkWithTemplateData, createSignDataForClaim, fetchProviderConfigs, fetchProviderHashRequirementsBy, fetchStatusUrl, generateAttestationNonce, generateInitSignature, generateSpecsFromRequestSpecTemplate, getAttestors, getDeviceType, getHttpProviderClaimParamsFromProof, getIdentifierFromClaimInfo, getMobileDeviceType, getProviderHashRequirementSpecFromProviderConfig, getProviderHashRequirementsFromSpec, getProviderParamsAsCanonicalizedString, getShortenedUrl, hashProofClaimParams, hashRequestSpec, initSession, isDesktopDevice, isHttpProviderClaimParams, isMobileDevice, recoverSignersOfSignedClaim, runTeeVerification, takePairsWhereValueIsArray, takeTemplateParametersFromProofs, transformForOnchain, updateSession, verifyProof, verifyTeeAttestation };
package/dist/index.js CHANGED
@@ -84,7 +84,7 @@ var require_package = __commonJS({
84
84
  "package.json"(exports2, module2) {
85
85
  module2.exports = {
86
86
  name: "@reclaimprotocol/js-sdk",
87
- version: "5.3.0-dev.1",
87
+ version: "5.4.0",
88
88
  description: "Designed to request proofs from the Reclaim protocol and manage the flow of claims and witness interactions.",
89
89
  main: "dist/index.js",
90
90
  types: "dist/index.d.ts",
@@ -203,6 +203,8 @@ __export(index_exports, {
203
203
  fetchProviderConfigs: () => fetchProviderConfigs,
204
204
  fetchProviderHashRequirementsBy: () => fetchProviderHashRequirementsBy,
205
205
  fetchStatusUrl: () => fetchStatusUrl,
206
+ generateAttestationNonce: () => generateAttestationNonce,
207
+ generateInitSignature: () => generateInitSignature,
206
208
  generateSpecsFromRequestSpecTemplate: () => generateSpecsFromRequestSpecTemplate,
207
209
  getAttestors: () => getAttestors,
208
210
  getDeviceType: () => getDeviceType,
@@ -2255,81 +2257,7 @@ var ReclaimProofRequest = class _ReclaimProofRequest {
2255
2257
  { paramName: "providerId", input: providerId, isString: true },
2256
2258
  { paramName: "appSecret", input: appSecret, isString: true }
2257
2259
  ], "the constructor");
2258
- if (options) {
2259
- if (options.acceptAiProviders) {
2260
- validateFunctionParams([
2261
- { paramName: "acceptAiProviders", input: options.acceptAiProviders }
2262
- ], "the constructor");
2263
- }
2264
- if (options.providerVersion) {
2265
- validateFunctionParams([
2266
- { paramName: "providerVersion", input: options.providerVersion, isString: true }
2267
- ], "the constructor");
2268
- }
2269
- if (options.log) {
2270
- validateFunctionParams([
2271
- { paramName: "log", input: options.log }
2272
- ], "the constructor");
2273
- }
2274
- if (options.useAppClip) {
2275
- validateFunctionParams([
2276
- { paramName: "useAppClip", input: options.useAppClip }
2277
- ], "the constructor");
2278
- }
2279
- if (options.device) {
2280
- validateFunctionParams([
2281
- { paramName: "device", input: options.device, isString: true }
2282
- ], "the constructor");
2283
- }
2284
- if (options.useBrowserExtension) {
2285
- validateFunctionParams([
2286
- { paramName: "useBrowserExtension", input: options.useBrowserExtension }
2287
- ], "the constructor");
2288
- }
2289
- if (options.extensionID) {
2290
- validateFunctionParams([
2291
- { paramName: "extensionID", input: options.extensionID, isString: true }
2292
- ], "the constructor");
2293
- }
2294
- if (options.envUrl) {
2295
- validateFunctionParams([
2296
- { paramName: "envUrl", input: options.envUrl, isString: true }
2297
- ], "the constructor");
2298
- }
2299
- if (options.portalUrl) {
2300
- validateFunctionParams([
2301
- { paramName: "portalUrl", input: options.portalUrl, isString: true }
2302
- ], "the constructor");
2303
- }
2304
- if (options.customSharePageUrl) {
2305
- validateFunctionParams([
2306
- { paramName: "customSharePageUrl", input: options.customSharePageUrl, isString: true }
2307
- ], "the constructor");
2308
- }
2309
- if (options.customAppClipUrl) {
2310
- validateFunctionParams([
2311
- { paramName: "customAppClipUrl", input: options.customAppClipUrl, isString: true }
2312
- ], "the constructor");
2313
- }
2314
- if (options.preferredLocale) {
2315
- validateFunctionParams([
2316
- { paramName: "preferredLocale", input: options.preferredLocale, isString: true }
2317
- ], "the constructor");
2318
- validateFunctionParamsWithFn({
2319
- paramName: "preferredLocale",
2320
- input: options.preferredLocale,
2321
- isValid: () => {
2322
- try {
2323
- Intl.getCanonicalLocales(options.preferredLocale);
2324
- return true;
2325
- } catch (error) {
2326
- logger10.info("Failed to canonicalize locale", error);
2327
- return false;
2328
- }
2329
- }
2330
- }, "the constructor");
2331
- }
2332
- }
2260
+ _ReclaimProofRequest.validateInitOptions(options, "the constructor");
2333
2261
  const proofRequestOptions = __spreadProps(__spreadValues({}, options), {
2334
2262
  acceptTeeAttestation: (_a = options == null ? void 0 : options.acceptTeeAttestation) != null ? _a : true
2335
2263
  });
@@ -2362,6 +2290,95 @@ var ReclaimProofRequest = class _ReclaimProofRequest {
2362
2290
  }
2363
2291
  });
2364
2292
  }
2293
+ /**
2294
+ * Initializes a new Reclaim proof request using a signature computed externally
2295
+ * (e.g. on a trusted backend), so `appSecret` never has to live on the client.
2296
+ *
2297
+ * The signature must be produced over `canonicalize({ providerId, timestamp })`
2298
+ * using the application's `appSecret` — see `generateInitSignature()` for the
2299
+ * exact algorithm. The same `timestamp` used at signing time must be passed here.
2300
+ *
2301
+ * TEE attestation: the attestation nonce depends on `sessionId`, which is only
2302
+ * known after the backend init call. To use TEE without exposing `appSecret`,
2303
+ * pass an async `getAttestationNonce` callback that derives the nonce on your
2304
+ * server using `generateAttestationNonce(appSecret, applicationId, sessionId, timestamp)`.
2305
+ * If `acceptTeeAttestation` is left enabled but no callback is provided, init throws.
2306
+ *
2307
+ * @param applicationId - Your Reclaim application ID
2308
+ * @param providerId - The ID of the provider to use for proof generation
2309
+ * @param sessionAuth - Pre-computed signature, the timestamp it was signed over,
2310
+ * and an optional async callback to compute the attestation nonce.
2311
+ * @param options - Optional configuration options for the proof request
2312
+ *
2313
+ * @example
2314
+ * ```typescript
2315
+ * // Backend (Node):
2316
+ * const timestamp = Date.now().toString();
2317
+ * const signature = await generateInitSignature(APP_SECRET, providerId, timestamp);
2318
+ * // ...return { signature, timestamp } to the client...
2319
+ *
2320
+ * // Client:
2321
+ * const proofRequest = await ReclaimProofRequest.initWithSignature(
2322
+ * applicationId,
2323
+ * providerId,
2324
+ * { signature, timestamp },
2325
+ * { acceptTeeAttestation: false }
2326
+ * );
2327
+ * ```
2328
+ */
2329
+ static initWithSignature(applicationId, providerId, sessionAuth, options) {
2330
+ return __async(this, null, function* () {
2331
+ var _a;
2332
+ try {
2333
+ validateFunctionParams([
2334
+ { paramName: "applicationId", input: applicationId, isString: true },
2335
+ { paramName: "providerId", input: providerId, isString: true },
2336
+ { paramName: "signature", input: sessionAuth == null ? void 0 : sessionAuth.signature, isString: true },
2337
+ { paramName: "timestamp", input: sessionAuth == null ? void 0 : sessionAuth.timestamp, isString: true }
2338
+ ], "initWithSignature");
2339
+ _ReclaimProofRequest.validateInitOptions(options, "initWithSignature");
2340
+ const proofRequestOptions = __spreadProps(__spreadValues({}, options), {
2341
+ acceptTeeAttestation: (_a = options == null ? void 0 : options.acceptTeeAttestation) != null ? _a : true
2342
+ });
2343
+ if (proofRequestOptions.acceptTeeAttestation && !sessionAuth.getAttestationNonce) {
2344
+ throw new InvalidParamError(
2345
+ "initWithSignature requires a `getAttestationNonce` callback when `acceptTeeAttestation` is enabled. Either pass `acceptTeeAttestation: false`, or provide a callback that computes the nonce server-side using `generateAttestationNonce(appSecret, applicationId, sessionId, timestamp)`."
2346
+ );
2347
+ }
2348
+ const proofRequestInstance = new _ReclaimProofRequest(applicationId, providerId, proofRequestOptions);
2349
+ proofRequestInstance.timeStamp = sessionAuth.timestamp;
2350
+ proofRequestInstance.setSignature(sessionAuth.signature);
2351
+ const data = yield initSession(
2352
+ providerId,
2353
+ applicationId,
2354
+ sessionAuth.timestamp,
2355
+ sessionAuth.signature,
2356
+ options == null ? void 0 : options.providerVersion
2357
+ );
2358
+ proofRequestInstance.sessionId = data.sessionId;
2359
+ proofRequestInstance.resolvedProviderVersion = data.resolvedProviderVersion;
2360
+ proofRequestInstance.context.reclaimSessionId = data.sessionId;
2361
+ if (proofRequestOptions.acceptTeeAttestation && sessionAuth.getAttestationNonce) {
2362
+ const attestationNonce = yield sessionAuth.getAttestationNonce(data.sessionId);
2363
+ validateFunctionParams(
2364
+ [{ input: attestationNonce, paramName: "attestationNonce", isString: true }],
2365
+ "initWithSignature"
2366
+ );
2367
+ proofRequestInstance.setAttestationContext(attestationNonce, {
2368
+ applicationId,
2369
+ sessionId: data.sessionId,
2370
+ timestamp: sessionAuth.timestamp,
2371
+ attestationVersion: SDK_TEE_ATTESTATION_VERSION
2372
+ });
2373
+ }
2374
+ return proofRequestInstance;
2375
+ } catch (error) {
2376
+ console.error(error);
2377
+ logger10.info("Failed to initialize ReclaimProofRequest with signature", error);
2378
+ throw new InitError("Failed to initialize ReclaimProofRequest with signature", error);
2379
+ }
2380
+ });
2381
+ }
2365
2382
  /**
2366
2383
  * Creates a ReclaimProofRequest instance from a JSON string representation
2367
2384
  *
@@ -2855,6 +2872,58 @@ var ReclaimProofRequest = class _ReclaimProofRequest {
2855
2872
  }
2856
2873
  return this.sessionId;
2857
2874
  }
2875
+ static validateInitOptions(options, caller) {
2876
+ if (!options) return;
2877
+ if (options.acceptAiProviders) {
2878
+ validateFunctionParams([{ paramName: "acceptAiProviders", input: options.acceptAiProviders }], caller);
2879
+ }
2880
+ if (options.providerVersion) {
2881
+ validateFunctionParams([{ paramName: "providerVersion", input: options.providerVersion, isString: true }], caller);
2882
+ }
2883
+ if (options.log) {
2884
+ validateFunctionParams([{ paramName: "log", input: options.log }], caller);
2885
+ }
2886
+ if (options.useAppClip) {
2887
+ validateFunctionParams([{ paramName: "useAppClip", input: options.useAppClip }], caller);
2888
+ }
2889
+ if (options.device) {
2890
+ validateFunctionParams([{ paramName: "device", input: options.device, isString: true }], caller);
2891
+ }
2892
+ if (options.useBrowserExtension) {
2893
+ validateFunctionParams([{ paramName: "useBrowserExtension", input: options.useBrowserExtension }], caller);
2894
+ }
2895
+ if (options.extensionID) {
2896
+ validateFunctionParams([{ paramName: "extensionID", input: options.extensionID, isString: true }], caller);
2897
+ }
2898
+ if (options.envUrl) {
2899
+ validateFunctionParams([{ paramName: "envUrl", input: options.envUrl, isString: true }], caller);
2900
+ }
2901
+ if (options.portalUrl) {
2902
+ validateFunctionParams([{ paramName: "portalUrl", input: options.portalUrl, isString: true }], caller);
2903
+ }
2904
+ if (options.customSharePageUrl) {
2905
+ validateFunctionParams([{ paramName: "customSharePageUrl", input: options.customSharePageUrl, isString: true }], caller);
2906
+ }
2907
+ if (options.customAppClipUrl) {
2908
+ validateFunctionParams([{ paramName: "customAppClipUrl", input: options.customAppClipUrl, isString: true }], caller);
2909
+ }
2910
+ if (options.preferredLocale) {
2911
+ validateFunctionParams([{ paramName: "preferredLocale", input: options.preferredLocale, isString: true }], caller);
2912
+ validateFunctionParamsWithFn({
2913
+ paramName: "preferredLocale",
2914
+ input: options.preferredLocale,
2915
+ isValid: () => {
2916
+ try {
2917
+ Intl.getCanonicalLocales(options.preferredLocale);
2918
+ return true;
2919
+ } catch (error) {
2920
+ logger10.info("Failed to canonicalize locale", error);
2921
+ return false;
2922
+ }
2923
+ }
2924
+ }, caller);
2925
+ }
2926
+ }
2858
2927
  // Private helper methods
2859
2928
  setSignature(signature) {
2860
2929
  try {
@@ -3533,6 +3602,33 @@ var ReclaimProofRequest = class _ReclaimProofRequest {
3533
3602
  return this.jsonProofResponse;
3534
3603
  }
3535
3604
  };
3605
+
3606
+ // src/utils/signatureUtils.ts
3607
+ var import_ethers7 = require("ethers");
3608
+ var import_canonicalize4 = __toESM(require("canonicalize"));
3609
+ function generateInitSignature(appSecret, providerId, timestamp) {
3610
+ return __async(this, null, function* () {
3611
+ validateFunctionParams([
3612
+ { input: appSecret, paramName: "appSecret", isString: true },
3613
+ { input: providerId, paramName: "providerId", isString: true },
3614
+ { input: timestamp, paramName: "timestamp", isString: true }
3615
+ ], "generateInitSignature");
3616
+ try {
3617
+ const wallet = new import_ethers7.ethers.Wallet(appSecret);
3618
+ const canonicalData = (0, import_canonicalize4.default)({ providerId, timestamp });
3619
+ if (!canonicalData) {
3620
+ throw new SignatureGeneratingError("Failed to canonicalize data for signing.");
3621
+ }
3622
+ const messageHash = import_ethers7.ethers.keccak256(new TextEncoder().encode(canonicalData));
3623
+ return yield wallet.signMessage(import_ethers7.ethers.getBytes(messageHash));
3624
+ } catch (err) {
3625
+ throw new SignatureGeneratingError(
3626
+ `Error generating init signature for providerId: ${providerId}`,
3627
+ err
3628
+ );
3629
+ }
3630
+ });
3631
+ }
3536
3632
  // Annotate the CommonJS export names for ESM import in node:
3537
3633
  0 && (module.exports = {
3538
3634
  ReclaimProofRequest,
@@ -3546,6 +3642,8 @@ var ReclaimProofRequest = class _ReclaimProofRequest {
3546
3642
  fetchProviderConfigs,
3547
3643
  fetchProviderHashRequirementsBy,
3548
3644
  fetchStatusUrl,
3645
+ generateAttestationNonce,
3646
+ generateInitSignature,
3549
3647
  generateSpecsFromRequestSpecTemplate,
3550
3648
  getAttestors,
3551
3649
  getDeviceType,