Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compat w/ Brave to support multi web3 providers #7728

Closed
wants to merge 1 commit into from

Conversation

bbondy
Copy link
Contributor

@bbondy bbondy commented Dec 24, 2019

This implements the spec changes needed for better compatibility with Brave:
brave/brave-browser#7503

It makes it so both extensions can co-exist.

This might not be the cleanest way to accomplish it. Happy to receive review comments and I'll improve it. Thanks!

Copy link
Contributor

@danfinlay danfinlay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to avoid adding complexity to the metamask-controller, which is ideally not platform-aware. I recommend adding the platform-dependent logic either in background.js or as a function passed in the platform parameter for the MM-controller.

@@ -74,6 +76,21 @@ module.exports = class MetamaskController extends EventEmitter {
*/
constructor (opts) {
super()
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We currently try to keep platform-specific API usage outside of the metamask-controller, so that it can be more platform-portable.

The way we currently do this is using the platform object passed into the MetaMask controller's constructor options.

In this case, I think an easier (and more flexible) approach would be putting this logic in background.js, which already has a runtime.onConnectExternal.addListener callback, which I think is a perfect place to add this conditional platform-distinguishing logic:
https://github.com/MetaMask/metamask-extension/blob/develop/app/scripts/background.js#L320

@bbondy bbondy force-pushed the develop branch 2 times, most recently from f72db47 to 6a12d7e Compare January 3, 2020 16:14
@Gudahtt Gudahtt self-requested a review January 6, 2020 16:24
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some reservations about the injectScript call being moved into a message handler. This would make it asynchronous, I believe? Not only is the script injection a performance-critical moment (as a delay here means delaying initialization), it also means that we're no longer guaranteeing the globals injected by MetaMask are present before a dapp tries to access them. e.g. it may be possible, if the message response is sufficiently slow, for the dapp to run prior to the script being injected. This could break many dapps.

Could you move this braveWallet API into the contentscript instead? If we could check extension.braveWallet synchronously directly in the contentscript, it'd eliminate both of the above concerns.

This implements the spec changes needed for better compatibility with Brave:
brave/brave-browser#7503

It makes it so both extensions can co-exist.
@bbondy bbondy reopened this Jan 15, 2020
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is fantastic! This addresses my earlier concerns.

@@ -1,3 +1,5 @@
/*global chrome*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to suggest that you use extensionizer instead, but that wouldn't work - that doesn't expose the braveWallet API.

Maybe we should update extensionizer to add that API? 🤔 In the meantime, this seems OK

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If braveWallet is a similar API to the chrome/extension APIs that are common in browsers, then it would be a good fit. By the name, it sounds more like a provider..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

braveWallet is an additional API. It would need to be added to the list of APIs in extensionizer. At the moment, that package only exports the APIs in that list.

It's not a cross-browser API of course, so I wasn't sure whether it was a good fit for that package.

start()
// If this is Brave, it requires coordination to know if we should be the
// web3 provider.
if (chrome.braveWallet && chrome.braveWallet.getWeb3Provider) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (chrome.braveWallet && chrome.braveWallet.getWeb3Provider) {
if (chrome && chrome.braveWallet && chrome.braveWallet.getWeb3Provider) {

Correct me if I'm wrong, but I suspect that the chrome global wouldn't exist on Firefox? I think we need to check for that here too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since chrome doesn't exist in firefox, this first clause would throw an undefined error. Either needs to be typeof chrome !== 'undefined' or you could import extensionizer and check extension.braveWallet to avoid this problem.

@bbondy
Copy link
Contributor Author

bbondy commented Jan 15, 2020

@Gudahtt @danfinlay
Sorry for the delay and thanks for the suggestion.

I updated it so it's all done from the content-script now but it's still async. I'm looking for a way to do it sync still. I'll update again once I figure that out.

Copy link
Contributor

@danfinlay danfinlay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it would crash Firefox in its current form.

start()
// If this is Brave, it requires coordination to know if we should be the
// web3 provider.
if (chrome.braveWallet && chrome.braveWallet.getWeb3Provider) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, since chrome doesn't exist in firefox, this first clause would throw an undefined error. Either needs to be typeof chrome !== 'undefined' or you could import extensionizer and check extension.braveWallet to avoid this problem.

@@ -1,3 +1,5 @@
/*global chrome*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If braveWallet is a similar API to the chrome/extension APIs that are common in browsers, then it would be a good fit. By the name, it sounds more like a provider..

if (chrome.braveWallet && chrome.braveWallet.getWeb3Provider) {
chrome.braveWallet.getWeb3Provider((provider) => {
if (provider === extension.runtime.id) {
injectScript(inpageBundle)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Gudahtt that injecting async is asking for trouble, so I really recommend addressing that for Brave's sake. Since this doesn't introduce any async operation to our WebExtension-based injection, I'm okay with this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep I'll get it working sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add the typeof check on chrome too.

@bbondy
Copy link
Contributor Author

bbondy commented Jan 17, 2020

I think I have a way to do this entirely without any changes to the extension itself. It would disable the particular content script if the extension is not the web3 provider. What do you think of that approach? Currently on MetaMask and the Brave fork of MetaMask would be supported so there'd be overlap functionality for things like phishing detection.

A second content script could be addd for outside of web3 functionality later if we wanted which wouldn't be disabled when the installed extension is not the web3 provider.

@Gudahtt
Copy link
Member

Gudahtt commented Jan 17, 2020

@bbondy That sounds great! That would be a lot simpler.

The chrome.braveWallet.getWeb3Provider API used earlier would still be useful for us to detect this scenario, and inform users what's going on. Otherwise they might try to use MetaMask via the browser action button and not understand why it can't connect. We can write up some copy explaining how to switch between MetaMask and Brave's wallet.

So would it be possible to leave that API accessible from the background? I realize I was the one to asked it to be moved to the contentscript, sorry about that 😅.

@bbondy
Copy link
Contributor Author

bbondy commented Jan 17, 2020

@Gudahtt yep that's a great idea so you can still inform the user based on the same condition I did in this PR.
It was a 1 line change to move it to the contentScripts context so no sweat 👍

@bbondy
Copy link
Contributor Author

bbondy commented Jan 21, 2020

Confirming the new approach with no extension changes will work. It'll dynamically disable the content script. We might want to do work in the future to break out functionality into 2 different content scripts depending on if it is web3 related or not, but I think that's low priority.

@bbondy bbondy closed this Jan 21, 2020
@bbondy
Copy link
Contributor Author

bbondy commented Feb 3, 2020

FYI that this landed on Brave Nightly and will be on Dev channel within a few days. Within 6 weeks it'll on Release channel assuming we don't uplift it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants