Open marcusmolchany opened 6 years ago
This issue now has a funding of 0.105 ETH (96.44 USD) attached to it.
I've added funding to this issue. I'd love for my site to work on FireFox with MetaMask without having to change my CSP. Thanks!
I think I can fix this issue, but want to verify that my approach would be correct one.
So the problem is that CSP won't allow inline script that is used here https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/contentscript.js#L30. There's manifest.json
property web_accessible_resources
that seems to allow injecting scripts that are specified there, but it's only applied if script is loaded with src
, not with textContent
.
I've tried quickly and replacing scriptTag.textContent = [script_content]
with scriptTag.src = [script_url]
seems to resolve issue with CSP in Firefox. If this approach is ok, I'll proceed with implementation.
Ok, this might be trickier than I expected. I see that loading with src
caused race condition in the past, going to look more closely into this.
thank you for starting @evgeniuz! I can set up an example application that uses my current CSP if that would help.
Sorry, but it seems that those two issues are inherently conflicting: when using scriptTag.src
there seems to be no way to ensure that script will load before all other scripts and using scriptTag.textContent
is disallowed by CSP.
I've noticed that you've tried to use hash to whitelist the script for inline, the file to hash is scripts/inpage.js
, but the problem is that sourceURL
comment is added here: https://github.com/MetaMask/metamask-extension/blob/master/app/scripts/contentscript.js#L12. Since this sourceURL
depends on extension ID, it may be different for each installation, so you cannot whitelist it reliably.
Removing sourceURL
from final build will allow to generate hash reliably, so you can whitelist it in CSP. And it can still be added in development build for easier debugging. But I cannot make this decision myself, need some input from Metamask team: is it ok to remove sourceURL
suffix in that line so that inline script is same on every installation and can be hashed and whitelisted in CSP?
Going to unassign myself from bounty, as I cannot find another solution at the moment.
@evgeniuz thank you very much for all the help here.
@marcusmolchany would you mind setting up a sample application? I'd like to play with setting up a workaround...
Hey @dmihal here is a sample application. If you open it in chrome, you should see that web3 is injected into window.web3
. If you open it using firefox, you should see that the CSP blocks web3 from being injected.
Here is the repo for the sample application. And this specifically is the CSP.
@dmihal Would you like to give this one a go? Feel free to claim it on Gitcoin by clicking 'Start Work', if so!
Is this still an issue? MetaMask seems to be working fine on FF for me.
Hey @KennethAshley, this is only an issue if you have a Content Security Policy. Does MetaMask successfully inject web3 on my sample application when you use Firefox?
This is a known bug in firefox. https://bugzilla.mozilla.org/show_bug.cgi?id=1267027. Comment on that issue to get it fixed soon. :)
@dmxsf1 are you still working on this issue?
@dmxsf1 are you still working on this issue?
@dmxsf1 are you still working on this issue?
@amitkumar991 Hello from Gitcoin Core - are you still working on this issue? Please submit a WIP PR or comment back within the next 3 days or you will be removed from this ticket and it will be returned to an ‘Open’ status. Please let us know if you have questions!
Funders only: Snooze warnings for 1 day | 3 days | 5 days | 10 days | 100 days
Any update? Is this fixed in newer versions of Firefox or Metamask?
Could this be fixed by Metamask or it should be reported to Firefox bugzilla? This should be fixed because many websites don't work because of that.
I believe the "correct" long term solution here is for dapps to change the way they interact with browser signers to better align with the official browser recommendation for pages and extensions communicating, which is via postMessage. I'm currently working on a solution to this, but it will be a big change that will require both dapp and extension buy-in and likely will be very slow to gain adoption.
I wanted to drop a comment here just to make people aware of the potential futures, but at the moment I don't believe there is a great solution. If I am successful, my hope is to get this new mechanism implemented in MetaMask eventually (likely side-by-side with the existing injection technique) and then from there we will try to get dapps to adopt this technique over time.
try to get dapps to adopt this technique over time.
Does it mean extending the Web3 protocol? (if that's correct to call that a protocol)
It means changing the way dapps communicate with "web3 enabled browsers". Rather than calling functions that were attached to window.ethereum
, instead fire and listen for events.
Hey guys, seems this issue is very old problem, but probably there doesn't exist even hotfix for this issue yet ?
So there is currently no way to use Metamask in Firefox ? (edit: with CSP enabled)
Going to follow also this thread https://bugzilla.mozilla.org/show_bug.cgi?id=1267027 but it also seems to be there for 4 years, so we should probably not expect this to be fixed anytime soon.
As I understand, to fix Metamask in FF, there would be need to change it's communication protocol to postMessages? Is that something what is planned?
I use MetaMask on Firefox and it seems to work, though I think I'm on a pretty old version at the moment. What page are you unable to use? Is it served via HTTP or HTTPS?
I use MetaMask on Firefox and it seems to work, though I think I'm on a pretty old version at the moment. What page are you unable to use? Is it served via HTTP or HTTPS?
Both, I was testing on localhost:3000 (http) and also live site with https. Tested with nightly FF (v77) and stable v75.
There is error regarding blocked contentscript.js
: Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
And there is no window.web3
neither ethereum
included.
Edit: Without enabled CSP it works. But we cannot turn that off and reduce web security.
It was failing only if there is a CSP specified on the page (via meta tag or response header). I have not tested it recently.
https://dai-hrd.keydonix.com works for me in Firefox 75.0 with MetaMask 7.7.8. I am able to click the connect button in the middle of the page, which pops up a MM prompt, and upon accepting I can interact with the UI. I get one error in my console which is from the Uniswap iframe in the page, not from MetaMask.
https://dai-hrd.keydonix.com works for me in Firefox 75.0 with MetaMask 7.7.8. I am able to click the connect button in the middle of the page, which pops up a MM prompt, and upon accepting I can interact with the UI. I get one error in my console which is from the Uniswap iframe in the page, not from MetaMask.
Yep, works for me too, but that site seems not to use CSP feature.
There is a possible workaround for pages with a CSP that disallows metamask injection.
If the dapp includes the equivalent of our inpage.js
bundle, the dapp should be able to talk to metamask. The inpage.js
bundle is rarely updated. Until this usecase/limitation is identified to be more common, we won't officially support this but it will work. You can use the inpage.js bundle as is or you can build your own with these parts: https://github.com/MetaMask/metamask-extension/blob/d908102636b6e55b6cbcf592d2d99e727b1b278f/app/scripts/inpage.js#L36-L70
There is a possible workaround for pages with a CSP that disallows metamask injection. If the dapp includes the equivalent of our
inpage.js
bundle, the dapp should be able to talk to metamask. Theinpage.js
bundle is rarely updated. Until this usecase/limitation is identified to be more common, we won't officially support this but it will work. You can use the inpage.js bundle as is or you can build your own with these parts:
Thanks @kumavis , seems this code HOT-fixed MM issue.
(function() {
if (
!window.ethereum &&
!window.web3 &&
navigator.userAgent.includes('Firefox')
) {
const script = document.createElement('script');
script.src = '/inpage-metamask.js';
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
}
})();
I took inpage.js
directly from archive of latest extension from Firefox store.
Also I will keep eye on this topic, so in case there is proper solution I can get rid of this temporary hot-fix.
I'll just highlight again what @kumavis said above: You don't need the whole inpage.js
bundle, you should be able to simply include these lines to construct your own ethereum provider:
import LocalMessageDuplexStream from 'post-message-stream'
import MetamaskInpageProvider from 'metamask-inpage-provider'
// setup background connection
const metamaskStream = new LocalMessageDuplexStream({
name: 'inpage',
target: 'contentscript',
})
// compose the inpage provider
const inpageProvider = new MetamaskInpageProvider(metamaskStream)
// set a high max listener count to avoid unnecesary warnings
inpageProvider.setMaxListeners(100)
// Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound
// `sendAsync` method on the prototype, causing `this` reference issues
const ethereum = new Proxy(inpageProvider, {
// straight up lie that we deleted the property so that it doesnt
// throw an error in strict mode
deleteProperty: () => true,
})
I first wanted to suggest browser.contentScripts for Firefox here, but the issue here is that the injected script must run as page code rather then extension code, so that wouldn't help.
Additionally, web_accessible_resources
has also been rejected at this point. (Maybe somebody can explain why having web pages wait for DOMContentLoaded before accessing metamask is a problem though?)
So it appears to me that the solution we've all been waiting for has already been summarized as part of a content script comment here:
// Eventually this streaming injection could be replaced with: // https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Language_Bindings/Components.utils.exportFunction // // But for now that is only Firefox // If we create a FireFox-only code path using that API, // MetaMask will be much faster loading and performant on Firefox.
So do the following steps on Firefox:
inpage.js
using Cu.exportFuntion
– from experience the code for this gets kinda messy but it's not overly bad; can't tell how this'll behave in combination with async functions thoughI suppose the bounty on this has expired though? 😬
I'm labelling this as "blocked" because the upstream issue has not been addressed yet: https://bugzilla.mozilla.org/show_bug.cgi?id=1446231
@ntninja I think that API was since deprecated? :thinking: So that might not be a viable option anymore. Not 100% sure though.
@Gudahtt: Which one? Where did you see that? I have extensions depending on that content-script API.
@ntninja See the warning at the beginning of this page: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM
I thought they had decided to pursue the cross-browser Web Extensions API, rather than pursue this or any other Firefox-specific API
To my knowledge that applies to writing extension stuff using XPCOM APIs, note here that while the documentation of exportFunction
is on the XPCOM part of the wiki, it is not exposed as an XPCOM API (at names like Components.utils.exportFunction
) but specifically as part of the content script global scope. While you can never be sure with Mozilla, I don't believe that they will stop exposing these 3 functions given their usefulness and given that they need a comparable mechanism for their own stuff in-browser anyways. There also is simply no alternative to this API to solving this anyways, so we might as well use it and make sure that they know about this and its important to this extension so that they at least don't remove without prior notice.
My read of this is that it's still deprecated, since it's part of the XPCOM API, despite it being exposed directly on the window
. But I don't see any removal notice, so I don't see any reason not to use it at least as an interim workaround in the meantime. I'll remove the blocked
label then.
Anybody interested in sponsoring me on this one?
I was debugging something related to this recently and noticed that the underlying Firefox bug only seems to affect CSPs set via header, not those set in a <meta>
tag. If anyone wants to try and repro this, keep that in mind! I used Heroku to add the CSP as a header, following the example linked in an earlier comment, and that worked.
This means that the problem has a fairly simple workaround; set your CSP via a <meta>
tag instead of using a header, and this bug shouldn't affect you! A CSP set via a <meta>
tag should still accomplish the same thing as one sent via header (as far as I know), but it bypasses this bug.
@Gudahtt Currently facing the same issue (FF 87 and white screen on MetaMask). Was trying to extract the vault, but keep on getting this error:
Setting up Sentry Remote Error Reporting for 'production': SENTRY_DSN initSentry.js:1:1426
Removing intrinsics.Promise.any initSentry.js:8:36495
Removing intrinsics.Reflect.@@toStringTag initSentry.js:8:36495
Removing intrinsics.%StringPrototype%.replaceAll initSentry.js:8:36495
Removing intrinsics.%ErrorPrototype%.stack initSentry.js:8:36495
unreachable code after return statement
ui-libs.js:1:439240
unreachable code after return statement
ui-libs.js:1:443126
unreachable code after return statement
ui-libs.js:1:444747
unreachable code after return statement
ui-libs.js:13:10549
unreachable code after return statement
ui-libs.js:13:10864
unreachable code after return statement
ui-libs.js:13:13651
Content Security Policy: The page’s settings blocked the loading of a resource at eval (“script-src”).
When visiting the home.html
page from the extension. What's a practical way to make it work? I tried temporarily disabling any CSP policies (using an extension and in the Firefox config) but that didn't work.
I am encountering this as well. Updating the CSP to a <meta>
tag does not seem to work. Here is my CSP for reference
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; font-src 'self' https://www.slant.co data: https://fonts.gstatic.com; connect-src 'self'; img-src 'self'; style-src 'self' https://fonts.googleapis.com; media-src 'self'; ">
Seems this issue is connected to users getting blank screens on FF: https://github.com/MetaMask/metamask-extension/issues/9196#issuecomment-867661016
I still wasn't able to resolve my problem.
For anyone working around this issue, I was able to get Firefox working by copying MyCrypto's workaround here: https://github.com/MyCryptoHQ/MyCrypto/pull/3292/files#diff-18092debc1d7fd5a37fa36476baa06bb492fe33df7dc8dde4576abfffaf73c88
Note, I had to use the exact versions of post-message-stream (3.0.0) and @metamask/inpage-provider (6.0.1) to get it to work, which is unfortunate because those packages are deprecated. I tested with the latest releases of those packages and also their replacements (@metamask/post-message-stream and @metamask/providers) but neither worked. No errors printed to console but Metamask never reacted to the connection request. @kumavis @rekmarks Any theories why that may be? Or other combinations I should try? Would love to move off the deprecated versions.
Finally, a few folks here have mentioned moving the CSP to a meta tag. That may work but it's not quite as secure as the server declaring the CSP before the browser receives any content. Better than nothing though.
Further to other comments, the MyCryptoHQ workaround doesn't seem to work and depends on libraries that have been abandoned or renamed and changed the relevant API's.
I couldn't find any updated solution, but after some time got this working:
const {WindowPostMessageStream} = require('@metamask/post-message-stream');
const { initializeProvider } = require('@metamask/providers');
// Firefox Metamask Hack
// Due to https://github.com/MetaMask/metamask-extension/issues/3133
(() => {
if (window.ethereum || window.web3) {
return;
}
if (navigator.userAgent.includes('Firefox')) {
// setup background connection
const metamaskStream = new WindowPostMessageStream({
name: 'metamask-inpage',
target: 'metamask-contentscript'
});
// this will initialize the provider and set it as window.ethereum
initializeProvider({
connectionStream: metamaskStream,
shouldShimWeb3: true
});
} else if (navigator.userAgent.includes('iPhone')) {
// injectMobile();
}
})();
I had to switch to browserify since this requires several node libraries, and I need client-side javascript obviously. It seems that's the case for most of the metamask helper modules
Would love to see this fixed!
+1 We'd love to see this fixed at ENS
This cant be for real ..... 0_o
How much does Google pay MetaMask to keep them from fixing issues that prevent it working in competing browsers?
This issue has been automatically marked as stale because it has not had recent activity in the last 90 days. It will be closed in 45 days if there is no further activity. The MetaMask team intends on reviewing this issue before close, and removing the stale label if it is still a bug. We welcome new comments on this issue. We do not intend on closing issues if they report bugs that are still reproducible. Thank you for your contributions.
Hey, as far as I can tell, my content security policy is preventing MetaMask from injecting its scripts. This is only happening in Firefox. It works correctly in Chrome, Safari, Opera, and Brave. My
script-src
directive looks like this:and I'm seeing this csp violation in the js console:
Unfortunately Firefox only shows a preview of the blocked script. I've tried sha256 hashing each of the scripts in the latest Metamask release and adding them to the CSP, but that did not work. If you have any ideas that would be great!
Browser: Firefox 58.0.1 Operating System: Mac OSX 10.13.2