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); }, ); }); });