@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.
@@ -759,9 +759,29 @@ export declare class ProofportSDK {
759
759
  *
760
760
  * @param circuit - Circuit type identifier
761
761
  * @param inputs - Circuit-specific inputs
762
- * @param options - Request options (message, dappName, dappIcon, nonce)
762
+ * @param options - Request options (message, dappName, dappIcon, nonce, returnScheme)
763
+ * @param options.returnScheme - Which app the ZKProofport app should switch back
764
+ * to once it has finished. Put **your own** deep link scheme here — the bare
765
+ * scheme your app registers, e.g. `'mydapp://'`. A web app can instead pass its
766
+ * own https origin, e.g. `'https://myapp.com'`.
767
+ *
768
+ * This is intentionally **not** a URL and not a return address: no path, query
769
+ * string or fragment is accepted, and the ZKProofport app never sends the proof
770
+ * there. The proof still comes back to you the same way it always did — over the
771
+ * relay, via `waitForProof()` / `waitForResult()`. `returnScheme` only answers
772
+ * "which app should come back to the foreground", exactly like the
773
+ * `redirect.native` value a wallet uses to hand control back after signing.
774
+ *
775
+ * **Omit it and nothing changes** — the user simply stays in the ZKProofport app
776
+ * after the proof and switches back manually. There is no auto-switch on proof
777
+ * failure either; only on success and on the user declining the request.
778
+ *
779
+ * Rejected with an error before the request is sent: empty or whitespace values,
780
+ * anything longer than 128 characters, values containing a path/query/fragment,
781
+ * and the `http:`, `file:`, `data:`, `javascript:`, `intent:`, `tel:`, `sms:`,
782
+ * `mailto:` families.
763
783
  * @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
764
- * @throws Error if signer not set or relay request fails
784
+ * @throws Error if signer not set, returnScheme is malformed, or the relay request fails
765
785
  *
766
786
  * @example
767
787
  * ```typescript
@@ -770,7 +790,7 @@ export declare class ProofportSDK {
770
790
  *
771
791
  * const relay = await sdk.createRelayRequest('coinbase_attestation', {
772
792
  * scope: 'myapp.com'
773
- * }, { dappName: 'My DApp' });
793
+ * }, { dappName: 'My DApp', returnScheme: 'mydapp://' });
774
794
  *
775
795
  * // Generate QR code from relay deep link
776
796
  * const qr = await sdk.generateQRCode(relay.deepLink);
@@ -785,6 +805,7 @@ export declare class ProofportSDK {
785
805
  dappName?: string;
786
806
  dappIcon?: string;
787
807
  nonce?: string;
808
+ returnScheme?: string;
788
809
  }): Promise<RelayProofRequest>;
789
810
  /**
790
811
  * Polls the relay for proof result status.
@@ -187,6 +187,22 @@ export declare function isProofportDeepLink(url: string, scheme?: string): boole
187
187
  * @returns Error message string, or null when the inputs are valid
188
188
  */
189
189
  export declare function validateMdlInputs(circuit: 'mdl_kr_ownership' | 'mdl_kr_age' | 'mdl_kr_region', inputs: CircuitInputs): string | null;
190
+ /**
191
+ * Longest accepted `returnScheme` value.
192
+ * Kept in sync with proofport-relay `src/returnScheme.ts`.
193
+ */
194
+ export declare const MAX_RETURN_SCHEME_LENGTH = 128;
195
+ /**
196
+ * Validates a `returnScheme` before it is sent to the relay, so a malformed
197
+ * value fails fast in the integrator's own code instead of coming back as a
198
+ * relay 400. The relay re-validates and is the authority.
199
+ *
200
+ * @param value - Candidate return target
201
+ * @returns `null` when acceptable, otherwise a human-readable error message
202
+ *
203
+ * @internal
204
+ */
205
+ export declare function validateReturnScheme(value: unknown): string | null;
190
206
  export declare function validateProofRequest(request: ProofRequest): {
191
207
  valid: boolean;
192
208
  error?: string;
package/dist/index.esm.js 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);