diff --git a/.depcheckrc.yml b/.depcheckrc.yml index 8883375e7..aa1bffde4 100644 --- a/.depcheckrc.yml +++ b/.depcheckrc.yml @@ -4,6 +4,7 @@ ignores: # webapp deps # + - '@lavamoat/snow' - '@babel/runtime' - '@fortawesome/fontawesome-free' - 'punycode' diff --git a/app/background.html b/app/background.html index 6a0150579..eabb3bf3a 100644 --- a/app/background.html +++ b/app/background.html @@ -4,6 +4,8 @@ + + {{@if(it.applyLavaMoat)}} diff --git a/app/home.html b/app/home.html index 4a4df3f4e..e4838a50e 100644 --- a/app/home.html +++ b/app/home.html @@ -13,6 +13,8 @@
+ + {{@if(it.applyLavaMoat)}} diff --git a/app/notification.html b/app/notification.html index 1f348f680..209a642a3 100644 --- a/app/notification.html +++ b/app/notification.html @@ -33,6 +33,8 @@
+ + {{@if(it.applyLavaMoat)}} diff --git a/app/popup.html b/app/popup.html index 831fe6122..978c237db 100644 --- a/app/popup.html +++ b/app/popup.html @@ -13,6 +13,8 @@
+ + {{@if(it.applyLavaMoat)}} diff --git a/app/scripts/use-snow.js b/app/scripts/use-snow.js new file mode 100644 index 000000000..11b01d78d --- /dev/null +++ b/app/scripts/use-snow.js @@ -0,0 +1,8 @@ +// eslint-disable-next-line import/unambiguous +(function () { + const log = console.log.bind(console); + const msg = 'SNOW INTERCEPTED NEW WINDOW CREATION IN METAMASK APP: '; + window.top.SNOW((win) => { + log(msg, win, win?.frameElement); + }); +})(); diff --git a/development/build/index.js b/development/build/index.js index a1a6874e6..eb93a6bde 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -66,6 +66,7 @@ async function defineAndRunBuildTasks() { isLavaMoat, policyOnly, shouldIncludeLockdown, + shouldIncludeSnow, shouldLintFenceFiles, skipStats, version, @@ -81,6 +82,7 @@ async function defineAndRunBuildTasks() { livereload, browserPlatforms, shouldIncludeLockdown, + shouldIncludeSnow, buildType, }); @@ -230,6 +232,12 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, 'Whether to include SES lockdown files in the extension bundle. Setting this to `false` can be useful during development if you want to handle lockdown errors later.', type: 'boolean', }) + .option('snow', { + default: true, + description: + 'Whether to include Snow files in the extension bundle. Setting this to `false` can be useful during development if you want to handle Snow errors later.', + type: 'boolean', + }) .option('policy-only', { default: false, description: @@ -263,6 +271,7 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, buildVersion, lintFenceFiles, lockdown, + snow, policyOnly, skipStats, task, @@ -292,6 +301,7 @@ testDev: Create an unoptimized, live-reloading build for debugging e2e tests.`, isLavaMoat: process.argv[0].includes('lavamoat'), policyOnly, shouldIncludeLockdown: lockdown, + shouldIncludeSnow: snow, shouldLintFenceFiles, skipStats, version, diff --git a/development/build/static.js b/development/build/static.js index 7e3ccf02f..af1b55c93 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -15,11 +15,21 @@ module.exports = function createStaticAssetTasks({ livereload, browserPlatforms, shouldIncludeLockdown = true, + shouldIncludeSnow = true, buildType, }) { - const [copyTargetsProd, copyTargetsDev] = getCopyTargets( - shouldIncludeLockdown, - ); + const copyTargetsProds = {}; + const copyTargetsDevs = {}; + + browserPlatforms.forEach((browser) => { + const [copyTargetsProd, copyTargetsDev] = getCopyTargets( + shouldIncludeLockdown, + // Snow currently only works on Chromium based browsers + shouldIncludeSnow && browser === 'chrome', + ); + copyTargetsProds[browser] = copyTargetsProd; + copyTargetsDevs[browser] = copyTargetsDev; + }); const additionalBuildTargets = { [BuildType.beta]: [ @@ -37,60 +47,60 @@ module.exports = function createStaticAssetTasks({ }; if (Object.keys(additionalBuildTargets).includes(buildType)) { - copyTargetsProd.push(...additionalBuildTargets[buildType]); - copyTargetsDev.push(...additionalBuildTargets[buildType]); + Object.entries(copyTargetsProds).forEach(([_, copyTargetsProd]) => + copyTargetsProd.push(...additionalBuildTargets[buildType]), + ); + Object.entries(copyTargetsDevs).forEach(([_, copyTargetsDev]) => + copyTargetsDev.push(...additionalBuildTargets[buildType]), + ); } - const prod = createTask( - TASKS.STATIC_PROD, - composeSeries( - ...copyTargetsProd.map((target) => { - return async function copyStaticAssets() { - await performCopy(target); - }; - }), - ), - ); - const dev = createTask( - TASKS.STATIC_DEV, - composeSeries( - ...copyTargetsDev.map((target) => { - return async function copyStaticAssets() { - await setupLiveCopy(target); - }; - }), - ), - ); + const prodTasks = []; + Object.entries(copyTargetsProds).forEach(([browser, copyTargetsProd]) => { + copyTargetsProd.forEach((target) => { + prodTasks.push(async function copyStaticAssets() { + await performCopy(target, browser); + }); + }); + }); + + const devTasks = []; + Object.entries(copyTargetsDevs).forEach(([browser, copyTargetsDev]) => { + copyTargetsDev.forEach((target) => { + devTasks.push(async function copyStaticAssets() { + await setupLiveCopy(target, browser); + }); + }); + }); + + const prod = createTask(TASKS.STATIC_PROD, composeSeries(...prodTasks)); + const dev = createTask(TASKS.STATIC_DEV, composeSeries(...devTasks)); return { dev, prod }; - async function setupLiveCopy(target) { + async function setupLiveCopy(target, browser) { const pattern = target.pattern || '/**/*'; watch(target.src + pattern, (event) => { livereload.changed(event.path); - performCopy(target); + performCopy(target, browser); }); - await performCopy(target); + await performCopy(target, browser); } - async function performCopy(target) { - await Promise.all( - browserPlatforms.map(async (platform) => { - if (target.pattern) { - await copyGlob( - target.src, - `${target.src}${target.pattern}`, - `./dist/${platform}/${target.dest}`, - ); - } else { - await copyGlob( - target.src, - `${target.src}`, - `./dist/${platform}/${target.dest}`, - ); - } - }), - ); + async function performCopy(target, browser) { + if (target.pattern) { + await copyGlob( + target.src, + `${target.src}${target.pattern}`, + `./dist/${browser}/${target.dest}`, + ); + } else { + await copyGlob( + target.src, + `${target.src}`, + `./dist/${browser}/${target.dest}`, + ); + } } async function copyGlob(baseDir, srcGlob, dest) { @@ -104,7 +114,7 @@ module.exports = function createStaticAssetTasks({ } }; -function getCopyTargets(shouldIncludeLockdown) { +function getCopyTargets(shouldIncludeLockdown, shouldIncludeSnow) { const allCopyTargets = [ { src: `./app/_locales/`, @@ -147,6 +157,16 @@ function getCopyTargets(shouldIncludeLockdown) { src: `./node_modules/globalthis/dist/browser.js`, dest: `globalthis.js`, }, + { + src: shouldIncludeSnow + ? `./node_modules/@lavamoat/snow/snow.prod.js` + : EMPTY_JS_FILE, + dest: `snow.js`, + }, + { + src: shouldIncludeSnow ? `./app/scripts/use-snow.js` : EMPTY_JS_FILE, + dest: `use-snow.js`, + }, { src: shouldIncludeLockdown ? `./node_modules/ses/dist/lockdown.umd.min.js` diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 5431b757e..abef5b6fe 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -4947,6 +4947,7 @@ "Node": true }, "packages": { + "@lavamoat/snow>is-cross-origin>is-window": true, "proxyquire>fill-keys>is-object": true, "react-inspector>is-dom>is-window": true } @@ -5346,4 +5347,4 @@ } } } -} \ No newline at end of file +} diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index e1d44f145..24bcf3f63 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -5782,6 +5782,7 @@ "Node": true }, "packages": { + "@lavamoat/snow>is-cross-origin>is-window": true, "proxyquire>fill-keys>is-object": true, "react-inspector>is-dom>is-window": true } @@ -6238,4 +6239,4 @@ } } } -} \ No newline at end of file +} diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 5431b757e..abef5b6fe 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -4947,6 +4947,7 @@ "Node": true }, "packages": { + "@lavamoat/snow>is-cross-origin>is-window": true, "proxyquire>fill-keys>is-object": true, "react-inspector>is-dom>is-window": true } @@ -5346,4 +5347,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index a6037616e..120643bdf 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "setup": "yarn install && yarn setup:postinstall", "setup:postinstall": "yarn patch-package && yarn allow-scripts", - "start": "yarn build:dev dev --apply-lavamoat=false", + "start": "yarn build:dev dev --apply-lavamoat=false --snow=false", "start:lavamoat": "yarn build:dev dev --apply-lavamoat=true", "start:mv3": "ENABLE_MV3=true yarn build:dev dev --apply-lavamoat=false", "dist": "yarn build dist", @@ -138,6 +138,7 @@ "@spruceid/siwe-parser": "^1.1.3", "@truffle/codec": "^0.11.18", "@truffle/decoder": "^5.1.0", + "@lavamoat/snow": "^1.2.1", "@zxing/browser": "^0.0.10", "@zxing/library": "0.8.0", "await-semaphore": "^0.1.1", diff --git a/yarn.lock b/yarn.lock index 29dde740a..756972d7c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2559,6 +2559,13 @@ through2 "^4.0.2" umd "^3.0.3" +"@lavamoat/snow@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@lavamoat/snow/-/snow-1.2.1.tgz#87587e46940b26a966b665e62cd867d0cfbce47e" + integrity sha512-gC4oyvjNkFOOjhL9W4wP1YC0dcdQJPYKNW8fbwcP5iYogLL2fs1KIsHoF41WIhuWQ9mUdfg1jKBCTq41m+5VSw== + dependencies: + is-cross-origin "^1.0.1" + "@ledgerhq/cryptoassets@^5.27.2": version "5.53.0" resolved "https://registry.yarnpkg.com/@ledgerhq/cryptoassets/-/cryptoassets-5.53.0.tgz#11dcc93211960c6fd6620392e4dd91896aaabe58" @@ -14476,6 +14483,13 @@ is-core-module@^2.4.0, is-core-module@^2.8.1, is-core-module@^2.9.0: dependencies: has "^1.0.3" +is-cross-origin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-cross-origin/-/is-cross-origin-1.0.1.tgz#b73ee0bbcf9f640a4c4f17bcf3cc229e3dae11e8" + integrity sha512-l0VqOliZJ0tJTFkNGa1kJilL9q+wCKw2wLX6qoXVtWUFKiqXvLaf4kAu4+9xAg6QJGKc41CDaFYSxmO9Iw1vuw== + dependencies: + is-window "^1.0.2" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"