diff --git a/.storybook/test-data.js b/.storybook/test-data.js index 43fe494dac79..35e037d45041 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -289,7 +289,6 @@ const state = { }, version: '0.6.0', }, - permissionName: 'wallet_snap_local:http://localhost:8080/', sourceCode: '(...)', status: 'stopped', svgIcon: '...', @@ -330,7 +329,6 @@ const state = { }, version: '0.6.0', }, - permissionName: 'wallet_snap_npm:http://localhost:8080/', sourceCode: '(...)', status: 'stopped', svgIcon: '...', diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 0080ba056675..6bfd407b9731 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Mit $1 verbinden.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Zugriff auf das Internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Verbinden Sie sich mit dem $1-Snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Regelmäßige Transaktionen planen und ausführen.", diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 716f4ce41144..6a5542a2aa0c 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Σύνδεση με $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Πρόσβαση στο Διαδίκτυο.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Συνδεθείτε στο Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Προγραμματισμός και εκτέλεση περιοδικών ενεργειών.", diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index c5aacd5d5b69..772a593ddd28 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2740,7 +2740,7 @@ }, "permission_accessNamedSnap": { "message": "Connect to $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Access the internet.", @@ -2748,7 +2748,7 @@ }, "permission_accessSnap": { "message": "Connect to the $1 snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Schedule and execute periodic actions.", diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index fac48c29a4a3..eb62c42f6541 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Conectarse a $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Acceso a internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Conéctese al complemento de $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Programar y ejecutar acciones periódicas.", diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index e9af316c961f..51edc2ceee55 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Se connecter à $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Accéder à internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Connexion au Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Planifiez et exécutez des actions périodiques.", diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index fdf132683109..2504e1bf10dd 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "$1 से कनेक्ट करें।", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "इंटरनेट एक्सेस करें।", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "$1 स्नैप से कनेक्ट करें।", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "समय-समय पर आने वाले क्रियाओं को शेड्यूल और निष्पादित करें।", diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 80f540915a10..a9a4dc57134c 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Hubungkan ke $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Akses internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Hubungkan ke Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Jadwalkan dan lakukan tindakan berkala.", diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index 7daf329c1bb6..42ee8847f4f8 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "$1 に接続。", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "インターネットにアクセスします。", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "$1 スナップに接続します。", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "定期的なアクションのスケジュール設定と実行。", diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index 82e616329221..6f759435fc90 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "$1 연결", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "인터넷에 액세스합니다.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "$1 스냅에 연결하세요.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "정기적 활동 예약 및 실행", diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index 47472350ee74..f56009a184da 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Conectar a $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Acesse a internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Conecte-se ao snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Agende e execute ações periódicas.", diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 3ecd3b04986d..071894ce74d1 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Подключиться к $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Доступ в Интернет.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Подключение к спапу $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Планируйте и выполняйте периодические действия.", diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index e09a91f01fef..d9091ae02f26 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Kumonekta sa $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "I-access ang Internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Kumonekta sa $1 snap.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Mag-iskedyul at magsagawa ng mga pana-panahong mga aksyon.", diff --git a/app/_locales/tr/messages.json b/app/_locales/tr/messages.json index 1474a9742f7e..eb7a36436ddd 100644 --- a/app/_locales/tr/messages.json +++ b/app/_locales/tr/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "$1 alanına bağlanın.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "İnternete erişim sağla.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "$1 snap'e bağlan.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Periyodik eylemleri planla ve gerçekleştir.", diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 40a838cabe03..78ecbc5e9d2d 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "Kết nối với $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "Truy cập Internet.", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "Kết nối với Snap $1.", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "Lên lịch và thực hiện các hành động theo định kỳ.", diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index e803fecdb3fd..ed01186d65e6 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -2713,7 +2713,7 @@ }, "permission_accessNamedSnap": { "message": "连接至$1。", - "description": "The description for the `wallet_snap_*` permission. $1 is the human-readable name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the human-readable name of the snap." }, "permission_accessNetwork": { "message": "访问互联网。", @@ -2721,7 +2721,7 @@ }, "permission_accessSnap": { "message": "连接到$1 Snap。", - "description": "The description for the `wallet_snap_*` permission. $1 is the name of the snap." + "description": "The description for the `wallet_snap` permission. $1 is the name of the snap." }, "permission_cronjob": { "message": "规划并执行定期操作。", diff --git a/app/scripts/controllers/permissions/specifications.test.js b/app/scripts/controllers/permissions/specifications.test.js index 3143c7f96ec0..0f3fb7a733c1 100644 --- a/app/scripts/controllers/permissions/specifications.test.js +++ b/app/scripts/controllers/permissions/specifications.test.js @@ -16,7 +16,7 @@ describe('PermissionController specifications', () => { describe('caveat specifications', () => { it('getCaveatSpecifications returns the expected specifications object', () => { const caveatSpecifications = getCaveatSpecifications({}); - expect(Object.keys(caveatSpecifications)).toHaveLength(7); + expect(Object.keys(caveatSpecifications)).toHaveLength(8); expect( caveatSpecifications[CaveatTypes.restrictReturnedAccounts].type, ).toStrictEqual(CaveatTypes.restrictReturnedAccounts); @@ -39,6 +39,9 @@ describe('PermissionController specifications', () => { expect(caveatSpecifications.rpcOrigin.type).toStrictEqual( SnapCaveatType.RpcOrigin, ); + expect(caveatSpecifications.snapIds.type).toStrictEqual( + SnapCaveatType.SnapIds, + ); }); describe('restrictReturnedAccounts', () => { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 7887244d823e..983ee5119875 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -754,7 +754,7 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(flask) const snapExecutionServiceArgs = { iframeUrl: new URL( - 'https://metamask.github.io/iframe-execution-environment/0.12.0', + 'https://metamask.github.io/iframe-execution-environment/0.13.0', ), messenger: this.controllerMessenger.getRestricted({ name: 'ExecutionService', @@ -782,6 +782,8 @@ export default class MetamaskController extends EventEmitter { `${this.permissionController.name}:revokeAllPermissions`, `${this.permissionController.name}:revokePermissions`, `${this.permissionController.name}:revokePermissionForAllSubjects`, + `${this.permissionController.name}:getSubjectNames`, + `${this.permissionController.name}:updateCaveat`, `${this.approvalController.name}:addRequest`, `${this.permissionController.name}:grantPermissions`, `${this.subjectMetadataController.name}:getSubjectMetadata`, @@ -4674,6 +4676,24 @@ export default class MetamaskController extends EventEmitter { } }; + ///: BEGIN:ONLY_INCLUDE_IN(flask) + updateCaveat = (origin, target, caveatType, caveatValue) => { + try { + this.controllerMessenger.call( + 'PermissionController:updateCaveat', + origin, + target, + caveatType, + caveatValue, + ); + } catch (exp) { + if (!(exp instanceof PermissionsRequestNotFoundError)) { + throw exp; + } + } + }; + ///: END:ONLY_INCLUDE_IN + rejectPermissionsRequest = (requestId) => { try { this.permissionController.rejectPermissionsRequest(requestId); diff --git a/app/scripts/migrations/081.test.js b/app/scripts/migrations/081.test.js new file mode 100644 index 000000000000..2a75ffec6720 --- /dev/null +++ b/app/scripts/migrations/081.test.js @@ -0,0 +1,162 @@ +import { migrate, version as newVersion } from './081'; + +describe('migration #81', () => { + it('should consolidate snap permissions as caveats under the wallet_snap permission', async () => { + const oldStorage = { + meta: { + version: 80, + }, + data: { + SnapController: {}, + PermissionController: { + subjects: { + 'example.com': { + permissions: { + 'wallet_snap_npm:foobar': { + caveats: null, + date: 2, + id: 'a7342F4b-beae-4525-a36c-c0635fd03359', + invoker: 'example.com', + parentCapability: 'wallet_snap_npm:foobar', + }, + 'wallet_snap_npm:baz': { + caveats: null, + date: 3, + id: 'x342A44-beae-4525-a36c-c0635fd03359', + invoker: 'example.com', + parentCapability: 'wallet_snap_npm:baz', + }, + }, + }, + 'aave.com': { + permissions: { + 'wallet_snap_npm:filsnap': { + caveats: null, + date: 10, + id: 'a7342F4b-beae-4525-a36c-c0635fd03359', + invoker: 'aave.com', + parentCapability: 'wallet_snap_npm:foobar', + }, + 'wallet_snap_npm:btcsnap': { + caveats: null, + date: 3, + id: 'x342A44-beae-4525-a36c-c0635fd03359', + invoker: 'aave.com', + parentCapability: 'wallet_snap_npm:btcsnap', + }, + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage).toStrictEqual({ + meta: { version: newVersion }, + data: { + SnapController: {}, + PermissionController: { + subjects: { + 'example.com': { + permissions: { + wallet_snap: { + caveats: [ + { + type: 'snapIds', + value: { + 'npm:foobar': {}, + 'npm:baz': {}, + }, + }, + ], + date: 3, + id: 'x342A44-beae-4525-a36c-c0635fd03359', + invoker: 'example.com', + parentCapability: 'wallet_snap', + }, + }, + }, + 'aave.com': { + permissions: { + wallet_snap: { + caveats: [ + { + type: 'snapIds', + value: { + 'npm:btcsnap': {}, + 'npm:filsnap': {}, + }, + }, + ], + date: 10, + id: 'a7342F4b-beae-4525-a36c-c0635fd03359', + invoker: 'aave.com', + parentCapability: 'wallet_snap', + }, + }, + }, + }, + }, + }, + }); + }); + + it('should leave state unchanged if there are no snap permissions', async () => { + const oldStorage = { + meta: { + version: 80, + }, + data: { + SnapController: {}, + PermissionController: { + subjects: { + 'example.com': { + permissions: { + eth_accounts: { + date: 2, + id: 'a7342F4b-beae-4525-a36c-c0635fd03359', + invoker: 'example.com', + parentCapability: 'eth_accounts', + }, + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); + + it('should leave state unchanged if there is no SnapController installed (i.e. not a flask build)', async () => { + const oldStorage = { + meta: { + version: 80, + }, + data: { + PermissionController: { + subjects: { + 'example.com': { + permissions: { + eth_accounts: { + date: 2, + id: 'a7342F4b-beae-4525-a36c-c0635fd03359', + invoker: 'example.com', + parentCapability: 'eth_accounts', + }, + }, + }, + }, + }, + }, + }; + + const newStorage = await migrate(oldStorage); + + expect(newStorage.data).toStrictEqual(oldStorage.data); + }); +}); diff --git a/app/scripts/migrations/081.ts b/app/scripts/migrations/081.ts new file mode 100644 index 000000000000..0162a43b6e49 --- /dev/null +++ b/app/scripts/migrations/081.ts @@ -0,0 +1,140 @@ +import { cloneDeep, isArray } from 'lodash'; +import { hasProperty, isObject } from '@metamask/utils'; + +export const version = 81; + +/** + * Prior to this migration, snap <> dapp permissions were wildcards i.e. `wallet_snap_*`. + * Now the permission has been changed to `wallet_snap` and the current snap permissions + * that are under wildcards will be added as caveats to a parent `wallet_snap` permission. + * + * @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist. + * @param originalVersionedData.meta - State metadata. + * @param originalVersionedData.meta.version - The current state version. + * @param originalVersionedData.data - The persisted MetaMask state, keyed by controller. + * @returns Updated versioned MetaMask extension state. + */ +export async function migrate(originalVersionedData: { + meta: { version: number }; + data: Record; +}) { + const versionedData = cloneDeep(originalVersionedData); + versionedData.meta.version = version; + const state = versionedData.data; + const newState = transformState(state); + versionedData.data = newState; + return versionedData; +} + +// We return state AS IS if there is any corruption +function transformState(state: Record) { + if ( + !hasProperty(state, 'SnapController') || + !hasProperty(state, 'PermissionController') || + !isObject(state.PermissionController) + ) { + return state; + } + const { PermissionController } = state; + + const { subjects } = PermissionController; + + if (!isObject(subjects)) { + return state; + } + + const snapPrefix = 'wallet_snap_'; + + for (const [subjectName, subject] of Object.entries(subjects)) { + if (!isObject(subject) || !isObject(subject.permissions)) { + return state; + } + // We keep track of the latest permission's date and associated id + // to assign to the wallet_snap permission after iterating through all permissions + let date = 1; + let id; + const { permissions } = subject; + // New permissions object that we use to tack on the `wallet_snap` permission + const updatedPermissions = { ...permissions }; + for (const [permissionName, permission] of Object.entries(permissions)) { + // check if the permission is namespaced + if (permissionName.startsWith(snapPrefix)) { + if ( + !isObject(permission) || + !hasProperty(permission, 'id') || + !hasProperty(permission, 'date') + ) { + return state; + } + // We create a wallet_snap key if we already don't have one + if (!hasProperty(updatedPermissions, 'wallet_snap')) { + updatedPermissions.wallet_snap = { + caveats: [{ type: 'snapIds', value: {} }], + invoker: subjectName, + parentCapability: 'wallet_snap', + }; + } + + // Check if the existing permission is valid + if (!isObject(updatedPermissions.wallet_snap)) { + return state; + } + + if ( + !isArray( + (updatedPermissions.wallet_snap as Record).caveats, + ) + ) { + return state; + } + + // Adding the snap name to the wallet_snap permission's caveat value + const snapId = permissionName.slice(snapPrefix.length); + const caveat = ( + (updatedPermissions.wallet_snap as Record) + .caveats as unknown[] + )[0]; + + if (!isObject(caveat)) { + return state; + } + + if ( + !hasProperty(caveat, 'type') || + caveat.type !== 'snapIds' || + !hasProperty(caveat, 'value') || + !isObject(caveat.value) + ) { + return state; + } + caveat.value[snapId] = {}; + + if ( + typeof permission.date !== 'number' || + typeof permission.id !== 'string' + ) { + return state; + } + + // updating the date & id as we iterate through all permissions + if (permission.date > date) { + date = permission.date; + id = permission.id; + } + + // finally deleting the stale permission + delete updatedPermissions[permissionName]; + } + } + + // we reassign the date and id here after iterating through all permissions + // and update the subject with the updated permissions + if (updatedPermissions.wallet_snap) { + (updatedPermissions.wallet_snap as Record).date = date; + (updatedPermissions.wallet_snap as Record).id = id; + subject.permissions = updatedPermissions; + } + } + + return state; +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 84b9b7e4cfa5..6bc0d0576f5f 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -84,6 +84,7 @@ import m077 from './077'; import * as m078 from './078'; import m079 from './079'; import m080 from './080'; +import * as m081 from './081'; const migrations = [ m002, @@ -165,6 +166,7 @@ const migrations = [ m078, m079, m080, + m081, ]; export default migrations; diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 2d824d949339..5cf58f0f37b2 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1298,7 +1298,7 @@ "@metamask/permission-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, @@ -1306,6 +1306,21 @@ "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>isomorphic-fetch": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1347,7 +1362,8 @@ "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/utils": true + "@metamask/utils": true, + "@metamask/utils>superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 17e096890659..28e091b8233b 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1364,7 +1364,7 @@ "@metamask/permission-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, @@ -1372,6 +1372,21 @@ "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>isomorphic-fetch": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1480,14 +1495,11 @@ } }, "@metamask/rpc-methods": { - "globals": { - "console.warn": true - }, "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/permission-controller": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, + "@metamask/rpc-methods>@metamask/permission-controller": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snaps-ui": true, "@metamask/snaps-utils": true, @@ -1510,6 +1522,36 @@ "browserify>buffer": true } }, + "@metamask/rpc-methods>@metamask/permission-controller": { + "packages": { + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils": true, + "@metamask/rpc-methods>nanoid": true, + "deep-freeze-strict": true, + "eth-rpc-errors": true, + "immer": true, + "json-rpc-engine": true + } + }, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/base-controller": { + "packages": { + "immer": true + } + }, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/rpc-methods>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1562,20 +1604,17 @@ "chrome.offscreen.createDocument": true, "chrome.offscreen.hasDocument": true, "clearTimeout": true, - "console.error": true, - "console.info": true, - "console.log": true, - "console.warn": true, "document.getElementById": true, "fetch.bind": true, "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/permission-controller": true, "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/permission-controller": true, + "@metamask/snaps-controllers>@metamask/subject-metadata-controller": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>gunzip-maybe": true, @@ -1583,7 +1622,6 @@ "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-utils": true, - "@metamask/subject-metadata-controller": true, "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, @@ -1591,6 +1629,41 @@ "pump": true } }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/base-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/snaps-controllers>@metamask/permission-controller": { + "packages": { + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/base-controller>@metamask/controller-utils": true, + "@metamask/snaps-controllers>nanoid": true, + "deep-freeze-strict": true, + "eth-rpc-errors": true, + "immer": true, + "json-rpc-engine": true + } + }, + "@metamask/snaps-controllers>@metamask/subject-metadata-controller": { + "packages": { + "@metamask/snaps-controllers>@metamask/base-controller": true + } + }, "@metamask/snaps-controllers>concat-stream": { "packages": { "@metamask/snaps-controllers>concat-stream>readable-stream": true, @@ -1747,6 +1820,9 @@ "globals": { "TextDecoder": true, "URL": true, + "console.error": true, + "console.log": true, + "console.warn": true, "document.body.appendChild": true, "document.createElement": true }, @@ -1754,6 +1830,7 @@ "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, "@metamask/snaps-utils>cron-parser": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "@metamask/utils": true, diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 17e096890659..28e091b8233b 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1364,7 +1364,7 @@ "@metamask/permission-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, @@ -1372,6 +1372,21 @@ "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>isomorphic-fetch": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1480,14 +1495,11 @@ } }, "@metamask/rpc-methods": { - "globals": { - "console.warn": true - }, "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/permission-controller": true, "@metamask/rpc-methods>@metamask/browser-passworder": true, + "@metamask/rpc-methods>@metamask/permission-controller": true, "@metamask/rpc-methods>nanoid": true, "@metamask/snaps-ui": true, "@metamask/snaps-utils": true, @@ -1510,6 +1522,36 @@ "browserify>buffer": true } }, + "@metamask/rpc-methods>@metamask/permission-controller": { + "packages": { + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/base-controller": true, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils": true, + "@metamask/rpc-methods>nanoid": true, + "deep-freeze-strict": true, + "eth-rpc-errors": true, + "immer": true, + "json-rpc-engine": true + } + }, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/base-controller": { + "packages": { + "immer": true + } + }, + "@metamask/rpc-methods>@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/rpc-methods>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1562,20 +1604,17 @@ "chrome.offscreen.createDocument": true, "chrome.offscreen.hasDocument": true, "clearTimeout": true, - "console.error": true, - "console.info": true, - "console.log": true, - "console.warn": true, "document.getElementById": true, "fetch.bind": true, "setTimeout": true }, "packages": { - "@metamask/base-controller": true, - "@metamask/permission-controller": true, "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, "@metamask/rpc-methods": true, + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/permission-controller": true, + "@metamask/snaps-controllers>@metamask/subject-metadata-controller": true, "@metamask/snaps-controllers>@xstate/fsm": true, "@metamask/snaps-controllers>concat-stream": true, "@metamask/snaps-controllers>gunzip-maybe": true, @@ -1583,7 +1622,6 @@ "@metamask/snaps-controllers>readable-web-to-node-stream": true, "@metamask/snaps-controllers>tar-stream": true, "@metamask/snaps-utils": true, - "@metamask/subject-metadata-controller": true, "@metamask/utils": true, "eth-rpc-errors": true, "json-rpc-engine": true, @@ -1591,6 +1629,41 @@ "pump": true } }, + "@metamask/snaps-controllers>@metamask/base-controller": { + "packages": { + "immer": true + } + }, + "@metamask/snaps-controllers>@metamask/base-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, + "@metamask/snaps-controllers>@metamask/permission-controller": { + "packages": { + "@metamask/snaps-controllers>@metamask/base-controller": true, + "@metamask/snaps-controllers>@metamask/base-controller>@metamask/controller-utils": true, + "@metamask/snaps-controllers>nanoid": true, + "deep-freeze-strict": true, + "eth-rpc-errors": true, + "immer": true, + "json-rpc-engine": true + } + }, + "@metamask/snaps-controllers>@metamask/subject-metadata-controller": { + "packages": { + "@metamask/snaps-controllers>@metamask/base-controller": true + } + }, "@metamask/snaps-controllers>concat-stream": { "packages": { "@metamask/snaps-controllers>concat-stream>readable-stream": true, @@ -1747,6 +1820,9 @@ "globals": { "TextDecoder": true, "URL": true, + "console.error": true, + "console.log": true, + "console.warn": true, "document.body.appendChild": true, "document.createElement": true }, @@ -1754,6 +1830,7 @@ "@metamask/key-tree>@noble/hashes": true, "@metamask/key-tree>@scure/base": true, "@metamask/snaps-utils>cron-parser": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, "@metamask/snaps-utils>rfdc": true, "@metamask/snaps-utils>validate-npm-package-name": true, "@metamask/utils": true, diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 2d824d949339..5cf58f0f37b2 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1298,7 +1298,7 @@ "@metamask/permission-controller": { "packages": { "@metamask/base-controller": true, - "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/controller-utils": true, "@metamask/permission-controller>nanoid": true, "deep-freeze-strict": true, "eth-rpc-errors": true, @@ -1306,6 +1306,21 @@ "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/controller-utils": { + "globals": { + "console.error": true, + "fetch": true, + "setTimeout": true + }, + "packages": { + "@metamask/controller-utils>isomorphic-fetch": true, + "browserify>buffer": true, + "eslint>fast-deep-equal": true, + "eth-ens-namehash": true, + "ethereumjs-util": true, + "ethjs>ethjs-unit": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1347,7 +1362,8 @@ "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/utils": true + "@metamask/utils": true, + "@metamask/utils>superstruct": true } }, "@metamask/rpc-methods>@metamask/browser-passworder": { diff --git a/lavamoat/build-system/policy.json b/lavamoat/build-system/policy.json index 59bdb76bebfb..492fb362fe1d 100644 --- a/lavamoat/build-system/policy.json +++ b/lavamoat/build-system/policy.json @@ -2891,7 +2891,7 @@ "console": true }, "packages": { - "eslint>ajv>fast-json-stable-stringify": true, + "@metamask/snaps-utils>fast-json-stable-stringify": true, "eslint>ajv>json-schema-traverse": true, "eslint>ajv>uri-js": true, "eslint>fast-deep-equal": true diff --git a/package.json b/package.json index 5f99891cdfd1..49e8cdaa6273 100644 --- a/package.json +++ b/package.json @@ -245,18 +245,18 @@ "@metamask/metamask-eth-abis": "^3.0.0", "@metamask/notification-controller": "^1.0.0", "@metamask/obs-store": "^5.0.0", - "@metamask/permission-controller": "^1.0.0", + "@metamask/permission-controller": "^2.0.0", "@metamask/phishing-controller": "^2.0.0", "@metamask/post-message-stream": "^6.0.0", "@metamask/providers": "^10.2.1", "@metamask/rate-limit-controller": "^1.0.0", - "@metamask/rpc-methods": "^0.28.0", + "@metamask/rpc-methods": "^0.30.0", "@metamask/scure-bip39": "^2.0.3", "@metamask/slip44": "^2.1.0", "@metamask/smart-transactions-controller": "^3.1.0", - "@metamask/snaps-controllers": "^0.28.0", - "@metamask/snaps-ui": "^0.28.0", - "@metamask/snaps-utils": "^0.28.0", + "@metamask/snaps-controllers": "^0.30.0", + "@metamask/snaps-ui": "^0.30.0", + "@metamask/snaps-utils": "^0.30.0", "@metamask/subject-metadata-controller": "^1.0.0", "@metamask/utils": "^3.6.0", "@ngraveio/bc-ur": "^1.1.6", diff --git a/shared/constants/permissions.ts b/shared/constants/permissions.ts index fd57e4f5e4da..4de83b52f8fa 100644 --- a/shared/constants/permissions.ts +++ b/shared/constants/permissions.ts @@ -5,7 +5,6 @@ export const CaveatTypes = Object.freeze({ export const RestrictedMethods = Object.freeze({ eth_accounts: 'eth_accounts', ///: BEGIN:ONLY_INCLUDE_IN(flask) - snap_confirm: 'snap_confirm', snap_dialog: 'snap_dialog', snap_notify: 'snap_notify', snap_manageState: 'snap_manageState', @@ -13,7 +12,7 @@ export const RestrictedMethods = Object.freeze({ snap_getBip32Entropy: 'snap_getBip32Entropy', snap_getBip44Entropy: 'snap_getBip44Entropy', snap_getEntropy: 'snap_getEntropy', - 'wallet_snap_*': 'wallet_snap_*', + wallet_snap: 'wallet_snap', ///: END:ONLY_INCLUDE_IN } as const); @@ -23,10 +22,6 @@ export const RestrictedMethods = Object.freeze({ * This is a fix for https://github.com/MetaMask/snaps-monorepo/issues/1103 and https://github.com/MetaMask/snaps-monorepo/issues/990. * TODO: Disable endowment:long-running and eth_account in stable. */ -export const PermissionNamespaces = Object.freeze({ - wallet_snap_: 'wallet_snap_*', -} as const); - export const EndowmentPermissions = Object.freeze({ 'endowment:network-access': 'endowment:network-access', 'endowment:transaction-insight': 'endowment:transaction-insight', @@ -34,6 +29,7 @@ export const EndowmentPermissions = Object.freeze({ 'endowment:ethereum-provider': 'endowment:ethereum-provider', 'endowment:rpc': 'endowment:rpc', 'endowment:long-running': 'endowment:long-running', + 'endowment:webassembly': 'endowment:webassembly', } as const); // Methods / permissions in external packages that we are temporarily excluding. diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 1313a21bc1bf..eff689cc2738 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -1,3 +1,7 @@ +const { + WALLET_SNAP_PERMISSION_KEY, + SnapCaveatType, +} = require('@metamask/snaps-utils'); const { merge } = require('lodash'); const { CHAIN_IDS } = require('../../shared/constants/network'); @@ -529,48 +533,22 @@ class FixtureBuilder { 'https://metamask.github.io': { origin: 'https://metamask.github.io', permissions: { - 'wallet_snap_npm:@metamask/test-snap-bip32': { + [WALLET_SNAP_PERMISSION_KEY]: { + caveats: [ + { + type: SnapCaveatType.SnapIds, + value: { + 'npm@metamask/test-snap-bip32': {}, + 'npm@metamask/test-snap-bip44': {}, + 'npm@metamask/test-snap-error': {}, + 'npm@metamask/test-snap-managestate': {}, + 'npm@metamask/test-snap-notification': {}, + }, + }, + ], id: 'CwdJq0x8N_b9FNxn6dVuP', - parentCapability: 'wallet_snap_npm:@metamask/test-snap-bip32', - invoker: 'https://metamask.github.io', - caveats: null, - date: 1664388714636, - }, - 'wallet_snap_npm:@metamask/test-snap-bip44': { - id: '8zH-0opWuZhvJew41FMVh', - parentCapability: 'wallet_snap_npm:@metamask/test-snap-bip44', - invoker: 'https://metamask.github.io', - caveats: null, - date: 1664388714636, - }, - 'wallet_snap_npm:@metamask/test-snap-confirm': { - id: 'Wb_1c9toBggBQWfOJwjMg', - parentCapability: 'wallet_snap_npm:@metamask/test-snap-confirm', - invoker: 'https://metamask.github.io', - caveats: null, - date: 1664388714636, - }, - 'wallet_snap_npm:@metamask/test-snap-error': { - id: '5FUZoCyimOWKTbuLCEOWa', - parentCapability: 'wallet_snap_npm:@metamask/test-snap-error', - invoker: 'https://metamask.github.io', - caveats: null, - date: 1664388714636, - }, - 'wallet_snap_npm:@metamask/test-snap-managestate': { - id: 'Z6XPdyuCHCf1pyqSiU7nh', - parentCapability: - 'wallet_snap_npm:@metamask/test-snap-managestate', - invoker: 'https://metamask.github.io', - caveats: null, - date: 1664388714636, - }, - 'wallet_snap_npm:@metamask/test-snap-notification': { - id: '_xfRMXzq0bs8QcXRcvjcP', - parentCapability: - 'wallet_snap_npm:@metamask/test-snap-notification', + parentCapability: WALLET_SNAP_PERMISSION_KEY, invoker: 'https://metamask.github.io', - caveats: null, date: 1664388714636, }, }, diff --git a/test/e2e/snaps/enums.js b/test/e2e/snaps/enums.js index 237a8f707809..c5992424c6d0 100644 --- a/test/e2e/snaps/enums.js +++ b/test/e2e/snaps/enums.js @@ -1,3 +1,3 @@ module.exports = { - TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/test-snaps/4.6.2/', + TEST_SNAPS_WEBSITE_URL: 'https://metamask.github.io/test-snaps/5.0.3/', }; diff --git a/test/e2e/snaps/test-snap-confirm.spec.js b/test/e2e/snaps/test-snap-confirm.spec.js deleted file mode 100644 index 4843dad42f66..000000000000 --- a/test/e2e/snaps/test-snap-confirm.spec.js +++ /dev/null @@ -1,100 +0,0 @@ -const { strict: assert } = require('assert'); -const { withFixtures } = require('../helpers'); -const FixtureBuilder = require('../fixture-builder'); -const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); - -describe('Test Snap Confirm', function () { - it('can pop up a snap confirm and get its result', async function () { - const ganacheOptions = { - accounts: [ - { - secretKey: - '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', - balance: 25000000000000000000, - }, - ], - }; - await withFixtures( - { - fixtures: new FixtureBuilder().build(), - ganacheOptions, - failOnConsoleError: false, - title: this.test.title, - }, - async ({ driver }) => { - await driver.navigate(); - - // enter pw into extension - await driver.fill('#password', 'correct horse battery staple'); - await driver.press('#password', driver.Key.ENTER); - - // navigate to test snaps page and connect - await driver.driver.get(TEST_SNAPS_WEBSITE_URL); - await driver.delay(1000); - const snapButton1 = await driver.findElement('#connectConfirmSnap'); - await driver.scrollToElement(snapButton1); - await driver.delay(1000); - await driver.clickElement('#connectConfirmSnap'); - await driver.delay(1000); - - // switch to metamask extension and click connect - let windowHandles = await driver.waitUntilXWindowHandles( - 2, - 1000, - 10000, - ); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.clickElement({ - text: 'Connect', - tag: 'button', - }); - - await driver.delay(2000); - - // approve install of snap - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.clickElement({ - text: 'Approve & install', - tag: 'button', - }); - - // delay for npm installation - await driver.delay(2000); - - // switch back to test snaps page - windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); - - // click send inputs on test snap page - const snapButton2 = await driver.findElement('#sendConfirmButton'); - await driver.scrollToElement(snapButton2); - await driver.delay(1000); - await driver.clickElement('#sendConfirmButton'); - - // hit 'approve' on the custom confirm - windowHandles = await driver.waitUntilXWindowHandles(2, 1000, 10000); - await driver.switchToWindowWithTitle( - 'MetaMask Notification', - windowHandles, - ); - await driver.clickElement({ - text: 'Approve', - tag: 'button', - }); - - // check the results of the custom confirm - windowHandles = await driver.waitUntilXWindowHandles(1, 1000, 10000); - await driver.switchToWindowWithTitle('Test Snaps', windowHandles); - const confirmResult = await driver.findElement('#confirmResult'); - assert.equal(await confirmResult.getText(), 'true'); - }, - ); - }); -}); diff --git a/test/e2e/snaps/test-snap-rpc.spec.js b/test/e2e/snaps/test-snap-rpc.spec.js index 22f6d6163729..19715ec36058 100644 --- a/test/e2e/snaps/test-snap-rpc.spec.js +++ b/test/e2e/snaps/test-snap-rpc.spec.js @@ -4,9 +4,7 @@ const FixtureBuilder = require('../fixture-builder'); const { TEST_SNAPS_WEBSITE_URL } = require('./enums'); describe('Test Snap RPC', function () { - // TODO: Re-enable this test once `test-snaps` is fixed. - // eslint-disable-next-line mocha/no-skipped-tests - it.skip('can use the cross-snap RPC endowment and produce a public key', async function () { + it('can use the cross-snap RPC endowment and produce a public key', async function () { const ganacheOptions = { accounts: [ { diff --git a/test/e2e/snaps/test-snap-update.spec.js b/test/e2e/snaps/test-snap-update.spec.js index 5339ded07ee1..1120f20b8822 100644 --- a/test/e2e/snaps/test-snap-update.spec.js +++ b/test/e2e/snaps/test-snap-update.spec.js @@ -115,7 +115,7 @@ describe('Test Snap update', function () { // look for the correct version text const versionResult = await driver.findElement('#updateSnapVersion'); await driver.delay(1000); - assert.equal(await versionResult.getText(), '"4.0.2"'); + assert.equal(await versionResult.getText(), '"5.0.1"'); }, ); }); diff --git a/ui/components/app/permission-page-container/permission-page-container.component.js b/ui/components/app/permission-page-container/permission-page-container.component.js index 60b39bd39d10..6b28f07cc74e 100644 --- a/ui/components/app/permission-page-container/permission-page-container.component.js +++ b/ui/components/app/permission-page-container/permission-page-container.component.js @@ -1,9 +1,19 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { isEqual } from 'lodash'; +///: BEGIN:ONLY_INCLUDE_IN(flask) +import { isObject } from '@metamask/utils'; +import { + SnapCaveatType, + WALLET_SNAP_PERMISSION_KEY, +} from '@metamask/rpc-methods'; +///: END:ONLY_INCLUDE_IN import { EVENT } from '../../../../shared/constants/metametrics'; import { PageContainerFooter } from '../../ui/page-container'; import PermissionsConnectFooter from '../permissions-connect-footer'; +///: BEGIN:ONLY_INCLUDE_IN(flask) +import { RestrictedMethods } from '../../../../shared/constants/permissions'; +///: END:ONLY_INCLUDE_IN import { PermissionPageContainerContent } from '.'; export default class PermissionPageContainer extends Component { @@ -12,6 +22,9 @@ export default class PermissionPageContainer extends Component { rejectPermissionsRequest: PropTypes.func.isRequired, selectedIdentities: PropTypes.array, allIdentitiesSelected: PropTypes.bool, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + currentPermissions: PropTypes.object, + ///: END:ONLY_INCLUDE_IN request: PropTypes.object, requestMetadata: PropTypes.object, targetSubjectMetadata: PropTypes.shape({ @@ -28,6 +41,9 @@ export default class PermissionPageContainer extends Component { requestMetadata: {}, selectedIdentities: [], allIdentitiesSelected: false, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + currentPermissions: {}, + ///: END:ONLY_INCLUDE_IN }; static contextTypes = { @@ -54,11 +70,46 @@ export default class PermissionPageContainer extends Component { getRequestedMethodState(methodNames) { return methodNames.reduce((acc, methodName) => { + ///: BEGIN:ONLY_INCLUDE_IN(flask) + if (methodName === RestrictedMethods.wallet_snap) { + acc[methodName] = this.getDedupedSnapPermissions(); + return acc; + } + ///: END:ONLY_INCLUDE_IN acc[methodName] = true; return acc; }, {}); } + ///: BEGIN:ONLY_INCLUDE_IN(flask) + getDedupedSnapPermissions() { + const permission = + this.props.request.permissions[WALLET_SNAP_PERMISSION_KEY]; + const requestedSnaps = permission?.caveats[0].value; + const currentSnaps = + this.props.currentPermissions[WALLET_SNAP_PERMISSION_KEY]?.caveats[0] + .value; + + if (!isObject(currentSnaps)) { + return permission; + } + + const requestedSnapKeys = requestedSnaps ? Object.keys(requestedSnaps) : []; + const currentSnapKeys = currentSnaps ? Object.keys(currentSnaps) : []; + const dedupedCaveats = requestedSnapKeys.reduce((acc, snapId) => { + if (!currentSnapKeys.includes(snapId)) { + acc[snapId] = {}; + } + return acc; + }, {}); + + return { + ...permission, + caveats: [{ type: SnapCaveatType.SnapIds, value: dedupedCaveats }], + }; + } + ///: END:ONLY_INCLUDE_IN + getRequestedMethodNames(props) { return Object.keys(props.request.permissions || {}); } diff --git a/ui/components/app/permission-page-container/permission-page-container.container.js b/ui/components/app/permission-page-container/permission-page-container.container.js index 031dfa6f05d8..47aaf070ecdf 100644 --- a/ui/components/app/permission-page-container/permission-page-container.container.js +++ b/ui/components/app/permission-page-container/permission-page-container.container.js @@ -1,10 +1,20 @@ import { connect } from 'react-redux'; -import { getMetaMaskIdentities } from '../../../selectors'; +import { + getMetaMaskIdentities, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + getPermissions, + ///: END:ONLY_INCLUDE_IN +} from '../../../selectors'; import PermissionPageContainer from './permission-page-container.component'; const mapStateToProps = (state, ownProps) => { const { selectedIdentities } = ownProps; - + ///: BEGIN:ONLY_INCLUDE_IN(flask) + const currentPermissions = getPermissions( + state, + ownProps.request.metadata?.origin, + ); + ///: END:ONLY_INCLUDE_IN const allIdentities = getMetaMaskIdentities(state); const allIdentitiesSelected = Object.keys(selectedIdentities).length === @@ -12,6 +22,9 @@ const mapStateToProps = (state, ownProps) => { return { allIdentitiesSelected, + ///: BEGIN:ONLY_INCLUDE_IN(flask) + currentPermissions, + ///: END:ONLY_INCLUDE_IN }; }; diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index b625c414d610..f17461fa069e 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -10,7 +10,6 @@ import { RestrictedMethods, ///: BEGIN:ONLY_INCLUDE_IN(flask) EndowmentPermissions, - PermissionNamespaces, ///: END:ONLY_INCLUDE_IN } from '../../../shared/constants/permissions'; ///: BEGIN:ONLY_INCLUDE_IN(flask) @@ -142,30 +141,29 @@ const PERMISSION_DESCRIPTIONS = deepFreeze({ rightIcon: null, weight: 3, }), - [RestrictedMethods['wallet_snap_*']]: (t, permissionName) => { + [RestrictedMethods.wallet_snap]: (t, _, permissionValue) => { + const snaps = permissionValue.caveats[0].value; const baseDescription = { leftIcon: 'fas fa-bolt', rightIcon: null, }; - - const snapId = permissionName.split('_').slice(-1); - const friendlyName = SNAPS_METADATA[snapId]?.name; - - if (friendlyName) { + return Object.keys(snaps).map((snapId) => { + const friendlyName = SNAPS_METADATA[snapId]?.name; + if (friendlyName) { + return { + ...baseDescription, + label: t('permission_accessNamedSnap', [ + + {friendlyName} + , + ]), + }; + } return { ...baseDescription, - label: t('permission_accessNamedSnap', [ - - {friendlyName} - , - ]), + label: t('permission_accessSnap', [snapId]), }; - } - - return { - ...baseDescription, - label: t('permission_accessSnap', [snapId]), - }; + }); }, [EndowmentPermissions['endowment:network-access']]: (t) => ({ label: t('permission_accessNetwork'), @@ -276,13 +274,6 @@ export const getPermissionDescription = ( if (Object.hasOwnProperty.call(PERMISSION_DESCRIPTIONS, permissionName)) { value = PERMISSION_DESCRIPTIONS[permissionName]; } - ///: BEGIN:ONLY_INCLUDE_IN(flask) - for (const namespace of Object.keys(PermissionNamespaces)) { - if (permissionName.startsWith(namespace)) { - value = PERMISSION_DESCRIPTIONS[PermissionNamespaces[namespace]]; - } - } - ///: END:ONLY_INCLUDE_IN const result = value(t, permissionName, permissionValue); if (!Array.isArray(result)) { diff --git a/ui/pages/settings/flask/view-snap/view-snap.js b/ui/pages/settings/flask/view-snap/view-snap.js index 5952c0e033ed..33e7f7001564 100644 --- a/ui/pages/settings/flask/view-snap/view-snap.js +++ b/ui/pages/settings/flask/view-snap/view-snap.js @@ -1,6 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; import { useDispatch, useSelector } from 'react-redux'; +import { + SnapCaveatType, + WALLET_SNAP_PERMISSION_KEY, +} from '@metamask/rpc-methods'; import Button from '../../../../components/ui/button'; import Typography from '../../../../components/ui/typography'; import { useI18nContext } from '../../../../hooks/useI18nContext'; @@ -23,11 +27,13 @@ import { enableSnap, removeSnap, removePermissionsFor, + updateCaveat, } from '../../../../store/actions'; import { getSnaps, - getSubjectsWithPermission, + getSubjectsWithSnapPermission, getPermissions, + getPermissionSubjects, } from '../../../../selectors'; import { formatDate } from '../../../../helpers/utils/util'; @@ -52,19 +58,14 @@ function ViewSnap() { }, [history, snap]); const connectedSubjects = useSelector((state) => - getSubjectsWithPermission(state, snap?.permissionName), + getSubjectsWithSnapPermission(state, snap?.id), ); const permissions = useSelector( (state) => snap && getPermissions(state, snap.id), ); + const subjects = useSelector((state) => getPermissionSubjects(state)); const dispatch = useDispatch(); - const onDisconnect = (connectedOrigin, snapPermissionName) => { - dispatch( - removePermissionsFor({ - [connectedOrigin]: [snapPermissionName], - }), - ); - }; + const onToggle = () => { if (snap.enabled) { dispatch(disableSnap(snap.id)); @@ -73,6 +74,30 @@ function ViewSnap() { } }; + const onDisconnect = (connectedOrigin, snapId) => { + const caveatValue = + subjects[connectedOrigin].permissions[WALLET_SNAP_PERMISSION_KEY] + .caveats[0].value; + const newCaveatValue = { ...caveatValue }; + delete newCaveatValue[snapId]; + if (Object.keys(newCaveatValue) > 0) { + dispatch( + updateCaveat( + connectedOrigin, + WALLET_SNAP_PERMISSION_KEY, + SnapCaveatType.SnapIds, + newCaveatValue, + ), + ); + } else { + dispatch( + removePermissionsFor({ + [connectedOrigin]: [WALLET_SNAP_PERMISSION_KEY], + }), + ); + } + }; + if (!snap) { return null; } @@ -171,7 +196,7 @@ function ViewSnap() { { - onDisconnect(origin, snap.permissionName); + onDisconnect(origin, snap.id); }} /> diff --git a/ui/selectors/permissions.js b/ui/selectors/permissions.js index 6459dc9c15f0..b9113a6e622e 100644 --- a/ui/selectors/permissions.js +++ b/ui/selectors/permissions.js @@ -1,3 +1,6 @@ +///: BEGIN:ONLY_INCLUDE_IN(flask) +import { WALLET_SNAP_PERMISSION_KEY } from '@metamask/rpc-methods'; +///: END:ONLY_INCLUDE_IN import { CaveatTypes } from '../../shared/constants/permissions'; import { getMetaMaskAccountsOrdered, @@ -118,6 +121,28 @@ export function getSubjectsWithPermission(state, permissionName) { return connectedSubjects; } +///: BEGIN:ONLY_INCLUDE_IN(flask) +export function getSubjectsWithSnapPermission(state, snapId) { + const subjects = getPermissionSubjects(state); + + return Object.entries(subjects) + .filter( + ([_origin, { permissions }]) => + permissions[WALLET_SNAP_PERMISSION_KEY]?.caveats[0].value[snapId], + ) + .map(([origin, _subject]) => { + const { extensionId, name, iconUrl } = + getTargetSubjectMetadata(state, origin) || {}; + return { + extensionId, + origin, + name, + iconUrl, + }; + }); +} +///: END:ONLY_INCLUDE_IN + /** * Returns an object mapping addresses to objects mapping origins to connected * subject info. Subject info objects have the following properties: diff --git a/ui/store/actions.ts b/ui/store/actions.ts index 6632a658e116..35296107edd5 100644 --- a/ui/store/actions.ts +++ b/ui/store/actions.ts @@ -3692,6 +3692,35 @@ export function removePermissionsFor( }; } +///: BEGIN:ONLY_INCLUDE_IN(flask) +/** + * Updates the caveat value for the specified origin, permission and caveat type. + * + * @param origin + * @param target + * @param caveatType + * @param caveatValue + */ +export function updateCaveat( + origin: string, + target: string, + caveatType: string, + caveatValue: Record, +): ThunkAction { + return (dispatch) => { + callBackgroundMethod( + 'updateCaveat', + [origin, target, caveatType, caveatValue], + (err) => { + if (err) { + dispatch(displayWarning(err)); + } + }, + ); + }; +} +///: END:ONLY_INCLUDE_IN + // Pending Approvals /** diff --git a/yarn.lock b/yarn.lock index 5fd55e85ac65..fac25ff91f45 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3539,16 +3539,29 @@ __metadata: languageName: node linkType: hard -"@metamask/approval-controller@npm:^1.0.0, @metamask/approval-controller@npm:^1.0.1": - version: 1.0.1 - resolution: "@metamask/approval-controller@npm:1.0.1" +"@metamask/approval-controller@npm:^1.0.0, @metamask/approval-controller@npm:^1.0.1, @metamask/approval-controller@npm:^1.1.0": + version: 1.1.0 + resolution: "@metamask/approval-controller@npm:1.1.0" dependencies: - "@metamask/base-controller": ^1.1.1 - "@metamask/controller-utils": ^1.0.0 + "@metamask/base-controller": ^1.1.2 + "@metamask/controller-utils": ^2.0.0 + eth-rpc-errors: ^4.0.0 + immer: ^9.0.6 + nanoid: ^3.1.31 + checksum: 96a354ccd4765eb997f35ccbc86114c40e6da839e83b89bf64eedc986d74f28898c204eae5037978497f823fabc2a675c9c19c1ccae6535f70eb7ab0a72cbfc4 + languageName: node + linkType: hard + +"@metamask/approval-controller@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/approval-controller@npm:2.0.0" + dependencies: + "@metamask/base-controller": ^2.0.0 + "@metamask/controller-utils": ^3.0.0 eth-rpc-errors: ^4.0.0 immer: ^9.0.6 nanoid: ^3.1.31 - checksum: 83b54946b948b0f97a5453328421666c8852b975bf045f6b23416579f1201feb390dc09941620fa4e480f76cd9a7b4f6e8f2c3e940ddd79f62491a81befe8c7c + checksum: 1db5f9c21b04fa4688c17cdfb7da0a14b3fee084fbd8c0cfdcc41572e54140ce093c24b811b85e8ee9d3ccd8987db04d9150d7c6d5ab21daf72b4364a05f3428 languageName: node linkType: hard @@ -3608,6 +3621,16 @@ __metadata: languageName: node linkType: hard +"@metamask/base-controller@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/base-controller@npm:2.0.0" + dependencies: + "@metamask/controller-utils": ^3.0.0 + immer: ^9.0.6 + checksum: afd7df59cbcd26261e3d015ac0669261efbfad8e106b55ae7184f7445979b867f78f0d56fe103566150236093847b3acc68473f979e46bd9c67f654857995458 + languageName: node + linkType: hard + "@metamask/base-controller@npm:~1.0.0": version: 1.0.0 resolution: "@metamask/base-controller@npm:1.0.0" @@ -3660,6 +3683,19 @@ __metadata: languageName: node linkType: hard +"@metamask/controller-utils@npm:^3.0.0": + version: 3.0.0 + resolution: "@metamask/controller-utils@npm:3.0.0" + dependencies: + eth-ens-namehash: ^2.0.8 + eth-rpc-errors: ^4.0.0 + ethereumjs-util: ^7.0.10 + ethjs-unit: ^0.1.6 + fast-deep-equal: ^3.1.3 + checksum: 44227aa9f716f86373a1a4fb86b7ae1c51199dd819f30a3a310a9f87838b7e11c1a3bb024572253bd3cb0258281596cfab8fbf317c3fe90962fa6cf426aa6858 + languageName: node + linkType: hard + "@metamask/design-tokens@npm:^1.6.0, @metamask/design-tokens@npm:^1.9.0": version: 1.11.1 resolution: "@metamask/design-tokens@npm:1.11.1" @@ -3910,7 +3946,7 @@ __metadata: languageName: node linkType: hard -"@metamask/key-tree@npm:^6.2.0, @metamask/key-tree@npm:^6.2.1": +"@metamask/key-tree@npm:^6.2.1": version: 6.2.1 resolution: "@metamask/key-tree@npm:6.2.1" dependencies: @@ -4033,7 +4069,7 @@ __metadata: languageName: node linkType: hard -"@metamask/permission-controller@npm:^1.0.0, @metamask/permission-controller@npm:^1.0.1": +"@metamask/permission-controller@npm:^1.0.1": version: 1.0.2 resolution: "@metamask/permission-controller@npm:1.0.2" dependencies: @@ -4053,6 +4089,46 @@ __metadata: languageName: node linkType: hard +"@metamask/permission-controller@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/permission-controller@npm:2.0.0" + dependencies: + "@metamask/approval-controller": ^1.1.0 + "@metamask/base-controller": ^1.1.2 + "@metamask/controller-utils": ^2.0.0 + "@metamask/types": ^1.1.0 + "@types/deep-freeze-strict": ^1.1.0 + deep-freeze-strict: ^1.1.1 + eth-rpc-errors: ^4.0.0 + immer: ^9.0.6 + json-rpc-engine: ^6.1.0 + nanoid: ^3.1.31 + peerDependencies: + "@metamask/approval-controller": ^1.1.0 + checksum: 152be8429ceebf7dfbd415ff12746ee9c0216fa4dfb90f825532fd216f6b2aa66061748fb0685ec23ad6bde21212c6ccd32a4219b803913d45b70f8ded45ac2e + languageName: node + linkType: hard + +"@metamask/permission-controller@npm:^3.0.0": + version: 3.0.0 + resolution: "@metamask/permission-controller@npm:3.0.0" + dependencies: + "@metamask/approval-controller": ^2.0.0 + "@metamask/base-controller": ^2.0.0 + "@metamask/controller-utils": ^3.0.0 + "@metamask/types": ^1.1.0 + "@types/deep-freeze-strict": ^1.1.0 + deep-freeze-strict: ^1.1.1 + eth-rpc-errors: ^4.0.0 + immer: ^9.0.6 + json-rpc-engine: ^6.1.0 + nanoid: ^3.1.31 + peerDependencies: + "@metamask/approval-controller": ^2.0.0 + checksum: 67e104d21b3f0258863ecaabd11cb587f10dbcc91ff9b081d8b9569d163d6d54dd5b8fb267d5416ab8e41c8c48b5103e92e013fd1916d492b72706cda2474962 + languageName: node + linkType: hard + "@metamask/phishing-controller@npm:^2.0.0": version: 2.0.0 resolution: "@metamask/phishing-controller@npm:2.0.0" @@ -4135,22 +4211,22 @@ __metadata: languageName: node linkType: hard -"@metamask/rpc-methods@npm:^0.28.0": - version: 0.28.0 - resolution: "@metamask/rpc-methods@npm:0.28.0" +"@metamask/rpc-methods@npm:^0.30.0": + version: 0.30.0 + resolution: "@metamask/rpc-methods@npm:0.30.0" dependencies: "@metamask/browser-passworder": ^4.0.2 - "@metamask/key-tree": ^6.2.0 - "@metamask/permission-controller": ^1.0.1 - "@metamask/snaps-ui": ^0.28.0 - "@metamask/snaps-utils": ^0.28.0 + "@metamask/key-tree": ^6.2.1 + "@metamask/permission-controller": ^3.0.0 + "@metamask/snaps-ui": ^0.30.0 + "@metamask/snaps-utils": ^0.30.0 "@metamask/types": ^1.1.0 "@metamask/utils": ^3.4.1 "@noble/hashes": ^1.1.3 eth-rpc-errors: ^4.0.2 nanoid: ^3.1.31 superstruct: ^1.0.3 - checksum: 4dcdd25a8462a3ba38898637d2f64250c7d173c601f22133332c41401c13cb465ead719f3233f9749a894857f2ffc329936d3b84221ff60355473b3e9c212598 + checksum: ae584a2ea403653199c17e4fe43bdf26d25f2dbab8609e48f85d6a1def762526370e145cf69dc5649ee501f6e170ea27161b3d908c62ff1e9617af5e23564793 languageName: node linkType: hard @@ -4197,20 +4273,20 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-controllers@npm:^0.28.0": - version: 0.28.0 - resolution: "@metamask/snaps-controllers@npm:0.28.0" +"@metamask/snaps-controllers@npm:^0.30.0": + version: 0.30.0 + resolution: "@metamask/snaps-controllers@npm:0.30.0" dependencies: - "@metamask/approval-controller": ^1.0.1 - "@metamask/base-controller": ^1.1.1 + "@metamask/approval-controller": ^2.0.0 + "@metamask/base-controller": ^2.0.0 "@metamask/object-multiplex": ^1.1.0 - "@metamask/permission-controller": ^1.0.1 + "@metamask/permission-controller": ^3.0.0 "@metamask/post-message-stream": ^6.1.0 - "@metamask/rpc-methods": ^0.28.0 - "@metamask/snaps-execution-environments": ^0.28.0 - "@metamask/snaps-registry": ^1.0.0 - "@metamask/snaps-utils": ^0.28.0 - "@metamask/subject-metadata-controller": ^1.0.1 + "@metamask/rpc-methods": ^0.30.0 + "@metamask/snaps-execution-environments": ^0.30.0 + "@metamask/snaps-registry": ^1.1.0 + "@metamask/snaps-utils": ^0.30.0 + "@metamask/subject-metadata-controller": ^2.0.0 "@metamask/utils": ^3.4.1 "@xstate/fsm": ^2.0.0 concat-stream: ^2.0.0 @@ -4224,18 +4300,19 @@ __metadata: pump: ^3.0.0 readable-web-to-node-stream: ^3.0.2 tar-stream: ^2.2.0 - checksum: 27b641ed7998e1cc52be354aab19ce6034aa2ec1df3f5f14e07d144ce029472f8f89b8896c32a3124489283ed26666f84b67412cdd213445e80975e2a324f3a2 + checksum: 022f875037fd058c237b8cba80e47a5ef222d379a073af4a35242e15c8c83ac902050ab8ae51a80536254b4ccb7e73b854c49b3ff5fac51154071da46d879e20 languageName: node linkType: hard -"@metamask/snaps-execution-environments@npm:^0.28.0": - version: 0.28.0 - resolution: "@metamask/snaps-execution-environments@npm:0.28.0" +"@metamask/snaps-execution-environments@npm:^0.30.0": + version: 0.30.0 + resolution: "@metamask/snaps-execution-environments@npm:0.30.0" dependencies: "@metamask/object-multiplex": ^1.2.0 "@metamask/post-message-stream": ^6.1.0 "@metamask/providers": ^10.2.0 - "@metamask/snaps-utils": ^0.28.0 + "@metamask/rpc-methods": ^0.30.0 + "@metamask/snaps-utils": ^0.30.0 "@metamask/utils": ^3.4.1 eth-rpc-errors: ^4.0.3 json-rpc-engine: ^6.1.0 @@ -4243,55 +4320,57 @@ __metadata: ses: ^0.18.1 stream-browserify: ^3.0.0 superstruct: ^1.0.3 - checksum: db4d26728141d236d64720120fe57540ab13399c10fa7fdc697f888bf0f780f33f6c462409657b3a531a91cc0545fbf759b66d4fd1242955d75ddb331bcabad4 + checksum: ee81caec7bf77703510983f62f3f2cf94753b624ba14691ff80ca30efab9a07ca329b278cd08323c72bcb3aeef7e78d089af4d35d14a469afc4f7bb8bc7e5fa7 languageName: node linkType: hard -"@metamask/snaps-registry@npm:^1.0.0": - version: 1.0.0 - resolution: "@metamask/snaps-registry@npm:1.0.0" +"@metamask/snaps-registry@npm:^1.0.0, @metamask/snaps-registry@npm:^1.1.0": + version: 1.1.0 + resolution: "@metamask/snaps-registry@npm:1.1.0" dependencies: "@metamask/utils": ^3.4.0 superstruct: ^1.0.3 - checksum: 6a127d4d2db30e6f3966f4f82f3810a22a79db62c84b5db2b95d189dd36fe59aa5de59f01203095c9f7f07a44c1bf049c0fc046931269327d0693d1274f8f154 + checksum: a67a9e7a30a2f7bc55d130b278573aa2bf043ab5c5935704ab8166898dadf37557284412f9b653f9ed52059a557a51b8472aabbe6887a06922d5526ead12199b languageName: node linkType: hard -"@metamask/snaps-ui@npm:^0.28.0": - version: 0.28.0 - resolution: "@metamask/snaps-ui@npm:0.28.0" +"@metamask/snaps-ui@npm:^0.30.0": + version: 0.30.0 + resolution: "@metamask/snaps-ui@npm:0.30.0" dependencies: "@metamask/utils": ^3.4.1 superstruct: ^1.0.3 - checksum: 19d28b279f1516ca90cc6d2ec45507b13186ab2cbfa554f72ae8e4c9e1437b773ac67fe38350bee78f47dd063b1cc3f04274e388d00b09e5e6c5938b273d6616 + checksum: a4612e08e830542b094bf995023221a24dfa45861d3ca919c1c11ae1bd3d6933789d40c667780145bcd3ff3053d0593e654ae1812ea9f3c7cc973d500cfb0a96 languageName: node linkType: hard -"@metamask/snaps-utils@npm:^0.28.0": - version: 0.28.0 - resolution: "@metamask/snaps-utils@npm:0.28.0" +"@metamask/snaps-utils@npm:^0.30.0": + version: 0.30.0 + resolution: "@metamask/snaps-utils@npm:0.30.0" dependencies: "@babel/core": ^7.18.6 "@babel/types": ^7.18.7 + "@metamask/permission-controller": ^3.0.0 "@metamask/providers": ^10.2.1 "@metamask/snaps-registry": ^1.0.0 - "@metamask/snaps-ui": ^0.28.0 + "@metamask/snaps-ui": ^0.30.0 "@metamask/utils": ^3.4.1 "@noble/hashes": ^1.1.3 "@scure/base": ^1.1.1 cron-parser: ^4.5.0 eth-rpc-errors: ^4.0.3 fast-deep-equal: ^3.1.3 + fast-json-stable-stringify: ^2.1.0 rfdc: ^1.3.0 semver: ^7.3.7 ses: ^0.18.1 superstruct: ^1.0.3 validate-npm-package-name: ^5.0.0 - checksum: 6c9653a9df3c77f5f2c69231d7e148d70fa001e42522e2e8f470f0e6fa1417b178d1b86515a231488a509589f98944cdf82a5ddc5e228f752d9ef81def393bb3 + checksum: 56334795dee7deeddd63badd35870ebb51ba5336071146bd6f48a9f7c1d703515241ac9371d7a4e054d77d7c6d06f34530e7b9439074339a46fea89920d32bce languageName: node linkType: hard -"@metamask/subject-metadata-controller@npm:^1.0.0, @metamask/subject-metadata-controller@npm:^1.0.1": +"@metamask/subject-metadata-controller@npm:^1.0.0": version: 1.0.1 resolution: "@metamask/subject-metadata-controller@npm:1.0.1" dependencies: @@ -4303,6 +4382,18 @@ __metadata: languageName: node linkType: hard +"@metamask/subject-metadata-controller@npm:^2.0.0": + version: 2.0.0 + resolution: "@metamask/subject-metadata-controller@npm:2.0.0" + dependencies: + "@metamask/base-controller": ^2.0.0 + "@metamask/permission-controller": ^3.0.0 + "@metamask/types": ^1.1.0 + immer: ^9.0.6 + checksum: 2997a7b6e2ae17e80c2f2a42fbcf7b6fdbcbebc782c9eedec98a4f38c1089192fde9a83c2021f7d602e1e67e2cc9af2fbc345bb3775a27970c92533fadfe8f96 + languageName: node + linkType: hard + "@metamask/test-dapp@npm:^5.6.0": version: 5.6.0 resolution: "@metamask/test-dapp@npm:5.6.0" @@ -24070,19 +24161,19 @@ __metadata: "@metamask/metamask-eth-abis": ^3.0.0 "@metamask/notification-controller": ^1.0.0 "@metamask/obs-store": ^5.0.0 - "@metamask/permission-controller": ^1.0.0 + "@metamask/permission-controller": ^2.0.0 "@metamask/phishing-controller": ^2.0.0 "@metamask/phishing-warning": ^2.0.1 "@metamask/post-message-stream": ^6.0.0 "@metamask/providers": ^10.2.1 "@metamask/rate-limit-controller": ^1.0.0 - "@metamask/rpc-methods": ^0.28.0 + "@metamask/rpc-methods": ^0.30.0 "@metamask/scure-bip39": ^2.0.3 "@metamask/slip44": ^2.1.0 "@metamask/smart-transactions-controller": ^3.1.0 - "@metamask/snaps-controllers": ^0.28.0 - "@metamask/snaps-ui": ^0.28.0 - "@metamask/snaps-utils": ^0.28.0 + "@metamask/snaps-controllers": ^0.30.0 + "@metamask/snaps-ui": ^0.30.0 + "@metamask/snaps-utils": ^0.30.0 "@metamask/subject-metadata-controller": ^1.0.0 "@metamask/test-dapp": ^5.6.0 "@metamask/utils": ^3.6.0