diff --git a/test/e2e/fixture-builder.js b/test/e2e/fixture-builder.js index 3e0c6921f..1313a21bc 100644 --- a/test/e2e/fixture-builder.js +++ b/test/e2e/fixture-builder.js @@ -234,6 +234,7 @@ function defaultFixture() { useTokenDetection: false, useCurrencyRateCheck: true, useMultiAccountBalanceChecker: true, + transactionSecurityCheckEnabled: true, openSeaTransactionSecurityProviderPopoverHasBeenShown: true, }, SmartTransactionsController: { @@ -347,6 +348,7 @@ function onboardingFixture() { useTokenDetection: false, useCurrencyRateCheck: true, useMultiAccountBalanceChecker: true, + transactionSecurityCheckEnabled: true, openSeaTransactionSecurityProviderPopoverHasBeenShown: true, }, SmartTransactionsController: { diff --git a/test/e2e/tests/security-provider.spec.js b/test/e2e/tests/security-provider.spec.js new file mode 100644 index 000000000..24dc00e54 --- /dev/null +++ b/test/e2e/tests/security-provider.spec.js @@ -0,0 +1,234 @@ +const { strict: assert } = require('assert'); +const { convertToHexValue, withFixtures } = require('../helpers'); +const FixtureBuilder = require('../fixture-builder'); + +const OPENSEA_URL = + 'https://eos9d7dmfj.execute-api.us-east-1.amazonaws.com/metamask/validate'; +/** + * @param {import('mockttp').Mockttp} mockServer - The mock server. + */ + +describe('Transaction security provider', function () { + let windowHandles; + + async function mockSecurityProviderDetection(mockServer, scenario) { + switch (scenario) { + case 'notMalicious': + await mockServer.forPost(OPENSEA_URL).thenCallback(() => { + return { + statusCode: 200, + json: { + flagAsDangerous: 0, + }, + }; + }); + break; + case 'malicious': + await mockServer.forPost(OPENSEA_URL).thenCallback(() => { + return { + statusCode: 200, + json: { + flagAsDangerous: 1, + reason: + 'If you sign this request, you may lose all of your assets for good', + reason_header: 'This could be a scam', + }, + }; + }); + break; + case 'notSafe': + await mockServer.forPost(OPENSEA_URL).thenCallback(() => { + return { + statusCode: 200, + json: { + flagAsDangerous: 2, + reason: + 'The security provider didn’t detect any known malicious activity, but it still may not be safe to continue.', + reason_header: 'Request may not be safe', + }, + }; + }); + break; + case 'requestNotVerified': + await mockServer.forPost(OPENSEA_URL).thenCallback(() => { + return { + statusCode: 500, + json: {}, + }; + }); + break; + default: + throw new Error(`Unknown scenario: ${scenario}`); + } + } + + const ganacheOptions = { + accounts: [ + { + secretKey: + '0x7C9529A67102755B7E6102D6D950AC5D5863C98713805CEC576B945B15B71EAC', + balance: convertToHexValue(25000000000000000000), + }, + ], + }; + + it('Should return malicious response', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesController({ + transactionSecurityCheckEnabled: true, + }) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => + await mockSecurityProviderDetection(mockServer, 'malicious'), + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage('http://127.0.0.1:8080/'); + windowHandles = await driver.getAllWindowHandles(); + + await driver.clickElement('#personalSign'); + + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + const warningHeader = await driver.isElementPresent({ + text: 'This could be a scam', + tag: 'h5', + }); + assert.equal(warningHeader, true); + }, + ); + }); + + it('Should return not safe response', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesController({ + transactionSecurityCheckEnabled: true, + }) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => + await mockSecurityProviderDetection(mockServer, 'notSafe'), + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage('http://127.0.0.1:8080/'); + windowHandles = await driver.getAllWindowHandles(); + + await driver.clickElement('#signTypedData'); + + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + const warningHeader = await driver.isElementPresent({ + text: 'Request may not be safe', + tag: 'h5', + }); + assert.equal(warningHeader, true); + }, + ); + }); + + it('Should return not malicious response', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesController({ + transactionSecurityCheckEnabled: true, + }) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => + await mockSecurityProviderDetection(mockServer, 'notMalicious'), + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage('http://127.0.0.1:8080/'); + windowHandles = await driver.getAllWindowHandles(); + + await driver.clickElement('#siwe'); + + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + const warningHeader = await driver.isElementPresent({ + text: 'Request may not be safe', + tag: 'h5', + }); + assert.equal(warningHeader, false); + }, + ); + }); + + it('Should return request not verified response', async function () { + await withFixtures( + { + fixtures: new FixtureBuilder() + .withPreferencesController({ + transactionSecurityCheckEnabled: true, + }) + .withPermissionControllerConnectedToTestDapp() + .build(), + ganacheOptions, + title: this.test.title, + testSpecificMock: async (mockServer) => + await mockSecurityProviderDetection(mockServer, 'requestNotVerified'), + dapp: true, + failOnConsoleError: false, + }, + async ({ driver }) => { + await driver.navigate(); + await driver.fill('#password', 'correct horse battery staple'); + await driver.press('#password', driver.Key.ENTER); + + await driver.openNewPage('http://127.0.0.1:8080/'); + windowHandles = await driver.getAllWindowHandles(); + + await driver.clickElement('#signTypedDataV4'); + + await driver.waitUntilXWindowHandles(3); + await driver.switchToWindowWithTitle( + 'MetaMask Notification', + windowHandles, + ); + const warningHeader = await driver.isElementPresent({ + text: 'Request not verified', + tag: 'h5', + }); + assert.equal(warningHeader, true); + }, + ); + }); +});