Reputation: 412
I know this has been asked already for the general case of Chrome extension script injection. I'm asking for my specific Web3js use case to see if anyone has any better ideas such that I don't need to inject.
I'm trying to sign an Ethereum transaction from a Chrome extension. To do this I'm using Web3.js. However, I need access to the window variable to instantiate web3. Something like:
if (window.ethereum) {
// current web3 providers
window.web3 = new Web3(window.ethereum);
await window.ethereum.enable();
} else if (window.web3) {
// fallback for older web3 providers
window.web3 = new Web3(window.web3.currentProvider);
} else {
// no web3 provider, user needs to install one in their browser
window.alert('No injected web3 provider detected');
}
Since the content_scripts of a Chrome extension can't access the browser's window, I've had to inject both the web3js code, and my script using it, like so:
// inject script.js into the page.
var s = document.createElement('script');
s.src = chrome.runtime.getURL('js/script.js');
s.onload = function() {
this.remove();
};
var w = document.createElement('script');
w.src = chrome.runtime.getURL('third-party/web3.min.js');
w.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(w).appendChild(s);
This works fine. However, most major webpages have a CSP to block unsafe-inlines and unsafe-evals, both of which are occurring with this approach. So, my extension only works on web-pages without this CSP.
Can anyone think of a better way to achieve what I'm trying to achieve, or at least a way to get around the CSP?
Upvotes: 0
Views: 1951
Reputation: 73576
There are several solutions:
Strip/modify the CSP header of the site using chrome.webRequest.onHeadersReceived event, see this example (it's for a different header so you will change the name).
Modify the libraries so they don't use eval
Run the library in an iframe exposed via web_accessible_resources. That iframe will be an extension page like the popup/options page and you can apply your own CSP in manifest.json, more info.
So, content script won't add third-party/web3.min.js
, instead it'll add an iframe:
var iframe = document.createElement('iframe');
iframe.src = chrome.runtime.getURL('iframe.html');
document.documentElement.appendChild(iframe);
iframe.html:
<script src="iframe.js"></script>
<script src="third-party/web3.min.js"></script>
Messaging will be somewhat complicated. Your page script (script.js) can use CustomEvent messaging to communicate with the content script which in turn can use chrome.runtime messaging to communicate with the iframe, example. Alternatively, use externally_connectable messaging directly so the page script (and the web page itself) can send messages to any extension script (the iframe script will also see it and decide if it should be handled by comparing sender.tab.id
to its own tab id obtained via chrome.tabs.getCurrent).
Upvotes: 3