@metamask-previews/kyc-controller 0.0.0-preview-ea6a28c61 → 0.0.0-preview-e12b5ece6

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/KycController-method-action-types.cjs.map +1 -1
  3. package/dist/KycController-method-action-types.d.cts +6 -4
  4. package/dist/KycController-method-action-types.d.cts.map +1 -1
  5. package/dist/KycController-method-action-types.d.mts +6 -4
  6. package/dist/KycController-method-action-types.d.mts.map +1 -1
  7. package/dist/KycController-method-action-types.mjs.map +1 -1
  8. package/dist/KycController.cjs +180 -145
  9. package/dist/KycController.cjs.map +1 -1
  10. package/dist/KycController.d.cts +40 -34
  11. package/dist/KycController.d.cts.map +1 -1
  12. package/dist/KycController.d.mts +40 -34
  13. package/dist/KycController.d.mts.map +1 -1
  14. package/dist/KycController.mjs +177 -144
  15. package/dist/KycController.mjs.map +1 -1
  16. package/dist/KycService-method-action-types.cjs.map +1 -1
  17. package/dist/KycService-method-action-types.d.cts +4 -4
  18. package/dist/KycService-method-action-types.d.mts +4 -4
  19. package/dist/KycService-method-action-types.mjs.map +1 -1
  20. package/dist/KycService.cjs +21 -13
  21. package/dist/KycService.cjs.map +1 -1
  22. package/dist/KycService.d.cts +4 -4
  23. package/dist/KycService.d.cts.map +1 -1
  24. package/dist/KycService.d.mts +4 -4
  25. package/dist/KycService.d.mts.map +1 -1
  26. package/dist/KycService.mjs +21 -13
  27. package/dist/KycService.mjs.map +1 -1
  28. package/dist/index.cjs +3 -1
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +2 -2
  31. package/dist/index.d.cts.map +1 -1
  32. package/dist/index.d.mts +2 -2
  33. package/dist/index.d.mts.map +1 -1
  34. package/dist/index.mjs +1 -1
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/types.cjs.map +1 -1
  37. package/dist/types.d.cts +50 -11
  38. package/dist/types.d.cts.map +1 -1
  39. package/dist/types.d.mts +50 -11
  40. package/dist/types.d.mts.map +1 -1
  41. package/dist/types.mjs.map +1 -1
  42. package/dist/vendorDisclaimerAcceptance.cjs +74 -0
  43. package/dist/vendorDisclaimerAcceptance.cjs.map +1 -0
  44. package/dist/vendorDisclaimerAcceptance.d.cts +39 -0
  45. package/dist/vendorDisclaimerAcceptance.d.cts.map +1 -0
  46. package/dist/vendorDisclaimerAcceptance.d.mts +39 -0
  47. package/dist/vendorDisclaimerAcceptance.d.mts.map +1 -0
  48. package/dist/vendorDisclaimerAcceptance.mjs +67 -0
  49. package/dist/vendorDisclaimerAcceptance.mjs.map +1 -0
  50. package/package.json +2 -2
@@ -9,7 +9,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _KycController_instances, _KycController_sumsubLauncher, _KycController_keypair, _KycController_authClientToken, _KycController_generation, _KycController_sessionStatusPollIntervalMs, _KycController_pollTimer, _KycController_pollToken, _KycController_userStatusPollIntervalMs, _KycController_userStatusPollTimer, _KycController_userStatusPolling, _KycController_userStatusPollToken, _KycController_localUserSecretStore, _KycController_startConsentsSession, _KycController_recordSessionDisclaimers, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_clearMoonPaySession, _KycController_dropTermsUnlessForVendor, _KycController_hasTermsForVendor, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_buildUkycSessionVendorFields, _KycController_createUkycSession, _KycController_fetchAndApplyUserStatus, _KycController_applyUserStatus, _KycController_ensureUserStatusPolling, _KycController_stopUserStatusPolling, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_cancelPendingSession, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_assertAttestedServerPublicKey, _KycController_fail;
12
+ var _KycController_instances, _KycController_sumsubLauncher, _KycController_moonpayFrameKeypair, _KycController_authClientToken, _KycController_generation, _KycController_sessionStatusPollIntervalMs, _KycController_pollTimer, _KycController_pollToken, _KycController_userStatusPollIntervalMs, _KycController_userStatusPollTimer, _KycController_userStatusPolling, _KycController_userStatusPollToken, _KycController_localUserSecretStore, _KycController_startConsentsSession, _KycController_recordSessionDisclaimers, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_clearMoonPaySession, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_buildUkycSessionVendorFields, _KycController_createUkycSession, _KycController_fetchAndApplyUserStatus, _KycController_applyUserStatus, _KycController_ensureUserStatusPolling, _KycController_stopUserStatusPolling, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_cancelPendingSession, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_assertAttestedServerPublicKey, _KycController_fail;
13
13
  import { BaseController } from "@metamask/base-controller";
14
14
  import { stringToBytes } from "@metamask/utils";
15
15
  import { x25519 } from "@noble/curves/ed25519";
@@ -21,6 +21,7 @@ import { verifyJwtChain } from "./ukyc/jwtChain.mjs";
21
21
  import { getOrCreateLocalUserSecret } from "./ukyc/localUserSecret.mjs";
22
22
  import { encodeStorageAccessTokenForHeader, signStorageAccessToken } from "./ukyc/storageAccessToken.mjs";
23
23
  import { wrapEncryptionKey } from "./ukyc/wrapEncryptionKey.mjs";
24
+ import { clearVendorDisclaimerAcceptance, hasVendorDisclaimerAcceptance, ironDisclaimerIds, recordVendorDisclaimerAcceptance } from "./vendorDisclaimerAcceptance.mjs";
24
25
  // === GENERAL ===
25
26
  export const controllerName = 'KycController';
26
27
  const FRAMES_BASE_URL = 'https://blocks.moonpay.com/platform/v1';
@@ -117,31 +118,19 @@ const kycControllerMetadata = {
117
118
  persist: false,
118
119
  usedInUi: false,
119
120
  },
120
- termsAcceptedAt: {
121
+ vendorDisclaimersAccepted: {
121
122
  includeInDebugSnapshot: true,
122
123
  includeInStateLogs: true,
123
124
  persist: true,
124
125
  usedInUi: false,
125
126
  },
126
- acceptedDisclaimerIds: {
127
+ providerDisclaimersAccepted: {
127
128
  includeInDebugSnapshot: true,
128
129
  includeInStateLogs: true,
129
130
  persist: true,
130
131
  usedInUi: false,
131
132
  },
132
- termsAcceptedVendor: {
133
- includeInDebugSnapshot: true,
134
- includeInStateLogs: true,
135
- persist: true,
136
- usedInUi: false,
137
- },
138
- sumsubTncAccepted: {
139
- includeInDebugSnapshot: true,
140
- includeInStateLogs: true,
141
- persist: true,
142
- usedInUi: false,
143
- },
144
- idosTncAccepted: {
133
+ idosDisclaimersAccepted: {
145
134
  includeInDebugSnapshot: true,
146
135
  includeInStateLogs: true,
147
136
  persist: true,
@@ -153,13 +142,13 @@ const kycControllerMetadata = {
153
142
  persist: false,
154
143
  usedInUi: false,
155
144
  },
156
- disclaimers: {
145
+ vendorDisclaimers: {
157
146
  includeInDebugSnapshot: false,
158
147
  includeInStateLogs: false,
159
148
  persist: false,
160
149
  usedInUi: true,
161
150
  },
162
- disclaimersError: {
151
+ vendorError: {
163
152
  includeInDebugSnapshot: true,
164
153
  includeInStateLogs: true,
165
154
  persist: false,
@@ -177,13 +166,13 @@ const kycControllerMetadata = {
177
166
  persist: false,
178
167
  usedInUi: true,
179
168
  },
180
- sessionToken: {
169
+ moonpaySessionToken: {
181
170
  includeInDebugSnapshot: false,
182
171
  includeInStateLogs: false,
183
172
  persist: false,
184
173
  usedInUi: false,
185
174
  },
186
- accessToken: {
175
+ moonpayAccessToken: {
187
176
  includeInDebugSnapshot: false,
188
177
  includeInStateLogs: false,
189
178
  persist: false,
@@ -244,6 +233,17 @@ const kycControllerMetadata = {
244
233
  usedInUi: true,
245
234
  },
246
235
  };
236
+ /**
237
+ * Constructs the default {@link KycVendorDisclaimersAccepted} value.
238
+ *
239
+ * @returns The default vendor-disclaimer acceptance map.
240
+ */
241
+ export function getDefaultKycVendorDisclaimersAccepted() {
242
+ return { moonpay: null, iron: null };
243
+ }
244
+ export function getDefaultKycProviderDisclaimersAccepted() {
245
+ return { sumsub: null };
246
+ }
247
247
  /**
248
248
  * Constructs the default {@link KycController} state.
249
249
  *
@@ -255,18 +255,16 @@ export function getDefaultKycControllerState() {
255
255
  statusMessage: '',
256
256
  error: null,
257
257
  email: null,
258
- termsAcceptedAt: null,
259
- acceptedDisclaimerIds: [],
260
- termsAcceptedVendor: null,
261
- sumsubTncAccepted: null,
262
- idosTncAccepted: null,
258
+ vendorDisclaimersAccepted: getDefaultKycVendorDisclaimersAccepted(),
259
+ providerDisclaimersAccepted: getDefaultKycProviderDisclaimersAccepted(),
260
+ idosDisclaimersAccepted: null,
263
261
  credentialReusabilityConsentGiven: null,
264
- disclaimers: [],
265
- disclaimersError: null,
262
+ vendorDisclaimers: [],
263
+ vendorError: null,
266
264
  sessionDisclaimers: null,
267
265
  geoCountry: null,
268
- sessionToken: null,
269
- accessToken: null,
266
+ moonpaySessionToken: null,
267
+ moonpayAccessToken: null,
270
268
  moonpayCustomerId: null,
271
269
  activeVendor: 'moonpay',
272
270
  activeProduct: null,
@@ -310,45 +308,62 @@ function isConsentConflictError(error) {
310
308
  error.httpStatus === 409);
311
309
  }
312
310
  /**
313
- * Maps a session-disclaimer catalog into the `{ key, version }` records the
314
- * record-consents API expects, or an empty list when the user declined that
315
- * category.
311
+ *
312
+ * @param value - The value to validate.
313
+ * @returns `true` when `value` is a valid consent record list.
314
+ */
315
+ function isValidConsentRecordList(value) {
316
+ return (Array.isArray(value) &&
317
+ value.every((item) => typeof item === 'object' &&
318
+ item !== null &&
319
+ typeof item.key === 'string' &&
320
+ typeof item.version === 'string'));
321
+ }
322
+ /**
323
+ * Maps accepted disclaimer records onto unconsented catalog documents.
316
324
  *
317
325
  * @param documents - Catalog documents for one consent category.
318
- * @param accepted - Whether the user accepted that category.
319
- * @returns Consent records, or `[]` when not accepted.
326
+ * @param accepted - Accepted `{ key, version }` records from the caller.
327
+ * @returns Consent records to POST, omitting already-consented documents.
320
328
  */
321
- function consentRecordsFromCatalog(documents, accepted) {
322
- if (!accepted) {
329
+ function consentRecordsFromAcceptedList(documents, accepted) {
330
+ if (accepted.length === 0) {
323
331
  return [];
324
332
  }
333
+ const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
325
334
  return documents
326
- .filter((document) => !document.consented)
335
+ .filter((document) => !document.consented &&
336
+ acceptedKeys.has(`${document.key}:${document.version}`))
327
337
  .map(({ key, version }) => ({ key, version }));
328
338
  }
329
339
  /**
330
- * Whether an accepted T&C2 category has no catalog documents. An empty list
331
- * would otherwise skip the POST and count as success.
340
+ * Whether accepted disclaimers reference a missing catalog category.
332
341
  *
333
342
  * @param documents - Catalog documents for one consent category.
334
- * @param accepted - Whether the user accepted that category.
335
- * @returns `true` when the user accepted and the catalog is empty.
343
+ * @param accepted - Accepted `{ key, version }` records from the caller.
344
+ * @returns `true` when the caller accepted docs but the catalog is empty.
336
345
  */
337
346
  function isAcceptedCategoryEmpty(documents, accepted) {
338
- return accepted && documents.length === 0;
347
+ return accepted.length > 0 && documents.length === 0;
339
348
  }
340
349
  /**
341
- * Whether an accepted category is still missing consent after a 409 re-GET:
342
- * empty catalog or any document still unconsented.
350
+ * Whether accepted disclaimers are still missing consent after a 409 re-GET:
351
+ * empty catalog or any accepted document still unconsented.
343
352
  *
344
353
  * @param documents - Latest catalog documents for one consent category.
345
- * @param accepted - Whether the user accepted that category.
354
+ * @param accepted - Accepted `{ key, version }` records from the caller.
346
355
  * @returns `true` when accepted documents are not fully consented.
347
356
  */
348
357
  function acceptedCategoryStillMissing(documents, accepted) {
349
- return (accepted &&
350
- (documents.length === 0 ||
351
- documents.some((document) => !document.consented)));
358
+ if (accepted.length === 0) {
359
+ return false;
360
+ }
361
+ if (documents.length === 0) {
362
+ return true;
363
+ }
364
+ const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
365
+ const relevant = documents.filter((document) => acceptedKeys.has(`${document.key}:${document.version}`));
366
+ return (relevant.length === 0 || relevant.some((document) => !document.consented));
352
367
  }
353
368
  /**
354
369
  * Vendors other than MoonPay skip Check/Auth frames and use the empty-shell
@@ -410,8 +425,8 @@ export class KycController extends BaseController {
410
425
  });
411
426
  _KycController_instances.add(this);
412
427
  _KycController_sumsubLauncher.set(this, void 0);
413
- /** Ephemeral X25519 keypair for the frame key exchange (never persisted). */
414
- _KycController_keypair.set(this, void 0);
428
+ /** MoonPay Check/Auth frame X25519 keypair (never persisted). */
429
+ _KycController_moonpayFrameKeypair.set(this, null);
415
430
  /** Auth-frame client token, kept out of state. */
416
431
  _KycController_authClientToken.set(this, null);
417
432
  /**
@@ -450,7 +465,6 @@ export class KycController extends BaseController {
450
465
  __classPrivateFieldSet(this, _KycController_sumsubLauncher, sumsubLauncher, "f");
451
466
  __classPrivateFieldSet(this, _KycController_sessionStatusPollIntervalMs, sessionStatusPollIntervalMs, "f");
452
467
  __classPrivateFieldSet(this, _KycController_userStatusPollIntervalMs, userStatusPollIntervalMs, "f");
453
- __classPrivateFieldSet(this, _KycController_keypair, generateKeyPair(), "f");
454
468
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
455
469
  }
456
470
  /**
@@ -473,10 +487,19 @@ export class KycController extends BaseController {
473
487
  // forces `phase` back through `session`/`check`, breaking an in-flight
474
488
  // Check/Auth frame flow. Leave the active flow untouched and let the
475
489
  // consumer drive it (or call `reset` first to start over).
490
+ const vendor = params?.vendor ?? 'moonpay';
476
491
  if (IN_PROGRESS_PHASES.includes(this.state.phase)) {
492
+ if (vendor === 'moonpay' && !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
493
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, generateKeyPair(), "f");
494
+ }
477
495
  return;
478
496
  }
479
- const vendor = params?.vendor ?? 'moonpay';
497
+ if (vendor === 'moonpay') {
498
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, generateKeyPair(), "f");
499
+ }
500
+ else {
501
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, null, "f");
502
+ }
480
503
  // `initialize` starts a fresh flow, so `activeProduct` is always reset to
481
504
  // this call's product (or `null`). Otherwise a prior run's product could
482
505
  // linger and cause `#continueAfterAuthentication` to auto-run the check /
@@ -487,8 +510,8 @@ export class KycController extends BaseController {
487
510
  }
488
511
  state.activeVendor = vendor;
489
512
  // MoonPay Check/Auth artifacts must not survive a switch to another
490
- // vendor: leftover `sessionToken` would keep `buildCheckFrameUrl` alive,
491
- // leftover `accessToken` / `#authClientToken` would keep Auth / KYC
513
+ // vendor: leftover `moonpaySessionToken` would keep `buildCheckFrameUrl` alive,
514
+ // leftover `moonpayAccessToken` / `#authClientToken` would keep Auth / KYC
492
515
  // calls bound to MoonPay, and leftover `moonpayCustomerId` would make
493
516
  // `getCustomerIdentity` report a MoonPay id under the wrong vendor.
494
517
  if (vendor !== 'moonpay') {
@@ -541,16 +564,14 @@ export class KycController extends BaseController {
541
564
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
542
565
  return;
543
566
  }
544
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, vendor);
545
- const hasTerms = Boolean(this.state.termsAcceptedAt) &&
546
- this.state.acceptedDisclaimerIds.length > 0;
567
+ const hasTerms = hasVendorDisclaimerAcceptance(this.state.vendorDisclaimersAccepted, vendor);
547
568
  if (hasTerms && this.state.email) {
548
569
  if (usesConsentsFlow(vendor)) {
549
570
  // Consents-path vendors require T&C2 flags; if they weren't persisted
550
571
  // (i.e. null from pre-migration state), require reacceptance.
551
- const sumsubTncSigned = this.state.sumsubTncAccepted;
552
- const idosTncSigned = this.state.idosTncAccepted;
553
- if (sumsubTncSigned === null || idosTncSigned === null) {
572
+ const { providerDisclaimersAccepted, idosDisclaimersAccepted } = this.state;
573
+ if (providerDisclaimersAccepted.sumsub === null ||
574
+ idosDisclaimersAccepted === null) {
554
575
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
555
576
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
556
577
  state.phase = 'terms';
@@ -559,12 +580,19 @@ export class KycController extends BaseController {
559
580
  return;
560
581
  }
561
582
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
562
- sumsubTncSigned,
563
- idosTncSigned,
583
+ providerDisclaimersAccepted: providerDisclaimersAccepted.sumsub,
584
+ idosDisclaimersAccepted,
564
585
  credentialReusabilityConsentGiven: this.state.credentialReusabilityConsentGiven ?? false,
565
586
  });
566
587
  }
567
588
  else {
589
+ // TODO: should this be here? or should it exist at all?
590
+ if (vendor === 'moonpay' && this.state.vendorDisclaimers.length === 0) {
591
+ await this.loadDisclaimers();
592
+ if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
593
+ return;
594
+ }
595
+ }
568
596
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_createSession).call(this);
569
597
  }
570
598
  return;
@@ -599,6 +627,7 @@ export class KycController extends BaseController {
599
627
  state.activeVendor = params.vendor;
600
628
  if (params.vendor !== 'moonpay') {
601
629
  __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
630
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, null, "f");
602
631
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearMoonPaySession).call(this, state);
603
632
  }
604
633
  });
@@ -608,10 +637,6 @@ export class KycController extends BaseController {
608
637
  vendor: params.vendor,
609
638
  email: params.email,
610
639
  });
611
- if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
612
- return;
613
- }
614
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, params.vendor);
615
640
  }
616
641
  catch (error) {
617
642
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
@@ -645,13 +670,13 @@ export class KycController extends BaseController {
645
670
  country,
646
671
  });
647
672
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
648
- state.disclaimers = disclaimers;
649
- state.disclaimersError = null;
673
+ state.vendorDisclaimers = disclaimers;
674
+ state.vendorError = null;
650
675
  });
651
676
  }
652
677
  catch (error) {
653
678
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
654
- state.disclaimersError = `Failed to load disclaimers: ${String(error)}`;
679
+ state.vendorError = `Failed to load disclaimers: ${String(error)}`;
655
680
  });
656
681
  }
657
682
  }
@@ -664,44 +689,47 @@ export class KycController extends BaseController {
664
689
  * @param params.product - The consuming feature the flow runs for. See
665
690
  * {@link initialize} for how the product drives the automatic post
666
691
  * authentication continuation.
667
- * @param params.sumsubTncSigned - Whether Sumsub T&C were accepted (T&C2).
668
- * Required for every vendor so callers explicitly declare acceptance.
669
- * @param params.idosTncSigned - Whether idOS T&C were accepted (T&C2).
670
- * Required for every vendor so callers explicitly declare acceptance.
692
+ * @param params.providerDisclaimersAccepted - Sumsub disclaimer documents the
693
+ * customer accepted (`{ key, version }` records). Required for every vendor
694
+ * so callers explicitly declare acceptance.
695
+ * @param params.idosDisclaimersAccepted - idOS disclaimer documents the
696
+ * customer accepted (`{ key, version }` records). Required for every vendor
697
+ * so callers explicitly declare acceptance.
671
698
  * @param params.credentialReusabilityConsentGiven - Whether the customer
672
699
  * consented to reuse existing idOS credentials. Used when recording
673
700
  * session-scoped disclaimers on the consents path. Defaults to `false`.
674
701
  */
675
702
  async acceptTermsAndStartSession(params) {
676
- const sumsubTncSigned = params?.sumsubTncSigned;
677
- const idosTncSigned = params?.idosTncSigned;
678
- if (typeof sumsubTncSigned !== 'boolean' ||
679
- typeof idosTncSigned !== 'boolean') {
703
+ const providerDisclaimersAccepted = params?.providerDisclaimersAccepted;
704
+ const idosDisclaimersAccepted = params?.idosDisclaimersAccepted;
705
+ if (!isValidConsentRecordList(providerDisclaimersAccepted) ||
706
+ !isValidConsentRecordList(idosDisclaimersAccepted)) {
680
707
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing T&C2 acceptance flags.');
681
708
  return;
682
709
  }
683
- const credentialReusabilityConsentGiven = params.credentialReusabilityConsentGiven ?? false;
710
+ const credentialReusabilityConsentGiven = params?.credentialReusabilityConsentGiven ?? false;
684
711
  const termsAcceptedAt = new Date().toISOString();
685
- const disclaimerIds = this.state.disclaimers.map((disclaimer) => disclaimer.id);
712
+ const disclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
686
713
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
687
- if (params.email) {
714
+ if (params?.email) {
688
715
  state.email = params.email;
689
716
  }
690
- if (params.product) {
717
+ if (params?.product) {
691
718
  state.activeProduct = params.product;
692
719
  }
693
- state.termsAcceptedAt = termsAcceptedAt;
694
- state.acceptedDisclaimerIds = disclaimerIds;
695
- state.termsAcceptedVendor = state.activeVendor;
696
- state.sumsubTncAccepted = sumsubTncSigned;
697
- state.idosTncAccepted = idosTncSigned;
720
+ state.vendorDisclaimersAccepted = recordVendorDisclaimerAcceptance(state.vendorDisclaimersAccepted, state.activeVendor, { termsAcceptedAt, disclaimerIds });
721
+ state.providerDisclaimersAccepted = {
722
+ ...state.providerDisclaimersAccepted,
723
+ sumsub: providerDisclaimersAccepted,
724
+ };
725
+ state.idosDisclaimersAccepted = idosDisclaimersAccepted;
698
726
  state.credentialReusabilityConsentGiven =
699
727
  credentialReusabilityConsentGiven;
700
728
  });
701
729
  if (usesConsentsFlow(this.state.activeVendor)) {
702
730
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
703
- sumsubTncSigned,
704
- idosTncSigned,
731
+ providerDisclaimersAccepted,
732
+ idosDisclaimersAccepted,
705
733
  credentialReusabilityConsentGiven,
706
734
  });
707
735
  return;
@@ -713,7 +741,12 @@ export class KycController extends BaseController {
713
741
  */
714
742
  clearSavedTerms() {
715
743
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
716
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
744
+ state.vendorDisclaimersAccepted =
745
+ getDefaultKycVendorDisclaimersAccepted();
746
+ state.providerDisclaimersAccepted =
747
+ getDefaultKycProviderDisclaimersAccepted();
748
+ state.idosDisclaimersAccepted = null;
749
+ state.credentialReusabilityConsentGiven = null;
717
750
  });
718
751
  }
719
752
  /**
@@ -771,9 +804,9 @@ export class KycController extends BaseController {
771
804
  }
772
805
  let accessToken;
773
806
  let clientToken;
774
- if (credsEnvelope) {
807
+ if (credsEnvelope && __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
775
808
  try {
776
- const { credentials } = decryptCredentials(credsEnvelope, __classPrivateFieldGet(this, _KycController_keypair, "f").privateKey);
809
+ const { credentials } = decryptCredentials(credsEnvelope, __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").privateKey);
777
810
  accessToken = credentials.accessToken;
778
811
  clientToken = credentials.clientToken;
779
812
  }
@@ -796,12 +829,14 @@ export class KycController extends BaseController {
796
829
  * @returns The Check-frame URL or `null`.
797
830
  */
798
831
  buildCheckFrameUrl() {
799
- if (this.state.activeVendor !== 'moonpay' || !this.state.sessionToken) {
832
+ if (this.state.activeVendor !== 'moonpay' ||
833
+ !this.state.moonpaySessionToken ||
834
+ !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
800
835
  return null;
801
836
  }
802
837
  const url = new URL(`${FRAMES_BASE_URL}/check-connection`);
803
- url.searchParams.set('sessionToken', this.state.sessionToken);
804
- url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
838
+ url.searchParams.set('sessionToken', this.state.moonpaySessionToken);
839
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").publicKeyHex);
805
840
  url.searchParams.set('channelId', CHANNEL_CHECK);
806
841
  url.searchParams.set('skipKyc', 'true');
807
842
  return url.toString();
@@ -812,12 +847,14 @@ export class KycController extends BaseController {
812
847
  * @returns The Auth-frame URL or `null`.
813
848
  */
814
849
  buildAuthFrameUrl() {
815
- if (this.state.activeVendor !== 'moonpay' || !__classPrivateFieldGet(this, _KycController_authClientToken, "f")) {
850
+ if (this.state.activeVendor !== 'moonpay' ||
851
+ !__classPrivateFieldGet(this, _KycController_authClientToken, "f") ||
852
+ !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
816
853
  return null;
817
854
  }
818
855
  const url = new URL(`${FRAMES_BASE_URL}/auth`);
819
856
  url.searchParams.set('clientToken', __classPrivateFieldGet(this, _KycController_authClientToken, "f"));
820
- url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
857
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").publicKeyHex);
821
858
  url.searchParams.set('channelId', CHANNEL_AUTH);
822
859
  return url.toString();
823
860
  }
@@ -840,9 +877,9 @@ export class KycController extends BaseController {
840
877
  * @returns Whether KYC is required.
841
878
  */
842
879
  async checkKycRequired(params) {
843
- const { accessToken } = this.state;
844
- if (!accessToken) {
845
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing accessToken — repeat the authentication step.');
880
+ const { moonpayAccessToken } = this.state;
881
+ if (!moonpayAccessToken) {
882
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing moonpayAccessToken — repeat the authentication step.');
846
883
  return false;
847
884
  }
848
885
  const country = params.country ?? this.state.geoCountry;
@@ -858,7 +895,11 @@ export class KycController extends BaseController {
858
895
  state.statusMessage = 'Checking KYC status...';
859
896
  });
860
897
  try {
861
- const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', { accessToken, country, capabilities: [{ product: params.product }] });
898
+ const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', {
899
+ accessToken: moonpayAccessToken,
900
+ country,
901
+ capabilities: [{ product: params.product }],
902
+ });
862
903
  // The flow was reset while the check was in flight; discard the result
863
904
  // rather than resurrecting a done/cached state on an idle controller.
864
905
  const applied = __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
@@ -1143,12 +1184,12 @@ export class KycController extends BaseController {
1143
1184
  state.phase = 'idle';
1144
1185
  state.statusMessage = '';
1145
1186
  state.error = null;
1146
- state.disclaimers = [];
1147
- state.disclaimersError = null;
1187
+ state.vendorDisclaimers = [];
1188
+ state.vendorError = null;
1148
1189
  state.sessionDisclaimers = null;
1149
1190
  state.credentialReusabilityConsentGiven = null;
1150
- state.sessionToken = null;
1151
- state.accessToken = null;
1191
+ state.moonpaySessionToken = null;
1192
+ state.moonpayAccessToken = null;
1152
1193
  state.moonpayCustomerId = null;
1153
1194
  state.activeVendor = 'moonpay';
1154
1195
  state.activeProduct = null;
@@ -1176,7 +1217,7 @@ export class KycController extends BaseController {
1176
1217
  });
1177
1218
  }
1178
1219
  }
1179
- _KycController_sumsubLauncher = new WeakMap(), _KycController_keypair = new WeakMap(), _KycController_authClientToken = new WeakMap(), _KycController_generation = new WeakMap(), _KycController_sessionStatusPollIntervalMs = new WeakMap(), _KycController_pollTimer = new WeakMap(), _KycController_pollToken = new WeakMap(), _KycController_userStatusPollIntervalMs = new WeakMap(), _KycController_userStatusPollTimer = new WeakMap(), _KycController_userStatusPolling = new WeakMap(), _KycController_userStatusPollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
1220
+ _KycController_sumsubLauncher = new WeakMap(), _KycController_moonpayFrameKeypair = new WeakMap(), _KycController_authClientToken = new WeakMap(), _KycController_generation = new WeakMap(), _KycController_sessionStatusPollIntervalMs = new WeakMap(), _KycController_pollTimer = new WeakMap(), _KycController_pollToken = new WeakMap(), _KycController_userStatusPollIntervalMs = new WeakMap(), _KycController_userStatusPollTimer = new WeakMap(), _KycController_userStatusPolling = new WeakMap(), _KycController_userStatusPollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
1180
1221
  return {
1181
1222
  get: async (path, entropySourceId) => this.messenger.call('UserStorageController:performGetStorage', path, entropySourceId),
1182
1223
  set: async (path, value, entropySourceId) => this.messenger.call('UserStorageController:performSetStorage', path, value, entropySourceId),
@@ -1188,13 +1229,14 @@ _KycController_sumsubLauncher = new WeakMap(), _KycController_keypair = new Weak
1188
1229
  * SumSub — skipping MoonPay Check/Auth frames.
1189
1230
  *
1190
1231
  * @param consents - T&C2 flags mapped onto the session disclaimer catalog.
1191
- * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1192
- * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1232
+ * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1233
+ * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1193
1234
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1194
1235
  * reuse was accepted.
1195
1236
  */
1196
1237
  async function _KycController_startConsentsSession(consents) {
1197
- const { email, acceptedDisclaimerIds } = this.state;
1238
+ const { email } = this.state;
1239
+ const acceptedDisclaimerIds = ironDisclaimerIds(this.state.vendorDisclaimersAccepted);
1198
1240
  if (!email) {
1199
1241
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for consents session.');
1200
1242
  return;
@@ -1329,8 +1371,8 @@ async function _KycController_startConsentsSession(consents) {
1329
1371
  *
1330
1372
  * @param sessionId - The UKYC session id.
1331
1373
  * @param consents - T&C2 flags mapped onto catalog documents.
1332
- * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1333
- * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1374
+ * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1375
+ * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1334
1376
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1335
1377
  * reuse was accepted.
1336
1378
  * @param generation - Flow generation captured by the caller.
@@ -1344,12 +1386,12 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1344
1386
  state.sessionDisclaimers = catalog;
1345
1387
  state.statusMessage = 'Submitting consents...';
1346
1388
  });
1347
- if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosTncSigned) ||
1348
- isAcceptedCategoryEmpty(catalog.kycProvider, consents.sumsubTncSigned)) {
1389
+ if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosDisclaimersAccepted) ||
1390
+ isAcceptedCategoryEmpty(catalog.kycProvider, consents.providerDisclaimersAccepted)) {
1349
1391
  throw new Error('Session disclaimer catalog is missing documents for an accepted category.');
1350
1392
  }
1351
- const idOS = consentRecordsFromCatalog(catalog.idOS, consents.idosTncSigned);
1352
- const kycProvider = consentRecordsFromCatalog(catalog.kycProvider, consents.sumsubTncSigned);
1393
+ const idOS = consentRecordsFromAcceptedList(catalog.idOS, consents.idosDisclaimersAccepted);
1394
+ const kycProvider = consentRecordsFromAcceptedList(catalog.kycProvider, consents.providerDisclaimersAccepted);
1353
1395
  const reuseUnchanged = catalog.credentialReusabilityConsentGiven ===
1354
1396
  consents.credentialReusabilityConsentGiven;
1355
1397
  if (idOS.length === 0 && kycProvider.length === 0 && reuseUnchanged) {
@@ -1380,8 +1422,9 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1380
1422
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1381
1423
  state.sessionDisclaimers = latest;
1382
1424
  });
1383
- const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosTncSigned);
1384
- const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.sumsubTncSigned);
1425
+ // TODO: Should we really be doing client side validation of these?
1426
+ const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosDisclaimersAccepted);
1427
+ const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.providerDisclaimersAccepted);
1385
1428
  const stillMissingReuse = consents.credentialReusabilityConsentGiven &&
1386
1429
  !latest.credentialReusabilityConsentGiven;
1387
1430
  if (stillMissingIdos || stillMissingProvider || stillMissingReuse) {
@@ -1393,7 +1436,9 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1393
1436
  * Creates a vendor session from the currently stored terms + email.
1394
1437
  */
1395
1438
  async function _KycController_createSession() {
1396
- const { email, termsAcceptedAt, acceptedDisclaimerIds } = this.state;
1439
+ const { email } = this.state;
1440
+ const termsAcceptedAt = this.state.vendorDisclaimersAccepted.moonpay?.termsAcceptedAt;
1441
+ const acceptedDisclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
1397
1442
  if (!email) {
1398
1443
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for session creation.');
1399
1444
  return;
@@ -1408,7 +1453,7 @@ async function _KycController_createSession() {
1408
1453
  // (or, on failure, invalid) session token, `buildAuthFrameUrl` cannot
1409
1454
  // return a URL tied to an old client token, and `checkKycRequired` cannot
1410
1455
  // run with an access token from an earlier authentication. The Check/Auth
1411
- // frames re-populate these for the new session. Because `sessionToken` is
1456
+ // frames re-populate these for the new session. Because `moonpaySessionToken` is
1412
1457
  // cleared here and only re-set on success, a failed creation leaves it
1413
1458
  // `null` rather than resurrecting the previous session.
1414
1459
  // Capture the flow generation so a `reset()` landing while the create
@@ -1421,13 +1466,13 @@ async function _KycController_createSession() {
1421
1466
  state.error = null;
1422
1467
  state.phase = 'session';
1423
1468
  state.statusMessage = 'Creating session...';
1424
- state.sessionToken = null;
1425
- state.accessToken = null;
1469
+ state.moonpaySessionToken = null;
1470
+ state.moonpayAccessToken = null;
1426
1471
  });
1427
1472
  try {
1428
1473
  const { sessionToken } = await this.messenger.call('KycService:createSession', { email, termsAcceptedAt, disclaimerIds: acceptedDisclaimerIds });
1429
1474
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
1430
- state.sessionToken = sessionToken;
1475
+ state.moonpaySessionToken = sessionToken;
1431
1476
  state.phase = 'check';
1432
1477
  state.statusMessage = 'Authenticating via Check frame...';
1433
1478
  });
@@ -1453,29 +1498,17 @@ async function _KycController_createSession() {
1453
1498
  });
1454
1499
  await this.loadDisclaimers();
1455
1500
  }
1456
- }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state) {
1457
- state.termsAcceptedAt = null;
1458
- state.acceptedDisclaimerIds = [];
1459
- state.termsAcceptedVendor = null;
1460
- state.sumsubTncAccepted = null;
1461
- state.idosTncAccepted = null;
1501
+ }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state, vendor) {
1502
+ const targetVendor = vendor ?? state.activeVendor;
1503
+ state.vendorDisclaimersAccepted = clearVendorDisclaimerAcceptance(state.vendorDisclaimersAccepted, targetVendor);
1504
+ state.providerDisclaimersAccepted =
1505
+ getDefaultKycProviderDisclaimersAccepted();
1506
+ state.idosDisclaimersAccepted = null;
1462
1507
  state.credentialReusabilityConsentGiven = null;
1463
1508
  }, _KycController_clearMoonPaySession = function _KycController_clearMoonPaySession(state) {
1464
1509
  state.moonpayCustomerId = null;
1465
- state.sessionToken = null;
1466
- state.accessToken = null;
1467
- }, _KycController_dropTermsUnlessForVendor = function _KycController_dropTermsUnlessForVendor(vendor) {
1468
- if (__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_hasTermsForVendor).call(this, vendor)) {
1469
- return;
1470
- }
1471
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1472
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
1473
- });
1474
- }, _KycController_hasTermsForVendor = function _KycController_hasTermsForVendor(vendor) {
1475
- if (this.state.termsAcceptedVendor === null) {
1476
- return false;
1477
- }
1478
- return this.state.termsAcceptedVendor === vendor;
1510
+ state.moonpaySessionToken = null;
1511
+ state.moonpayAccessToken = null;
1479
1512
  }, _KycController_handleCheckOutcome =
1480
1513
  /**
1481
1514
  * Applies a Check-frame outcome.
@@ -1487,7 +1520,7 @@ async function _KycController_createSession() {
1487
1520
  async function _KycController_handleCheckOutcome(status, accessToken, clientToken) {
1488
1521
  if (status === 'active' && accessToken) {
1489
1522
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1490
- state.accessToken = accessToken;
1523
+ state.moonpayAccessToken = accessToken;
1491
1524
  state.phase = 'form';
1492
1525
  state.statusMessage = 'Already authenticated. Review to submit.';
1493
1526
  });
@@ -1517,7 +1550,7 @@ async function _KycController_handleCheckOutcome(status, accessToken, clientToke
1517
1550
  async function _KycController_handleAuthOutcome(status, accessToken) {
1518
1551
  if (status === 'active' && accessToken) {
1519
1552
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1520
- state.accessToken = accessToken;
1553
+ state.moonpayAccessToken = accessToken;
1521
1554
  state.phase = 'form';
1522
1555
  state.statusMessage = 'Authenticated. Review to submit.';
1523
1556
  });
@@ -1580,7 +1613,7 @@ async function _KycController_continueAfterAuthentication() {
1580
1613
  return {
1581
1614
  vendor: 'moonpay',
1582
1615
  vendorMetadata: {
1583
- moonPayAccessToken: this.state.accessToken,
1616
+ moonPayAccessToken: this.state.moonpayAccessToken,
1584
1617
  moonPayUserId: this.state.moonpayCustomerId,
1585
1618
  },
1586
1619
  };