{"version":3,"file":"getEntropy.mjs","sourceRoot":"","sources":["../../src/restricted/getEntropy.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,wCAAwC;AAC9E,OAAO,EAAE,SAAS,EAAE,6BAA6B;AAEjD,OAAO,EAAE,iBAAiB,EAAE,8BAA8B;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,8BAA8B;AAE1E,OAAO,EAAE,YAAY,EAAE,wBAAwB;AAI/C,OAAO,EACL,qBAAqB,EACrB,eAAe,EACf,yBAAyB,EAC1B,qBAAiB;AAElB,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAkBrC,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;IACzC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC;CAC3B,CAAC,CAAC;AAUH,MAAM,oBAAoB,GAItB,CAAC,EACH,cAAc,GAAG,IAAI,EACrB,WAAW,EACX,SAAS,GAC6B,EAAE,EAAE;IAC1C,OAAO;QACL,cAAc,EAAE,cAAc,CAAC,gBAAgB;QAC/C,UAAU;QACV,cAAc;QACd,oBAAoB,EAAE,wBAAwB,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;QAC1E,YAAY,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC;KACjC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,WAAW,GAAuC;IACtD,gBAAgB,EAAE,IAAI;IACtB,qBAAqB,EAAE,IAAI;CAC5B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,UAAU;IACV,oBAAoB;IACpB,WAAW;IACX,WAAW,EAAE,CAAC,uCAAuC,CAAC;CAC9C,CAAC,CAAC;AAoBZ;;;;;;;;;;;;;GAaG;AACH,SAAS,wBAAwB,CAAC,EAChC,WAAW,EAAE,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,EACxD,SAAS,GAC6B;IACtC,OAAO,KAAK,UAAU,UAAU,CAC9B,OAAkD;QAElD,MAAM,EACJ,MAAM,EACN,OAAO,EAAE,EAAE,MAAM,EAAE,GACpB,GAAG,OAAO,CAAC;QAEZ,YAAY,CACV,MAAM,EACN,oBAAoB,EACpB,sCAAsC,EACtC,SAAS,CAAC,aAAa,CACxB,CAAC;QAEF,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,IAAI,GAAG,MAAM,yBAAyB,CAC1C,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,EACrC,MAAM,CAAC,MAAM,CACd,CAAC;QAEF,OAAO,qBAAqB,CAAC;YAC3B,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,IAAI;YACJ,KAAK,EAAE,iBAAiB;YACxB,sBAAsB,EAAE,qBAAqB,EAAE;SAChD,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { CryptographicFunctions } from '@metamask/key-tree';\nimport type { Messenger } from '@metamask/messenger';\nimport type {\n  PermissionSpecificationBuilder,\n  RestrictedMethodOptions,\n  ValidPermissionSpecification,\n} from '@metamask/permission-controller';\nimport { PermissionType, SubjectType } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type { GetEntropyParams, GetEntropyResult } from '@metamask/snaps-sdk';\nimport { SIP_6_MAGIC_VALUE } from '@metamask/snaps-utils';\nimport type { Infer } from '@metamask/superstruct';\nimport { literal, object, optional, string } from '@metamask/superstruct';\nimport type { NonEmptyArray } from '@metamask/utils';\nimport { assertStruct } from '@metamask/utils';\n\nimport type { KeyringControllerWithKeyringV2UnsafeAction } from '../types';\nimport type { MethodHooksObject } from '../utils';\nimport {\n  deriveEntropyFromSeed,\n  getMnemonicSeed,\n  getValueFromEntropySource,\n} from '../utils';\n\nconst targetName = 'snap_getEntropy';\n\nexport type GetEntropyMessengerActions =\n  KeyringControllerWithKeyringV2UnsafeAction;\n\ntype GetEntropySpecificationBuilderOptions = {\n  allowedCaveats?: Readonly<NonEmptyArray<string>> | null;\n  methodHooks: GetEntropyHooks;\n  messenger: Messenger<string, GetEntropyMessengerActions>;\n};\n\ntype GetEntropySpecification = ValidPermissionSpecification<{\n  permissionType: PermissionType.RestrictedMethod;\n  targetName: typeof targetName;\n  methodImplementation: ReturnType<typeof getEntropyImplementation>;\n  allowedCaveats: Readonly<NonEmptyArray<string>> | null;\n}>;\n\nexport const GetEntropyArgsStruct = object({\n  version: literal(1),\n  salt: optional(string()),\n  source: optional(string()),\n});\n\n/**\n * @property version - The version of the `snap_getEntropy` method. This must be\n * the numeric literal `1`.\n * @property salt - A string to use as the salt when deriving the entropy. If\n * omitted, the salt will be an empty string.\n */\nexport type GetEntropyArgs = Infer<typeof GetEntropyArgsStruct>;\n\nconst specificationBuilder: PermissionSpecificationBuilder<\n  PermissionType.RestrictedMethod,\n  GetEntropySpecificationBuilderOptions,\n  GetEntropySpecification\n> = ({\n  allowedCaveats = null,\n  methodHooks,\n  messenger,\n}: GetEntropySpecificationBuilderOptions) => {\n  return {\n    permissionType: PermissionType.RestrictedMethod,\n    targetName,\n    allowedCaveats,\n    methodImplementation: getEntropyImplementation({ methodHooks, messenger }),\n    subjectTypes: [SubjectType.Snap],\n  };\n};\n\nconst methodHooks: MethodHooksObject<GetEntropyHooks> = {\n  getUnlockPromise: true,\n  getClientCryptography: true,\n};\n\n/**\n * Get a deterministic 256-bit entropy value, specific to the Snap and the\n * user's account. You can use this entropy to generate a private key, or any\n * other value that requires a high level of randomness. Other Snaps can't\n * access this entropy, and it changes if the user's secret recovery phrase\n * changes.\n *\n * You can optionally specify a salt to generate different entropy for different\n * purposes. Using a salt results in entropy unrelated to the entropy generated\n * without a salt.\n *\n * This value is deterministic: it's always the same for the same Snap, user\n * account, and salt.\n *\n * @example\n * ```json name=\"Manifest\"\n * {\n *   \"initialPermissions\": {\n *     \"snap_getEntropy\": {}\n *   }\n * }\n * ```\n * ```ts name=\"Usage\"\n * const entropy = await snap.request({\n *   method: 'snap_getEntropy',\n *   params: {\n *     version: 1,\n *     salt: 'foo', // Optional.\n *   },\n * })\n *\n * // '0x...'\n * console.log(entropy)\n * ```\n */\nexport const getEntropyBuilder = Object.freeze({\n  targetName,\n  specificationBuilder,\n  methodHooks,\n  actionNames: ['KeyringController:withKeyringV2Unsafe'],\n} as const);\n\nexport type GetEntropyHooks = {\n  /**\n   * Waits for the extension to be unlocked.\n   *\n   * @returns A promise that resolves once the extension is unlocked.\n   */\n  getUnlockPromise: (shouldShowUnlockRequest: boolean) => Promise<void>;\n\n  /**\n   * Get the cryptographic functions to use for the client. This may return an\n   * empty object or `undefined` to fall back to the default cryptographic\n   * functions.\n   *\n   * @returns The cryptographic functions to use for the client.\n   */\n  getClientCryptography: () => CryptographicFunctions | undefined;\n};\n\n/**\n * Builds the method implementation for `snap_getEntropy`. The implementation\n * is based on the reference implementation of\n * [SIP-6](https://metamask.github.io/SIPs/SIPS/sip-6).\n *\n * @param options - The options.\n * @param options.messenger - The messenger.\n * @param options.methodHooks - The RPC method hooks.\n * @param options.methodHooks.getUnlockPromise - The method to get a promise that resolves\n * once the extension is unlocked.\n * @param options.methodHooks.getClientCryptography - A function to retrieve the cryptographic\n * functions to use for the client.\n * @returns The method implementation.\n */\nfunction getEntropyImplementation({\n  methodHooks: { getUnlockPromise, getClientCryptography },\n  messenger,\n}: GetEntropySpecificationBuilderOptions) {\n  return async function getEntropy(\n    options: RestrictedMethodOptions<GetEntropyParams>,\n  ): Promise<GetEntropyResult> {\n    const {\n      params,\n      context: { origin },\n    } = options;\n\n    assertStruct(\n      params,\n      GetEntropyArgsStruct,\n      'Invalid \"snap_getEntropy\" parameters',\n      rpcErrors.invalidParams,\n    );\n\n    await getUnlockPromise(true);\n\n    const seed = await getValueFromEntropySource(\n      getMnemonicSeed.bind(null, messenger),\n      params.source,\n    );\n\n    return deriveEntropyFromSeed({\n      input: origin,\n      salt: params.salt,\n      seed,\n      magic: SIP_6_MAGIC_VALUE,\n      cryptographicFunctions: getClientCryptography(),\n    });\n  };\n}\n"]}