@zkproofport-app/sdk 0.2.8 → 0.2.9

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.mjs CHANGED
@@ -606,6 +606,70 @@ function validateMdlInputs(circuit, inputs) {
606
606
  }
607
607
  return null;
608
608
  }
609
+ /**
610
+ * Longest accepted `returnScheme` value.
611
+ * Kept in sync with proofport-relay `src/returnScheme.ts`.
612
+ */
613
+ const MAX_RETURN_SCHEME_LENGTH = 128;
614
+ /** RFC 3986 scheme (`ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )`) followed by exactly `://`. */
615
+ const BARE_SCHEME_RE = /^[a-z][a-z0-9+.-]*:\/\/$/;
616
+ /** `https://host[:port]` with no userinfo, path, query or fragment. */
617
+ 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})?$/;
618
+ const DENIED_RETURN_SCHEMES = new Set([
619
+ 'about',
620
+ 'blob',
621
+ 'content',
622
+ 'data',
623
+ 'facetime',
624
+ 'facetime-audio',
625
+ 'file',
626
+ 'ftp',
627
+ 'http',
628
+ 'intent',
629
+ 'javascript',
630
+ 'jar',
631
+ 'mailto',
632
+ 'sms',
633
+ 'tel',
634
+ 'vbscript',
635
+ ]);
636
+ /**
637
+ * Validates a `returnScheme` before it is sent to the relay, so a malformed
638
+ * value fails fast in the integrator's own code instead of coming back as a
639
+ * relay 400. The relay re-validates and is the authority.
640
+ *
641
+ * @param value - Candidate return target
642
+ * @returns `null` when acceptable, otherwise a human-readable error message
643
+ *
644
+ * @internal
645
+ */
646
+ function validateReturnScheme(value) {
647
+ if (typeof value !== 'string') {
648
+ return 'returnScheme must be a string';
649
+ }
650
+ if (value.length === 0) {
651
+ return 'returnScheme must not be empty';
652
+ }
653
+ // Length is checked before any regex so a huge string never reaches the matcher.
654
+ if (value.length > MAX_RETURN_SCHEME_LENGTH) {
655
+ return `returnScheme must be at most ${MAX_RETURN_SCHEME_LENGTH} characters`;
656
+ }
657
+ if (/\s/.test(value)) {
658
+ return 'returnScheme must not contain whitespace';
659
+ }
660
+ const normalized = value.toLowerCase();
661
+ if (HTTPS_ORIGIN_RE.test(normalized)) {
662
+ return null;
663
+ }
664
+ if (!BARE_SCHEME_RE.test(normalized)) {
665
+ 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';
666
+ }
667
+ const schemeName = normalized.slice(0, normalized.indexOf(':'));
668
+ if (DENIED_RETURN_SCHEMES.has(schemeName)) {
669
+ return `returnScheme "${schemeName}" is not allowed`;
670
+ }
671
+ return null;
672
+ }
609
673
  function validateProofRequest(request) {
610
674
  if (!request.requestId) {
611
675
  return { valid: false, error: 'Missing requestId' };
@@ -4999,6 +5063,14 @@ class ProofportSDK {
4999
5063
  throw new Error(`${mdlError} (circuit: ${circuit})`);
5000
5064
  }
5001
5065
  }
5066
+ // Return target: validated before we burn a challenge, so a typo surfaces
5067
+ // as a local error instead of a relay 400 on the second round trip.
5068
+ if (options.returnScheme !== undefined) {
5069
+ const returnSchemeError = validateReturnScheme(options.returnScheme);
5070
+ if (returnSchemeError) {
5071
+ throw new Error(returnSchemeError);
5072
+ }
5073
+ }
5002
5074
  // Get challenge + requestId from relay
5003
5075
  const { requestId, challenge } = await this.getChallenge();
5004
5076
  const body = {
@@ -5019,6 +5091,8 @@ class ProofportSDK {
5019
5091
  body.dappIcon = options.dappIcon;
5020
5092
  if (options.nonce)
5021
5093
  body.nonce = options.nonce;
5094
+ if (options.returnScheme)
5095
+ body.returnScheme = options.returnScheme;
5022
5096
  const response = await fetch(`${this.relayUrl}/api/v1/proof/request`, {
5023
5097
  method: 'POST',
5024
5098
  headers: {
@@ -5319,9 +5393,29 @@ class ProofportSDK {
5319
5393
  *
5320
5394
  * @param circuit - Circuit type identifier
5321
5395
  * @param inputs - Circuit-specific inputs
5322
- * @param options - Request options (message, dappName, dappIcon, nonce)
5396
+ * @param options - Request options (message, dappName, dappIcon, nonce, returnScheme)
5397
+ * @param options.returnScheme - Which app the ZKProofport app should switch back
5398
+ * to once it has finished. Put **your own** deep link scheme here — the bare
5399
+ * scheme your app registers, e.g. `'mydapp://'`. A web app can instead pass its
5400
+ * own https origin, e.g. `'https://myapp.com'`.
5401
+ *
5402
+ * This is intentionally **not** a URL and not a return address: no path, query
5403
+ * string or fragment is accepted, and the ZKProofport app never sends the proof
5404
+ * there. The proof still comes back to you the same way it always did — over the
5405
+ * relay, via `waitForProof()` / `waitForResult()`. `returnScheme` only answers
5406
+ * "which app should come back to the foreground", exactly like the
5407
+ * `redirect.native` value a wallet uses to hand control back after signing.
5408
+ *
5409
+ * **Omit it and nothing changes** — the user simply stays in the ZKProofport app
5410
+ * after the proof and switches back manually. There is no auto-switch on proof
5411
+ * failure either; only on success and on the user declining the request.
5412
+ *
5413
+ * Rejected with an error before the request is sent: empty or whitespace values,
5414
+ * anything longer than 128 characters, values containing a path/query/fragment,
5415
+ * and the `http:`, `file:`, `data:`, `javascript:`, `intent:`, `tel:`, `sms:`,
5416
+ * `mailto:` families.
5323
5417
  * @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
5324
- * @throws Error if signer not set or relay request fails
5418
+ * @throws Error if signer not set, returnScheme is malformed, or the relay request fails
5325
5419
  *
5326
5420
  * @example
5327
5421
  * ```typescript
@@ -5330,7 +5424,7 @@ class ProofportSDK {
5330
5424
  *
5331
5425
  * const relay = await sdk.createRelayRequest('coinbase_attestation', {
5332
5426
  * scope: 'myapp.com'
5333
- * }, { dappName: 'My DApp' });
5427
+ * }, { dappName: 'My DApp', returnScheme: 'mydapp://' });
5334
5428
  *
5335
5429
  * // Generate QR code from relay deep link
5336
5430
  * const qr = await sdk.generateQRCode(relay.deepLink);