2022-08-16 08:12:00 +02:00
|
|
|
import { strict as assert } from 'assert';
|
|
|
|
import sinon from 'sinon';
|
|
|
|
import proxyquire from 'proxyquire';
|
2023-07-31 14:48:48 +02:00
|
|
|
import {
|
|
|
|
ListNames,
|
|
|
|
METAMASK_STALELIST_URL,
|
|
|
|
METAMASK_HOTLIST_DIFF_URL,
|
|
|
|
PHISHING_CONFIG_BASE_URL,
|
|
|
|
METAMASK_STALELIST_FILE,
|
|
|
|
METAMASK_HOTLIST_DIFF_FILE,
|
|
|
|
} from '@metamask/phishing-controller';
|
2022-11-24 20:59:07 +01:00
|
|
|
import { ApprovalRequestNotFoundError } from '@metamask/approval-controller';
|
|
|
|
import { PermissionsRequestNotFoundError } from '@metamask/permission-controller';
|
2022-12-13 21:20:24 +01:00
|
|
|
import nock from 'nock';
|
2022-08-16 08:12:00 +02:00
|
|
|
|
|
|
|
const Ganache = require('../../test/e2e/ganache');
|
|
|
|
|
|
|
|
const ganacheServer = new Ganache();
|
|
|
|
|
|
|
|
const browserPolyfillMock = {
|
|
|
|
runtime: {
|
|
|
|
id: 'fake-extension-id',
|
|
|
|
onInstalled: {
|
|
|
|
addListener: () => undefined,
|
|
|
|
},
|
|
|
|
onMessageExternal: {
|
|
|
|
addListener: () => undefined,
|
|
|
|
},
|
|
|
|
getPlatformInfo: async () => 'mac',
|
|
|
|
},
|
2022-11-22 17:56:26 +01:00
|
|
|
storage: {
|
|
|
|
local: {
|
|
|
|
get: sinon.stub().resolves({}),
|
|
|
|
set: sinon.stub().resolves(),
|
|
|
|
},
|
|
|
|
},
|
2022-08-16 08:12:00 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
let loggerMiddlewareMock;
|
|
|
|
const createLoggerMiddlewareMock = () => (req, res, next) => {
|
|
|
|
if (loggerMiddlewareMock) {
|
|
|
|
loggerMiddlewareMock.requests.push(req);
|
|
|
|
next((cb) => {
|
|
|
|
loggerMiddlewareMock.responses.push(res);
|
|
|
|
cb();
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
next();
|
|
|
|
};
|
|
|
|
|
2022-08-19 15:43:08 +02:00
|
|
|
const TEST_SEED =
|
|
|
|
'debris dizzy just program just float decrease vacant alarm reduce speak stadium';
|
|
|
|
|
2022-08-16 08:12:00 +02:00
|
|
|
const MetaMaskController = proxyquire('./metamask-controller', {
|
|
|
|
'./lib/createLoggerMiddleware': { default: createLoggerMiddlewareMock },
|
|
|
|
}).default;
|
|
|
|
|
|
|
|
describe('MetaMaskController', function () {
|
|
|
|
let metamaskController;
|
|
|
|
const sandbox = sinon.createSandbox();
|
|
|
|
const noop = () => undefined;
|
|
|
|
|
|
|
|
before(async function () {
|
|
|
|
await ganacheServer.start();
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function () {
|
2023-07-31 14:48:48 +02:00
|
|
|
nock(PHISHING_CONFIG_BASE_URL)
|
2022-12-13 21:20:24 +01:00
|
|
|
.persist()
|
2023-07-31 14:48:48 +02:00
|
|
|
.get(METAMASK_STALELIST_FILE)
|
2022-12-13 21:20:24 +01:00
|
|
|
.reply(
|
|
|
|
200,
|
|
|
|
JSON.stringify({
|
|
|
|
version: 2,
|
|
|
|
tolerance: 2,
|
2023-07-31 14:48:48 +02:00
|
|
|
lastUpdated: 1,
|
|
|
|
eth_phishing_detect_config: {
|
|
|
|
fuzzylist: [],
|
|
|
|
allowlist: [],
|
|
|
|
blocklist: ['127.0.0.1'],
|
|
|
|
name: ListNames.MetaMask,
|
|
|
|
},
|
|
|
|
phishfort_hotlist: {
|
|
|
|
blocklist: [],
|
|
|
|
name: ListNames.Phishfort,
|
|
|
|
},
|
2022-12-13 21:20:24 +01:00
|
|
|
}),
|
|
|
|
)
|
2023-07-31 14:48:48 +02:00
|
|
|
.get(METAMASK_HOTLIST_DIFF_FILE)
|
2023-02-24 16:09:00 +01:00
|
|
|
.reply(
|
|
|
|
200,
|
|
|
|
JSON.stringify([
|
|
|
|
{ url: '127.0.0.1', targetList: 'blocklist', timestamp: 0 },
|
|
|
|
]),
|
|
|
|
);
|
2022-08-16 08:12:00 +02:00
|
|
|
metamaskController = new MetaMaskController({
|
|
|
|
showUserConfirmation: noop,
|
|
|
|
encryptor: {
|
|
|
|
encrypt(_, object) {
|
|
|
|
this.object = object;
|
|
|
|
return Promise.resolve('mock-encrypted');
|
|
|
|
},
|
|
|
|
decrypt() {
|
|
|
|
return Promise.resolve(this.object);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
initLangCode: 'en_US',
|
|
|
|
platform: {
|
|
|
|
showTransactionNotification: () => undefined,
|
|
|
|
getVersion: () => 'foo',
|
|
|
|
},
|
|
|
|
browser: browserPolyfillMock,
|
|
|
|
infuraProjectId: 'foo',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
sandbox.restore();
|
2022-12-13 21:20:24 +01:00
|
|
|
nock.cleanAll();
|
2022-08-16 08:12:00 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
after(async function () {
|
|
|
|
await ganacheServer.quit();
|
|
|
|
});
|
|
|
|
|
2023-07-31 14:48:48 +02:00
|
|
|
describe('Phishing Detection Mock', function () {
|
|
|
|
it('should be updated to use v1 of the API', function () {
|
|
|
|
// Update the fixture above if this test fails
|
|
|
|
assert.equal(
|
|
|
|
METAMASK_STALELIST_URL,
|
|
|
|
'https://phishing-detection.metafi.codefi.network/v1/stalelist',
|
|
|
|
);
|
|
|
|
assert.equal(
|
|
|
|
METAMASK_HOTLIST_DIFF_URL,
|
|
|
|
'https://phishing-detection.metafi.codefi.network/v1/diffsSince',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-16 08:12:00 +02:00
|
|
|
describe('#addNewAccount', function () {
|
|
|
|
it('two parallel calls with same accountCount give same result', async function () {
|
|
|
|
await metamaskController.createNewVaultAndKeychain('test@123');
|
|
|
|
const [addNewAccountResult1, addNewAccountResult2] = await Promise.all([
|
|
|
|
metamaskController.addNewAccount(1),
|
|
|
|
metamaskController.addNewAccount(1),
|
|
|
|
]);
|
2023-08-16 11:19:41 +02:00
|
|
|
assert.equal(addNewAccountResult1, addNewAccountResult2);
|
2022-08-16 08:12:00 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it('two successive calls with same accountCount give same result', async function () {
|
|
|
|
await metamaskController.createNewVaultAndKeychain('test@123');
|
2022-08-18 21:39:04 +02:00
|
|
|
const addNewAccountResult1 = await metamaskController.addNewAccount(1);
|
|
|
|
const addNewAccountResult2 = await metamaskController.addNewAccount(1);
|
2023-08-16 11:19:41 +02:00
|
|
|
assert.equal(addNewAccountResult1, addNewAccountResult2);
|
2022-08-16 08:12:00 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
it('two successive calls with different accountCount give different results', async function () {
|
|
|
|
await metamaskController.createNewVaultAndKeychain('test@123');
|
|
|
|
const addNewAccountResult1 = await metamaskController.addNewAccount(1);
|
|
|
|
const addNewAccountResult2 = await metamaskController.addNewAccount(2);
|
2023-08-16 11:19:41 +02:00
|
|
|
assert.notEqual(addNewAccountResult1, addNewAccountResult2);
|
2022-08-16 08:12:00 +02:00
|
|
|
});
|
|
|
|
});
|
2022-08-18 21:39:04 +02:00
|
|
|
|
2022-08-19 15:43:08 +02:00
|
|
|
describe('#importAccountWithStrategy', function () {
|
|
|
|
it('two sequential calls with same strategy give same result', async function () {
|
|
|
|
let keyringControllerState1;
|
|
|
|
let keyringControllerState2;
|
|
|
|
const importPrivkey =
|
|
|
|
'4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553';
|
|
|
|
|
|
|
|
await metamaskController.createNewVaultAndKeychain('test@123');
|
|
|
|
await Promise.all([
|
2023-08-17 09:11:51 +02:00
|
|
|
metamaskController.importAccountWithStrategy('privateKey', [
|
2022-08-19 15:43:08 +02:00
|
|
|
importPrivkey,
|
|
|
|
]),
|
|
|
|
Promise.resolve(1).then(() => {
|
|
|
|
keyringControllerState1 = JSON.stringify(
|
|
|
|
metamaskController.keyringController.memStore.getState(),
|
|
|
|
);
|
2023-08-17 09:11:51 +02:00
|
|
|
metamaskController.importAccountWithStrategy('privateKey', [
|
2022-08-19 15:43:08 +02:00
|
|
|
importPrivkey,
|
|
|
|
]);
|
|
|
|
}),
|
|
|
|
Promise.resolve(2).then(() => {
|
|
|
|
keyringControllerState2 = JSON.stringify(
|
|
|
|
metamaskController.keyringController.memStore.getState(),
|
|
|
|
);
|
|
|
|
}),
|
|
|
|
]);
|
|
|
|
assert.deepEqual(keyringControllerState1, keyringControllerState2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#createNewVaultAndRestore', function () {
|
|
|
|
it('two successive calls with same inputs give same result', async function () {
|
|
|
|
const result1 = await metamaskController.createNewVaultAndRestore(
|
|
|
|
'test@123',
|
|
|
|
TEST_SEED,
|
|
|
|
);
|
|
|
|
const result2 = await metamaskController.createNewVaultAndRestore(
|
|
|
|
'test@123',
|
|
|
|
TEST_SEED,
|
|
|
|
);
|
|
|
|
assert.deepEqual(result1, result2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#createNewVaultAndKeychain', function () {
|
|
|
|
it('two successive calls with same inputs give same result', async function () {
|
|
|
|
const result1 = await metamaskController.createNewVaultAndKeychain(
|
|
|
|
'test@123',
|
|
|
|
);
|
|
|
|
const result2 = await metamaskController.createNewVaultAndKeychain(
|
|
|
|
'test@123',
|
|
|
|
);
|
|
|
|
assert.notEqual(result1, undefined);
|
|
|
|
assert.deepEqual(result1, result2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-19 14:30:40 +02:00
|
|
|
describe('#addToken', function () {
|
|
|
|
const address = '0x514910771af9ca656af840dff83e8264ecf986ca';
|
|
|
|
const symbol = 'LINK';
|
|
|
|
const decimals = 18;
|
|
|
|
|
|
|
|
it('two parallel calls with same token details give same result', async function () {
|
|
|
|
const supportsInterfaceStub = sinon
|
|
|
|
.stub()
|
|
|
|
.returns(Promise.resolve(false));
|
|
|
|
sinon
|
|
|
|
.stub(metamaskController.tokensController, '_createEthersContract')
|
|
|
|
.callsFake(() =>
|
|
|
|
Promise.resolve({ supportsInterface: supportsInterfaceStub }),
|
|
|
|
);
|
|
|
|
|
|
|
|
const [token1, token2] = await Promise.all([
|
|
|
|
metamaskController.getApi().addToken(address, symbol, decimals),
|
|
|
|
metamaskController.getApi().addToken(address, symbol, decimals),
|
|
|
|
]);
|
|
|
|
assert.deepEqual(token1, token2);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-10-31 06:52:31 +01:00
|
|
|
describe('#removePermissionsFor', function () {
|
|
|
|
it('should not propagate PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new PermissionsRequestNotFoundError('123');
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
revokePermissions: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// Line below will not throw error, in case it throws this test case will fail.
|
|
|
|
metamaskController.removePermissionsFor({ subject: 'test_subject' });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should propagate Error other than PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new Error();
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
revokePermissions: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert.throws(() => {
|
|
|
|
metamaskController.removePermissionsFor({ subject: 'test_subject' });
|
|
|
|
}, error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#rejectPermissionsRequest', function () {
|
|
|
|
it('should not propagate PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new PermissionsRequestNotFoundError('123');
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
rejectPermissionsRequest: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// Line below will not throw error, in case it throws this test case will fail.
|
|
|
|
metamaskController.rejectPermissionsRequest('DUMMY_ID');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should propagate Error other than PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new Error();
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
rejectPermissionsRequest: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert.throws(() => {
|
|
|
|
metamaskController.rejectPermissionsRequest('DUMMY_ID');
|
|
|
|
}, error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#acceptPermissionsRequest', function () {
|
|
|
|
it('should not propagate PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new PermissionsRequestNotFoundError('123');
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
acceptPermissionsRequest: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// Line below will not throw error, in case it throws this test case will fail.
|
|
|
|
metamaskController.acceptPermissionsRequest('DUMMY_ID');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should propagate Error other than PermissionsRequestNotFoundError', function () {
|
|
|
|
const error = new Error();
|
|
|
|
metamaskController.permissionController = {
|
|
|
|
acceptPermissionsRequest: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert.throws(() => {
|
|
|
|
metamaskController.acceptPermissionsRequest('DUMMY_ID');
|
|
|
|
}, error);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#resolvePendingApproval', function () {
|
2023-06-13 11:17:32 +02:00
|
|
|
it('should not propagate ApprovalRequestNotFoundError', async function () {
|
2022-10-31 06:52:31 +01:00
|
|
|
const error = new ApprovalRequestNotFoundError('123');
|
|
|
|
metamaskController.approvalController = {
|
|
|
|
accept: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// Line below will not throw error, in case it throws this test case will fail.
|
2023-06-13 11:17:32 +02:00
|
|
|
await metamaskController.resolvePendingApproval(
|
|
|
|
'DUMMY_ID',
|
|
|
|
'DUMMY_VALUE',
|
|
|
|
);
|
2022-10-31 06:52:31 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
it('should propagate Error other than ApprovalRequestNotFoundError', function () {
|
|
|
|
const error = new Error();
|
|
|
|
metamaskController.approvalController = {
|
|
|
|
accept: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
2023-06-13 11:17:32 +02:00
|
|
|
assert.rejects(
|
|
|
|
() =>
|
|
|
|
metamaskController.resolvePendingApproval('DUMMY_ID', 'DUMMY_VALUE'),
|
|
|
|
error,
|
|
|
|
);
|
2022-10-31 06:52:31 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#rejectPendingApproval', function () {
|
|
|
|
it('should not propagate ApprovalRequestNotFoundError', function () {
|
|
|
|
const error = new ApprovalRequestNotFoundError('123');
|
|
|
|
metamaskController.approvalController = {
|
|
|
|
reject: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
// Line below will not throw error, in case it throws this test case will fail.
|
|
|
|
metamaskController.rejectPendingApproval('DUMMY_ID', {
|
|
|
|
code: 1,
|
|
|
|
message: 'DUMMY_MESSAGE',
|
|
|
|
data: 'DUMMY_DATA',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should propagate Error other than ApprovalRequestNotFoundError', function () {
|
|
|
|
const error = new Error();
|
|
|
|
metamaskController.approvalController = {
|
|
|
|
reject: () => {
|
|
|
|
throw error;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
assert.throws(() => {
|
|
|
|
metamaskController.rejectPendingApproval('DUMMY_ID', {
|
|
|
|
code: 1,
|
|
|
|
message: 'DUMMY_MESSAGE',
|
|
|
|
data: 'DUMMY_DATA',
|
|
|
|
});
|
|
|
|
}, error);
|
|
|
|
});
|
|
|
|
});
|
2022-08-16 08:12:00 +02:00
|
|
|
});
|