@calimero-network/mero-js 27.2.0 → 27.3.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/dist/index.cjs CHANGED
@@ -70,6 +70,7 @@ __export(index_exports, {
70
70
  claimedRelease: () => claimedRelease,
71
71
  cloudNodeReleaseUrl: () => cloudNodeReleaseUrl,
72
72
  compareVersions: () => compareVersions,
73
+ confirmationCode: () => confirmationCode,
73
74
  consentReturn: () => consentReturn,
74
75
  createQuoteVerifier: () => createQuoteVerifier,
75
76
  createSealedFetch: () => createSealedFetch,
@@ -1569,6 +1570,17 @@ ${generation}`;
1569
1570
  function publisherBindingBytes(cluster, org, signerId, generation) {
1570
1571
  return new TextEncoder().encode(publisherBindingMessage(cluster, org, signerId, generation));
1571
1572
  }
1573
+ var CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
1574
+ async function confirmationCode(requestId) {
1575
+ const h = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(requestId)));
1576
+ const word = (h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]) >>> 0;
1577
+ let code = "";
1578
+ for (let i = 0; i < 6; i++) {
1579
+ if (i === 3) code += "-";
1580
+ code += CROCKFORD[word >>> 27 - 5 * i & 31];
1581
+ }
1582
+ return code;
1583
+ }
1572
1584
  function consentReturn(href) {
1573
1585
  const url2 = typeof href === "string" ? new URL(href) : href;
1574
1586
  const requestId = url2.searchParams.get("request_id");
@@ -2342,16 +2354,34 @@ var CalimeroClient = class {
2342
2354
  }
2343
2355
  /**
2344
2356
  * {@link requestConsent}, then send the browser to the consent page
2345
- * (`navigate`, by default `window.location.assign`). Answers the request
2346
- * once `navigate` returns: with a popup (`url => window.open(url)`), poll it
2347
- * with {@link waitForConsent}.
2357
+ * (`navigate`, by default `window.location.assign`). Pass `navigate` itself
2358
+ * or {@link OpenConsentOptions}, whose `confirm` runs first with the node's
2359
+ * answer so the app can show the person its `code`; when it answers `false`
2360
+ * the page is not opened. When the node sends a `code` that is not
2361
+ * {@link confirmationCode} of `requestId`, it throws `CalimeroError`
2362
+ * (`CONSENT_CODE_MISMATCH`) and does not navigate. Answers the request
2363
+ * once `navigate` returns (or `confirm` declines): with a popup
2364
+ * (`url => window.open(url)`), poll it with {@link waitForConsent}.
2348
2365
  */
2349
- async openConsentPage(request, navigate = (url2) => {
2350
- const w = globalThis.window;
2351
- if (!w) throw new Error("no window to open the consent page in; pass `navigate`");
2352
- w.location.assign(url2);
2353
- }) {
2366
+ async openConsentPage(request, navigateOrOptions = {}) {
2367
+ const options = typeof navigateOrOptions === "function" ? { navigate: navigateOrOptions } : navigateOrOptions;
2368
+ const navigate = options.navigate ?? ((url2) => {
2369
+ const w = globalThis.window;
2370
+ if (!w) throw new Error("no window to open the consent page in; pass `navigate`");
2371
+ w.location.assign(url2);
2372
+ });
2354
2373
  const started = await this.requestConsent(request);
2374
+ if (started.code !== void 0) {
2375
+ const expected = await confirmationCode(started.requestId);
2376
+ if (started.code !== expected) {
2377
+ throw new CalimeroError(200, "CONSENT_CODE_MISMATCH", "the consent page code does not match the request", {
2378
+ requestId: started.requestId,
2379
+ code: started.code,
2380
+ expected
2381
+ });
2382
+ }
2383
+ }
2384
+ if (options.confirm && !await options.confirm(started)) return started;
2355
2385
  navigate(started.url);
2356
2386
  return started;
2357
2387
  }