1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 01:47:00 +01:00

Add lockdown e2e test (#12562)

This PR adds an e2e test to ensure that the background and UI environments are locked down. It reuses the logic from the `protect-intrinsics.test.js`, and runs in both Chrome and Firefox.
This commit is contained in:
Erik Marks 2021-11-02 17:01:01 -07:00 committed by GitHub
parent 1298a8cdc6
commit 5f0fd9d1c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 184 additions and 64 deletions

View File

@ -191,9 +191,10 @@ module.exports = {
'app/scripts/lockdown-more.js',
'development/**/*.js',
'test/e2e/**/*.js',
'test/lib/wait-until-called.js',
'test/env.js',
'test/setup.js',
'test/helpers/protect-intrinsics-helpers.js',
'test/lib/wait-until-called.js',
'jest.config.js',
],
parserOptions: {
@ -204,6 +205,7 @@ module.exports = {
files: [
'app/scripts/lockdown-run.js',
'app/scripts/lockdown-more.js',
'test/helpers/protect-intrinsics-helpers.js',
'test/unit-global/protect-intrinsics.test.js',
],
globals: {

View File

@ -0,0 +1,89 @@
const { strict: assert } = require('assert');
const { Browser } = require('selenium-webdriver');
const {
getGlobalProperties,
testIntrinsic,
} = require('../../helpers/protect-intrinsics-helpers');
const { withFixtures } = require('../helpers');
const { PAGES } = require('../webdriver/driver');
const isFirefox = process.env.SELENIUM_BROWSER === Browser.FIREFOX;
/**
* This script iterates over all named intrinsics and tests that they are locked
* down per ses/lockdown.
*
* We set globalThis to window in Firefox because the test fails otherwise.
* We believe this is due to some Selenium-related shenanigans. In the browser,
* this behavior is not a problem.
*/
const lockdownTestScript = `
${isFirefox ? 'globalThis = window;' : ''}
const assert = {
equal: (value, comparison, message) => {
if (value !== comparison) {
throw new Error(message || 'not equal');
}
},
ok: (value, message) => {
if (!value) {
throw new Error(message || 'not ok');
}
},
};
${getGlobalProperties.toString()}
${testIntrinsic.toString()}
try {
getGlobalProperties().forEach((propertyName) => {
console.log('Testing intrinsic:', propertyName);
testIntrinsic(propertyName);
})
console.log('Lockdown test successful!');
return true;
} catch (error) {
console.log('Lockdown test failed.', error);
return false;
}
`;
describe('lockdown', function () {
const ganacheOptions = {
accounts: [
{
secretKey:
'0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC',
balance: 25000000000000000000,
},
],
};
it('the UI and background environments are locked down', async function () {
await withFixtures(
{
// The fixtures used here is arbitrary. Any fixture would do.
fixtures: 'imported-account',
ganacheOptions,
title: this.test.title,
},
async ({ driver }) => {
await driver.navigate(PAGES.HOME);
assert.equal(
await driver.executeScript(lockdownTestScript),
true,
'The UI environment should be locked down.',
);
await driver.navigate(PAGES.BACKGROUND);
assert.equal(
await driver.executeScript(lockdownTestScript),
true,
'The background environment should be locked down.',
);
},
);
});
});

View File

@ -49,6 +49,10 @@ class Driver {
};
}
async executeScript(script, ...args) {
return this.driver.executeScript(script, args);
}
buildLocator(locator) {
if (typeof locator === 'string') {
// If locator is a string we assume its a css selector
@ -388,6 +392,7 @@ function collectMetrics() {
}
Driver.PAGES = {
BACKGROUND: 'background',
HOME: 'home',
NOTIFICATION: 'notification',
POPUP: 'popup',

View File

@ -0,0 +1,81 @@
const { strict: assert } = require('assert');
module.exports = {
getGlobalProperties,
testIntrinsic,
};
/**
* Gets the global intrinsic property names in a locked down environemnt.
*
* @returns {Set<string>} All global intrinsic property names.
*/
function getGlobalProperties() {
// These are Agoric inventions, and we don't care about them.
const ignoreList = new Set([
'Compartment',
'HandledPromise',
'StaticModuleRecord',
]);
const namedIntrinsics = Reflect.ownKeys(new Compartment().globalThis);
return new Set(
[
// Added to global scope by ses/dist/lockdown.cjs.
...namedIntrinsics,
// TODO: Also include the named platform globals
// This grabs every enumerable property on globalThis.
// ...Object.keys(globalThis),
].filter((propertyName) => !ignoreList.has(propertyName)),
);
}
/**
* Performs a number of assertions on the specified intrinsic property to
* ensure that the environment is locked down properly.
* Throws if any assertion fails.
*
* @param {string} propertyName - The name of the intrinsic property to test.
*/
function testIntrinsic(propertyName) {
const descriptor = Reflect.getOwnPropertyDescriptor(globalThis, propertyName);
assert.ok(
descriptor,
`globalThis["${propertyName}"] should have a descriptor`,
);
// As long as Object.isFrozen is the true Object.isFrozen, the object
// it is called with cannot lie about being frozen.
const value = globalThis[propertyName];
if (value !== globalThis) {
assert.equal(
Object.isFrozen(value),
true,
`value of universal property globalThis["${propertyName}"] should be frozen`,
);
}
// The writability of properties with accessors cannot be modified.
if ('set' in descriptor || 'get' in descriptor) {
assert.equal(
descriptor.configurable,
false,
`globalThis["${propertyName}"] should be non-configurable`,
);
} else {
assert.equal(
descriptor.configurable,
false,
`globalThis["${propertyName}"] should be non-configurable`,
);
assert.equal(
descriptor.writable,
false,
`globalThis["${propertyName}"] should be non-writable`,
);
}
}

View File

@ -1,72 +1,15 @@
import 'ses/lockdown';
import '../../app/scripts/lockdown-run';
import '../../app/scripts/lockdown-more';
import { strict as assert } from 'assert';
// These are Agoric inventions, and we don't care about them.
const ignoreList = new Set([
'Compartment',
'HandledPromise',
'StaticModuleRecord',
]);
import {
getGlobalProperties,
testIntrinsic,
} from '../helpers/protect-intrinsics-helpers';
describe('non-modifiable intrinsics', function () {
const namedIntrinsics = Reflect.ownKeys(new Compartment().globalThis);
const globalProperties = new Set(
[
// Added to global scope by ses/dist/lockdown.cjs.
...namedIntrinsics,
// TODO: Also include the named platform globals
// This grabs every enumerable property on globalThis.
// ...Object.keys(globalThis),
].filter((propertyName) => !ignoreList.has(propertyName)),
);
globalProperties.forEach((propertyName) => {
getGlobalProperties().forEach((propertyName) => {
it(`intrinsic globalThis["${propertyName}"]`, function () {
const descriptor = Reflect.getOwnPropertyDescriptor(
globalThis,
propertyName,
);
assert.ok(
descriptor,
`globalThis["${propertyName}"] should have a descriptor`,
);
// As long as Object.isFrozen is the true Object.isFrozen, the object
// it is called with cannot lie about being frozen.
const value = globalThis[propertyName];
if (value !== globalThis) {
assert.equal(
Object.isFrozen(value),
true,
`value of universal property globalThis["${propertyName}"] should be frozen`,
);
}
// The writability of properties with accessors cannot be modified.
if ('set' in descriptor || 'get' in descriptor) {
assert.equal(
descriptor.configurable,
false,
`globalThis["${propertyName}"] should be non-configurable`,
);
} else {
assert.equal(
descriptor.configurable,
false,
`globalThis["${propertyName}"] should be non-configurable`,
);
assert.equal(
descriptor.writable,
false,
`globalThis["${propertyName}"] should be non-writable`,
);
}
testIntrinsic(propertyName);
});
});
});