{"version":3,"file":"UserStorageController.cjs","sourceRoot":"","sources":["../../../src/controllers/user-storage/UserStorageController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n  AddressBookControllerContactUpdatedEvent,\n  AddressBookControllerContactDeletedEvent,\n  AddressBookControllerActions,\n  AddressBookControllerListAction,\n  AddressBookControllerSetAction,\n  AddressBookControllerDeleteAction,\n} from '@metamask/address-book-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n  ControllerGetStateAction,\n  ControllerStateChangeEvent,\n  StateMetadata,\n} from '@metamask/base-controller';\nimport type {\n  TraceCallback,\n  TraceContext,\n  TraceRequest,\n} from '@metamask/controller-utils';\nimport { KeyringTypes } from '@metamask/keyring-controller';\nimport type {\n  KeyringControllerGetStateAction,\n  KeyringControllerLockEvent,\n  KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { SnapControllerHandleRequestAction } from '@metamask/snaps-controllers';\n\nimport { BACKUPANDSYNC_FEATURES } from './constants';\nimport { syncContactsWithUserStorage } from './contact-syncing/controller-integration';\nimport { setupContactSyncingSubscriptions } from './contact-syncing/setup-subscriptions';\nimport type { UserStorageControllerMethodActions } from './UserStorageController-method-action-types';\nimport type {\n  UserStorageGenericFeatureKey,\n  UserStorageGenericPathWithFeatureAndKey,\n  UserStorageGenericPathWithFeatureOnly,\n} from '../../sdk';\nimport { Env, UserStorage } from '../../sdk';\nimport type { NativeScrypt } from '../../shared/types/encryption';\nimport { EventQueue } from '../../shared/utils/event-queue';\nimport { createSnapSignMessageRequest } from '../authentication/auth-snap-requests';\nimport type {\n  AuthenticationControllerGetBearerTokenAction,\n  AuthenticationControllerGetSessionProfileAction,\n  AuthenticationControllerIsSignedInAction,\n  AuthenticationControllerPerformSignInAction,\n} from '../authentication/AuthenticationController-method-action-types';\n\nconst controllerName = 'UserStorageController';\n\n// State\nexport type UserStorageControllerState = {\n  /**\n   * Condition used by UI and to determine if we can use some of the User Storage methods.\n   */\n  isBackupAndSyncEnabled: boolean;\n  /**\n   * Loading state for the backup and sync update\n   */\n  isBackupAndSyncUpdateLoading: boolean;\n  /**\n   * Condition used by UI to determine if account syncing is enabled.\n   */\n  isAccountSyncingEnabled: boolean;\n  /**\n   * Condition used by UI to determine if contact syncing is enabled.\n   */\n  isContactSyncingEnabled: boolean;\n  /**\n   * Condition used by UI to determine if contact syncing is in progress.\n   */\n  isContactSyncingInProgress: boolean;\n};\n\nexport const defaultState: UserStorageControllerState = {\n  isBackupAndSyncEnabled: true,\n  isBackupAndSyncUpdateLoading: false,\n  isAccountSyncingEnabled: true,\n  isContactSyncingEnabled: true,\n  isContactSyncingInProgress: false,\n};\n\nconst metadata: StateMetadata<UserStorageControllerState> = {\n  isBackupAndSyncEnabled: {\n    includeInStateLogs: true,\n    persist: true,\n    includeInDebugSnapshot: true,\n    usedInUi: true,\n  },\n  isBackupAndSyncUpdateLoading: {\n    includeInStateLogs: false,\n    persist: false,\n    includeInDebugSnapshot: false,\n    usedInUi: true,\n  },\n  isAccountSyncingEnabled: {\n    includeInStateLogs: true,\n    persist: true,\n    includeInDebugSnapshot: true,\n    usedInUi: true,\n  },\n  isContactSyncingEnabled: {\n    includeInStateLogs: true,\n    persist: true,\n    includeInDebugSnapshot: true,\n    usedInUi: true,\n  },\n  isContactSyncingInProgress: {\n    includeInStateLogs: false,\n    persist: false,\n    includeInDebugSnapshot: false,\n    usedInUi: true,\n  },\n};\n\ntype ControllerConfig = {\n  env: Env;\n  contactSyncing?: {\n    /**\n     * Callback that fires when contact sync updates a contact.\n     * This is used for analytics.\n     */\n    onContactUpdated?: (profileId: string) => void;\n\n    /**\n     * Callback that fires when contact sync deletes a contact.\n     * This is used for analytics.\n     */\n    onContactDeleted?: (profileId: string) => void;\n\n    /**\n     * Callback that fires when an erroneous situation happens during contact sync.\n     * This is used for analytics.\n     */\n    onContactSyncErroneousSituation?: (\n      profileId: string,\n      situationMessage: string,\n      sentryContext?: Record<string, unknown>,\n    ) => void;\n  };\n};\n\nconst MESSENGER_EXPOSED_METHODS = [\n  'performGetStorage',\n  'performGetStorageAllFeatureEntries',\n  'performSetStorage',\n  'performBatchSetStorage',\n  'performDeleteStorage',\n  'performBatchDeleteStorage',\n  'getStorageKey',\n  'performDeleteStorageAllFeatureEntries',\n  'listEntropySources',\n  'setIsBackupAndSyncFeatureEnabled',\n  'setIsContactSyncingInProgress',\n  'syncContactsWithUserStorage',\n] as const;\n\nexport type UserStorageControllerGetStateAction = ControllerGetStateAction<\n  typeof controllerName,\n  UserStorageControllerState\n>;\nexport type Actions =\n  | UserStorageControllerGetStateAction\n  | UserStorageControllerMethodActions;\n\nexport type AllowedActions =\n  // Keyring Requests\n  | KeyringControllerGetStateAction\n  // Snap Requests\n  | SnapControllerHandleRequestAction\n  // Auth Requests\n  | AuthenticationControllerGetBearerTokenAction\n  | AuthenticationControllerGetSessionProfileAction\n  | AuthenticationControllerPerformSignInAction\n  | AuthenticationControllerIsSignedInAction\n  // Contact Syncing\n  | AddressBookControllerListAction\n  | AddressBookControllerSetAction\n  | AddressBookControllerDeleteAction\n  | AddressBookControllerActions;\n\n// Messenger events\nexport type UserStorageControllerStateChangeEvent = ControllerStateChangeEvent<\n  typeof controllerName,\n  UserStorageControllerState\n>;\n\nexport type Events = UserStorageControllerStateChangeEvent;\n\nexport type AllowedEvents =\n  | KeyringControllerLockEvent\n  | KeyringControllerUnlockEvent\n  // Address Book Events\n  | AddressBookControllerContactUpdatedEvent\n  | AddressBookControllerContactDeletedEvent;\n\n// Messenger\nexport type UserStorageControllerMessenger = Messenger<\n  typeof controllerName,\n  Actions | AllowedActions,\n  Events | AllowedEvents\n>;\n\n/**\n * Reusable controller that allows any team to store synchronized data for a given user.\n * These can be settings shared cross MetaMask clients, or data we want to persist when uninstalling/reinstalling.\n *\n * NOTE:\n * - data stored on UserStorage is FULLY encrypted, with the only keys stored/managed on the client.\n * - No one can access this data unless they are have the SRP and are able to run the signing snap.\n */\nexport class UserStorageController extends BaseController<\n  typeof controllerName,\n  UserStorageControllerState,\n  UserStorageControllerMessenger\n> {\n  readonly #userStorage: UserStorage;\n\n  readonly #auth = {\n    getProfileId: async (entropySourceId?: string) => {\n      const sessionProfile = await this.messenger.call(\n        'AuthenticationController:getSessionProfile',\n        entropySourceId,\n      );\n      return sessionProfile?.profileId;\n    },\n    isSignedIn: () => {\n      return this.messenger.call('AuthenticationController:isSignedIn');\n    },\n    signIn: async () => {\n      return await this.messenger.call(\n        'AuthenticationController:performSignIn',\n      );\n    },\n  };\n\n  readonly #config: ControllerConfig = {\n    env: Env.PRD,\n  };\n\n  readonly #trace: TraceCallback;\n\n  #isUnlocked = false;\n\n  #storageKeyCache: Record<`metamask:${string}`, string> = {};\n\n  readonly #keyringController = {\n    setupLockedStateSubscriptions: () => {\n      const { isUnlocked } = this.messenger.call('KeyringController:getState');\n      this.#isUnlocked = isUnlocked;\n\n      this.messenger.subscribe('KeyringController:unlock', () => {\n        this.#isUnlocked = true;\n      });\n\n      this.messenger.subscribe('KeyringController:lock', () => {\n        this.#isUnlocked = false;\n      });\n    },\n  };\n\n  readonly #nativeScryptCrypto: NativeScrypt | undefined = undefined;\n\n  eventQueue = new EventQueue();\n\n  constructor({\n    messenger,\n    state,\n    config,\n    nativeScryptCrypto,\n    trace,\n  }: {\n    messenger: UserStorageControllerMessenger;\n    state?: UserStorageControllerState;\n    config?: Partial<ControllerConfig>;\n    nativeScryptCrypto?: NativeScrypt;\n    trace?: TraceCallback;\n  }) {\n    super({\n      messenger,\n      metadata,\n      name: controllerName,\n      state: { ...defaultState, ...state },\n    });\n\n    this.#config = {\n      ...this.#config,\n      ...config,\n    };\n    this.#trace =\n      trace ??\n      (async <ReturnType>(\n        _request: TraceRequest,\n        fn?: (context?: TraceContext) => ReturnType,\n      ): Promise<ReturnType> => {\n        if (!fn) {\n          return undefined as ReturnType;\n        }\n        return await Promise.resolve(fn());\n      });\n\n    this.#userStorage = new UserStorage(\n      {\n        env: this.#config.env,\n        auth: {\n          getAccessToken: (entropySourceId?: string) =>\n            this.messenger.call(\n              'AuthenticationController:getBearerToken',\n              entropySourceId,\n            ),\n          getUserProfile: async (entropySourceId?: string) => {\n            return await this.messenger.call(\n              'AuthenticationController:getSessionProfile',\n              entropySourceId,\n            );\n          },\n          signMessage: (message: string, entropySourceId?: string) =>\n            this.#snapSignMessage(\n              message as `metamask:${string}`,\n              entropySourceId,\n            ),\n        },\n      },\n      {\n        storage: {\n          getStorageKey: async (message) =>\n            this.#storageKeyCache[message] ?? null,\n          setStorageKey: async (message, key) => {\n            this.#storageKeyCache[message] = key;\n          },\n        },\n      },\n    );\n\n    this.messenger.registerMethodActionHandlers(\n      this,\n      MESSENGER_EXPOSED_METHODS,\n    );\n\n    this.#keyringController.setupLockedStateSubscriptions();\n    this.#nativeScryptCrypto = nativeScryptCrypto;\n\n    // Contact Syncing\n    setupContactSyncingSubscriptions({\n      getUserStorageControllerInstance: () => this,\n      getMessenger: () => this.messenger,\n      trace: this.#trace,\n    });\n  }\n\n  /**\n   * Allows retrieval of stored data. Data stored is string formatted.\n   * Developers can extend the entry path and entry name through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}.${key}` that matches schema\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns the decrypted string contents found from user storage (or null if not found)\n   */\n  public async performGetStorage(\n    path: UserStorageGenericPathWithFeatureAndKey,\n    entropySourceId?: string,\n  ): Promise<string | null> {\n    return await this.#userStorage.getItem(path, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows retrieval of all stored data for a specific feature. Data stored is formatted as an array of strings.\n   * Developers can extend the entry path through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}` that matches schema\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns the array of decrypted string contents found from user storage (or null if not found)\n   */\n  public async performGetStorageAllFeatureEntries(\n    path: UserStorageGenericPathWithFeatureOnly,\n    entropySourceId?: string,\n  ): Promise<string[] | null> {\n    return await this.#userStorage.getAllFeatureItems(path, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows storage of user data. Data stored must be string formatted.\n   * Developers can extend the entry path and entry name through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}.${key}` that matches schema\n   * @param value - The string data you want to store.\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns nothing. NOTE that an error is thrown if fails to store data.\n   */\n  public async performSetStorage(\n    path: UserStorageGenericPathWithFeatureAndKey,\n    value: string,\n    entropySourceId?: string,\n  ): Promise<void> {\n    return await this.#userStorage.setItem(path, value, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows storage of multiple user data entries for one specific feature. Data stored must be string formatted.\n   * Developers can extend the entry path through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}` that matches schema\n   * @param values - data to store, in the form of an array of `[entryKey, entryValue]` pairs\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns nothing. NOTE that an error is thrown if fails to store data.\n   */\n  public async performBatchSetStorage(\n    path: UserStorageGenericPathWithFeatureOnly,\n    values: [UserStorageGenericFeatureKey, string][],\n    entropySourceId?: string,\n  ): Promise<void> {\n    return await this.#userStorage.batchSetItems(path, values, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows deletion of user data. Developers can extend the entry path and entry name through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}.${key}` that matches schema\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns nothing. NOTE that an error is thrown if fails to delete data.\n   */\n  public async performDeleteStorage(\n    path: UserStorageGenericPathWithFeatureAndKey,\n    entropySourceId?: string,\n  ): Promise<void> {\n    return await this.#userStorage.deleteItem(path, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows deletion of all user data entries for a specific feature.\n   * Developers can extend the entry path through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}` that matches schema\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns nothing. NOTE that an error is thrown if fails to delete data.\n   */\n  public async performDeleteStorageAllFeatureEntries(\n    path: UserStorageGenericPathWithFeatureOnly,\n    entropySourceId?: string,\n  ): Promise<void> {\n    return await this.#userStorage.deleteAllFeatureItems(path, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Allows delete of multiple user data entries for one specific feature. Data deleted must be string formatted.\n   * Developers can extend the entry path through the `schema.ts` file.\n   *\n   * @param path - string in the form of `${feature}` that matches schema\n   * @param values - data to store, in the form of an array of entryKey[]\n   * @param entropySourceId - The entropy source ID used to generate the encryption key.\n   * @returns nothing. NOTE that an error is thrown if fails to store data.\n   */\n  public async performBatchDeleteStorage(\n    path: UserStorageGenericPathWithFeatureOnly,\n    values: UserStorageGenericFeatureKey[],\n    entropySourceId?: string,\n  ): Promise<void> {\n    return await this.#userStorage.batchDeleteItems(path, values, {\n      nativeScryptCrypto: this.#nativeScryptCrypto,\n      entropySourceId,\n    });\n  }\n\n  /**\n   * Retrieves the storage key, for internal use only!\n   *\n   * @returns the storage key\n   */\n  public async getStorageKey(): Promise<string> {\n    return await this.#userStorage.getStorageKey();\n  }\n\n  /**\n   * Flushes the storage key cache.\n   * CAUTION: This is only public for testing purposes.\n   * It should not be used in production code.\n   */\n  public flushStorageKeyCache(): void {\n    this.#storageKeyCache = {};\n  }\n\n  /**\n   * Lists all the available HD keyring metadata IDs.\n   * These IDs can be used in a multi-SRP context to segregate data specific to different SRPs.\n   *\n   * @returns A promise that resolves to an array of HD keyring metadata IDs.\n   */\n  async listEntropySources(): Promise<string[]> {\n    if (!this.#isUnlocked) {\n      throw new Error(\n        'listEntropySources - unable to list entropy sources, wallet is locked',\n      );\n    }\n\n    const { keyrings } = this.messenger.call('KeyringController:getState');\n    return keyrings\n      .filter((keyring) => keyring.type === KeyringTypes.hd.toString())\n      .map((keyring) => keyring.metadata.id);\n  }\n\n  #_snapSignMessageCache: Record<`metamask:${string}`, string> = {};\n\n  /**\n   * Signs a specific message using an underlying auth snap.\n   *\n   * @param message - A specific tagged message to sign.\n   * @param entropySourceId - The entropy source ID used to derive the key,\n   * when multiple sources are available (Multi-SRP).\n   * @returns A Signature created by the snap.\n   */\n  async #snapSignMessage(\n    message: `metamask:${string}`,\n    entropySourceId?: string,\n  ): Promise<string> {\n    // the message is SRP specific already, so there's no need to use the entropySourceId in the cache\n    if (this.#_snapSignMessageCache[message]) {\n      return this.#_snapSignMessageCache[message];\n    }\n\n    if (!this.#isUnlocked) {\n      throw new Error(\n        '#snapSignMessage - unable to call snap, wallet is locked',\n      );\n    }\n\n    const result = (await this.messenger.call(\n      'SnapController:handleRequest',\n      createSnapSignMessageRequest(message, entropySourceId),\n    )) as string;\n\n    this.#_snapSignMessageCache[message] = result;\n\n    return result;\n  }\n\n  public async setIsBackupAndSyncFeatureEnabled(\n    feature: keyof typeof BACKUPANDSYNC_FEATURES,\n    enabled: boolean,\n  ): Promise<void> {\n    try {\n      this.#setIsBackupAndSyncUpdateLoading(true);\n\n      if (enabled) {\n        // If any of the features are enabled, we need to ensure the user is signed in\n        const isSignedIn = this.#auth.isSignedIn();\n        if (!isSignedIn) {\n          await this.#auth.signIn();\n        }\n      }\n\n      this.update((state) => {\n        if (feature === BACKUPANDSYNC_FEATURES.main) {\n          state.isBackupAndSyncEnabled = enabled;\n        }\n\n        if (feature === BACKUPANDSYNC_FEATURES.accountSyncing) {\n          state.isAccountSyncingEnabled = enabled;\n        }\n\n        if (feature === BACKUPANDSYNC_FEATURES.contactSyncing) {\n          state.isContactSyncingEnabled = enabled;\n        }\n      });\n    } catch (e) {\n      // istanbul ignore next\n      const errorMessage = e instanceof Error ? e.message : JSON.stringify(e);\n      // istanbul ignore next\n      throw new Error(\n        `${controllerName} - failed to ${enabled ? 'enable' : 'disable'} ${feature} - ${errorMessage}`,\n      );\n    } finally {\n      this.#setIsBackupAndSyncUpdateLoading(false);\n    }\n  }\n\n  #setIsBackupAndSyncUpdateLoading(\n    isBackupAndSyncUpdateLoading: boolean,\n  ): void {\n    this.update((state) => {\n      state.isBackupAndSyncUpdateLoading = isBackupAndSyncUpdateLoading;\n    });\n  }\n\n  /**\n   * Sets the isContactSyncingInProgress flag to prevent infinite loops during contact synchronization\n   *\n   * @param isContactSyncingInProgress - Whether contact syncing is in progress\n   */\n  async setIsContactSyncingInProgress(\n    isContactSyncingInProgress: boolean,\n  ): Promise<void> {\n    this.update((state) => {\n      state.isContactSyncingInProgress = isContactSyncingInProgress;\n    });\n  }\n\n  /**\n   * Syncs the address book list with the user storage address book list.\n   * This method is used to make sure that the address book list is up-to-date with the user storage address book list and vice-versa.\n   * It will add new contacts to the address book list, update/merge conflicting contacts and re-upload the results in some cases to the user storage.\n   */\n  async syncContactsWithUserStorage(): Promise<void> {\n    const profileId = await this.#auth.getProfileId();\n\n    const config = {\n      onContactUpdated: () => {\n        this.#config?.contactSyncing?.onContactUpdated?.(profileId);\n      },\n      onContactDeleted: () => {\n        this.#config?.contactSyncing?.onContactDeleted?.(profileId);\n      },\n      onContactSyncErroneousSituation: (\n        errorMessage: string,\n        sentryContext?: Record<string, unknown>,\n      ) => {\n        this.#config?.contactSyncing?.onContactSyncErroneousSituation?.(\n          profileId,\n          errorMessage,\n          sentryContext,\n        );\n      },\n    };\n\n    await syncContactsWithUserStorage(config, {\n      getMessenger: () => this.messenger,\n      getUserStorageControllerInstance: () => this,\n      trace: this.#trace,\n    });\n  }\n}\n"]}