@metamask-previews/kyc-controller 0.11.0-preview-b4b0d7a09 → 0.11.0-preview-55fcf3ef7

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/CHANGELOG.md CHANGED
@@ -17,13 +17,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
17
  - Cache successful `KycService.fetchIdosEnclaveJwks` and `KycService.fetchIdosRelayJwks` responses in the service query cache for 24 hours ([#10894](https://github.com/MetaMask/core/pull/10894))
18
18
  - `KycService:invalidateQueries` drops the cached keys
19
19
 
20
- ### Removed
21
-
22
- - **BREAKING:** Remove `email` from `KycControllerState` ([#10987](https://github.com/MetaMask/core/pull/10987))
23
- - `startSession` no longer reads a verified email from the partner identity token or stores it
24
- - A consent or partner-identity token failure from `startSession` is rethrown as `KycController.startSession: failed to mint a partner identity token`, with the original error as `cause`
25
- - `recordVendorDisclaimers` no longer requires a stored email
26
-
27
20
  ## [0.11.0]
28
21
 
29
22
  ### Changed
@@ -7,11 +7,10 @@ import type { KycController } from './KycController.js';
7
7
  * Starts a KYC session for the given vendor. Reuses a latest vendor session
8
8
  * when one exists; otherwise creates a UKYC session.
9
9
  *
10
- * Creating a vendor customer and UKYC session requires a partner identity
11
- * token, which both requests send as `partnerIdentityToken`. A failure
12
- * while recording consent or minting that token is rethrown as
13
- * `KycController.startSession: failed to mint a partner identity token`,
14
- * with the original error as `cause`.
10
+ * The verified email stored on controller state comes from the partner
11
+ * identity token. When that request returns HTTP 422, a stored email is
12
+ * kept for an existing session. Creating a vendor customer and UKYC session
13
+ * requires the token, which both requests send as `partnerIdentityToken`.
15
14
  *
16
15
  * @param params - The session parameters.
17
16
  * @param params.vendor - Identity vendor for the session.
@@ -1 +1 @@
1
- {"version":3,"file":"KycController-method-action-types.d.ts","sourceRoot":"","sources":["../src/KycController-method-action-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"KycController-method-action-types.d.ts","sourceRoot":"","sources":["../src/KycController-method-action-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"KycController-method-action-types.js","sourceRoot":"","sources":["../src/KycController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { KycController } from './KycController.js';\n\n/**\n * Starts a KYC session for the given vendor. Reuses a latest vendor session\n * when one exists; otherwise creates a UKYC session.\n *\n * Creating a vendor customer and UKYC session requires a partner identity\n * token, which both requests send as `partnerIdentityToken`. A failure\n * while recording consent or minting that token is rethrown as\n * `KycController.startSession: failed to mint a partner identity token`,\n * with the original error as `cause`.\n *\n * @param params - The session parameters.\n * @param params.vendor - Identity vendor for the session.\n * @param params.aal2Token - AAL2 authentication token. Required only when a\n * UKYC session must be created, where it is sent as the Authorization bearer\n * value. Omit it when reusing an existing session.\n * @returns The current or newly created session status.\n */\nexport type KycControllerStartSessionAction = {\n type: `KycController:startSession`;\n handler: KycController['startSession'];\n};\n\n/**\n * Stops session-status polling and restores default controller state.\n */\nexport type KycControllerResetAction = {\n type: `KycController:reset`;\n handler: KycController['reset'];\n};\n\n/**\n * Restores the controller to its default state.\n */\nexport type KycControllerClearStateAction = {\n type: `KycController:clearState`;\n handler: KycController['clearState'];\n};\n\n/**\n * Fetches the latest UKYC session status for a vendor.\n *\n * @param vendor - Identity vendor whose latest session should be queried.\n * @returns The session status, or `null` when none exists.\n */\nexport type KycControllerGetSessionStatusForVendorAction = {\n type: `KycController:getSessionStatusForVendor`;\n handler: KycController['getSessionStatusForVendor'];\n};\n\n/**\n * Returns the durable outcome of the identity-provider flow.\n *\n * @returns The latest provider-flow status.\n */\nexport type KycControllerGetProviderFlowStatusAction = {\n type: `KycController:getProviderFlowStatus`;\n handler: KycController['getProviderFlowStatus'];\n};\n\n/**\n * Returns the session already stored on state.\n *\n * Starts session-status polling when `finalStatus` is not `approved`,\n * `rejected`, or `retry`. Does not fetch status or refresh capability\n * authorization.\n *\n * @returns The session status stored at call time.\n * @throws If there is no session on state.\n */\nexport type KycControllerRefreshSessionStatusAction = {\n type: `KycController:refreshSessionStatus`;\n handler: KycController['refreshSessionStatus'];\n};\n\n/**\n * Returns the persisted session status.\n *\n * Does not call the network and does not start session-status polling.\n *\n * @returns The session on state, or `null` when none is stored.\n */\nexport type KycControllerReadSessionStatusAction = {\n type: `KycController:readSessionStatus`;\n handler: KycController['readSessionStatus'];\n};\n\n/**\n * Fetches `GET /sessions/{id}/status` once and writes the result onto state.\n *\n * Does not start the session-status polling timer.\n *\n * @param sessionId - UKYC session id.\n * @returns The fetched session status.\n */\nexport type KycControllerFetchSessionStatusOnceAction = {\n type: `KycController:fetchSessionStatusOnce`;\n handler: KycController['fetchSessionStatusOnce'];\n};\n\n/**\n * Starts polling `GET /sessions/{id}/status` for\n * {@link KycControllerState.sessionStatus}'s current `id`. Each tick writes\n * the result onto state only when the payload changed. The first poll runs\n * immediately. Each later wait starts at 10 seconds and grows by 10 seconds\n * after every poll, including a failed one. Starting the loop again resets\n * that delay. The loop stops once `finalStatus` is `approved`, `rejected`,\n * or `retry`, or when {@link reset} / {@link clearState} runs.\n *\n * @throws If there is no current session id to poll.\n */\nexport type KycControllerStartSessionStatusPollingAction = {\n type: `KycController:startSessionStatusPolling`;\n handler: KycController['startSessionStatusPolling'];\n};\n\n/**\n * Fetches the idOS + KYC-provider disclaimer catalog. Pass exactly one of\n * `sessionId` or `country`:\n *\n * - `{ sessionId }` → {@link KycService.fetchSessionDisclaimersBySessionId}\n * (`GET /sessions/{sessionId}/disclaimers`)\n * - `{ country }` → {@link KycService.fetchSessionDisclaimersByCountry}\n * (`GET /disclaimers?country=`)\n *\n * A session-id fetch also writes the catalog to `sessionDisclaimers`.\n *\n * @param params - The parameters. Provide exactly one of `sessionId` or\n * `country`.\n * @param params.sessionId - The UKYC session id.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The catalog. Session fetches include consent state; country\n * fetches do not.\n */\nexport type KycControllerFetchSessionDisclaimersAction = {\n type: `KycController:fetchSessionDisclaimers`;\n handler: KycController['fetchSessionDisclaimers'];\n};\n\n/**\n * Fetches the session-scoped disclaimer catalog and records consents\n * derived from the T&C2 flags. Already-consented catalog rows are omitted\n * from the POST. A 409 is re-checked with a GET: continue only when every\n * accepted document is now consented, otherwise fail closed.\n *\n * @param params - Accepted session-disclaimer records.\n * @param params.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.\n * @param params.idosDisclaimersAccepted - Accepted idOS disclaimer records.\n * @param params.credentialReusabilityConsentGiven - Whether credential\n * reuse was accepted.\n */\nexport type KycControllerRecordSessionDisclaimersAction = {\n type: `KycController:recordSessionDisclaimers`;\n handler: KycController['recordSessionDisclaimers'];\n};\n\n/**\n * Fetches the current session status and reports whether consent was given.\n *\n * @returns Whether `consentStatus` is `given`.\n * @throws If there is no session on state.\n */\nexport type KycControllerHasCompletedSessionDisclaimersAction = {\n type: `KycController:hasCompletedSessionDisclaimers`;\n handler: KycController['hasCompletedSessionDisclaimers'];\n};\n\n/**\n * Fetches the vendor T&Cs the customer must accept before a session is\n * created (`GET /vendors/{vendor}/disclaimers?country=`).\n *\n * @param params - The parameters.\n * @param params.vendor - Identity vendor. Defaults to `moonpay`.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The disclaimers.\n */\nexport type KycControllerFetchVendorDisclaimersAction = {\n type: `KycController:fetchVendorDisclaimers`;\n handler: KycController['fetchVendorDisclaimers'];\n};\n\n/**\n * Records vendor T&C acceptance via {@link KycService.submitVendorDisclaimers}\n * and persists the accepted ids on state.\n *\n * @param params - The parameters.\n * @param params.disclaimerIds - Accepted vendor T&C ids.\n * @returns The vendor signing records.\n * @throws If `vendor` is missing from state.\n */\nexport type KycControllerRecordVendorDisclaimersAction = {\n type: `KycController:recordVendorDisclaimers`;\n handler: KycController['recordVendorDisclaimers'];\n};\n\n/**\n * Fetches the current vendor T&C catalog and returns whether every document\n * is already recorded in {@link KycControllerState.vendorDisclaimersAccepted}.\n *\n * @returns Whether persisted acceptance covers the fetched catalog.\n * @throws If `vendor` or `geoCountry` is missing from state.\n */\nexport type KycControllerHasCompletedVendorDisclaimersAction = {\n type: `KycController:hasCompletedVendorDisclaimers`;\n handler: KycController['hasCompletedVendorDisclaimers'];\n};\n\n/**\n * Presents the identity-provider verification UI. Currently launches SumSub.\n *\n * @param params - Optional SDK presentation options.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\nexport type KycControllerLaunchProviderFlowAction = {\n type: `KycController:launchProviderFlow`;\n handler: KycController['launchProviderFlow'];\n};\n\n/**\n * Union of all KycController action types.\n */\nexport type KycControllerMethodActions =\n | KycControllerStartSessionAction\n | KycControllerResetAction\n | KycControllerClearStateAction\n | KycControllerGetSessionStatusForVendorAction\n | KycControllerGetProviderFlowStatusAction\n | KycControllerRefreshSessionStatusAction\n | KycControllerReadSessionStatusAction\n | KycControllerFetchSessionStatusOnceAction\n | KycControllerStartSessionStatusPollingAction\n | KycControllerFetchSessionDisclaimersAction\n | KycControllerRecordSessionDisclaimersAction\n | KycControllerHasCompletedSessionDisclaimersAction\n | KycControllerFetchVendorDisclaimersAction\n | KycControllerRecordVendorDisclaimersAction\n | KycControllerHasCompletedVendorDisclaimersAction\n | KycControllerLaunchProviderFlowAction;\n"]}
1
+ {"version":3,"file":"KycController-method-action-types.js","sourceRoot":"","sources":["../src/KycController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { KycController } from './KycController.js';\n\n/**\n * Starts a KYC session for the given vendor. Reuses a latest vendor session\n * when one exists; otherwise creates a UKYC session.\n *\n * The verified email stored on controller state comes from the partner\n * identity token. When that request returns HTTP 422, a stored email is\n * kept for an existing session. Creating a vendor customer and UKYC session\n * requires the token, which both requests send as `partnerIdentityToken`.\n *\n * @param params - The session parameters.\n * @param params.vendor - Identity vendor for the session.\n * @param params.aal2Token - AAL2 authentication token. Required only when a\n * UKYC session must be created, where it is sent as the Authorization bearer\n * value. Omit it when reusing an existing session.\n * @returns The current or newly created session status.\n */\nexport type KycControllerStartSessionAction = {\n type: `KycController:startSession`;\n handler: KycController['startSession'];\n};\n\n/**\n * Stops session-status polling and restores default controller state.\n */\nexport type KycControllerResetAction = {\n type: `KycController:reset`;\n handler: KycController['reset'];\n};\n\n/**\n * Restores the controller to its default state.\n */\nexport type KycControllerClearStateAction = {\n type: `KycController:clearState`;\n handler: KycController['clearState'];\n};\n\n/**\n * Fetches the latest UKYC session status for a vendor.\n *\n * @param vendor - Identity vendor whose latest session should be queried.\n * @returns The session status, or `null` when none exists.\n */\nexport type KycControllerGetSessionStatusForVendorAction = {\n type: `KycController:getSessionStatusForVendor`;\n handler: KycController['getSessionStatusForVendor'];\n};\n\n/**\n * Returns the durable outcome of the identity-provider flow.\n *\n * @returns The latest provider-flow status.\n */\nexport type KycControllerGetProviderFlowStatusAction = {\n type: `KycController:getProviderFlowStatus`;\n handler: KycController['getProviderFlowStatus'];\n};\n\n/**\n * Returns the session already stored on state.\n *\n * Starts session-status polling when `finalStatus` is not `approved`,\n * `rejected`, or `retry`. Does not fetch status or refresh capability\n * authorization.\n *\n * @returns The session status stored at call time.\n * @throws If there is no session on state.\n */\nexport type KycControllerRefreshSessionStatusAction = {\n type: `KycController:refreshSessionStatus`;\n handler: KycController['refreshSessionStatus'];\n};\n\n/**\n * Returns the persisted session status.\n *\n * Does not call the network and does not start session-status polling.\n *\n * @returns The session on state, or `null` when none is stored.\n */\nexport type KycControllerReadSessionStatusAction = {\n type: `KycController:readSessionStatus`;\n handler: KycController['readSessionStatus'];\n};\n\n/**\n * Fetches `GET /sessions/{id}/status` once and writes the result onto state.\n *\n * Does not start the session-status polling timer.\n *\n * @param sessionId - UKYC session id.\n * @returns The fetched session status.\n */\nexport type KycControllerFetchSessionStatusOnceAction = {\n type: `KycController:fetchSessionStatusOnce`;\n handler: KycController['fetchSessionStatusOnce'];\n};\n\n/**\n * Starts polling `GET /sessions/{id}/status` for\n * {@link KycControllerState.sessionStatus}'s current `id`. Each tick writes\n * the result onto state only when the payload changed. The first poll runs\n * immediately. Each later wait starts at 10 seconds and grows by 10 seconds\n * after every poll, including a failed one. Starting the loop again resets\n * that delay. The loop stops once `finalStatus` is `approved`, `rejected`,\n * or `retry`, or when {@link reset} / {@link clearState} runs.\n *\n * @throws If there is no current session id to poll.\n */\nexport type KycControllerStartSessionStatusPollingAction = {\n type: `KycController:startSessionStatusPolling`;\n handler: KycController['startSessionStatusPolling'];\n};\n\n/**\n * Fetches the idOS + KYC-provider disclaimer catalog. Pass exactly one of\n * `sessionId` or `country`:\n *\n * - `{ sessionId }` → {@link KycService.fetchSessionDisclaimersBySessionId}\n * (`GET /sessions/{sessionId}/disclaimers`)\n * - `{ country }` → {@link KycService.fetchSessionDisclaimersByCountry}\n * (`GET /disclaimers?country=`)\n *\n * A session-id fetch also writes the catalog to `sessionDisclaimers`.\n *\n * @param params - The parameters. Provide exactly one of `sessionId` or\n * `country`.\n * @param params.sessionId - The UKYC session id.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The catalog. Session fetches include consent state; country\n * fetches do not.\n */\nexport type KycControllerFetchSessionDisclaimersAction = {\n type: `KycController:fetchSessionDisclaimers`;\n handler: KycController['fetchSessionDisclaimers'];\n};\n\n/**\n * Fetches the session-scoped disclaimer catalog and records consents\n * derived from the T&C2 flags. Already-consented catalog rows are omitted\n * from the POST. A 409 is re-checked with a GET: continue only when every\n * accepted document is now consented, otherwise fail closed.\n *\n * @param params - Accepted session-disclaimer records.\n * @param params.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.\n * @param params.idosDisclaimersAccepted - Accepted idOS disclaimer records.\n * @param params.credentialReusabilityConsentGiven - Whether credential\n * reuse was accepted.\n */\nexport type KycControllerRecordSessionDisclaimersAction = {\n type: `KycController:recordSessionDisclaimers`;\n handler: KycController['recordSessionDisclaimers'];\n};\n\n/**\n * Fetches the current session status and reports whether consent was given.\n *\n * @returns Whether `consentStatus` is `given`.\n * @throws If there is no session on state.\n */\nexport type KycControllerHasCompletedSessionDisclaimersAction = {\n type: `KycController:hasCompletedSessionDisclaimers`;\n handler: KycController['hasCompletedSessionDisclaimers'];\n};\n\n/**\n * Fetches the vendor T&Cs the customer must accept before a session is\n * created (`GET /vendors/{vendor}/disclaimers?country=`).\n *\n * @param params - The parameters.\n * @param params.vendor - Identity vendor. Defaults to `moonpay`.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The disclaimers.\n */\nexport type KycControllerFetchVendorDisclaimersAction = {\n type: `KycController:fetchVendorDisclaimers`;\n handler: KycController['fetchVendorDisclaimers'];\n};\n\n/**\n * Records vendor T&C acceptance via {@link KycService.submitVendorDisclaimers}\n * and persists the accepted ids on state.\n *\n * @param params - The parameters.\n * @param params.disclaimerIds - Accepted vendor T&C ids.\n * @returns The vendor signing records.\n * @throws If `vendor` is missing from state.\n */\nexport type KycControllerRecordVendorDisclaimersAction = {\n type: `KycController:recordVendorDisclaimers`;\n handler: KycController['recordVendorDisclaimers'];\n};\n\n/**\n * Fetches the current vendor T&C catalog and returns whether every document\n * is already recorded in {@link KycControllerState.vendorDisclaimersAccepted}.\n *\n * @returns Whether persisted acceptance covers the fetched catalog.\n * @throws If `vendor` or `geoCountry` is missing from state.\n */\nexport type KycControllerHasCompletedVendorDisclaimersAction = {\n type: `KycController:hasCompletedVendorDisclaimers`;\n handler: KycController['hasCompletedVendorDisclaimers'];\n};\n\n/**\n * Presents the identity-provider verification UI. Currently launches SumSub.\n *\n * @param params - Optional SDK presentation options.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\nexport type KycControllerLaunchProviderFlowAction = {\n type: `KycController:launchProviderFlow`;\n handler: KycController['launchProviderFlow'];\n};\n\n/**\n * Union of all KycController action types.\n */\nexport type KycControllerMethodActions =\n | KycControllerStartSessionAction\n | KycControllerResetAction\n | KycControllerClearStateAction\n | KycControllerGetSessionStatusForVendorAction\n | KycControllerGetProviderFlowStatusAction\n | KycControllerRefreshSessionStatusAction\n | KycControllerReadSessionStatusAction\n | KycControllerFetchSessionStatusOnceAction\n | KycControllerStartSessionStatusPollingAction\n | KycControllerFetchSessionDisclaimersAction\n | KycControllerRecordSessionDisclaimersAction\n | KycControllerHasCompletedSessionDisclaimersAction\n | KycControllerFetchVendorDisclaimersAction\n | KycControllerRecordVendorDisclaimersAction\n | KycControllerHasCompletedVendorDisclaimersAction\n | KycControllerLaunchProviderFlowAction;\n"]}
@@ -21,6 +21,8 @@ export type KycProviderFlowStatus = (typeof KYC_PROVIDER_FLOW_STATUSES)[number];
21
21
  * Describes the shape of the state object for {@link KycController}.
22
22
  */
23
23
  export type KycControllerState = {
24
+ /** Email associated with the session (sourced from the account). */
25
+ email: string | null;
24
26
  vendor: KycVendor | null;
25
27
  /** Resolved ISO 3166-1 alpha-3 country code. */
26
28
  geoCountry: string | null;
@@ -129,11 +131,10 @@ export declare class KycController extends BaseController<typeof controllerName,
129
131
  * Starts a KYC session for the given vendor. Reuses a latest vendor session
130
132
  * when one exists; otherwise creates a UKYC session.
131
133
  *
132
- * Creating a vendor customer and UKYC session requires a partner identity
133
- * token, which both requests send as `partnerIdentityToken`. A failure
134
- * while recording consent or minting that token is rethrown as
135
- * `KycController.startSession: failed to mint a partner identity token`,
136
- * with the original error as `cause`.
134
+ * The verified email stored on controller state comes from the partner
135
+ * identity token. When that request returns HTTP 422, a stored email is
136
+ * kept for an existing session. Creating a vendor customer and UKYC session
137
+ * requires the token, which both requests send as `partnerIdentityToken`.
137
138
  *
138
139
  * @param params - The session parameters.
139
140
  * @param params.vendor - Identity vendor for the session.
@@ -1 +1 @@
1
- {"version":3,"file":"KycController.d.ts","sourceRoot":"","sources":["../src/KycController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8DAA8D,EAE/D,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,qDAAqD,EAAE,MAAM,wCAAwC,CAAC;AACpH,OAAO,KAAK,EACV,4CAA4C,EAC5C,4CAA4C,EAC7C,MAAM,gDAAgD,CAAC;AAKxD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACzF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AASnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAM/D,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,8BAA8B,EAC9B,qBAAqB,EACrB,gBAAgB,EAChB,SAAS,EACT,4BAA4B,EAC5B,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAmBpB,eAAO,MAAM,cAAc,kBAAkB,CAAC;AAE9C,eAAO,MAAM,0BAA0B,YACrC,aAAa,EACb,WAAW,EACX,WAAW,EACX,QAAQ,CACA,CAAC;AAEX;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,CAAC,CAAC;AAchF;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAEzB,gDAAgD;IAChD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B,wEAAwE;IACxE,aAAa,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAEvC,oEAAoE;IACpE,kBAAkB,EAAE,qBAAqB,CAAC;IAG1C;;;;OAIG;IACH,yBAAyB,EAAE,4BAA4B,CAAC;IACxD;;;;;;OAMG;IACH,2BAA2B,EAAE,8BAA8B,CAAC;IAC5D;;;;;OAKG;IACH,uBAAuB,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC;IACnD;;;;;OAKG;IACH,iCAAiC,EAAE,OAAO,GAAG,IAAI,CAAC;CACnD,CAAC;AAqDF;;;;GAIG;AACH,wBAAgB,sCAAsC,IAAI,4BAA4B,CAErF;AAED;;;;GAIG;AACH,wBAAgB,wCAAwC,IAAI,8BAA8B,CAEzF;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,IAAI,kBAAkB,CAWjE;AAED;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GACrC;IACE,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB,GACD;IACE,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,KAAK,CAAC;CACnB,CAAC;AAuBN,MAAM,MAAM,2BAA2B,GAAG,wBAAwB,CAChE,OAAO,cAAc,EACrB,kBAAkB,CACnB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAC5B,2BAA2B,GAC3B,0BAA0B,CAAC;AAE/B,KAAK,cAAc,GACf,uBAAuB,GACvB,4CAA4C,GAC5C,4CAA4C,GAC5C,qDAAqD,GACrD,8DAA8D,CAAC;AAEnE,MAAM,MAAM,6BAA6B,GAAG,0BAA0B,CACpE,OAAO,cAAc,EACrB,kBAAkB,CACnB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,6BAA6B,CAAC;AAEhE,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAC5C,OAAO,cAAc,EACrB,oBAAoB,GAAG,cAAc,EACrC,mBAAmB,GAAG,aAAa,CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,sBAAsB,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpC;;;OAGG;IACH,cAAc,EAAE,iBAAiB,CAAC;CACnC,CAAC;AAIF;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,cAAc,CAC/C,OAAO,cAAc,EACrB,kBAAkB,EAClB,sBAAsB,CACvB;;IAcC;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,oBAAoB,EAerE;IAyBD;;;;;;;;;;;;;;;;OAgBG;IACG,YAAY,CAAC,MAAM,EAAE;QACzB,MAAM,EAAE,SAAS,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAsF5B;IAED;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;IAED;;OAEG;IACH,UAAU,IAAI,IAAI,CAcjB;IAED;;;;;OAKG;IACH,yBAAyB,CACvB,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAElC;IAED;;;;OAIG;IACH,qBAAqB,IAAI,qBAAqB,CAE7C;IAGD;;;;;;;;;OASG;IACH,oBAAoB,IAAI,gBAAgB,CAUvC;IAED;;;;;;OAMG;IACH,iBAAiB,IAAI,gBAAgB,GAAG,IAAI,CAE3C;IAED;;;;;;;OAOG;IACG,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CASzE;IAED;;;;;;;;;;OAUG;IACH,yBAAyB,IAAI,IAAI,CA2BhC;IAgOD;;;;;;;;;;;;;;;;;OAiBG;IACG,uBAAuB,CAC3B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,qBAAqB,GAAG,qBAAqB,CAAC,CA6BxD;IAED;;;;;;;;;;;OAWG;IACG,wBAAwB,CAAC,MAAM,EAAE;QACrC,2BAA2B,EAAE,gBAAgB,EAAE,CAAC;QAChD,uBAAuB,EAAE,gBAAgB,EAAE,CAAC;QAC5C,iCAAiC,EAAE,OAAO,CAAC;KAC5C,GAAG,OAAO,CAAC,IAAI,CAAC,CAuChB;IAED;;;;;OAKG;IACG,8BAA8B,IAAI,OAAO,CAAC,OAAO,CAAC,CAcvD;IAED;;;;;;;;OAQG;IACG,sBAAsB,CAAC,MAAM,EAAE;QACnC,MAAM,CAAC,EAAE,SAAS,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;KACjB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAE3B;IAED;;;;;;;;OAQG;IACG,uBAAuB,CAAC,MAAM,EAAE;QACpC,aAAa,EAAE,MAAM,EAAE,CAAC;KACzB,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA2B9B;IAED;;;;;;OAMG;IACG,6BAA6B,IAAI,OAAO,CAAC,OAAO,CAAC,CAmBtD;IAED;;;;;;;OAOG;IACH,kBAAkB,CAAC,EACjB,MAAM,EACN,KAAK,GACN,EAAE;QACD,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAGjC;CAkLF"}
1
+ {"version":3,"file":"KycController.d.ts","sourceRoot":"","sources":["../src/KycController.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { BaseController } from '@metamask/base-controller';
2
2
  import { stringToBytes } from '@metamask/utils';
3
3
  import { x25519 } from '@noble/curves/ed25519';
4
4
  import { toBase64Url } from './encoding.js';
5
+ import { getEmailFromPartnerIdentityToken, isEmailRequiredError, } from './partnerIdentityToken.js';
5
6
  import { isSumSubFlowCompleted, isSumSubFlowFailed, } from './providers/sumsub.js';
6
7
  import { consentRecordsFromAcceptedList } from './sessionDisclaimers.js';
7
8
  import { needsCapabilityAuthorizationRefresh, FINAL_STATUSES_TO_STOP_POLLING, } from './types.js';
@@ -28,6 +29,12 @@ const UKYC_CAPABILITY_TOKEN_TTL_MS = 72 * 60 * 60 * 1000;
28
29
  // step, so the delays are 10s, 20s, 30s, and so on.
29
30
  const SESSION_STATUS_POLL_INTERVAL_MS = 10_000;
30
31
  const kycControllerMetadata = {
32
+ email: {
33
+ includeInDebugSnapshot: false,
34
+ includeInStateLogs: false,
35
+ persist: true,
36
+ usedInUi: false,
37
+ },
31
38
  vendor: {
32
39
  includeInDebugSnapshot: true,
33
40
  includeInStateLogs: true,
@@ -100,6 +107,7 @@ export function getDefaultKycProviderDisclaimersAccepted() {
100
107
  */
101
108
  export function getDefaultKycControllerState() {
102
109
  return {
110
+ email: null,
103
111
  vendor: null,
104
112
  geoCountry: null,
105
113
  sessionStatus: null,
@@ -168,28 +176,39 @@ export class KycController extends BaseController {
168
176
  }
169
177
  /**
170
178
  * Records identity-sharing consent for the vendor's audience, then mints a
171
- * partner identity token.
179
+ * partner identity token and reads the verified email claim from JWT `ext`.
172
180
  *
173
181
  * @param vendor - Identity vendor whose partner audience to request.
174
- * @returns The minted token.
175
- * @throws If consent recording or token minting fails, including HTTP 422
176
- * (`EmailRequiredError`).
182
+ * @returns The minted token and its verified email, or `null` when the
183
+ * profile has no verified email (HTTP 422 / `EmailRequiredError`).
177
184
  */
178
185
  async #getPartnerIdentityForVendor(vendor) {
179
186
  // TODO: Fix this typing. Safe for now as only Iron is used
180
187
  const audience = vendor;
181
188
  await this.messenger.call('AuthenticatedUserStorageService:putIdentitySharingConsent', { audience, granted: true });
182
- return await this.messenger.call('AuthenticationController:getPartnerIdentityToken', ['email'], audience);
189
+ let partnerIdentityToken;
190
+ try {
191
+ partnerIdentityToken = await this.messenger.call('AuthenticationController:getPartnerIdentityToken', ['email'], audience);
192
+ }
193
+ catch (error) {
194
+ if (isEmailRequiredError(error)) {
195
+ return null;
196
+ }
197
+ throw error;
198
+ }
199
+ return {
200
+ partnerIdentityToken,
201
+ email: getEmailFromPartnerIdentityToken(partnerIdentityToken),
202
+ };
183
203
  }
184
204
  /**
185
205
  * Starts a KYC session for the given vendor. Reuses a latest vendor session
186
206
  * when one exists; otherwise creates a UKYC session.
187
207
  *
188
- * Creating a vendor customer and UKYC session requires a partner identity
189
- * token, which both requests send as `partnerIdentityToken`. A failure
190
- * while recording consent or minting that token is rethrown as
191
- * `KycController.startSession: failed to mint a partner identity token`,
192
- * with the original error as `cause`.
208
+ * The verified email stored on controller state comes from the partner
209
+ * identity token. When that request returns HTTP 422, a stored email is
210
+ * kept for an existing session. Creating a vendor customer and UKYC session
211
+ * requires the token, which both requests send as `partnerIdentityToken`.
193
212
  *
194
213
  * @param params - The session parameters.
195
214
  * @param params.vendor - Identity vendor for the session.
@@ -199,6 +218,14 @@ export class KycController extends BaseController {
199
218
  * @returns The current or newly created session status.
200
219
  */
201
220
  async startSession(params) {
221
+ const partnerIdentity = await this.#getPartnerIdentityForVendor(params.vendor);
222
+ const email = partnerIdentity?.email ?? this.state.email;
223
+ if (!email) {
224
+ throw new Error('KycController missing verified email for vendor');
225
+ }
226
+ if (this.state.email !== null && this.state.email !== email) {
227
+ throw new Error('KycController already initialized with a different email');
228
+ }
202
229
  if (this.state.vendor !== null && this.state.vendor !== params.vendor) {
203
230
  throw new Error('KycController already initialized with a different vendor');
204
231
  }
@@ -207,13 +234,18 @@ export class KycController extends BaseController {
207
234
  this.state.geoCountry !== geoCountry) {
208
235
  throw new Error('KycController already initialized with a different geoCountry');
209
236
  }
237
+ this.update((state) => {
238
+ state.email = email;
239
+ state.vendor = params.vendor;
240
+ state.geoCountry = geoCountry;
241
+ if (state.sessionStatus === null) {
242
+ state.providerFlowStatus = 'not_started';
243
+ }
244
+ });
210
245
  if (this.state.sessionStatus === null) {
211
246
  const sessionStatus = await this.messenger.call('KycService:getSessionStatusForVendor', params.vendor);
212
247
  if (sessionStatus !== null) {
213
248
  this.update((state) => {
214
- state.vendor = params.vendor;
215
- state.geoCountry = geoCountry;
216
- state.providerFlowStatus = 'not_started';
217
249
  state.sessionStatus = sessionStatus;
218
250
  });
219
251
  return this.#refreshAuthorizationsIfNeeded();
@@ -223,34 +255,20 @@ export class KycController extends BaseController {
223
255
  if (!params.aal2Token) {
224
256
  throw new Error('KycController.startSession: aal2Token is required to create a KYC session.');
225
257
  }
226
- // Mint before writing state so a failure leaves vendor and country unset.
227
- let partnerIdentityToken;
228
- try {
229
- partnerIdentityToken = await this.#getPartnerIdentityForVendor(params.vendor);
258
+ if (!partnerIdentity) {
259
+ throw new Error('KycController missing partner identity token for vendor');
230
260
  }
231
- catch (error) {
232
- throw new Error('KycController.startSession: failed to mint a partner identity token', { cause: error });
233
- }
234
- this.update((state) => {
235
- state.vendor = params.vendor;
236
- state.geoCountry = geoCountry;
237
- state.providerFlowStatus = 'not_started';
238
- });
239
261
  await this.messenger.call('KycService:createVendorCustomer', {
240
262
  vendor: params.vendor,
241
- partnerIdentityToken,
263
+ partnerIdentityToken: partnerIdentity.partnerIdentityToken,
242
264
  });
243
265
  return this.#createUkycSession({
244
266
  vendor: params.vendor,
245
267
  geoCountry,
246
268
  aal2Token: params.aal2Token,
247
- partnerIdentityToken,
269
+ partnerIdentityToken: partnerIdentity.partnerIdentityToken,
248
270
  });
249
271
  }
250
- this.update((state) => {
251
- state.vendor = params.vendor;
252
- state.geoCountry = geoCountry;
253
- });
254
272
  const sessionStatus = await this.messenger.call('KycService:getSessionStatus', { sessionId: this.state.sessionStatus.id });
255
273
  this.update((state) => {
256
274
  state.sessionStatus = sessionStatus;
@@ -271,6 +289,7 @@ export class KycController extends BaseController {
271
289
  clearState() {
272
290
  this.#stopSessionStatusPolling();
273
291
  this.update((state) => {
292
+ state.email = null;
274
293
  state.vendor = null;
275
294
  state.geoCountry = null;
276
295
  state.sessionStatus = null;
@@ -653,6 +672,9 @@ export class KycController extends BaseController {
653
672
  if (!this.state.vendor) {
654
673
  throw new Error('No vendor was found');
655
674
  }
675
+ if (!this.state.email) {
676
+ throw new Error('No email was found');
677
+ }
656
678
  const { vendor } = this.state;
657
679
  const signings = await this.messenger.call('KycService:submitVendorDisclaimers', {
658
680
  vendor,
@@ -1 +1 @@
1
- {"version":3,"file":"KycController.js","sourceRoot":"","sources":["../src/KycController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AuthenticatedUserStorageServicePutIdentitySharingConsentAction,\n IdentitySharingAudience,\n} from '@metamask/authenticated-user-storage';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { AuthenticationControllerGetPartnerIdentityTokenAction } from '@metamask/profile-sync-controller/auth';\nimport type {\n UserStorageControllerPerformGetStorageAction,\n UserStorageControllerPerformSetStorageAction,\n} from '@metamask/profile-sync-controller/user-storage';\nimport { stringToBytes } from '@metamask/utils';\nimport { x25519 } from '@noble/curves/ed25519';\n\nimport { toBase64Url } from './encoding.js';\nimport type { KycControllerMethodActions } from './KycController-method-action-types.js';\nimport type { KycServiceMethodActions } from './KycService-method-action-types.js';\nimport type {\n CapabilityAuthorization,\n EncryptionSchema,\n} from './KycService.js';\nimport {\n isSumSubFlowCompleted,\n isSumSubFlowFailed,\n} from './providers/sumsub.js';\nimport type { KycSumSubLauncher } from './providers/sumsub.js';\nimport { consentRecordsFromAcceptedList } from './sessionDisclaimers.js';\nimport {\n needsCapabilityAuthorizationRefresh,\n FINAL_STATUSES_TO_STOP_POLLING,\n} from './types.js';\nimport type {\n KycConsentRecord,\n KycDisclaimer,\n KycDisclaimersCatalog,\n KycProviderDisclaimersAccepted,\n KycSessionDisclaimers,\n KycSessionStatus,\n KycVendor,\n KycVendorDisclaimersAccepted,\n KycVendorSigning,\n} from './types.js';\nimport { deriveClientMaterial } from './ukyc/deriveClientMaterial.js';\nimport { assertAttestedServerPublicKey } from './ukyc/jwtChain.js';\nimport {\n getOrCreateLocalUserSecret,\n UkycLocalUserSecretStore,\n} from './ukyc/localUserSecret.js';\nimport {\n encodeStorageAccessTokenForHeader,\n signStorageAccessToken,\n} from './ukyc/storageAccessToken.js';\nimport { wrapEncryptionKey } from './ukyc/wrapEncryptionKey.js';\nimport {\n areVendorDisclaimersCompleted,\n recordVendorDisclaimerAcceptance,\n} from './vendorDisclaimers.js';\n\n// === GENERAL ===\n\nexport const controllerName = 'KycController';\n\nexport const KYC_PROVIDER_FLOW_STATUSES = [\n 'not_started',\n 'submitted',\n 'abandoned',\n 'failed',\n] as const;\n\n/**\n * Durable outcome of the identity-provider flow.\n *\n * Unlike the KYC session's `finalStatus`, this distinguishes a newly-created\n * pending session from a provider flow that the customer actually submitted.\n */\nexport type KycProviderFlowStatus = (typeof KYC_PROVIDER_FLOW_STATUSES)[number];\n\n// Lifetime of the read-only `ukyc_capability_token` minted when creating a\n// UKYC session. The storage-and-auth spec requires the token's `expires_at` to\n// cover the KYC session's expected lifetime — including the provider journey —\n// rather than a fixed short window, so this is a session-scoped window.\nconst UKYC_CAPABILITY_TOKEN_TTL_MS = 72 * 60 * 60 * 1000;\n\n// First wait between UKYC session-status polls. Each later wait grows by this\n// step, so the delays are 10s, 20s, 30s, and so on.\nconst SESSION_STATUS_POLL_INTERVAL_MS = 10_000;\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link KycController}.\n */\nexport type KycControllerState = {\n vendor: KycVendor | null;\n\n /** Resolved ISO 3166-1 alpha-3 country code. */\n geoCountry: string | null;\n\n /** Latest UKYC session status, or `null` when none has been fetched. */\n sessionStatus: KycSessionStatus | null;\n\n /** Last durable identity-provider flow outcome for this session. */\n providerFlowStatus: KycProviderFlowStatus;\n\n // TODO: Check if we need truly need to persist these accepted disclaimers\n /**\n * Persisted vendor-disclaimer acceptance (T&C1) with fixed `moonpay` and\n * `iron` keys. MoonPay stores only `termsAcceptedAt`; Iron stores\n * `disclaimerIds`.\n */\n vendorDisclaimersAccepted: KycVendorDisclaimersAccepted;\n /**\n * KYC-provider disclaimer documents the customer accepted during the last\n * terms acceptance (persisted `{ key, version }` records under `sumsub`).\n * Consents-path vendors require this when resuming a session. `null` for\n * acceptance recorded before this field existed (treated as requiring\n * reacceptance).\n */\n providerDisclaimersAccepted: KycProviderDisclaimersAccepted;\n /**\n * idOS disclaimer documents the customer accepted during the last terms\n * acceptance (persisted `{ key, version }` records). Consents-path vendors\n * require this when resuming a session. `null` for acceptance recorded\n * before this field existed (treated as requiring reacceptance).\n */\n idosDisclaimersAccepted: KycConsentRecord[] | null;\n /**\n * Whether the customer consented to reuse existing idOS credentials\n * during this session. Applied when recording session-scoped disclaimers.\n * Not persisted: a new UKYC session must collect reuse consent again.\n * `null` when never set (treated as `false`).\n */\n credentialReusabilityConsentGiven: boolean | null;\n};\n\nconst kycControllerMetadata = {\n vendor: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n geoCountry: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n sessionStatus: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n providerFlowStatus: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n vendorDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n providerDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n idosDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n credentialReusabilityConsentGiven: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<KycControllerState>;\n\n/**\n * Constructs the default {@link KycVendorDisclaimersAccepted} value.\n *\n * @returns The default vendor-disclaimer acceptance map.\n */\nexport function getDefaultKycVendorDisclaimersAccepted(): KycVendorDisclaimersAccepted {\n return { moonpay: null, iron: null };\n}\n\n/**\n * Constructs the default {@link KycProviderDisclaimersAccepted} value.\n *\n * @returns The default provider-disclaimer acceptance map.\n */\nexport function getDefaultKycProviderDisclaimersAccepted(): KycProviderDisclaimersAccepted {\n return { sumsub: null };\n}\n\n/**\n * Constructs the default {@link KycController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultKycControllerState(): KycControllerState {\n return {\n vendor: null,\n geoCountry: null,\n sessionStatus: null,\n providerFlowStatus: 'not_started',\n vendorDisclaimersAccepted: getDefaultKycVendorDisclaimersAccepted(),\n providerDisclaimersAccepted: getDefaultKycProviderDisclaimersAccepted(),\n idosDisclaimersAccepted: null,\n credentialReusabilityConsentGiven: null,\n };\n}\n\n/**\n * Parameters for {@link KycController.fetchSessionDisclaimers}. Provide\n * exactly one of `sessionId` or `country`.\n */\nexport type FetchSessionDisclaimersParams =\n | {\n /** UKYC session id from `KycService.createUkycSession`. */\n sessionId: string;\n country?: never;\n }\n | {\n /** ISO 3166-1 alpha-3 country code for `GET /disclaimers?country=`. */\n country: string;\n sessionId?: never;\n };\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'startSession',\n 'reset',\n 'clearState',\n 'getSessionStatusForVendor',\n 'getProviderFlowStatus',\n 'refreshSessionStatus',\n 'readSessionStatus',\n 'fetchSessionStatusOnce',\n 'startSessionStatusPolling',\n 'fetchSessionDisclaimers',\n 'recordSessionDisclaimers',\n 'hasCompletedSessionDisclaimers',\n 'fetchVendorDisclaimers',\n 'recordVendorDisclaimers',\n 'hasCompletedVendorDisclaimers',\n 'launchProviderFlow',\n] as const;\n\nexport type KycControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n KycControllerState\n>;\n\nexport type KycControllerActions =\n | KycControllerGetStateAction\n | KycControllerMethodActions;\n\ntype AllowedActions =\n | KycServiceMethodActions\n | UserStorageControllerPerformGetStorageAction\n | UserStorageControllerPerformSetStorageAction\n | AuthenticationControllerGetPartnerIdentityTokenAction\n | AuthenticatedUserStorageServicePutIdentitySharingConsentAction;\n\nexport type KycControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n KycControllerState\n>;\n\nexport type KycControllerEvents = KycControllerStateChangeEvent;\n\ntype AllowedEvents = never;\n\nexport type KycControllerMessenger = Messenger<\n typeof controllerName,\n KycControllerActions | AllowedActions,\n KycControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing a {@link KycController}.\n */\nexport type KycControllerOptions = {\n messenger: KycControllerMessenger;\n state?: Partial<KycControllerState>;\n /**\n * Platform adapter that presents the SumSub SDK. Injected by each client so\n * the controller stays platform-agnostic.\n */\n sumsubLauncher: KycSumSubLauncher;\n};\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `KycController` orchestrates the vendor-backed KYC / identity-verification\n * flow (MoonPay identity + SumSub documents) behind a vendor-neutral, per\n * product surface used by ramps and card. It owns all state and HTTP\n * orchestration (via `KycService`), while vendor protocol handling and\n * platform-specific presentation (WebView/iframe, SumSub SDK) are delegated.\n */\nexport class KycController extends BaseController<\n typeof controllerName,\n KycControllerState,\n KycControllerMessenger\n> {\n readonly #sumsubLauncher: KycSumSubLauncher;\n\n readonly #localUserSecretStore: UkycLocalUserSecretStore;\n\n /** Handle for the scheduled next session-status poll, or `null`. */\n #sessionStatusPollTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Monotonic polling token. Bumped when the loop stops so an in-flight fetch\n * neither writes state nor schedules a follow-up.\n */\n #sessionStatusPollToken = 0;\n\n /**\n * Constructs a new {@link KycController}.\n *\n * @param options - The constructor options.\n * @param options.messenger - The messenger suited for this controller.\n * @param options.state - Partial initial state; merged over defaults.\n * @param options.sumsubLauncher - The platform SumSub launcher adapter.\n */\n constructor({ messenger, state, sumsubLauncher }: KycControllerOptions) {\n super({\n messenger,\n metadata: kycControllerMetadata,\n name: controllerName,\n state: { ...getDefaultKycControllerState(), ...state },\n });\n\n this.#sumsubLauncher = sumsubLauncher;\n this.#localUserSecretStore = new UkycLocalUserSecretStore(this.messenger);\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Records identity-sharing consent for the vendor's audience, then mints a\n * partner identity token.\n *\n * @param vendor - Identity vendor whose partner audience to request.\n * @returns The minted token.\n * @throws If consent recording or token minting fails, including HTTP 422\n * (`EmailRequiredError`).\n */\n async #getPartnerIdentityForVendor(vendor: KycVendor): Promise<string> {\n // TODO: Fix this typing. Safe for now as only Iron is used\n const audience = vendor as IdentitySharingAudience;\n await this.messenger.call(\n 'AuthenticatedUserStorageService:putIdentitySharingConsent',\n { audience, granted: true },\n );\n return await this.messenger.call(\n 'AuthenticationController:getPartnerIdentityToken',\n ['email'],\n audience,\n );\n }\n\n /**\n * Starts a KYC session for the given vendor. Reuses a latest vendor session\n * when one exists; otherwise creates a UKYC session.\n *\n * Creating a vendor customer and UKYC session requires a partner identity\n * token, which both requests send as `partnerIdentityToken`. A failure\n * while recording consent or minting that token is rethrown as\n * `KycController.startSession: failed to mint a partner identity token`,\n * with the original error as `cause`.\n *\n * @param params - The session parameters.\n * @param params.vendor - Identity vendor for the session.\n * @param params.aal2Token - AAL2 authentication token. Required only when a\n * UKYC session must be created, where it is sent as the Authorization bearer\n * value. Omit it when reusing an existing session.\n * @returns The current or newly created session status.\n */\n async startSession(params: {\n vendor: KycVendor;\n aal2Token?: string;\n }): Promise<KycSessionStatus> {\n if (this.state.vendor !== null && this.state.vendor !== params.vendor) {\n throw new Error(\n 'KycController already initialized with a different vendor',\n );\n }\n\n const geoCountry = await this.messenger.call('KycService:getGeoCountry');\n if (\n this.state.geoCountry !== null &&\n this.state.geoCountry !== geoCountry\n ) {\n throw new Error(\n 'KycController already initialized with a different geoCountry',\n );\n }\n\n if (this.state.sessionStatus === null) {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatusForVendor',\n params.vendor,\n );\n if (sessionStatus !== null) {\n this.update((state) => {\n state.vendor = params.vendor;\n state.geoCountry = geoCountry;\n state.providerFlowStatus = 'not_started';\n state.sessionStatus = sessionStatus;\n });\n return this.#refreshAuthorizationsIfNeeded();\n }\n\n // TODO: Probably move this into it's own method? Feels like startSession is a little overloaded.\n // It's assumed that if the session does not exist, the customer does not exist either\n if (!params.aal2Token) {\n throw new Error(\n 'KycController.startSession: aal2Token is required to create a KYC session.',\n );\n }\n\n // Mint before writing state so a failure leaves vendor and country unset.\n let partnerIdentityToken: string;\n try {\n partnerIdentityToken = await this.#getPartnerIdentityForVendor(\n params.vendor,\n );\n } catch (error) {\n throw new Error(\n 'KycController.startSession: failed to mint a partner identity token',\n { cause: error },\n );\n }\n\n this.update((state) => {\n state.vendor = params.vendor;\n state.geoCountry = geoCountry;\n state.providerFlowStatus = 'not_started';\n });\n\n await this.messenger.call('KycService:createVendorCustomer', {\n vendor: params.vendor,\n partnerIdentityToken,\n });\n\n return this.#createUkycSession({\n vendor: params.vendor,\n geoCountry,\n aal2Token: params.aal2Token,\n partnerIdentityToken,\n });\n }\n\n this.update((state) => {\n state.vendor = params.vendor;\n state.geoCountry = geoCountry;\n });\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId: this.state.sessionStatus.id },\n );\n\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n // TODO: Should we resume polling here?\n return this.#refreshAuthorizationsIfNeeded();\n }\n\n /**\n * Stops session-status polling and restores default controller state.\n */\n async reset(): Promise<void> {\n this.#stopSessionStatusPolling();\n this.clearState();\n }\n\n /**\n * Restores the controller to its default state.\n */\n clearState(): void {\n this.#stopSessionStatusPolling();\n this.update((state) => {\n state.vendor = null;\n state.geoCountry = null;\n state.sessionStatus = null;\n state.providerFlowStatus = 'not_started';\n state.vendorDisclaimersAccepted =\n getDefaultKycVendorDisclaimersAccepted();\n state.providerDisclaimersAccepted =\n getDefaultKycProviderDisclaimersAccepted();\n state.idosDisclaimersAccepted = null;\n state.credentialReusabilityConsentGiven = null;\n });\n }\n\n /**\n * Fetches the latest UKYC session status for a vendor.\n *\n * @param vendor - Identity vendor whose latest session should be queried.\n * @returns The session status, or `null` when none exists.\n */\n getSessionStatusForVendor(\n vendor: KycVendor,\n ): Promise<KycSessionStatus | null> {\n return this.messenger.call('KycService:getSessionStatusForVendor', vendor);\n }\n\n /**\n * Returns the durable outcome of the identity-provider flow.\n *\n * @returns The latest provider-flow status.\n */\n getProviderFlowStatus(): KycProviderFlowStatus {\n return this.state.providerFlowStatus;\n }\n\n // TODO: Perhaps this should be renamed to resumeSession()?\n /**\n * Returns the session already stored on state.\n *\n * Starts session-status polling when `finalStatus` is not `approved`,\n * `rejected`, or `retry`. Does not fetch status or refresh capability\n * authorization.\n *\n * @returns The session status stored at call time.\n * @throws If there is no session on state.\n */\n refreshSessionStatus(): KycSessionStatus {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n if (\n !FINAL_STATUSES_TO_STOP_POLLING.has(this.state.sessionStatus.finalStatus)\n ) {\n this.startSessionStatusPolling();\n }\n return this.state.sessionStatus;\n }\n\n /**\n * Returns the persisted session status.\n *\n * Does not call the network and does not start session-status polling.\n *\n * @returns The session on state, or `null` when none is stored.\n */\n readSessionStatus(): KycSessionStatus | null {\n return this.state.sessionStatus;\n }\n\n /**\n * Fetches `GET /sessions/{id}/status` once and writes the result onto state.\n *\n * Does not start the session-status polling timer.\n *\n * @param sessionId - UKYC session id.\n * @returns The fetched session status.\n */\n async fetchSessionStatusOnce(sessionId: string): Promise<KycSessionStatus> {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId },\n );\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n return sessionStatus;\n }\n\n /**\n * Starts polling `GET /sessions/{id}/status` for\n * {@link KycControllerState.sessionStatus}'s current `id`. Each tick writes\n * the result onto state only when the payload changed. The first poll runs\n * immediately. Each later wait starts at 10 seconds and grows by 10 seconds\n * after every poll, including a failed one. Starting the loop again resets\n * that delay. The loop stops once `finalStatus` is `approved`, `rejected`,\n * or `retry`, or when {@link reset} / {@link clearState} runs.\n *\n * @throws If there is no current session id to poll.\n */\n startSessionStatusPolling(): void {\n const sessionId = this.state.sessionStatus?.id;\n if (!sessionId) {\n throw new Error('No session was found');\n }\n\n this.#stopSessionStatusPolling();\n const token = this.#sessionStatusPollToken;\n let completedPolls = 0;\n\n const tick = async (): Promise<void> => {\n const shouldStop = await this.#pollSessionStatusOnce(sessionId, token);\n if (shouldStop) {\n return;\n }\n completedPolls += 1;\n this.#sessionStatusPollTimer = setTimeout(() => {\n this.#sessionStatusPollTimer = null;\n // `tick` swallows its own errors and therefore never rejects.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n tick();\n }, SESSION_STATUS_POLL_INTERVAL_MS * completedPolls);\n this.#sessionStatusPollTimer.unref?.();\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n tick();\n }\n\n /**\n * Fetches session status for the polled session and records it when it\n * differs from state.\n *\n * @param sessionId - Session the loop started for.\n * @param token - Polling token captured when the loop started.\n * @returns Whether the loop should stop.\n */\n async #pollSessionStatusOnce(\n sessionId: string,\n token: number,\n ): Promise<boolean> {\n try {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId },\n );\n if (this.#sessionStatusPollToken !== token) {\n return true;\n }\n\n // TODO: This check seems fragile\n if (\n JSON.stringify(this.state.sessionStatus) !==\n JSON.stringify(sessionStatus)\n ) {\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n }\n\n if (FINAL_STATUSES_TO_STOP_POLLING.has(sessionStatus.finalStatus)) {\n this.#stopSessionStatusPolling();\n return true;\n }\n return false;\n } catch {\n return this.#sessionStatusPollToken !== token;\n }\n }\n\n /**\n * Stops the session-status polling loop.\n */\n #stopSessionStatusPolling(): void {\n this.#sessionStatusPollToken += 1;\n if (this.#sessionStatusPollTimer !== null) {\n clearTimeout(this.#sessionStatusPollTimer);\n this.#sessionStatusPollTimer = null;\n }\n }\n\n /**\n * Creates or reuses a UKYC session, wraps the `data_encryption_key` and\n * `ukyc_capability_token` against the returned encryption schemas, and\n * submits both via authorizations. Stores the resulting session status.\n * kyc-api returns the existing session if one with the same vendor and\n * canonicalUserId already exists.\n *\n * @param params - Vendor, country, and tokens used to create the session.\n * @param params.vendor - Identity vendor for the UKYC session.\n * @param params.geoCountry - ISO 3166-1 alpha-3 country of residence.\n * @param params.aal2Token - AAL2 authentication token sent as the\n * Authorization bearer value for session creation.\n * @param params.partnerIdentityToken - Partner identity token minted for\n * the vendor's audience.\n * @returns The created or refreshed session status.\n */\n async #createUkycSession(params: {\n vendor: KycVendor;\n geoCountry: string;\n aal2Token: string;\n partnerIdentityToken: string;\n }): Promise<KycSessionStatus> {\n // Establish a per-session X25519 keypair used to seal both secrets. The\n // private half stays on the device; the public half is registered on the\n // session so the server can open later authorizations. Each encryption\n // schema from session creation supplies the matching server public key.\n const sessionClientPrivateKey = x25519.utils.randomSecretKey();\n const sessionClientPublicKey = toBase64Url(\n x25519.getPublicKey(sessionClientPrivateKey),\n );\n // Residence is the ISO 3166-1 alpha-3 country already resolved for\n // disclaimers / KYC-required; fetch it if this sub-flow started without\n // that earlier step.\n const {\n sessionId,\n encryptionDataKey: encryptionDataKeySchema,\n ukycCapabilityToken: capabilityTokenSchema,\n } = await this.messenger.call('KycService:createUkycSession', {\n sessionClientPublicKey,\n residenceCountry: params.geoCountry,\n vendor: params.vendor,\n aal2Token: params.aal2Token,\n partnerIdentityToken: params.partnerIdentityToken,\n });\n\n return this.#setAuthorizations({\n sessionId,\n sessionClientPrivateKey,\n sessionClientPublicKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n });\n }\n\n /**\n * Verifies encryption schemas, wraps the `data_encryption_key` and\n * `ukyc_capability_token`, and submits both via\n * {@link KycService.setAuthorizations}. Stores the resulting session status.\n *\n * @param params - Session key material and encryption schemas.\n * @param params.sessionId - UKYC session id to authorize.\n * @param params.sessionClientPrivateKey - Per-session X25519 private key\n * used to seal both secrets.\n * @param params.sessionClientPublicKey - Matching public key registered on\n * the session (must correspond to `sessionClientPrivateKey`).\n * @param params.encryptionDataKeySchema - Encryption schema for the data\n * encryption key.\n * @param params.capabilityTokenSchema - Encryption schema for the capability\n * token.\n * @returns The session status after authorizations are applied.\n */\n async #setAuthorizations(params: {\n sessionId: string;\n sessionClientPrivateKey: Uint8Array;\n sessionClientPublicKey: string;\n encryptionDataKeySchema: EncryptionSchema;\n capabilityTokenSchema: EncryptionSchema;\n }): Promise<KycSessionStatus> {\n const {\n sessionId,\n sessionClientPrivateKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n } = params;\n\n await this.#verifyWrappingKeys(\n encryptionDataKeySchema,\n capabilityTokenSchema,\n );\n\n const { wrappedEncryptionDataKey, wrappedUkycCapabilityToken } =\n await this.#generateWrappedAuthorizations(\n sessionClientPrivateKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n );\n\n const sessionStatus = await this.messenger.call(\n 'KycService:setAuthorizations',\n {\n sessionId,\n wrappedEncryptionDataKey,\n wrappedUkycCapabilityToken,\n },\n );\n\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n\n return sessionStatus;\n }\n\n /**\n * Mints a new per-session X25519 keypair, reissues wrapping keys for the\n * current session, and submits wrapped authorizations.\n *\n * @returns The session status after authorizations are applied.\n * @throws If there is no session on state.\n */\n async #refreshAuthorizations(): Promise<KycSessionStatus> {\n const sessionId = this.state.sessionStatus?.id;\n if (!sessionId) {\n throw new Error('No session was found');\n }\n\n const sessionClientPrivateKey = x25519.utils.randomSecretKey();\n const sessionClientPublicKey = toBase64Url(\n x25519.getPublicKey(sessionClientPrivateKey),\n );\n\n const {\n encryptionDataKey: encryptionDataKeySchema,\n ukycCapabilityToken: capabilityTokenSchema,\n } = await this.messenger.call('KycService:resetWrappingKeys', {\n sessionId,\n sessionClientPublicKey,\n });\n\n return this.#setAuthorizations({\n sessionId,\n sessionClientPrivateKey,\n sessionClientPublicKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n });\n }\n\n /**\n * Refreshes and resubmits the UKYC capability authorization when the current\n * session reports it as `new` or `expired`. Uses the `sessionStatus` already\n * on state (callers are responsible for refreshing status when needed).\n * No-ops when KYC has already finished (`finalStatus` is `approved` or\n * `rejected`) or the capability token is `pending`, `stored`, or `wiped`.\n *\n * @returns The current or refreshed session status.\n * @throws If there is no session on state when a refresh is required.\n */\n async #refreshAuthorizationsIfNeeded(): Promise<KycSessionStatus> {\n const { sessionStatus } = this.state;\n if (!sessionStatus) {\n throw new Error('No session was found');\n }\n\n if (!needsCapabilityAuthorizationRefresh(sessionStatus)) {\n return sessionStatus;\n }\n return this.#refreshAuthorizations();\n }\n\n /**\n * Fetches the idOS + KYC-provider disclaimer catalog. Pass exactly one of\n * `sessionId` or `country`:\n *\n * - `{ sessionId }` → {@link KycService.fetchSessionDisclaimersBySessionId}\n * (`GET /sessions/{sessionId}/disclaimers`)\n * - `{ country }` → {@link KycService.fetchSessionDisclaimersByCountry}\n * (`GET /disclaimers?country=`)\n *\n * A session-id fetch also writes the catalog to `sessionDisclaimers`.\n *\n * @param params - The parameters. Provide exactly one of `sessionId` or\n * `country`.\n * @param params.sessionId - The UKYC session id.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The catalog. Session fetches include consent state; country\n * fetches do not.\n */\n async fetchSessionDisclaimers(\n params: FetchSessionDisclaimersParams,\n ): Promise<KycSessionDisclaimers | KycDisclaimersCatalog> {\n const { sessionId, country } = params as {\n sessionId?: string;\n country?: string;\n };\n if (sessionId && country) {\n throw new Error(\n 'KycController.fetchSessionDisclaimers: provide exactly one of sessionId or country.',\n );\n }\n\n if (country) {\n return this.messenger.call(\n 'KycService:fetchSessionDisclaimersByCountry',\n { country },\n );\n }\n\n if (!sessionId) {\n throw new Error(\n 'KycController.fetchSessionDisclaimers: provide exactly one of sessionId or country.',\n );\n }\n\n const catalog = await this.messenger.call(\n 'KycService:fetchSessionDisclaimersBySessionId',\n { sessionId },\n );\n return catalog;\n }\n\n /**\n * Fetches the session-scoped disclaimer catalog and records consents\n * derived from the T&C2 flags. Already-consented catalog rows are omitted\n * from the POST. A 409 is re-checked with a GET: continue only when every\n * accepted document is now consented, otherwise fail closed.\n *\n * @param params - Accepted session-disclaimer records.\n * @param params.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.\n * @param params.idosDisclaimersAccepted - Accepted idOS disclaimer records.\n * @param params.credentialReusabilityConsentGiven - Whether credential\n * reuse was accepted.\n */\n async recordSessionDisclaimers(params: {\n providerDisclaimersAccepted: KycConsentRecord[];\n idosDisclaimersAccepted: KycConsentRecord[];\n credentialReusabilityConsentGiven: boolean;\n }): Promise<void> {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n\n // TODO: Check if these can simply be mapped to `{key, version}` pairs instead\n const disclaimers = await this.messenger.call(\n 'KycService:fetchSessionDisclaimersBySessionId',\n { sessionId: this.state.sessionStatus.id },\n );\n\n const idOS = consentRecordsFromAcceptedList(\n disclaimers.idOS,\n params.idosDisclaimersAccepted,\n );\n const kycProvider = consentRecordsFromAcceptedList(\n disclaimers.kycProvider,\n params.providerDisclaimersAccepted,\n );\n\n try {\n await this.messenger.call('KycService:submitSessionDisclaimers', {\n sessionId: this.state.sessionStatus.id,\n idOS,\n kycProvider,\n credentialReusabilityConsentGiven:\n params.credentialReusabilityConsentGiven,\n });\n } catch {\n // A 409 means the session already recorded these consents.\n }\n this.update((state) => {\n // TODO: This shouldn't be hardcoded to sumsub\n state.providerDisclaimersAccepted.sumsub =\n params.providerDisclaimersAccepted;\n state.idosDisclaimersAccepted = params.idosDisclaimersAccepted;\n state.credentialReusabilityConsentGiven =\n params.credentialReusabilityConsentGiven;\n });\n }\n\n /**\n * Fetches the current session status and reports whether consent was given.\n *\n * @returns Whether `consentStatus` is `given`.\n * @throws If there is no session on state.\n */\n async hasCompletedSessionDisclaimers(): Promise<boolean> {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n\n // TODO: remove this explicit call to the service and use the state directly\n // after we have established the pattern for resuming a session after wallet\n // restart more concretely\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId: this.state.sessionStatus.id },\n );\n\n return sessionStatus.consentStatus === 'given';\n }\n\n /**\n * Fetches the vendor T&Cs the customer must accept before a session is\n * created (`GET /vendors/{vendor}/disclaimers?country=`).\n *\n * @param params - The parameters.\n * @param params.vendor - Identity vendor. Defaults to `moonpay`.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The disclaimers.\n */\n async fetchVendorDisclaimers(params: {\n vendor?: KycVendor;\n country: string;\n }): Promise<KycDisclaimer[]> {\n return this.messenger.call('KycService:fetchVendorDisclaimers', params);\n }\n\n /**\n * Records vendor T&C acceptance via {@link KycService.submitVendorDisclaimers}\n * and persists the accepted ids on state.\n *\n * @param params - The parameters.\n * @param params.disclaimerIds - Accepted vendor T&C ids.\n * @returns The vendor signing records.\n * @throws If `vendor` is missing from state.\n */\n async recordVendorDisclaimers(params: {\n disclaimerIds: string[];\n }): Promise<KycVendorSigning[]> {\n if (!this.state.vendor) {\n throw new Error('No vendor was found');\n }\n\n const { vendor } = this.state;\n\n const signings = await this.messenger.call(\n 'KycService:submitVendorDisclaimers',\n {\n vendor,\n disclaimerIds: params.disclaimerIds,\n },\n );\n\n // TODO: this only works for Iron right now\n this.update((state) => {\n state.vendorDisclaimersAccepted = recordVendorDisclaimerAcceptance(\n state.vendorDisclaimersAccepted,\n vendor,\n {\n disclaimerIds: params.disclaimerIds,\n },\n );\n });\n\n return signings;\n }\n\n /**\n * Fetches the current vendor T&C catalog and returns whether every document\n * is already recorded in {@link KycControllerState.vendorDisclaimersAccepted}.\n *\n * @returns Whether persisted acceptance covers the fetched catalog.\n * @throws If `vendor` or `geoCountry` is missing from state.\n */\n async hasCompletedVendorDisclaimers(): Promise<boolean> {\n if (!this.state.vendor) {\n throw new Error('No vendor was found');\n }\n if (!this.state.geoCountry) {\n throw new Error('No geoCountry was found');\n }\n\n const fetched = await this.fetchVendorDisclaimers({\n vendor: this.state.vendor,\n country: this.state.geoCountry,\n });\n\n // TODO: this only works for Iron right now\n return areVendorDisclaimersCompleted(\n this.state.vendorDisclaimersAccepted,\n this.state.vendor,\n fetched,\n );\n }\n\n /**\n * Presents the identity-provider verification UI. Currently launches SumSub.\n *\n * @param params - Optional SDK presentation options.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\n launchProviderFlow({\n locale,\n debug,\n }: {\n locale?: string;\n debug?: boolean;\n }): Promise<KycProviderFlowStatus> {\n // Currently only sumsub is supported and must be used for Iron\n return this.#launchSumsubFlow({ locale, debug });\n }\n\n /**\n * Runs the SumSub document-verification sub-flow end to end:\n *\n * 1. fetches the SumSub applicant access token; and\n * 2. presents the SDK via the injected launcher.\n *\n * Capability authorization must already be valid on\n * {@link KycControllerState.sessionStatus} (see\n * {@link KycController.#refreshAuthorizationsIfNeeded}).\n *\n * @param params - Optional parameters.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\n async #launchSumsubFlow(params?: {\n locale?: string;\n debug?: boolean;\n }): Promise<KycProviderFlowStatus> {\n const sessionId = this.state.sessionStatus?.id;\n if (!this.#sumsubLauncher.isAvailable() || !sessionId) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n return 'failed';\n }\n\n try {\n // TODO: check if the sumsub and idos disclaimers are accepted\n const { applicantAccessToken } = await this.messenger.call(\n 'KycService:createJourney',\n sessionId,\n );\n\n // Track whether the SDK ever reported a successful completion or its own\n // failure. A resolved `launch` alone does not imply success — the\n // applicant may have abandoned the flow, or the SDK may have reported\n // that it could not run.\n let reachedCompletion = false;\n let sdkFailed = false;\n\n const result = await this.#sumsubLauncher.launch({\n applicantAccessToken,\n onTokenExpiration: async () => {\n const journey = await this.messenger.call(\n 'KycService:createJourney',\n sessionId,\n );\n return journey.applicantAccessToken;\n },\n onStatusChange: (_prev, next) => {\n if (isSumSubFlowCompleted(next)) {\n reachedCompletion = true;\n }\n if (isSumSubFlowFailed(next)) {\n sdkFailed = true;\n }\n },\n locale: params?.locale ?? 'en',\n debug: params?.debug ?? false,\n });\n\n // Some native SDKs resolve with their final status without first\n // delivering the corresponding state-change callback.\n reachedCompletion ||= isSumSubFlowCompleted(result.status);\n sdkFailed ||= isSumSubFlowFailed(result.status);\n\n const currentSessionStatus = this.state.sessionStatus;\n if (currentSessionStatus?.id !== sessionId) {\n return 'failed';\n }\n\n if (sdkFailed) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n return 'failed';\n }\n\n if (reachedCompletion) {\n // Once the SDK completes, the authoritative verification decision comes\n // from the UKYC backend, not the SDK result.\n this.update((state) => {\n state.sessionStatus = {\n ...currentSessionStatus,\n finalStatus: 'pending',\n };\n state.providerFlowStatus = 'submitted';\n });\n this.startSessionStatusPolling();\n return 'submitted';\n }\n\n this.update((state) => {\n state.providerFlowStatus = 'abandoned';\n });\n return 'abandoned';\n } catch {\n if (this.state.sessionStatus?.id === sessionId) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n }\n return 'failed';\n }\n }\n\n /**\n * Verifies each schema's jwtChain against the matching issuer JWKS, then\n * confirms the returned server public key matches the value attested inside\n * the verified JWT payload before trusting it for wrapping.\n * `encryptionDataKey` is attested by the idOS enclave; `ukycCapabilityToken`\n * by the idOS relay.\n *\n * @param encryptionDataKey - Encryption schema for the data encryption key.\n * @param capabilityTokenSchema - Encryption schema for the capability token.\n */\n async #verifyWrappingKeys(\n encryptionDataKey: EncryptionSchema,\n capabilityTokenSchema: EncryptionSchema,\n ): Promise<void> {\n const [{ keys: idosEnclaveKeys }, { keys: idosRelayKeys }] =\n await Promise.all([\n this.messenger.call('KycService:fetchIdosEnclaveJwks'),\n this.messenger.call('KycService:fetchIdosRelayJwks'),\n ]);\n assertAttestedServerPublicKey(idosEnclaveKeys, encryptionDataKey);\n assertAttestedServerPublicKey(idosRelayKeys, capabilityTokenSchema);\n }\n\n /**\n * Derives the `data_encryption_key` from the `local_user_secret`, mints a\n * capability token, and wraps both for the session server. Only the wrapped\n * (encrypted) material ever leaves the device.\n *\n * Only the client holds the signing key derived from `local_user_secret`, so\n * only the client can mint the token.\n *\n * @param sessionClientPrivateKey - Per-session X25519 private key used to\n * seal both secrets.\n * @param encryptionDataKey - Encryption schema for the data encryption key.\n * @param capabilityTokenSchema - Encryption schema for the capability token.\n * @returns The wrapped encryption key and capability token.\n */\n async #generateWrappedAuthorizations(\n sessionClientPrivateKey: Uint8Array,\n encryptionDataKey: EncryptionSchema,\n capabilityTokenSchema: EncryptionSchema,\n ): Promise<{\n wrappedEncryptionDataKey: CapabilityAuthorization;\n wrappedUkycCapabilityToken: CapabilityAuthorization;\n }> {\n const localUserSecret = await getOrCreateLocalUserSecret(\n this.#localUserSecretStore,\n );\n const clientMaterial = deriveClientMaterial(localUserSecret);\n const wrappedEncryptionDataKey = wrapEncryptionKey(\n sessionClientPrivateKey,\n encryptionDataKey.serverPublicKey.x,\n clientMaterial.dataEncryptionKey,\n );\n\n const ukycCapabilityToken = signStorageAccessToken({\n material: clientMaterial,\n // TODO: Confirm with idOS when this can be switched back to read and a separate token is sent for write\n operations: ['read', 'write'],\n expiresAt: new Date(Date.now() + UKYC_CAPABILITY_TOKEN_TTL_MS),\n });\n const wrappedUkycCapabilityToken = wrapEncryptionKey(\n sessionClientPrivateKey,\n capabilityTokenSchema.serverPublicKey.x,\n stringToBytes(encodeStorageAccessTokenForHeader(ukycCapabilityToken)),\n );\n\n return { wrappedEncryptionDataKey, wrappedUkycCapabilityToken };\n }\n}\n"]}
1
+ {"version":3,"file":"KycController.js","sourceRoot":"","sources":["../src/KycController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AuthenticatedUserStorageServicePutIdentitySharingConsentAction,\n IdentitySharingAudience,\n} from '@metamask/authenticated-user-storage';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { AuthenticationControllerGetPartnerIdentityTokenAction } from '@metamask/profile-sync-controller/auth';\nimport type {\n UserStorageControllerPerformGetStorageAction,\n UserStorageControllerPerformSetStorageAction,\n} from '@metamask/profile-sync-controller/user-storage';\nimport { stringToBytes } from '@metamask/utils';\nimport { x25519 } from '@noble/curves/ed25519';\n\nimport { toBase64Url } from './encoding.js';\nimport type { KycControllerMethodActions } from './KycController-method-action-types.js';\nimport type { KycServiceMethodActions } from './KycService-method-action-types.js';\nimport type {\n CapabilityAuthorization,\n EncryptionSchema,\n} from './KycService.js';\nimport {\n getEmailFromPartnerIdentityToken,\n isEmailRequiredError,\n} from './partnerIdentityToken.js';\nimport {\n isSumSubFlowCompleted,\n isSumSubFlowFailed,\n} from './providers/sumsub.js';\nimport type { KycSumSubLauncher } from './providers/sumsub.js';\nimport { consentRecordsFromAcceptedList } from './sessionDisclaimers.js';\nimport {\n needsCapabilityAuthorizationRefresh,\n FINAL_STATUSES_TO_STOP_POLLING,\n} from './types.js';\nimport type {\n KycConsentRecord,\n KycDisclaimer,\n KycDisclaimersCatalog,\n KycProviderDisclaimersAccepted,\n KycSessionDisclaimers,\n KycSessionStatus,\n KycVendor,\n KycVendorDisclaimersAccepted,\n KycVendorSigning,\n} from './types.js';\nimport { deriveClientMaterial } from './ukyc/deriveClientMaterial.js';\nimport { assertAttestedServerPublicKey } from './ukyc/jwtChain.js';\nimport {\n getOrCreateLocalUserSecret,\n UkycLocalUserSecretStore,\n} from './ukyc/localUserSecret.js';\nimport {\n encodeStorageAccessTokenForHeader,\n signStorageAccessToken,\n} from './ukyc/storageAccessToken.js';\nimport { wrapEncryptionKey } from './ukyc/wrapEncryptionKey.js';\nimport {\n areVendorDisclaimersCompleted,\n recordVendorDisclaimerAcceptance,\n} from './vendorDisclaimers.js';\n\n// === GENERAL ===\n\nexport const controllerName = 'KycController';\n\nexport const KYC_PROVIDER_FLOW_STATUSES = [\n 'not_started',\n 'submitted',\n 'abandoned',\n 'failed',\n] as const;\n\n/**\n * Durable outcome of the identity-provider flow.\n *\n * Unlike the KYC session's `finalStatus`, this distinguishes a newly-created\n * pending session from a provider flow that the customer actually submitted.\n */\nexport type KycProviderFlowStatus = (typeof KYC_PROVIDER_FLOW_STATUSES)[number];\n\n// Lifetime of the read-only `ukyc_capability_token` minted when creating a\n// UKYC session. The storage-and-auth spec requires the token's `expires_at` to\n// cover the KYC session's expected lifetime — including the provider journey —\n// rather than a fixed short window, so this is a session-scoped window.\nconst UKYC_CAPABILITY_TOKEN_TTL_MS = 72 * 60 * 60 * 1000;\n\n// First wait between UKYC session-status polls. Each later wait grows by this\n// step, so the delays are 10s, 20s, 30s, and so on.\nconst SESSION_STATUS_POLL_INTERVAL_MS = 10_000;\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link KycController}.\n */\nexport type KycControllerState = {\n /** Email associated with the session (sourced from the account). */\n email: string | null;\n\n vendor: KycVendor | null;\n\n /** Resolved ISO 3166-1 alpha-3 country code. */\n geoCountry: string | null;\n\n /** Latest UKYC session status, or `null` when none has been fetched. */\n sessionStatus: KycSessionStatus | null;\n\n /** Last durable identity-provider flow outcome for this session. */\n providerFlowStatus: KycProviderFlowStatus;\n\n // TODO: Check if we need truly need to persist these accepted disclaimers\n /**\n * Persisted vendor-disclaimer acceptance (T&C1) with fixed `moonpay` and\n * `iron` keys. MoonPay stores only `termsAcceptedAt`; Iron stores\n * `disclaimerIds`.\n */\n vendorDisclaimersAccepted: KycVendorDisclaimersAccepted;\n /**\n * KYC-provider disclaimer documents the customer accepted during the last\n * terms acceptance (persisted `{ key, version }` records under `sumsub`).\n * Consents-path vendors require this when resuming a session. `null` for\n * acceptance recorded before this field existed (treated as requiring\n * reacceptance).\n */\n providerDisclaimersAccepted: KycProviderDisclaimersAccepted;\n /**\n * idOS disclaimer documents the customer accepted during the last terms\n * acceptance (persisted `{ key, version }` records). Consents-path vendors\n * require this when resuming a session. `null` for acceptance recorded\n * before this field existed (treated as requiring reacceptance).\n */\n idosDisclaimersAccepted: KycConsentRecord[] | null;\n /**\n * Whether the customer consented to reuse existing idOS credentials\n * during this session. Applied when recording session-scoped disclaimers.\n * Not persisted: a new UKYC session must collect reuse consent again.\n * `null` when never set (treated as `false`).\n */\n credentialReusabilityConsentGiven: boolean | null;\n};\n\nconst kycControllerMetadata = {\n email: {\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n persist: true,\n usedInUi: false,\n },\n vendor: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n geoCountry: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n sessionStatus: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n providerFlowStatus: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: true,\n },\n vendorDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n providerDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n idosDisclaimersAccepted: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n credentialReusabilityConsentGiven: {\n includeInDebugSnapshot: true,\n includeInStateLogs: true,\n persist: true,\n usedInUi: false,\n },\n} satisfies StateMetadata<KycControllerState>;\n\n/**\n * Constructs the default {@link KycVendorDisclaimersAccepted} value.\n *\n * @returns The default vendor-disclaimer acceptance map.\n */\nexport function getDefaultKycVendorDisclaimersAccepted(): KycVendorDisclaimersAccepted {\n return { moonpay: null, iron: null };\n}\n\n/**\n * Constructs the default {@link KycProviderDisclaimersAccepted} value.\n *\n * @returns The default provider-disclaimer acceptance map.\n */\nexport function getDefaultKycProviderDisclaimersAccepted(): KycProviderDisclaimersAccepted {\n return { sumsub: null };\n}\n\n/**\n * Constructs the default {@link KycController} state.\n *\n * @returns The default state.\n */\nexport function getDefaultKycControllerState(): KycControllerState {\n return {\n email: null,\n vendor: null,\n geoCountry: null,\n sessionStatus: null,\n providerFlowStatus: 'not_started',\n vendorDisclaimersAccepted: getDefaultKycVendorDisclaimersAccepted(),\n providerDisclaimersAccepted: getDefaultKycProviderDisclaimersAccepted(),\n idosDisclaimersAccepted: null,\n credentialReusabilityConsentGiven: null,\n };\n}\n\n/**\n * Parameters for {@link KycController.fetchSessionDisclaimers}. Provide\n * exactly one of `sessionId` or `country`.\n */\nexport type FetchSessionDisclaimersParams =\n | {\n /** UKYC session id from `KycService.createUkycSession`. */\n sessionId: string;\n country?: never;\n }\n | {\n /** ISO 3166-1 alpha-3 country code for `GET /disclaimers?country=`. */\n country: string;\n sessionId?: never;\n };\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'startSession',\n 'reset',\n 'clearState',\n 'getSessionStatusForVendor',\n 'getProviderFlowStatus',\n 'refreshSessionStatus',\n 'readSessionStatus',\n 'fetchSessionStatusOnce',\n 'startSessionStatusPolling',\n 'fetchSessionDisclaimers',\n 'recordSessionDisclaimers',\n 'hasCompletedSessionDisclaimers',\n 'fetchVendorDisclaimers',\n 'recordVendorDisclaimers',\n 'hasCompletedVendorDisclaimers',\n 'launchProviderFlow',\n] as const;\n\nexport type KycControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n KycControllerState\n>;\n\nexport type KycControllerActions =\n | KycControllerGetStateAction\n | KycControllerMethodActions;\n\ntype AllowedActions =\n | KycServiceMethodActions\n | UserStorageControllerPerformGetStorageAction\n | UserStorageControllerPerformSetStorageAction\n | AuthenticationControllerGetPartnerIdentityTokenAction\n | AuthenticatedUserStorageServicePutIdentitySharingConsentAction;\n\nexport type KycControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n KycControllerState\n>;\n\nexport type KycControllerEvents = KycControllerStateChangeEvent;\n\ntype AllowedEvents = never;\n\nexport type KycControllerMessenger = Messenger<\n typeof controllerName,\n KycControllerActions | AllowedActions,\n KycControllerEvents | AllowedEvents\n>;\n\n/**\n * Options for constructing a {@link KycController}.\n */\nexport type KycControllerOptions = {\n messenger: KycControllerMessenger;\n state?: Partial<KycControllerState>;\n /**\n * Platform adapter that presents the SumSub SDK. Injected by each client so\n * the controller stays platform-agnostic.\n */\n sumsubLauncher: KycSumSubLauncher;\n};\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * `KycController` orchestrates the vendor-backed KYC / identity-verification\n * flow (MoonPay identity + SumSub documents) behind a vendor-neutral, per\n * product surface used by ramps and card. It owns all state and HTTP\n * orchestration (via `KycService`), while vendor protocol handling and\n * platform-specific presentation (WebView/iframe, SumSub SDK) are delegated.\n */\nexport class KycController extends BaseController<\n typeof controllerName,\n KycControllerState,\n KycControllerMessenger\n> {\n readonly #sumsubLauncher: KycSumSubLauncher;\n\n readonly #localUserSecretStore: UkycLocalUserSecretStore;\n\n /** Handle for the scheduled next session-status poll, or `null`. */\n #sessionStatusPollTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Monotonic polling token. Bumped when the loop stops so an in-flight fetch\n * neither writes state nor schedules a follow-up.\n */\n #sessionStatusPollToken = 0;\n\n /**\n * Constructs a new {@link KycController}.\n *\n * @param options - The constructor options.\n * @param options.messenger - The messenger suited for this controller.\n * @param options.state - Partial initial state; merged over defaults.\n * @param options.sumsubLauncher - The platform SumSub launcher adapter.\n */\n constructor({ messenger, state, sumsubLauncher }: KycControllerOptions) {\n super({\n messenger,\n metadata: kycControllerMetadata,\n name: controllerName,\n state: { ...getDefaultKycControllerState(), ...state },\n });\n\n this.#sumsubLauncher = sumsubLauncher;\n this.#localUserSecretStore = new UkycLocalUserSecretStore(this.messenger);\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Records identity-sharing consent for the vendor's audience, then mints a\n * partner identity token and reads the verified email claim from JWT `ext`.\n *\n * @param vendor - Identity vendor whose partner audience to request.\n * @returns The minted token and its verified email, or `null` when the\n * profile has no verified email (HTTP 422 / `EmailRequiredError`).\n */\n async #getPartnerIdentityForVendor(vendor: KycVendor): Promise<{\n partnerIdentityToken: string;\n email: string;\n } | null> {\n // TODO: Fix this typing. Safe for now as only Iron is used\n const audience = vendor as IdentitySharingAudience;\n await this.messenger.call(\n 'AuthenticatedUserStorageService:putIdentitySharingConsent',\n { audience, granted: true },\n );\n let partnerIdentityToken: string;\n try {\n partnerIdentityToken = await this.messenger.call(\n 'AuthenticationController:getPartnerIdentityToken',\n ['email'],\n audience,\n );\n } catch (error) {\n if (isEmailRequiredError(error)) {\n return null;\n }\n throw error;\n }\n return {\n partnerIdentityToken,\n email: getEmailFromPartnerIdentityToken(partnerIdentityToken),\n };\n }\n\n /**\n * Starts a KYC session for the given vendor. Reuses a latest vendor session\n * when one exists; otherwise creates a UKYC session.\n *\n * The verified email stored on controller state comes from the partner\n * identity token. When that request returns HTTP 422, a stored email is\n * kept for an existing session. Creating a vendor customer and UKYC session\n * requires the token, which both requests send as `partnerIdentityToken`.\n *\n * @param params - The session parameters.\n * @param params.vendor - Identity vendor for the session.\n * @param params.aal2Token - AAL2 authentication token. Required only when a\n * UKYC session must be created, where it is sent as the Authorization bearer\n * value. Omit it when reusing an existing session.\n * @returns The current or newly created session status.\n */\n async startSession(params: {\n vendor: KycVendor;\n aal2Token?: string;\n }): Promise<KycSessionStatus> {\n const partnerIdentity = await this.#getPartnerIdentityForVendor(\n params.vendor,\n );\n const email = partnerIdentity?.email ?? this.state.email;\n if (!email) {\n throw new Error('KycController missing verified email for vendor');\n }\n if (this.state.email !== null && this.state.email !== email) {\n throw new Error(\n 'KycController already initialized with a different email',\n );\n }\n if (this.state.vendor !== null && this.state.vendor !== params.vendor) {\n throw new Error(\n 'KycController already initialized with a different vendor',\n );\n }\n\n const geoCountry = await this.messenger.call('KycService:getGeoCountry');\n if (\n this.state.geoCountry !== null &&\n this.state.geoCountry !== geoCountry\n ) {\n throw new Error(\n 'KycController already initialized with a different geoCountry',\n );\n }\n\n this.update((state) => {\n state.email = email;\n state.vendor = params.vendor;\n state.geoCountry = geoCountry;\n if (state.sessionStatus === null) {\n state.providerFlowStatus = 'not_started';\n }\n });\n\n if (this.state.sessionStatus === null) {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatusForVendor',\n params.vendor,\n );\n if (sessionStatus !== null) {\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n return this.#refreshAuthorizationsIfNeeded();\n }\n\n // TODO: Probably move this into it's own method? Feels like startSession is a little overloaded.\n // It's assumed that if the session does not exist, the customer does not exist either\n if (!params.aal2Token) {\n throw new Error(\n 'KycController.startSession: aal2Token is required to create a KYC session.',\n );\n }\n\n if (!partnerIdentity) {\n throw new Error(\n 'KycController missing partner identity token for vendor',\n );\n }\n\n await this.messenger.call('KycService:createVendorCustomer', {\n vendor: params.vendor,\n partnerIdentityToken: partnerIdentity.partnerIdentityToken,\n });\n\n return this.#createUkycSession({\n vendor: params.vendor,\n geoCountry,\n aal2Token: params.aal2Token,\n partnerIdentityToken: partnerIdentity.partnerIdentityToken,\n });\n }\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId: this.state.sessionStatus.id },\n );\n\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n // TODO: Should we resume polling here?\n return this.#refreshAuthorizationsIfNeeded();\n }\n\n /**\n * Stops session-status polling and restores default controller state.\n */\n async reset(): Promise<void> {\n this.#stopSessionStatusPolling();\n this.clearState();\n }\n\n /**\n * Restores the controller to its default state.\n */\n clearState(): void {\n this.#stopSessionStatusPolling();\n this.update((state) => {\n state.email = null;\n state.vendor = null;\n state.geoCountry = null;\n state.sessionStatus = null;\n state.providerFlowStatus = 'not_started';\n state.vendorDisclaimersAccepted =\n getDefaultKycVendorDisclaimersAccepted();\n state.providerDisclaimersAccepted =\n getDefaultKycProviderDisclaimersAccepted();\n state.idosDisclaimersAccepted = null;\n state.credentialReusabilityConsentGiven = null;\n });\n }\n\n /**\n * Fetches the latest UKYC session status for a vendor.\n *\n * @param vendor - Identity vendor whose latest session should be queried.\n * @returns The session status, or `null` when none exists.\n */\n getSessionStatusForVendor(\n vendor: KycVendor,\n ): Promise<KycSessionStatus | null> {\n return this.messenger.call('KycService:getSessionStatusForVendor', vendor);\n }\n\n /**\n * Returns the durable outcome of the identity-provider flow.\n *\n * @returns The latest provider-flow status.\n */\n getProviderFlowStatus(): KycProviderFlowStatus {\n return this.state.providerFlowStatus;\n }\n\n // TODO: Perhaps this should be renamed to resumeSession()?\n /**\n * Returns the session already stored on state.\n *\n * Starts session-status polling when `finalStatus` is not `approved`,\n * `rejected`, or `retry`. Does not fetch status or refresh capability\n * authorization.\n *\n * @returns The session status stored at call time.\n * @throws If there is no session on state.\n */\n refreshSessionStatus(): KycSessionStatus {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n if (\n !FINAL_STATUSES_TO_STOP_POLLING.has(this.state.sessionStatus.finalStatus)\n ) {\n this.startSessionStatusPolling();\n }\n return this.state.sessionStatus;\n }\n\n /**\n * Returns the persisted session status.\n *\n * Does not call the network and does not start session-status polling.\n *\n * @returns The session on state, or `null` when none is stored.\n */\n readSessionStatus(): KycSessionStatus | null {\n return this.state.sessionStatus;\n }\n\n /**\n * Fetches `GET /sessions/{id}/status` once and writes the result onto state.\n *\n * Does not start the session-status polling timer.\n *\n * @param sessionId - UKYC session id.\n * @returns The fetched session status.\n */\n async fetchSessionStatusOnce(sessionId: string): Promise<KycSessionStatus> {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId },\n );\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n return sessionStatus;\n }\n\n /**\n * Starts polling `GET /sessions/{id}/status` for\n * {@link KycControllerState.sessionStatus}'s current `id`. Each tick writes\n * the result onto state only when the payload changed. The first poll runs\n * immediately. Each later wait starts at 10 seconds and grows by 10 seconds\n * after every poll, including a failed one. Starting the loop again resets\n * that delay. The loop stops once `finalStatus` is `approved`, `rejected`,\n * or `retry`, or when {@link reset} / {@link clearState} runs.\n *\n * @throws If there is no current session id to poll.\n */\n startSessionStatusPolling(): void {\n const sessionId = this.state.sessionStatus?.id;\n if (!sessionId) {\n throw new Error('No session was found');\n }\n\n this.#stopSessionStatusPolling();\n const token = this.#sessionStatusPollToken;\n let completedPolls = 0;\n\n const tick = async (): Promise<void> => {\n const shouldStop = await this.#pollSessionStatusOnce(sessionId, token);\n if (shouldStop) {\n return;\n }\n completedPolls += 1;\n this.#sessionStatusPollTimer = setTimeout(() => {\n this.#sessionStatusPollTimer = null;\n // `tick` swallows its own errors and therefore never rejects.\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n tick();\n }, SESSION_STATUS_POLL_INTERVAL_MS * completedPolls);\n this.#sessionStatusPollTimer.unref?.();\n };\n\n // eslint-disable-next-line @typescript-eslint/no-floating-promises\n tick();\n }\n\n /**\n * Fetches session status for the polled session and records it when it\n * differs from state.\n *\n * @param sessionId - Session the loop started for.\n * @param token - Polling token captured when the loop started.\n * @returns Whether the loop should stop.\n */\n async #pollSessionStatusOnce(\n sessionId: string,\n token: number,\n ): Promise<boolean> {\n try {\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId },\n );\n if (this.#sessionStatusPollToken !== token) {\n return true;\n }\n\n // TODO: This check seems fragile\n if (\n JSON.stringify(this.state.sessionStatus) !==\n JSON.stringify(sessionStatus)\n ) {\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n }\n\n if (FINAL_STATUSES_TO_STOP_POLLING.has(sessionStatus.finalStatus)) {\n this.#stopSessionStatusPolling();\n return true;\n }\n return false;\n } catch {\n return this.#sessionStatusPollToken !== token;\n }\n }\n\n /**\n * Stops the session-status polling loop.\n */\n #stopSessionStatusPolling(): void {\n this.#sessionStatusPollToken += 1;\n if (this.#sessionStatusPollTimer !== null) {\n clearTimeout(this.#sessionStatusPollTimer);\n this.#sessionStatusPollTimer = null;\n }\n }\n\n /**\n * Creates or reuses a UKYC session, wraps the `data_encryption_key` and\n * `ukyc_capability_token` against the returned encryption schemas, and\n * submits both via authorizations. Stores the resulting session status.\n * kyc-api returns the existing session if one with the same vendor and\n * canonicalUserId already exists.\n *\n * @param params - Vendor, country, and tokens used to create the session.\n * @param params.vendor - Identity vendor for the UKYC session.\n * @param params.geoCountry - ISO 3166-1 alpha-3 country of residence.\n * @param params.aal2Token - AAL2 authentication token sent as the\n * Authorization bearer value for session creation.\n * @param params.partnerIdentityToken - Partner identity token minted for\n * the vendor's audience.\n * @returns The created or refreshed session status.\n */\n async #createUkycSession(params: {\n vendor: KycVendor;\n geoCountry: string;\n aal2Token: string;\n partnerIdentityToken: string;\n }): Promise<KycSessionStatus> {\n // Establish a per-session X25519 keypair used to seal both secrets. The\n // private half stays on the device; the public half is registered on the\n // session so the server can open later authorizations. Each encryption\n // schema from session creation supplies the matching server public key.\n const sessionClientPrivateKey = x25519.utils.randomSecretKey();\n const sessionClientPublicKey = toBase64Url(\n x25519.getPublicKey(sessionClientPrivateKey),\n );\n // Residence is the ISO 3166-1 alpha-3 country already resolved for\n // disclaimers / KYC-required; fetch it if this sub-flow started without\n // that earlier step.\n const {\n sessionId,\n encryptionDataKey: encryptionDataKeySchema,\n ukycCapabilityToken: capabilityTokenSchema,\n } = await this.messenger.call('KycService:createUkycSession', {\n sessionClientPublicKey,\n residenceCountry: params.geoCountry,\n vendor: params.vendor,\n aal2Token: params.aal2Token,\n partnerIdentityToken: params.partnerIdentityToken,\n });\n\n return this.#setAuthorizations({\n sessionId,\n sessionClientPrivateKey,\n sessionClientPublicKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n });\n }\n\n /**\n * Verifies encryption schemas, wraps the `data_encryption_key` and\n * `ukyc_capability_token`, and submits both via\n * {@link KycService.setAuthorizations}. Stores the resulting session status.\n *\n * @param params - Session key material and encryption schemas.\n * @param params.sessionId - UKYC session id to authorize.\n * @param params.sessionClientPrivateKey - Per-session X25519 private key\n * used to seal both secrets.\n * @param params.sessionClientPublicKey - Matching public key registered on\n * the session (must correspond to `sessionClientPrivateKey`).\n * @param params.encryptionDataKeySchema - Encryption schema for the data\n * encryption key.\n * @param params.capabilityTokenSchema - Encryption schema for the capability\n * token.\n * @returns The session status after authorizations are applied.\n */\n async #setAuthorizations(params: {\n sessionId: string;\n sessionClientPrivateKey: Uint8Array;\n sessionClientPublicKey: string;\n encryptionDataKeySchema: EncryptionSchema;\n capabilityTokenSchema: EncryptionSchema;\n }): Promise<KycSessionStatus> {\n const {\n sessionId,\n sessionClientPrivateKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n } = params;\n\n await this.#verifyWrappingKeys(\n encryptionDataKeySchema,\n capabilityTokenSchema,\n );\n\n const { wrappedEncryptionDataKey, wrappedUkycCapabilityToken } =\n await this.#generateWrappedAuthorizations(\n sessionClientPrivateKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n );\n\n const sessionStatus = await this.messenger.call(\n 'KycService:setAuthorizations',\n {\n sessionId,\n wrappedEncryptionDataKey,\n wrappedUkycCapabilityToken,\n },\n );\n\n this.update((state) => {\n state.sessionStatus = sessionStatus;\n });\n\n return sessionStatus;\n }\n\n /**\n * Mints a new per-session X25519 keypair, reissues wrapping keys for the\n * current session, and submits wrapped authorizations.\n *\n * @returns The session status after authorizations are applied.\n * @throws If there is no session on state.\n */\n async #refreshAuthorizations(): Promise<KycSessionStatus> {\n const sessionId = this.state.sessionStatus?.id;\n if (!sessionId) {\n throw new Error('No session was found');\n }\n\n const sessionClientPrivateKey = x25519.utils.randomSecretKey();\n const sessionClientPublicKey = toBase64Url(\n x25519.getPublicKey(sessionClientPrivateKey),\n );\n\n const {\n encryptionDataKey: encryptionDataKeySchema,\n ukycCapabilityToken: capabilityTokenSchema,\n } = await this.messenger.call('KycService:resetWrappingKeys', {\n sessionId,\n sessionClientPublicKey,\n });\n\n return this.#setAuthorizations({\n sessionId,\n sessionClientPrivateKey,\n sessionClientPublicKey,\n encryptionDataKeySchema,\n capabilityTokenSchema,\n });\n }\n\n /**\n * Refreshes and resubmits the UKYC capability authorization when the current\n * session reports it as `new` or `expired`. Uses the `sessionStatus` already\n * on state (callers are responsible for refreshing status when needed).\n * No-ops when KYC has already finished (`finalStatus` is `approved` or\n * `rejected`) or the capability token is `pending`, `stored`, or `wiped`.\n *\n * @returns The current or refreshed session status.\n * @throws If there is no session on state when a refresh is required.\n */\n async #refreshAuthorizationsIfNeeded(): Promise<KycSessionStatus> {\n const { sessionStatus } = this.state;\n if (!sessionStatus) {\n throw new Error('No session was found');\n }\n\n if (!needsCapabilityAuthorizationRefresh(sessionStatus)) {\n return sessionStatus;\n }\n return this.#refreshAuthorizations();\n }\n\n /**\n * Fetches the idOS + KYC-provider disclaimer catalog. Pass exactly one of\n * `sessionId` or `country`:\n *\n * - `{ sessionId }` → {@link KycService.fetchSessionDisclaimersBySessionId}\n * (`GET /sessions/{sessionId}/disclaimers`)\n * - `{ country }` → {@link KycService.fetchSessionDisclaimersByCountry}\n * (`GET /disclaimers?country=`)\n *\n * A session-id fetch also writes the catalog to `sessionDisclaimers`.\n *\n * @param params - The parameters. Provide exactly one of `sessionId` or\n * `country`.\n * @param params.sessionId - The UKYC session id.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The catalog. Session fetches include consent state; country\n * fetches do not.\n */\n async fetchSessionDisclaimers(\n params: FetchSessionDisclaimersParams,\n ): Promise<KycSessionDisclaimers | KycDisclaimersCatalog> {\n const { sessionId, country } = params as {\n sessionId?: string;\n country?: string;\n };\n if (sessionId && country) {\n throw new Error(\n 'KycController.fetchSessionDisclaimers: provide exactly one of sessionId or country.',\n );\n }\n\n if (country) {\n return this.messenger.call(\n 'KycService:fetchSessionDisclaimersByCountry',\n { country },\n );\n }\n\n if (!sessionId) {\n throw new Error(\n 'KycController.fetchSessionDisclaimers: provide exactly one of sessionId or country.',\n );\n }\n\n const catalog = await this.messenger.call(\n 'KycService:fetchSessionDisclaimersBySessionId',\n { sessionId },\n );\n return catalog;\n }\n\n /**\n * Fetches the session-scoped disclaimer catalog and records consents\n * derived from the T&C2 flags. Already-consented catalog rows are omitted\n * from the POST. A 409 is re-checked with a GET: continue only when every\n * accepted document is now consented, otherwise fail closed.\n *\n * @param params - Accepted session-disclaimer records.\n * @param params.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.\n * @param params.idosDisclaimersAccepted - Accepted idOS disclaimer records.\n * @param params.credentialReusabilityConsentGiven - Whether credential\n * reuse was accepted.\n */\n async recordSessionDisclaimers(params: {\n providerDisclaimersAccepted: KycConsentRecord[];\n idosDisclaimersAccepted: KycConsentRecord[];\n credentialReusabilityConsentGiven: boolean;\n }): Promise<void> {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n\n // TODO: Check if these can simply be mapped to `{key, version}` pairs instead\n const disclaimers = await this.messenger.call(\n 'KycService:fetchSessionDisclaimersBySessionId',\n { sessionId: this.state.sessionStatus.id },\n );\n\n const idOS = consentRecordsFromAcceptedList(\n disclaimers.idOS,\n params.idosDisclaimersAccepted,\n );\n const kycProvider = consentRecordsFromAcceptedList(\n disclaimers.kycProvider,\n params.providerDisclaimersAccepted,\n );\n\n try {\n await this.messenger.call('KycService:submitSessionDisclaimers', {\n sessionId: this.state.sessionStatus.id,\n idOS,\n kycProvider,\n credentialReusabilityConsentGiven:\n params.credentialReusabilityConsentGiven,\n });\n } catch {\n // A 409 means the session already recorded these consents.\n }\n this.update((state) => {\n // TODO: This shouldn't be hardcoded to sumsub\n state.providerDisclaimersAccepted.sumsub =\n params.providerDisclaimersAccepted;\n state.idosDisclaimersAccepted = params.idosDisclaimersAccepted;\n state.credentialReusabilityConsentGiven =\n params.credentialReusabilityConsentGiven;\n });\n }\n\n /**\n * Fetches the current session status and reports whether consent was given.\n *\n * @returns Whether `consentStatus` is `given`.\n * @throws If there is no session on state.\n */\n async hasCompletedSessionDisclaimers(): Promise<boolean> {\n if (!this.state.sessionStatus) {\n throw new Error('No session was found');\n }\n\n // TODO: remove this explicit call to the service and use the state directly\n // after we have established the pattern for resuming a session after wallet\n // restart more concretely\n const sessionStatus = await this.messenger.call(\n 'KycService:getSessionStatus',\n { sessionId: this.state.sessionStatus.id },\n );\n\n return sessionStatus.consentStatus === 'given';\n }\n\n /**\n * Fetches the vendor T&Cs the customer must accept before a session is\n * created (`GET /vendors/{vendor}/disclaimers?country=`).\n *\n * @param params - The parameters.\n * @param params.vendor - Identity vendor. Defaults to `moonpay`.\n * @param params.country - ISO 3166-1 alpha-3 country code.\n * @returns The disclaimers.\n */\n async fetchVendorDisclaimers(params: {\n vendor?: KycVendor;\n country: string;\n }): Promise<KycDisclaimer[]> {\n return this.messenger.call('KycService:fetchVendorDisclaimers', params);\n }\n\n /**\n * Records vendor T&C acceptance via {@link KycService.submitVendorDisclaimers}\n * and persists the accepted ids on state.\n *\n * @param params - The parameters.\n * @param params.disclaimerIds - Accepted vendor T&C ids.\n * @returns The vendor signing records.\n * @throws If `vendor` is missing from state.\n */\n async recordVendorDisclaimers(params: {\n disclaimerIds: string[];\n }): Promise<KycVendorSigning[]> {\n if (!this.state.vendor) {\n throw new Error('No vendor was found');\n }\n\n if (!this.state.email) {\n throw new Error('No email was found');\n }\n\n const { vendor } = this.state;\n\n const signings = await this.messenger.call(\n 'KycService:submitVendorDisclaimers',\n {\n vendor,\n disclaimerIds: params.disclaimerIds,\n },\n );\n\n // TODO: this only works for Iron right now\n this.update((state) => {\n state.vendorDisclaimersAccepted = recordVendorDisclaimerAcceptance(\n state.vendorDisclaimersAccepted,\n vendor,\n {\n disclaimerIds: params.disclaimerIds,\n },\n );\n });\n\n return signings;\n }\n\n /**\n * Fetches the current vendor T&C catalog and returns whether every document\n * is already recorded in {@link KycControllerState.vendorDisclaimersAccepted}.\n *\n * @returns Whether persisted acceptance covers the fetched catalog.\n * @throws If `vendor` or `geoCountry` is missing from state.\n */\n async hasCompletedVendorDisclaimers(): Promise<boolean> {\n if (!this.state.vendor) {\n throw new Error('No vendor was found');\n }\n if (!this.state.geoCountry) {\n throw new Error('No geoCountry was found');\n }\n\n const fetched = await this.fetchVendorDisclaimers({\n vendor: this.state.vendor,\n country: this.state.geoCountry,\n });\n\n // TODO: this only works for Iron right now\n return areVendorDisclaimersCompleted(\n this.state.vendorDisclaimersAccepted,\n this.state.vendor,\n fetched,\n );\n }\n\n /**\n * Presents the identity-provider verification UI. Currently launches SumSub.\n *\n * @param params - Optional SDK presentation options.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\n launchProviderFlow({\n locale,\n debug,\n }: {\n locale?: string;\n debug?: boolean;\n }): Promise<KycProviderFlowStatus> {\n // Currently only sumsub is supported and must be used for Iron\n return this.#launchSumsubFlow({ locale, debug });\n }\n\n /**\n * Runs the SumSub document-verification sub-flow end to end:\n *\n * 1. fetches the SumSub applicant access token; and\n * 2. presents the SDK via the injected launcher.\n *\n * Capability authorization must already be valid on\n * {@link KycControllerState.sessionStatus} (see\n * {@link KycController.#refreshAuthorizationsIfNeeded}).\n *\n * @param params - Optional parameters.\n * @param params.locale - BCP-47 locale for the SDK UI.\n * @param params.debug - Enables SDK debug logging.\n * @returns The durable provider-flow outcome.\n */\n async #launchSumsubFlow(params?: {\n locale?: string;\n debug?: boolean;\n }): Promise<KycProviderFlowStatus> {\n const sessionId = this.state.sessionStatus?.id;\n if (!this.#sumsubLauncher.isAvailable() || !sessionId) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n return 'failed';\n }\n\n try {\n // TODO: check if the sumsub and idos disclaimers are accepted\n const { applicantAccessToken } = await this.messenger.call(\n 'KycService:createJourney',\n sessionId,\n );\n\n // Track whether the SDK ever reported a successful completion or its own\n // failure. A resolved `launch` alone does not imply success — the\n // applicant may have abandoned the flow, or the SDK may have reported\n // that it could not run.\n let reachedCompletion = false;\n let sdkFailed = false;\n\n const result = await this.#sumsubLauncher.launch({\n applicantAccessToken,\n onTokenExpiration: async () => {\n const journey = await this.messenger.call(\n 'KycService:createJourney',\n sessionId,\n );\n return journey.applicantAccessToken;\n },\n onStatusChange: (_prev, next) => {\n if (isSumSubFlowCompleted(next)) {\n reachedCompletion = true;\n }\n if (isSumSubFlowFailed(next)) {\n sdkFailed = true;\n }\n },\n locale: params?.locale ?? 'en',\n debug: params?.debug ?? false,\n });\n\n // Some native SDKs resolve with their final status without first\n // delivering the corresponding state-change callback.\n reachedCompletion ||= isSumSubFlowCompleted(result.status);\n sdkFailed ||= isSumSubFlowFailed(result.status);\n\n const currentSessionStatus = this.state.sessionStatus;\n if (currentSessionStatus?.id !== sessionId) {\n return 'failed';\n }\n\n if (sdkFailed) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n return 'failed';\n }\n\n if (reachedCompletion) {\n // Once the SDK completes, the authoritative verification decision comes\n // from the UKYC backend, not the SDK result.\n this.update((state) => {\n state.sessionStatus = {\n ...currentSessionStatus,\n finalStatus: 'pending',\n };\n state.providerFlowStatus = 'submitted';\n });\n this.startSessionStatusPolling();\n return 'submitted';\n }\n\n this.update((state) => {\n state.providerFlowStatus = 'abandoned';\n });\n return 'abandoned';\n } catch {\n if (this.state.sessionStatus?.id === sessionId) {\n this.update((state) => {\n state.providerFlowStatus = 'failed';\n });\n }\n return 'failed';\n }\n }\n\n /**\n * Verifies each schema's jwtChain against the matching issuer JWKS, then\n * confirms the returned server public key matches the value attested inside\n * the verified JWT payload before trusting it for wrapping.\n * `encryptionDataKey` is attested by the idOS enclave; `ukycCapabilityToken`\n * by the idOS relay.\n *\n * @param encryptionDataKey - Encryption schema for the data encryption key.\n * @param capabilityTokenSchema - Encryption schema for the capability token.\n */\n async #verifyWrappingKeys(\n encryptionDataKey: EncryptionSchema,\n capabilityTokenSchema: EncryptionSchema,\n ): Promise<void> {\n const [{ keys: idosEnclaveKeys }, { keys: idosRelayKeys }] =\n await Promise.all([\n this.messenger.call('KycService:fetchIdosEnclaveJwks'),\n this.messenger.call('KycService:fetchIdosRelayJwks'),\n ]);\n assertAttestedServerPublicKey(idosEnclaveKeys, encryptionDataKey);\n assertAttestedServerPublicKey(idosRelayKeys, capabilityTokenSchema);\n }\n\n /**\n * Derives the `data_encryption_key` from the `local_user_secret`, mints a\n * capability token, and wraps both for the session server. Only the wrapped\n * (encrypted) material ever leaves the device.\n *\n * Only the client holds the signing key derived from `local_user_secret`, so\n * only the client can mint the token.\n *\n * @param sessionClientPrivateKey - Per-session X25519 private key used to\n * seal both secrets.\n * @param encryptionDataKey - Encryption schema for the data encryption key.\n * @param capabilityTokenSchema - Encryption schema for the capability token.\n * @returns The wrapped encryption key and capability token.\n */\n async #generateWrappedAuthorizations(\n sessionClientPrivateKey: Uint8Array,\n encryptionDataKey: EncryptionSchema,\n capabilityTokenSchema: EncryptionSchema,\n ): Promise<{\n wrappedEncryptionDataKey: CapabilityAuthorization;\n wrappedUkycCapabilityToken: CapabilityAuthorization;\n }> {\n const localUserSecret = await getOrCreateLocalUserSecret(\n this.#localUserSecretStore,\n );\n const clientMaterial = deriveClientMaterial(localUserSecret);\n const wrappedEncryptionDataKey = wrapEncryptionKey(\n sessionClientPrivateKey,\n encryptionDataKey.serverPublicKey.x,\n clientMaterial.dataEncryptionKey,\n );\n\n const ukycCapabilityToken = signStorageAccessToken({\n material: clientMaterial,\n // TODO: Confirm with idOS when this can be switched back to read and a separate token is sent for write\n operations: ['read', 'write'],\n expiresAt: new Date(Date.now() + UKYC_CAPABILITY_TOKEN_TTL_MS),\n });\n const wrappedUkycCapabilityToken = wrapEncryptionKey(\n sessionClientPrivateKey,\n capabilityTokenSchema.serverPublicKey.x,\n stringToBytes(encodeStorageAccessTokenForHeader(ukycCapabilityToken)),\n );\n\n return { wrappedEncryptionDataKey, wrappedUkycCapabilityToken };\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Reads the email claim from a partner identity JWT.
3
+ *
4
+ * Live tokens put email under `ext`.
5
+ *
6
+ * @param token - Compact JWT returned by AuthenticationController.
7
+ * @returns The verified email claim.
8
+ * @throws If the token is malformed, the payload or `ext` is not an object,
9
+ * the email claim is missing, or `ext.email_verified` is not `true`.
10
+ */
11
+ export declare function getEmailFromPartnerIdentityToken(token: string): string;
12
+ /**
13
+ * Whether `error` is an HTTP 422 from partner-identity token minting
14
+ * (`EmailRequiredError.status`).
15
+ *
16
+ * @param error - The caught error.
17
+ * @returns True when `error.status` is 422.
18
+ */
19
+ export declare function isEmailRequiredError(error: unknown): boolean;
20
+ //# sourceMappingURL=partnerIdentityToken.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partnerIdentityToken.d.ts","sourceRoot":"","sources":["../src/partnerIdentityToken.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAwCtE;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE5D"}
@@ -0,0 +1,51 @@
1
+ import { bytesToString, isObject } from '@metamask/utils';
2
+ import { base64UrlToBytes } from './encoding.js';
3
+ /**
4
+ * Reads the email claim from a partner identity JWT.
5
+ *
6
+ * Live tokens put email under `ext`.
7
+ *
8
+ * @param token - Compact JWT returned by AuthenticationController.
9
+ * @returns The verified email claim.
10
+ * @throws If the token is malformed, the payload or `ext` is not an object,
11
+ * the email claim is missing, or `ext.email_verified` is not `true`.
12
+ */
13
+ export function getEmailFromPartnerIdentityToken(token) {
14
+ const [, payloadSegment] = token.split('.');
15
+ if (!payloadSegment) {
16
+ throw new Error('KycController: partner identity token is not a well-formed JWT');
17
+ }
18
+ let payload;
19
+ try {
20
+ payload = JSON.parse(bytesToString(base64UrlToBytes(payloadSegment)));
21
+ }
22
+ catch {
23
+ throw new Error('KycController: failed to decode partner identity token payload');
24
+ }
25
+ if (!isObject(payload)) {
26
+ throw new Error('KycController: partner identity token payload is not an object');
27
+ }
28
+ const { ext } = payload;
29
+ if (!isObject(ext)) {
30
+ throw new Error('KycController: partner identity token payload has no ext object');
31
+ }
32
+ const { email, email_verified: emailVerified } = ext;
33
+ if (typeof email !== 'string' || email.length === 0) {
34
+ throw new Error('KycController: partner identity token does not contain an email claim');
35
+ }
36
+ if (emailVerified !== true) {
37
+ throw new Error('KycController: partner identity token email is not verified');
38
+ }
39
+ return email;
40
+ }
41
+ /**
42
+ * Whether `error` is an HTTP 422 from partner-identity token minting
43
+ * (`EmailRequiredError.status`).
44
+ *
45
+ * @param error - The caught error.
46
+ * @returns True when `error.status` is 422.
47
+ */
48
+ export function isEmailRequiredError(error) {
49
+ return isObject(error) && error.status === 422;
50
+ }
51
+ //# sourceMappingURL=partnerIdentityToken.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partnerIdentityToken.js","sourceRoot":"","sources":["../src/partnerIdentityToken.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,UAAU,gCAAgC,CAAC,KAAa;IAC5D,MAAM,CAAC,EAAE,cAAc,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;IACJ,CAAC;IAED,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IACxE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,gEAAgE,CACjE,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACrD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;IACJ,CAAC;IACD,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,OAAO,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,CAAC;AACjD,CAAC","sourcesContent":["import { bytesToString, isObject } from '@metamask/utils';\n\nimport { base64UrlToBytes } from './encoding.js';\n\n/**\n * Reads the email claim from a partner identity JWT.\n *\n * Live tokens put email under `ext`.\n *\n * @param token - Compact JWT returned by AuthenticationController.\n * @returns The verified email claim.\n * @throws If the token is malformed, the payload or `ext` is not an object,\n * the email claim is missing, or `ext.email_verified` is not `true`.\n */\nexport function getEmailFromPartnerIdentityToken(token: string): string {\n const [, payloadSegment] = token.split('.');\n if (!payloadSegment) {\n throw new Error(\n 'KycController: partner identity token is not a well-formed JWT',\n );\n }\n\n let payload: unknown;\n try {\n payload = JSON.parse(bytesToString(base64UrlToBytes(payloadSegment)));\n } catch {\n throw new Error(\n 'KycController: failed to decode partner identity token payload',\n );\n }\n\n if (!isObject(payload)) {\n throw new Error(\n 'KycController: partner identity token payload is not an object',\n );\n }\n const { ext } = payload;\n if (!isObject(ext)) {\n throw new Error(\n 'KycController: partner identity token payload has no ext object',\n );\n }\n const { email, email_verified: emailVerified } = ext;\n if (typeof email !== 'string' || email.length === 0) {\n throw new Error(\n 'KycController: partner identity token does not contain an email claim',\n );\n }\n if (emailVerified !== true) {\n throw new Error(\n 'KycController: partner identity token email is not verified',\n );\n }\n return email;\n}\n\n/**\n * Whether `error` is an HTTP 422 from partner-identity token minting\n * (`EmailRequiredError.status`).\n *\n * @param error - The caught error.\n * @returns True when `error.status` is 422.\n */\nexport function isEmailRequiredError(error: unknown): boolean {\n return isObject(error) && error.status === 422;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/kyc-controller",
3
- "version": "0.11.0-preview-b4b0d7a09",
3
+ "version": "0.11.0-preview-55fcf3ef7",
4
4
  "description": "Shared KYC / identity verification controller used across MetaMask clients",
5
5
  "keywords": [
6
6
  "Ethereum",