@zkproofport-app/sdk 0.2.8 → 0.2.10

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/dist/index.js CHANGED
@@ -611,6 +611,70 @@ function validateMdlInputs(circuit, inputs) {
611
611
  }
612
612
  return null;
613
613
  }
614
+ /**
615
+ * Longest accepted `returnScheme` value.
616
+ * Kept in sync with proofport-relay `src/returnScheme.ts`.
617
+ */
618
+ const MAX_RETURN_SCHEME_LENGTH = 128;
619
+ /** RFC 3986 scheme (`ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )`) followed by exactly `://`. */
620
+ const BARE_SCHEME_RE = /^[a-z][a-z0-9+.-]*:\/\/$/;
621
+ /** `https://host[:port]` with no userinfo, path, query or fragment. */
622
+ const HTTPS_ORIGIN_RE = /^https:\/\/[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+(:[0-9]{1,5})?$/;
623
+ const DENIED_RETURN_SCHEMES = new Set([
624
+ 'about',
625
+ 'blob',
626
+ 'content',
627
+ 'data',
628
+ 'facetime',
629
+ 'facetime-audio',
630
+ 'file',
631
+ 'ftp',
632
+ 'http',
633
+ 'intent',
634
+ 'javascript',
635
+ 'jar',
636
+ 'mailto',
637
+ 'sms',
638
+ 'tel',
639
+ 'vbscript',
640
+ ]);
641
+ /**
642
+ * Validates a `returnScheme` before it is sent to the relay, so a malformed
643
+ * value fails fast in the integrator's own code instead of coming back as a
644
+ * relay 400. The relay re-validates and is the authority.
645
+ *
646
+ * @param value - Candidate return target
647
+ * @returns `null` when acceptable, otherwise a human-readable error message
648
+ *
649
+ * @internal
650
+ */
651
+ function validateReturnScheme(value) {
652
+ if (typeof value !== 'string') {
653
+ return 'returnScheme must be a string';
654
+ }
655
+ if (value.length === 0) {
656
+ return 'returnScheme must not be empty';
657
+ }
658
+ // Length is checked before any regex so a huge string never reaches the matcher.
659
+ if (value.length > MAX_RETURN_SCHEME_LENGTH) {
660
+ return `returnScheme must be at most ${MAX_RETURN_SCHEME_LENGTH} characters`;
661
+ }
662
+ if (/\s/.test(value)) {
663
+ return 'returnScheme must not contain whitespace';
664
+ }
665
+ const normalized = value.toLowerCase();
666
+ if (HTTPS_ORIGIN_RE.test(normalized)) {
667
+ return null;
668
+ }
669
+ if (!BARE_SCHEME_RE.test(normalized)) {
670
+ return 'returnScheme must be a bare custom scheme such as "mydapp://" or an https origin such as "https://myapp.com" — paths, query strings and fragments are not accepted';
671
+ }
672
+ const schemeName = normalized.slice(0, normalized.indexOf(':'));
673
+ if (DENIED_RETURN_SCHEMES.has(schemeName)) {
674
+ return `returnScheme "${schemeName}" is not allowed`;
675
+ }
676
+ return null;
677
+ }
614
678
  function validateProofRequest(request) {
615
679
  if (!request.requestId) {
616
680
  return { valid: false, error: 'Missing requestId' };
@@ -2137,6 +2201,14 @@ class ProofportSDK {
2137
2201
  throw new Error(`${mdlError} (circuit: ${circuit})`);
2138
2202
  }
2139
2203
  }
2204
+ // Return target: validated before we burn a challenge, so a typo surfaces
2205
+ // as a local error instead of a relay 400 on the second round trip.
2206
+ if (options.returnScheme !== undefined) {
2207
+ const returnSchemeError = validateReturnScheme(options.returnScheme);
2208
+ if (returnSchemeError) {
2209
+ throw new Error(returnSchemeError);
2210
+ }
2211
+ }
2140
2212
  // Get challenge + requestId from relay
2141
2213
  const { requestId, challenge } = await this.getChallenge();
2142
2214
  const body = {
@@ -2157,6 +2229,8 @@ class ProofportSDK {
2157
2229
  body.dappIcon = options.dappIcon;
2158
2230
  if (options.nonce)
2159
2231
  body.nonce = options.nonce;
2232
+ if (options.returnScheme)
2233
+ body.returnScheme = options.returnScheme;
2160
2234
  const response = await fetch(`${this.relayUrl}/api/v1/proof/request`, {
2161
2235
  method: 'POST',
2162
2236
  headers: {
@@ -2457,9 +2531,29 @@ class ProofportSDK {
2457
2531
  *
2458
2532
  * @param circuit - Circuit type identifier
2459
2533
  * @param inputs - Circuit-specific inputs
2460
- * @param options - Request options (message, dappName, dappIcon, nonce)
2534
+ * @param options - Request options (message, dappName, dappIcon, nonce, returnScheme)
2535
+ * @param options.returnScheme - Which app the ZKProofport app should switch back
2536
+ * to once it has finished. Put **your own** deep link scheme here — the bare
2537
+ * scheme your app registers, e.g. `'mydapp://'`. A web app can instead pass its
2538
+ * own https origin, e.g. `'https://myapp.com'`.
2539
+ *
2540
+ * This is intentionally **not** a URL and not a return address: no path, query
2541
+ * string or fragment is accepted, and the ZKProofport app never sends the proof
2542
+ * there. The proof still comes back to you the same way it always did — over the
2543
+ * relay, via `waitForProof()` / `waitForResult()`. `returnScheme` only answers
2544
+ * "which app should come back to the foreground", exactly like the
2545
+ * `redirect.native` value a wallet uses to hand control back after signing.
2546
+ *
2547
+ * **Omit it and nothing changes** — the user simply stays in the ZKProofport app
2548
+ * after the proof and switches back manually. There is no auto-switch on proof
2549
+ * failure either; only on success and on the user declining the request.
2550
+ *
2551
+ * Rejected with an error before the request is sent: empty or whitespace values,
2552
+ * anything longer than 128 characters, values containing a path/query/fragment,
2553
+ * and the `http:`, `file:`, `data:`, `javascript:`, `intent:`, `tel:`, `sms:`,
2554
+ * `mailto:` families.
2461
2555
  * @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
2462
- * @throws Error if signer not set or relay request fails
2556
+ * @throws Error if signer not set, returnScheme is malformed, or the relay request fails
2463
2557
  *
2464
2558
  * @example
2465
2559
  * ```typescript
@@ -2468,7 +2562,7 @@ class ProofportSDK {
2468
2562
  *
2469
2563
  * const relay = await sdk.createRelayRequest('coinbase_attestation', {
2470
2564
  * scope: 'myapp.com'
2471
- * }, { dappName: 'My DApp' });
2565
+ * }, { dappName: 'My DApp', returnScheme: 'mydapp://' });
2472
2566
  *
2473
2567
  * // Generate QR code from relay deep link
2474
2568
  * const qr = await sdk.generateQRCode(relay.deepLink);