1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-02 14:15:06 +01:00
metamask-extension/app/scripts/controllers/permissions/specifications.test.js

366 lines
12 KiB
JavaScript
Raw Normal View History

import { SnapCaveatType } from '@metamask/rpc-methods';
Permission System 2.0 (#12243) # Permission System 2.0 ## Background This PR migrates the extension permission system to [the new `PermissionController`](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions). The original permission system, based on [`rpc-cap`](https://github.com/MetaMask/rpc-cap), introduced [`ZCAP-LD`](https://w3c-ccg.github.io/zcap-ld/)-like permissions to our JSON-RPC stack. We used it to [implement](https://github.com/MetaMask/metamask-extension/pull/7004) what we called "LoginPerSite" in [version 7.7.0](https://github.com/MetaMask/metamask-extension/releases/tag/v7.7.0) of the extension, which enabled the user to choose which accounts, if any, should be exposed to each dapp. While that was a worthwhile feature in and of itself, we wanted a permission _system_ in order to enable everything we are going to with Snaps. Unfortunately, the original permission system was difficult to use, and necessitated the creation of the original `PermissionsController` (note the "s"), which was more or less a wrapper for `rpc-cap`. With this PR, we shake off the yoke of the original permission system, in favor of the modular, self-contained, ergonomic, and more mature permission system 2.0. Note that [the `PermissionController` readme](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions/README.md) explains how the new permission system works. The `PermissionController` and `SubjectMetadataController` are currently shipped via `@metamask/snap-controllers`. This is a temporary state of affairs, and we'll move them to `@metamask/controllers` once they've landed in prod. ## Changes in Detail First, the changes in this PR are not as big as they seem. Roughly half of the additions in this PR are fixtures in the test for the new migration (number 68), and a significant portion of the remaining ~2500 lines are due to find-and-replace changes in other test fixtures and UI files. - The extension `PermissionsController` has been deleted, and completely replaced with the new `PermissionController` from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The original `PermissionsController` "domain metadata" functionality is now managed by the new `SubjectMetadataController`, also from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The permission activity and history log controller has been renamed `PermissionLogController` and has its own top-level state key, but is otherwise functionally equivalent to the existing implementation. - Migration number 68 has been added to account for the new state changes. - The tests in `app/scripts/controllers/permissions` have been migrated from `mocha` to `jest`. Reviewers should focus their attention on the following files: - `app/scripts/` - `metamask-controller.js` - This is where most of the integration work for the new `PermissionController` occurs. Some functions that were internal to the original controller were moved here. - `controllers/permissions/` - `selectors.js` - These selectors are for `ControllerMessenger` selector subscriptions. The actual subscriptions occur in `metamask-controller.js`. See the `ControllerMessenger` implementation for details. - `specifications.js` - The caveat and permission specifications are required by the new `PermissionController`, and are used to specify the `eth_accounts` permission and its JSON-RPC method implementation. See the `PermissionController` readme for details. - `migrations/068.js` - The new state should be cross-referenced with the controllers that manage it. The accompanying tests should also be thoroughly reviewed. Some files may appear new but have just moved and/or been renamed: - `app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js` - This was previously implemented in `controllers/permissions/permissionsMethodMiddleware.js`. - `test/mocks/permissions.js` - A truncated version of `test/mocks/permission-controller.js`. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-12-07 04:16:49 +01:00
import {
CaveatTypes,
RestrictedMethods,
} from '../../../../shared/constants/permissions';
import {
getCaveatSpecifications,
getPermissionSpecifications,
unrestrictedMethods,
} from './specifications';
// Note: This causes Date.now() to return the number 1.
jest.useFakeTimers('modern').setSystemTime(1);
describe('PermissionController specifications', () => {
describe('caveat specifications', () => {
it('getCaveatSpecifications returns the expected specifications object', () => {
const caveatSpecifications = getCaveatSpecifications({});
[FLASK] BREAKING - snaps-monorepo@0.30.0 (#17718) * updated snap permission to wallet_snap, updated tests and added migration * updated snap packages * yarn.lock fix * fixed errors * override policy * update policy * undo override * updated localization message descriptions * updated lavamoat policy * more policy updates * update permission controller version * update policy * update fixture builder * updated code to include permission value to satisfy wallet_snap permission description call * fix import issue * update test-snaps version * added missing actions, added snap permission dedupe function * prettier fix * fix fencing * add more fencing * prettier fix * fix fencing (again) * added new action and selector and updated view snap accordingly * update test snaps website version * unfence request variable * add fencing * add optional chaining to fix type error * update migration # * remove old migration * prettier fix * fix migration test * fix fencing * added missing fencing * updated code to workaround fencing * update test-snaps site version and remove snap confirm test * update snap packages * update policies * fix merge marker issue * update test * more fixes * fix permissions * update test * fixed test * Bump test-snaps and iframe-execution-environment * remove unused snap permission from fixture builder * update policies * undo comment removal, update selector implementation * removed unnecessary function, updated migration, updated caveat action * remove optional chaining * fix type issue * more type fixes * fix migration test * remove isFlask check, make migration logic more robust * update coverage * Update LavaMoat policies * Update test/e2e/snaps/enums.js * add extra bail condition * Revert "add extra bail condition" This reverts commit b45c53dcfc6e6e35a5e283d4955d6d6ea9ca5965. * Revert "Revert "add extra bail condition"" This reverts commit cd2ded677935c9cdab0c02b6af55474c83727f60. * fix test * add SnapController entry to state object * updated permission name and caveat type with hardcoded values * add extra test for non-flask scenario * update lavamoat policies * fix locale messages * change coverage target * re-enable rpc snap test * revert locale message change * fix el message * reverted changes --------- Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
2023-03-08 19:29:23 +01:00
expect(Object.keys(caveatSpecifications)).toHaveLength(8);
Permission System 2.0 (#12243) # Permission System 2.0 ## Background This PR migrates the extension permission system to [the new `PermissionController`](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions). The original permission system, based on [`rpc-cap`](https://github.com/MetaMask/rpc-cap), introduced [`ZCAP-LD`](https://w3c-ccg.github.io/zcap-ld/)-like permissions to our JSON-RPC stack. We used it to [implement](https://github.com/MetaMask/metamask-extension/pull/7004) what we called "LoginPerSite" in [version 7.7.0](https://github.com/MetaMask/metamask-extension/releases/tag/v7.7.0) of the extension, which enabled the user to choose which accounts, if any, should be exposed to each dapp. While that was a worthwhile feature in and of itself, we wanted a permission _system_ in order to enable everything we are going to with Snaps. Unfortunately, the original permission system was difficult to use, and necessitated the creation of the original `PermissionsController` (note the "s"), which was more or less a wrapper for `rpc-cap`. With this PR, we shake off the yoke of the original permission system, in favor of the modular, self-contained, ergonomic, and more mature permission system 2.0. Note that [the `PermissionController` readme](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions/README.md) explains how the new permission system works. The `PermissionController` and `SubjectMetadataController` are currently shipped via `@metamask/snap-controllers`. This is a temporary state of affairs, and we'll move them to `@metamask/controllers` once they've landed in prod. ## Changes in Detail First, the changes in this PR are not as big as they seem. Roughly half of the additions in this PR are fixtures in the test for the new migration (number 68), and a significant portion of the remaining ~2500 lines are due to find-and-replace changes in other test fixtures and UI files. - The extension `PermissionsController` has been deleted, and completely replaced with the new `PermissionController` from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The original `PermissionsController` "domain metadata" functionality is now managed by the new `SubjectMetadataController`, also from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The permission activity and history log controller has been renamed `PermissionLogController` and has its own top-level state key, but is otherwise functionally equivalent to the existing implementation. - Migration number 68 has been added to account for the new state changes. - The tests in `app/scripts/controllers/permissions` have been migrated from `mocha` to `jest`. Reviewers should focus their attention on the following files: - `app/scripts/` - `metamask-controller.js` - This is where most of the integration work for the new `PermissionController` occurs. Some functions that were internal to the original controller were moved here. - `controllers/permissions/` - `selectors.js` - These selectors are for `ControllerMessenger` selector subscriptions. The actual subscriptions occur in `metamask-controller.js`. See the `ControllerMessenger` implementation for details. - `specifications.js` - The caveat and permission specifications are required by the new `PermissionController`, and are used to specify the `eth_accounts` permission and its JSON-RPC method implementation. See the `PermissionController` readme for details. - `migrations/068.js` - The new state should be cross-referenced with the controllers that manage it. The accompanying tests should also be thoroughly reviewed. Some files may appear new but have just moved and/or been renamed: - `app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js` - This was previously implemented in `controllers/permissions/permissionsMethodMiddleware.js`. - `test/mocks/permissions.js` - A truncated version of `test/mocks/permission-controller.js`. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-12-07 04:16:49 +01:00
expect(
caveatSpecifications[CaveatTypes.restrictReturnedAccounts].type,
).toStrictEqual(CaveatTypes.restrictReturnedAccounts);
expect(caveatSpecifications.permittedDerivationPaths.type).toStrictEqual(
SnapCaveatType.PermittedDerivationPaths,
);
expect(caveatSpecifications.permittedCoinTypes.type).toStrictEqual(
SnapCaveatType.PermittedCoinTypes,
);
expect(caveatSpecifications.snapKeyring.type).toStrictEqual(
SnapCaveatType.SnapKeyring,
);
expect(caveatSpecifications.snapCronjob.type).toStrictEqual(
SnapCaveatType.SnapCronjob,
);
expect(caveatSpecifications.transactionOrigin.type).toStrictEqual(
SnapCaveatType.TransactionOrigin,
);
expect(caveatSpecifications.rpcOrigin.type).toStrictEqual(
SnapCaveatType.RpcOrigin,
);
[FLASK] BREAKING - snaps-monorepo@0.30.0 (#17718) * updated snap permission to wallet_snap, updated tests and added migration * updated snap packages * yarn.lock fix * fixed errors * override policy * update policy * undo override * updated localization message descriptions * updated lavamoat policy * more policy updates * update permission controller version * update policy * update fixture builder * updated code to include permission value to satisfy wallet_snap permission description call * fix import issue * update test-snaps version * added missing actions, added snap permission dedupe function * prettier fix * fix fencing * add more fencing * prettier fix * fix fencing (again) * added new action and selector and updated view snap accordingly * update test snaps website version * unfence request variable * add fencing * add optional chaining to fix type error * update migration # * remove old migration * prettier fix * fix migration test * fix fencing * added missing fencing * updated code to workaround fencing * update test-snaps site version and remove snap confirm test * update snap packages * update policies * fix merge marker issue * update test * more fixes * fix permissions * update test * fixed test * Bump test-snaps and iframe-execution-environment * remove unused snap permission from fixture builder * update policies * undo comment removal, update selector implementation * removed unnecessary function, updated migration, updated caveat action * remove optional chaining * fix type issue * more type fixes * fix migration test * remove isFlask check, make migration logic more robust * update coverage * Update LavaMoat policies * Update test/e2e/snaps/enums.js * add extra bail condition * Revert "add extra bail condition" This reverts commit b45c53dcfc6e6e35a5e283d4955d6d6ea9ca5965. * Revert "Revert "add extra bail condition"" This reverts commit cd2ded677935c9cdab0c02b6af55474c83727f60. * fix test * add SnapController entry to state object * updated permission name and caveat type with hardcoded values * add extra test for non-flask scenario * update lavamoat policies * fix locale messages * change coverage target * re-enable rpc snap test * revert locale message change * fix el message * reverted changes --------- Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
2023-03-08 19:29:23 +01:00
expect(caveatSpecifications.snapIds.type).toStrictEqual(
SnapCaveatType.SnapIds,
);
Permission System 2.0 (#12243) # Permission System 2.0 ## Background This PR migrates the extension permission system to [the new `PermissionController`](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions). The original permission system, based on [`rpc-cap`](https://github.com/MetaMask/rpc-cap), introduced [`ZCAP-LD`](https://w3c-ccg.github.io/zcap-ld/)-like permissions to our JSON-RPC stack. We used it to [implement](https://github.com/MetaMask/metamask-extension/pull/7004) what we called "LoginPerSite" in [version 7.7.0](https://github.com/MetaMask/metamask-extension/releases/tag/v7.7.0) of the extension, which enabled the user to choose which accounts, if any, should be exposed to each dapp. While that was a worthwhile feature in and of itself, we wanted a permission _system_ in order to enable everything we are going to with Snaps. Unfortunately, the original permission system was difficult to use, and necessitated the creation of the original `PermissionsController` (note the "s"), which was more or less a wrapper for `rpc-cap`. With this PR, we shake off the yoke of the original permission system, in favor of the modular, self-contained, ergonomic, and more mature permission system 2.0. Note that [the `PermissionController` readme](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions/README.md) explains how the new permission system works. The `PermissionController` and `SubjectMetadataController` are currently shipped via `@metamask/snap-controllers`. This is a temporary state of affairs, and we'll move them to `@metamask/controllers` once they've landed in prod. ## Changes in Detail First, the changes in this PR are not as big as they seem. Roughly half of the additions in this PR are fixtures in the test for the new migration (number 68), and a significant portion of the remaining ~2500 lines are due to find-and-replace changes in other test fixtures and UI files. - The extension `PermissionsController` has been deleted, and completely replaced with the new `PermissionController` from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The original `PermissionsController` "domain metadata" functionality is now managed by the new `SubjectMetadataController`, also from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The permission activity and history log controller has been renamed `PermissionLogController` and has its own top-level state key, but is otherwise functionally equivalent to the existing implementation. - Migration number 68 has been added to account for the new state changes. - The tests in `app/scripts/controllers/permissions` have been migrated from `mocha` to `jest`. Reviewers should focus their attention on the following files: - `app/scripts/` - `metamask-controller.js` - This is where most of the integration work for the new `PermissionController` occurs. Some functions that were internal to the original controller were moved here. - `controllers/permissions/` - `selectors.js` - These selectors are for `ControllerMessenger` selector subscriptions. The actual subscriptions occur in `metamask-controller.js`. See the `ControllerMessenger` implementation for details. - `specifications.js` - The caveat and permission specifications are required by the new `PermissionController`, and are used to specify the `eth_accounts` permission and its JSON-RPC method implementation. See the `PermissionController` readme for details. - `migrations/068.js` - The new state should be cross-referenced with the controllers that manage it. The accompanying tests should also be thoroughly reviewed. Some files may appear new but have just moved and/or been renamed: - `app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js` - This was previously implemented in `controllers/permissions/permissionsMethodMiddleware.js`. - `test/mocks/permissions.js` - A truncated version of `test/mocks/permission-controller.js`. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-12-07 04:16:49 +01:00
});
describe('restrictReturnedAccounts', () => {
describe('decorator', () => {
it('returns the first array member included in the caveat value', async () => {
const getIdentities = jest.fn();
const { decorator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
const method = async () => ['0x1', '0x2', '0x3'];
const caveat = {
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x1', '0x2'],
};
const decorated = decorator(method, caveat);
expect(await decorated()).toStrictEqual(['0x1']);
});
it('returns an empty array if no array members are included in the caveat value', async () => {
const getIdentities = jest.fn();
const { decorator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
const method = async () => ['0x1', '0x2', '0x3'];
const caveat = {
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x5'],
};
const decorated = decorator(method, caveat);
expect(await decorated()).toStrictEqual([]);
});
it('returns an empty array if the method result is an empty array', async () => {
const getIdentities = jest.fn();
const { decorator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
const method = async () => [];
const caveat = {
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x1', '0x2'],
};
const decorated = decorator(method, caveat);
expect(await decorated()).toStrictEqual([]);
});
});
describe('validator', () => {
it('rejects invalid array values', () => {
const getIdentities = jest.fn();
const { validator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
[null, 'foo', {}, []].forEach((invalidValue) => {
expect(() => validator({ value: invalidValue })).toThrow(
/Expected non-empty array of Ethereum addresses\.$/u,
);
});
});
it('rejects falsy or non-string addresses', () => {
const getIdentities = jest.fn();
const { validator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
[[{}], [[]], [null], ['']].forEach((invalidValue) => {
expect(() => validator({ value: invalidValue })).toThrow(
/Expected an array of Ethereum addresses. Received:/u,
);
});
});
it('rejects addresses that have no corresponding identity', () => {
const getIdentities = jest.fn().mockImplementationOnce(() => {
return {
'0x1': true,
'0x3': true,
};
});
const { validator } = getCaveatSpecifications({ getIdentities })[
CaveatTypes.restrictReturnedAccounts
];
expect(() => validator({ value: ['0x1', '0x2', '0x3'] })).toThrow(
/Received unrecognized address:/u,
);
});
});
});
});
describe('permission specifications', () => {
it('getPermissionSpecifications returns the expected specifications object', () => {
const permissionSpecifications = getPermissionSpecifications({});
expect(Object.keys(permissionSpecifications)).toHaveLength(1);
expect(
permissionSpecifications[RestrictedMethods.eth_accounts].targetKey,
).toStrictEqual(RestrictedMethods.eth_accounts);
});
describe('eth_accounts', () => {
describe('factory', () => {
it('constructs a valid eth_accounts permission', () => {
const getIdentities = jest.fn();
const getAllAccounts = jest.fn();
const { factory } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
expect(
factory(
{ invoker: 'foo.bar', target: 'eth_accounts' },
{ approvedAccounts: ['0x1'] },
),
).toStrictEqual({
caveats: [
{
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x1'],
},
],
date: 1,
id: expect.any(String),
invoker: 'foo.bar',
parentCapability: 'eth_accounts',
});
});
it('throws an error if no approvedAccounts are specified', () => {
const getIdentities = jest.fn();
const getAllAccounts = jest.fn();
const { factory } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
expect(() =>
factory(
{ invoker: 'foo.bar', target: 'eth_accounts' },
{}, // no approvedAccounts
),
).toThrow(/No approved accounts specified\.$/u);
});
it('throws an error if any caveats are specified directly', () => {
const getIdentities = jest.fn();
const getAllAccounts = jest.fn();
const { factory } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
expect(() =>
factory(
{
caveats: [
{
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x1', '0x2'],
},
],
invoker: 'foo.bar',
target: 'eth_accounts',
},
{ approvedAccounts: ['0x1'] },
),
).toThrow(/Received unexpected caveats./u);
});
});
describe('methodImplementation', () => {
it('returns the keyring accounts in lastSelected order', async () => {
const getIdentities = jest.fn().mockImplementationOnce(() => {
return {
'0x1': {
lastSelected: 1,
},
'0x2': {},
'0x3': {
lastSelected: 3,
},
'0x4': {
lastSelected: 3,
},
};
});
const getAllAccounts = jest
.fn()
.mockImplementationOnce(() => ['0x1', '0x2', '0x3', '0x4']);
const { methodImplementation } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
expect(await methodImplementation()).toStrictEqual([
'0x3',
'0x4',
'0x1',
'0x2',
]);
});
it('throws if a keyring account is missing an address (case 1)', async () => {
const getIdentities = jest.fn().mockImplementationOnce(() => {
return {
'0x2': {
lastSelected: 3,
},
'0x3': {
lastSelected: 3,
},
};
});
const getAllAccounts = jest
.fn()
.mockImplementationOnce(() => ['0x1', '0x2', '0x3']);
const { methodImplementation } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
captureKeyringTypesWithMissingIdentities: jest.fn(),
Permission System 2.0 (#12243) # Permission System 2.0 ## Background This PR migrates the extension permission system to [the new `PermissionController`](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions). The original permission system, based on [`rpc-cap`](https://github.com/MetaMask/rpc-cap), introduced [`ZCAP-LD`](https://w3c-ccg.github.io/zcap-ld/)-like permissions to our JSON-RPC stack. We used it to [implement](https://github.com/MetaMask/metamask-extension/pull/7004) what we called "LoginPerSite" in [version 7.7.0](https://github.com/MetaMask/metamask-extension/releases/tag/v7.7.0) of the extension, which enabled the user to choose which accounts, if any, should be exposed to each dapp. While that was a worthwhile feature in and of itself, we wanted a permission _system_ in order to enable everything we are going to with Snaps. Unfortunately, the original permission system was difficult to use, and necessitated the creation of the original `PermissionsController` (note the "s"), which was more or less a wrapper for `rpc-cap`. With this PR, we shake off the yoke of the original permission system, in favor of the modular, self-contained, ergonomic, and more mature permission system 2.0. Note that [the `PermissionController` readme](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions/README.md) explains how the new permission system works. The `PermissionController` and `SubjectMetadataController` are currently shipped via `@metamask/snap-controllers`. This is a temporary state of affairs, and we'll move them to `@metamask/controllers` once they've landed in prod. ## Changes in Detail First, the changes in this PR are not as big as they seem. Roughly half of the additions in this PR are fixtures in the test for the new migration (number 68), and a significant portion of the remaining ~2500 lines are due to find-and-replace changes in other test fixtures and UI files. - The extension `PermissionsController` has been deleted, and completely replaced with the new `PermissionController` from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The original `PermissionsController` "domain metadata" functionality is now managed by the new `SubjectMetadataController`, also from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The permission activity and history log controller has been renamed `PermissionLogController` and has its own top-level state key, but is otherwise functionally equivalent to the existing implementation. - Migration number 68 has been added to account for the new state changes. - The tests in `app/scripts/controllers/permissions` have been migrated from `mocha` to `jest`. Reviewers should focus their attention on the following files: - `app/scripts/` - `metamask-controller.js` - This is where most of the integration work for the new `PermissionController` occurs. Some functions that were internal to the original controller were moved here. - `controllers/permissions/` - `selectors.js` - These selectors are for `ControllerMessenger` selector subscriptions. The actual subscriptions occur in `metamask-controller.js`. See the `ControllerMessenger` implementation for details. - `specifications.js` - The caveat and permission specifications are required by the new `PermissionController`, and are used to specify the `eth_accounts` permission and its JSON-RPC method implementation. See the `PermissionController` readme for details. - `migrations/068.js` - The new state should be cross-referenced with the controllers that manage it. The accompanying tests should also be thoroughly reviewed. Some files may appear new but have just moved and/or been renamed: - `app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js` - This was previously implemented in `controllers/permissions/permissionsMethodMiddleware.js`. - `test/mocks/permissions.js` - A truncated version of `test/mocks/permission-controller.js`. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-12-07 04:16:49 +01:00
})[RestrictedMethods.eth_accounts];
await expect(() => methodImplementation()).rejects.toThrow(
'Missing identity for address: "0x1".',
);
});
it('throws if a keyring account is missing an address (case 2)', async () => {
const getIdentities = jest.fn().mockImplementationOnce(() => {
return {
'0x1': {
lastSelected: 1,
},
'0x3': {
lastSelected: 3,
},
};
});
const getAllAccounts = jest
.fn()
.mockImplementationOnce(() => ['0x1', '0x2', '0x3']);
const { methodImplementation } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
captureKeyringTypesWithMissingIdentities: jest.fn(),
Permission System 2.0 (#12243) # Permission System 2.0 ## Background This PR migrates the extension permission system to [the new `PermissionController`](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions). The original permission system, based on [`rpc-cap`](https://github.com/MetaMask/rpc-cap), introduced [`ZCAP-LD`](https://w3c-ccg.github.io/zcap-ld/)-like permissions to our JSON-RPC stack. We used it to [implement](https://github.com/MetaMask/metamask-extension/pull/7004) what we called "LoginPerSite" in [version 7.7.0](https://github.com/MetaMask/metamask-extension/releases/tag/v7.7.0) of the extension, which enabled the user to choose which accounts, if any, should be exposed to each dapp. While that was a worthwhile feature in and of itself, we wanted a permission _system_ in order to enable everything we are going to with Snaps. Unfortunately, the original permission system was difficult to use, and necessitated the creation of the original `PermissionsController` (note the "s"), which was more or less a wrapper for `rpc-cap`. With this PR, we shake off the yoke of the original permission system, in favor of the modular, self-contained, ergonomic, and more mature permission system 2.0. Note that [the `PermissionController` readme](https://github.com/MetaMask/snaps-skunkworks/tree/main/packages/controllers/src/permissions/README.md) explains how the new permission system works. The `PermissionController` and `SubjectMetadataController` are currently shipped via `@metamask/snap-controllers`. This is a temporary state of affairs, and we'll move them to `@metamask/controllers` once they've landed in prod. ## Changes in Detail First, the changes in this PR are not as big as they seem. Roughly half of the additions in this PR are fixtures in the test for the new migration (number 68), and a significant portion of the remaining ~2500 lines are due to find-and-replace changes in other test fixtures and UI files. - The extension `PermissionsController` has been deleted, and completely replaced with the new `PermissionController` from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The original `PermissionsController` "domain metadata" functionality is now managed by the new `SubjectMetadataController`, also from [`@metamask/snap-controllers`](https://www.npmjs.com/package/@metamask/snap-controllers). - The permission activity and history log controller has been renamed `PermissionLogController` and has its own top-level state key, but is otherwise functionally equivalent to the existing implementation. - Migration number 68 has been added to account for the new state changes. - The tests in `app/scripts/controllers/permissions` have been migrated from `mocha` to `jest`. Reviewers should focus their attention on the following files: - `app/scripts/` - `metamask-controller.js` - This is where most of the integration work for the new `PermissionController` occurs. Some functions that were internal to the original controller were moved here. - `controllers/permissions/` - `selectors.js` - These selectors are for `ControllerMessenger` selector subscriptions. The actual subscriptions occur in `metamask-controller.js`. See the `ControllerMessenger` implementation for details. - `specifications.js` - The caveat and permission specifications are required by the new `PermissionController`, and are used to specify the `eth_accounts` permission and its JSON-RPC method implementation. See the `PermissionController` readme for details. - `migrations/068.js` - The new state should be cross-referenced with the controllers that manage it. The accompanying tests should also be thoroughly reviewed. Some files may appear new but have just moved and/or been renamed: - `app/scripts/lib/rpc-method-middleware/handlers/request-accounts.js` - This was previously implemented in `controllers/permissions/permissionsMethodMiddleware.js`. - `test/mocks/permissions.js` - A truncated version of `test/mocks/permission-controller.js`. Co-authored-by: Mark Stacey <markjstacey@gmail.com>
2021-12-07 04:16:49 +01:00
})[RestrictedMethods.eth_accounts];
await expect(() => methodImplementation()).rejects.toThrow(
'Missing identity for address: "0x2".',
);
});
});
describe('validator', () => {
it('accepts valid permissions', () => {
const getIdentities = jest.fn();
const getAllAccounts = jest.fn();
const { validator } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
expect(() =>
validator({
caveats: [
{
type: CaveatTypes.restrictReturnedAccounts,
value: ['0x1', '0x2'],
},
],
date: 1,
id: expect.any(String),
invoker: 'foo.bar',
parentCapability: 'eth_accounts',
}),
).not.toThrow();
});
it('rejects invalid caveats', () => {
const getIdentities = jest.fn();
const getAllAccounts = jest.fn();
const { validator } = getPermissionSpecifications({
getIdentities,
getAllAccounts,
})[RestrictedMethods.eth_accounts];
[null, [], [1, 2], [{ type: 'foobar' }]].forEach(
(invalidCaveatsValue) => {
expect(() =>
validator({
caveats: invalidCaveatsValue,
date: 1,
id: expect.any(String),
invoker: 'foo.bar',
parentCapability: 'eth_accounts',
}),
).toThrow(/Invalid caveats./u);
},
);
});
});
});
});
describe('unrestricted methods', () => {
it('defines the unrestricted methods', () => {
expect(Array.isArray(unrestrictedMethods)).toBe(true);
expect(Object.isFrozen(unrestrictedMethods)).toBe(true);
});
});
});