diff --git a/packages/snaps-rpc-methods/jest.config.js b/packages/snaps-rpc-methods/jest.config.js index 9d6aa634ac..7756db68a4 100644 --- a/packages/snaps-rpc-methods/jest.config.js +++ b/packages/snaps-rpc-methods/jest.config.js @@ -10,8 +10,8 @@ module.exports = deepmerge(baseConfig, { ], coverageThreshold: { global: { - branches: 97.28, - functions: 98.84, + branches: 97.29, + functions: 98.85, lines: 99.14, statements: 98.81, }, diff --git a/packages/snaps-rpc-methods/src/permissions.test.ts b/packages/snaps-rpc-methods/src/permissions.test.ts index 013f5587a3..068f6b8743 100644 --- a/packages/snaps-rpc-methods/src/permissions.test.ts +++ b/packages/snaps-rpc-methods/src/permissions.test.ts @@ -197,7 +197,14 @@ describe('buildSnapRestrictedMethodSpecifications', () => { it('returns the expected object', () => { const specifications = buildSnapRestrictedMethodSpecifications( [], - {}, + { + getUnlockPromise: jest.fn(), + getClientCryptography: jest.fn(), + isOnPhishingList: jest.fn(), + maybeUpdatePhishingList: jest.fn(), + getSnapKeyring: jest.fn(), + getPreferences: jest.fn(), + }, new Messenger({ namespace: 'SnapsRestrictedMethods' }), ); expect(specifications).toMatchInlineSnapshot(` @@ -316,4 +323,21 @@ describe('buildSnapRestrictedMethodSpecifications', () => { } `); }); + + it('excludes the specified permissions', () => { + const specifications = buildSnapRestrictedMethodSpecifications( + ['snap_dialog'], + { + getUnlockPromise: jest.fn(), + getClientCryptography: jest.fn(), + isOnPhishingList: jest.fn(), + maybeUpdatePhishingList: jest.fn(), + getSnapKeyring: jest.fn(), + getPreferences: jest.fn(), + }, + new Messenger({ namespace: 'SnapsRestrictedMethods' }), + ); + + expect(specifications.snap_dialog).toBeUndefined(); + }); }); diff --git a/packages/snaps-rpc-methods/src/permissions.ts b/packages/snaps-rpc-methods/src/permissions.ts index bed80afdec..a974957022 100644 --- a/packages/snaps-rpc-methods/src/permissions.ts +++ b/packages/snaps-rpc-methods/src/permissions.ts @@ -1,4 +1,4 @@ -import { selectHooks } from '@metamask/json-rpc-engine/v2'; +import { selectHooks, assertExpectedHooks } from '@metamask/json-rpc-engine/v2'; import { createRestrictedMethodMessenger, type PermissionConstraint, @@ -70,27 +70,40 @@ export const buildSnapRestrictedMethodSpecifications = ( excludedPermissions: string[], hooks: Record, messenger: RestrictedMethodMessenger, -) => - Object.values(restrictedMethodPermissionBuilders).reduce< +) => { + const permissionBuilders = Object.values( + restrictedMethodPermissionBuilders, + ).filter((builder) => !excludedPermissions.includes(builder.targetName)); + + const expectedHookNames = new Set( + permissionBuilders.flatMap((builder) => + builder.methodHooks + ? Object.getOwnPropertyNames(builder.methodHooks) + : [], + ), + ); + + assertExpectedHooks(hooks, expectedHookNames); + + return permissionBuilders.reduce< Record >( ( specifications, { targetName, specificationBuilder, methodHooks, actionNames }, ) => { - if (!excludedPermissions.includes(targetName)) { - specifications[targetName] = specificationBuilder({ - methodHooks: selectHooks(hooks, methodHooks), - messenger: createRestrictedMethodMessenger({ - namespace: targetName, - rootMessenger: messenger, - actionNames: actionNames as readonly [ - RestrictedMethodActions['type'], - ], - }), - }); - } + specifications[targetName] = specificationBuilder({ + methodHooks: selectHooks(hooks, methodHooks), + messenger: createRestrictedMethodMessenger({ + namespace: targetName, + rootMessenger: messenger, + actionNames: actionNames as readonly [ + RestrictedMethodActions['type'], + ], + }), + }); return specifications; }, {}, ); +}; diff --git a/packages/snaps-simulation/src/methods/specifications.ts b/packages/snaps-simulation/src/methods/specifications.ts index 9754ec4f2b..36579c42a9 100644 --- a/packages/snaps-simulation/src/methods/specifications.ts +++ b/packages/snaps-simulation/src/methods/specifications.ts @@ -73,6 +73,7 @@ export function getPermissionSpecifications({ hooks, options, }: GetPermissionSpecificationsOptions): PermissionSpecificationMap { + const { getClientCryptography } = hooks; return { [caip25EndowmentBuilder.targetName]: caip25EndowmentBuilder.specificationBuilder({}), @@ -81,11 +82,12 @@ export function getPermissionSpecifications({ EXCLUDED_SNAP_PERMISSIONS, { // Shared hooks. - ...hooks, + getClientCryptography, // Snaps-specific hooks. getPreferences: getGetPreferencesMethodImplementation(options), getUnlockPromise: asyncResolve(true), + getSnapKeyring: asyncResolve(null), // TODO: Allow the user to specify the result of this function. isOnPhishingList: resolve(false),