diff --git a/app/core/Permissions/specifications.js b/app/core/Permissions/specifications.js index dc5a974d80f..9f728e0dd80 100644 --- a/app/core/Permissions/specifications.js +++ b/app/core/Permissions/specifications.js @@ -87,7 +87,7 @@ export const getCaveatSpecifications = ({ getIdentities }) => ({ export const getPermissionSpecifications = ({ getAllAccounts }) => ({ [PermissionKeys.eth_accounts]: { permissionType: PermissionType.RestrictedMethod, - targetKey: PermissionKeys.eth_accounts, + targetName: PermissionKeys.eth_accounts, allowedCaveats: [CaveatTypes.restrictReturnedAccounts], factory: (permissionOptions, requestData) => { diff --git a/app/core/Permissions/specifications.test.js b/app/core/Permissions/specifications.test.js index 089581f7f5d..d21ddbc7f9e 100644 --- a/app/core/Permissions/specifications.test.js +++ b/app/core/Permissions/specifications.test.js @@ -132,7 +132,7 @@ describe('PermissionController specifications', () => { const permissionSpecifications = getPermissionSpecifications({}); expect(Object.keys(permissionSpecifications)).toHaveLength(1); expect( - permissionSpecifications[RestrictedMethods.eth_accounts].targetKey, + permissionSpecifications[RestrictedMethods.eth_accounts].targetName, ).toStrictEqual(RestrictedMethods.eth_accounts); }); diff --git a/app/core/RPCMethods/RPCMethodMiddleware.test.ts b/app/core/RPCMethods/RPCMethodMiddleware.test.ts index 869806eee90..c4aba33937a 100644 --- a/app/core/RPCMethods/RPCMethodMiddleware.test.ts +++ b/app/core/RPCMethods/RPCMethodMiddleware.test.ts @@ -15,6 +15,7 @@ import { getPermittedAccounts } from '../Permissions'; import { RPC } from '../../constants/network'; import { getRpcMethodMiddleware } from './RPCMethodMiddleware'; import AppConstants from '../AppConstants'; +import { PermissionConstraint } from '@metamask/permission-controller'; jest.mock('../Engine', () => ({ context: { @@ -32,6 +33,10 @@ jest.mock('../Engine', () => ({ newUnsignedPersonalMessage: jest.fn(), newUnsignedTypedMessage: jest.fn(), }, + PermissionController: { + requestPermissions: jest.fn(), + getPermissions: jest.fn(), + }, }, })); const MockEngine = Engine as Omit & { @@ -39,6 +44,7 @@ const MockEngine = Engine as Omit & { NetworkController: Record; PreferencesController: Record; TransactionController: Record; + PermissionController: Record; }; }; @@ -416,6 +422,66 @@ describe('getRpcMethodMiddleware', () => { }); } + describe('wallet_requestPermissions', () => { + it('can requestPermissions for eth_accounts', async () => { + MockEngine.context.PermissionController.requestPermissions.mockImplementation( + async () => [ + { + eth_accounts: { + parentCapability: 'eth_accounts', + caveats: [], + }, + }, + ], + ); + const middleware = getRpcMethodMiddleware({ + ...getMinimalOptions(), + hostname: 'example.metamask.io', + }); + const request = { + jsonrpc, + id: 1, + method: 'wallet_requestPermissions', + params: [ + { + eth_accounts: {}, + }, + ], + }; + const response = await callMiddleware({ middleware, request }); + expect( + (response as JsonRpcSuccess).result, + ).toEqual([{ parentCapability: 'eth_accounts', caveats: [] }]); + }); + }); + + describe('wallet_getPermissions', () => { + it('can getPermissions', async () => { + MockEngine.context.PermissionController.getPermissions.mockImplementation( + () => ({ + eth_accounts: { + parentCapability: 'eth_accounts', + caveats: [], + }, + }), + ); + const middleware = getRpcMethodMiddleware({ + ...getMinimalOptions(), + hostname: 'example.metamask.io', + }); + const request = { + jsonrpc, + id: 1, + method: 'wallet_getPermissions', + params: [], + }; + const response = await callMiddleware({ middleware, request }); + expect( + (response as JsonRpcSuccess).result, + ).toEqual([{ parentCapability: 'eth_accounts', caveats: [] }]); + }); + }); + describe('eth_sendTransaction', () => { describe('browser', () => { it('sends the transaction and returns the resulting hash', async () => { diff --git a/app/core/RPCMethods/RPCMethodMiddleware.ts b/app/core/RPCMethods/RPCMethodMiddleware.ts index b25cdc7acc1..ddfe9550bd1 100644 --- a/app/core/RPCMethods/RPCMethodMiddleware.ts +++ b/app/core/RPCMethods/RPCMethodMiddleware.ts @@ -1,6 +1,9 @@ import { Alert } from 'react-native'; import { getVersion } from 'react-native-device-info'; -import { createAsyncMiddleware } from 'json-rpc-engine'; +import { + createAsyncMiddleware, + JsonRpcEngineCallbackError, +} from 'json-rpc-engine'; import { ethErrors } from 'eth-json-rpc-errors'; import { EndFlowOptions, @@ -11,6 +14,7 @@ import { recoverPersonalSignature } from '@metamask/eth-sig-util'; import RPCMethods from './index.js'; import { RPC } from '../../constants/network'; import { NetworksChainId, NetworkType } from '@metamask/controller-utils'; +import { permissionRpcMethods } from '@metamask/permission-controller'; import Networks, { blockTagParamIndex, getAllNetworks, @@ -248,7 +252,52 @@ export const getRpcMethodMiddleware = ({ return responseData; }; + const [requestPermissionsHandler, getPermissionsHandler] = + permissionRpcMethods.handlers; + const rpcMethods: any = { + wallet_getPermissions: async () => + new Promise((resolve) => { + getPermissionsHandler.implementation( + req, + res, + next, + () => { + resolve(undefined); + }, + { + getPermissionsForOrigin: + Engine.context.PermissionController.getPermissions.bind( + Engine.context.PermissionController, + hostname, + ), + }, + ); + }), + wallet_requestPermissions: async () => + new Promise((resolve, reject) => { + requestPermissionsHandler + .implementation( + req, + res, + next, + (err: JsonRpcEngineCallbackError | undefined) => { + if (err) { + return reject(err); + } + resolve(undefined); + }, + { + requestPermissionsForOrigin: + Engine.context.PermissionController.requestPermissions.bind( + Engine.context.PermissionController, + { origin: hostname }, + ), + }, + ) + ?.then(resolve) + .catch(reject); + }), eth_getTransactionByHash: async () => { res.result = await polyfillGasPrice('getTransactionByHash', req.params); }, diff --git a/package.json b/package.json index 0da7e06f2af..7aea99b8af9 100644 --- a/package.json +++ b/package.json @@ -165,7 +165,7 @@ "@metamask/gas-fee-controller": "4.0.0", "@metamask/keyring-controller": "^1.0.1", "@metamask/network-controller": "^5.0.0", - "@metamask/permission-controller": "~3.0.0", + "@metamask/permission-controller": "^4.0.1", "@metamask/phishing-controller": "^3.0.0", "@metamask/preferences-controller": "^2.1.0", "@metamask/sdk-communication-layer": "^0.5.0", diff --git a/yarn.lock b/yarn.lock index 8da49e59aa7..cadd8808eeb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5110,7 +5110,7 @@ "@metamask/base-controller" "^2.0.0" "@metamask/controller-utils" "^3.0.0" -"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^2.0.0", "@metamask/approval-controller@^2.1.1", "@metamask/approval-controller@^3.4.0": +"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^2.1.1", "@metamask/approval-controller@^3.3.0", "@metamask/approval-controller@^3.4.0": version "3.4.0" resolved "https://registry.yarnpkg.com/@metamask/approval-controller/-/approval-controller-3.4.0.tgz#282900361d42f785578728b45014ff8cb5e557ea" integrity sha512-DjqrhiX9+W/Fh6Crr7FPJ87Y/uhPWzBvfXGtekv1LHZNmEtUxkrA7aelddUM0fpTdURIGT4aNGBoQudFidc+Lw== @@ -5195,7 +5195,7 @@ resolved "https://registry.yarnpkg.com/@metamask/contract-metadata/-/contract-metadata-2.2.0.tgz#277764d0d56e37180ae7644a9d11eb96295b36fc" integrity sha512-SM6A4C7vXNbVpgMTX67kfW8QWvu3eSXxMZlY5PqZBTkvri1s9zgQ0uwRkK5r2VXNEoVmXCDnnEX/tX5EzzgNUQ== -"@metamask/controller-utils@^1.0.0", "@metamask/controller-utils@^3.0.0", "@metamask/controller-utils@^3.4.0", "@metamask/controller-utils@~3.0.0": +"@metamask/controller-utils@^1.0.0", "@metamask/controller-utils@^3.0.0", "@metamask/controller-utils@^3.4.0", "@metamask/controller-utils@^4.0.1", "@metamask/controller-utils@~3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@metamask/controller-utils/-/controller-utils-3.0.0.tgz#e0984cdab14280409297671b5858891527c5e4ee" integrity sha512-JjFWBZnnh5DSX2tRsw5xtXxaqVkTzaW7mkSZ+lL3LoCAw47Cf8zGP1kGR6VKxcceKi+MpEFvZr7gf1OFnOoEjw== @@ -5378,18 +5378,18 @@ "@metamask/safe-event-emitter" "^2.0.0" through2 "^2.0.3" -"@metamask/permission-controller@~3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-3.0.0.tgz#2c58f749c4fc192743fd2e5fad5ffa503ba1c068" - integrity sha512-902jw48yetCsNo6DGrXKHDWWz/QzdmC90O6Am5WgUmwUlboU9Mr0uS8Fp8b7qPQiDZRXz8PvckodyEX2XNW+tQ== +"@metamask/permission-controller@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-4.0.1.tgz#b3eee18b49cd9be9e7241e1038fd0df30d546867" + integrity sha512-LMhD2+3QHmrYQzs81/ZUf473or+B+HmKLpVwpC0L1FfAeSrEpcDrfxWbGtYwiMo9wqNqwN2UAH7ifNy5rudtsA== dependencies: - "@metamask/approval-controller" "^2.0.0" - "@metamask/base-controller" "^2.0.0" - "@metamask/controller-utils" "^3.0.0" - "@metamask/types" "^1.1.0" + "@metamask/approval-controller" "^3.3.0" + "@metamask/base-controller" "^3.0.0" + "@metamask/controller-utils" "^4.0.1" + "@metamask/utils" "^5.0.2" "@types/deep-freeze-strict" "^1.1.0" deep-freeze-strict "^1.1.1" - eth-rpc-errors "^4.0.0" + eth-rpc-errors "^4.0.2" immer "^9.0.6" json-rpc-engine "^6.1.0" nanoid "^3.1.31"