Warn about multiple MetaMask instances running (#13836)
* Add text warning on startup page * Try to detect extensions with browser API * Setup messaging between different versions of extension * Cleanup * Cleanup * Simplify check for multiple instances running * Fix a doc string + use webextension-polyfill * Fix test * Mock webextension-polyfill * Mock correctly * Catch error and show warning in both extensions * Mock as promise * Address comments * Rename build ids * Run detection code only if Chrome * Add Firefox warnings * Cleanup imports * Update connection ids * Run detection code for Firefox * Add test * Add missing await * Update tests * Cleanup * Cleanup * Improve testing * Improve tests * Log errors from sendMessage * Cleanup Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>feature/default_network_editable
parent
74b5401302
commit
72d2977e72
@ -0,0 +1,55 @@ |
||||
/** |
||||
* Sets up two-way communication between the |
||||
* mainline version of extension and Flask build |
||||
* in order to detect & warn if there are two different |
||||
* versions running simultaneously. |
||||
*/ |
||||
|
||||
import browser from 'webextension-polyfill'; |
||||
import { |
||||
PLATFORM_CHROME, |
||||
PLATFORM_FIREFOX, |
||||
CHROME_BUILD_IDS, |
||||
FIREFOX_BUILD_IDS, |
||||
} from '../../shared/constants/app'; |
||||
import { getPlatform } from './lib/util'; |
||||
|
||||
const MESSAGE_TEXT = 'isRunning'; |
||||
|
||||
const showWarning = () => |
||||
console.warn('Warning! You have multiple instances of MetaMask running!'); |
||||
|
||||
/** |
||||
* Handles the ping message sent from other extension. |
||||
* Displays console warning if it's active. |
||||
* |
||||
* @param message - The message received from the other extension |
||||
*/ |
||||
export const onMessageReceived = (message) => { |
||||
if (message === MESSAGE_TEXT) { |
||||
showWarning(); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* Sends the ping message sent to other extensions to detect whether it's active or not. |
||||
*/ |
||||
export const checkForMultipleVersionsRunning = async () => { |
||||
if (getPlatform() !== PLATFORM_CHROME && getPlatform() !== PLATFORM_FIREFOX) { |
||||
return; |
||||
} |
||||
const buildIds = |
||||
getPlatform() === PLATFORM_CHROME ? CHROME_BUILD_IDS : FIREFOX_BUILD_IDS; |
||||
|
||||
const thisBuild = browser.runtime.id; |
||||
|
||||
for (const id of buildIds) { |
||||
if (id !== thisBuild) { |
||||
try { |
||||
await browser.runtime.sendMessage(id, MESSAGE_TEXT); |
||||
} catch (error) { |
||||
// Should do nothing if receiving end was not reached (no other instances running)
|
||||
} |
||||
} |
||||
} |
||||
}; |
@ -0,0 +1,104 @@ |
||||
import { strict as assert } from 'assert'; |
||||
import browser from 'webextension-polyfill'; |
||||
import sinon from 'sinon'; |
||||
import { |
||||
PLATFORM_CHROME, |
||||
PLATFORM_EDGE, |
||||
METAMASK_BETA_CHROME_ID, |
||||
METAMASK_PROD_CHROME_ID, |
||||
METAMASK_FLASK_CHROME_ID, |
||||
} from '../../shared/constants/app'; |
||||
import { |
||||
checkForMultipleVersionsRunning, |
||||
onMessageReceived, |
||||
} from './detect-multiple-instances'; |
||||
import * as util from './lib/util'; |
||||
|
||||
describe('multiple instances running detector', function () { |
||||
const PING_MESSAGE = 'isRunning'; |
||||
|
||||
let sendMessageStub = sinon.stub(); |
||||
|
||||
beforeEach(async function () { |
||||
sinon.replace(browser, 'runtime', { |
||||
sendMessage: sendMessageStub, |
||||
id: METAMASK_BETA_CHROME_ID, |
||||
}); |
||||
|
||||
sinon.stub(util, 'getPlatform').callsFake((_) => { |
||||
return PLATFORM_CHROME; |
||||
}); |
||||
}); |
||||
|
||||
afterEach(function () { |
||||
sinon.restore(); |
||||
}); |
||||
|
||||
describe('checkForMultipleVersionsRunning', function () { |
||||
it('should send ping message to multiple instances', async function () { |
||||
await checkForMultipleVersionsRunning(); |
||||
|
||||
assert(sendMessageStub.calledTwice); |
||||
assert( |
||||
sendMessageStub |
||||
.getCall(0) |
||||
.calledWithExactly(METAMASK_PROD_CHROME_ID, PING_MESSAGE), |
||||
); |
||||
assert( |
||||
sendMessageStub |
||||
.getCall(1) |
||||
.calledWithExactly(METAMASK_FLASK_CHROME_ID, PING_MESSAGE), |
||||
); |
||||
}); |
||||
|
||||
it('should not send ping message if platform is not Chrome or Firefox', async function () { |
||||
util.getPlatform.restore(); |
||||
sendMessageStub = sinon.stub(); |
||||
|
||||
sinon.stub(util, 'getPlatform').callsFake((_) => { |
||||
return PLATFORM_EDGE; |
||||
}); |
||||
|
||||
await checkForMultipleVersionsRunning(); |
||||
|
||||
assert(sendMessageStub.notCalled); |
||||
}); |
||||
|
||||
it('should not expose an error outside if sendMessage throws', async function () { |
||||
sinon.restore(); |
||||
|
||||
sinon.replace(browser, 'runtime', { |
||||
sendMessage: sinon.stub().throws(), |
||||
id: METAMASK_BETA_CHROME_ID, |
||||
}); |
||||
|
||||
const spy = sinon.spy(checkForMultipleVersionsRunning); |
||||
|
||||
await checkForMultipleVersionsRunning(); |
||||
|
||||
assert(!spy.threw()); |
||||
}); |
||||
}); |
||||
|
||||
describe('onMessageReceived', function () { |
||||
beforeEach(function () { |
||||
sinon.spy(console, 'warn'); |
||||
}); |
||||
|
||||
it('should print warning message to on ping message received', async function () { |
||||
onMessageReceived(PING_MESSAGE); |
||||
|
||||
assert( |
||||
console.warn.calledWithExactly( |
||||
'Warning! You have multiple instances of MetaMask running!', |
||||
), |
||||
); |
||||
}); |
||||
|
||||
it('should not print warning message if wrong message received', async function () { |
||||
onMessageReceived(PING_MESSAGE.concat('wrong')); |
||||
|
||||
assert(console.warn.notCalled); |
||||
}); |
||||
}); |
||||
}); |
Loading…
Reference in new issue