Open alexristich opened 6 years ago
Related to https://github.com/gbaptista/luminous/issues/55. I'm also reviewing these as part of #1861.
I am using this fixture for testing. It comes with an inline script that prints the value of navigator.doNotTrack
. Since it's a tiny inline script, anything asynchronous fails to run in time to change its output. If you open the developer console, you'll see the page also continuously prints the value of navigator.doNotTrack
every millisecond until it becomes either "1" or "0", which helps you see what your injection delay is.
I just pushed a work-in-progress using the contentScripts
API. A few things to note:
1) This code currently does not work on Chrome.
2) In having conditional injection in Firefox 59+, we by necessity need to have conditional injection in Chrome as well, as we can no longer list the specified content scripts in manifest.json
.
3) For some reason, "<all_urls">
is not permitted to be used in the matches
key when registering the content scripts. I'll file a Bugzilla issue on this soon.
4) I think passing standardized configuration objects will be challenging for certain scripts. In supercookie.js
we have a checkEnabledAndThirdParty
query. Checking the enabled
state is easy with the contentScripts.register()
way of injecting things, given we can check for the absence of a property in the configuration object - this would indicate the script was injected with the contentScripts
API. However, determining whether something is third-party wouldn't be possible without receiving some context from the background page. Given this, I believe we would still need to engage message passing in some cases.
I think the next steps are to (a) decide on which approach, tabs.executeScript()
or webNavigation.onCommitted()
, should be used for conditional injection in browsers that don't yet support the contentScripts
API, and (b) figure out a reasonable way to pass configuration to the content scripts. I think the answer for (b) might lie in sending the code as a code string and appending the configuration. Here's some interesting thoughts on this problem in any case: https://stackoverflow.com/a/40815514
Bug for tracking the second point listed in my comment above: https://bugzilla.mozilla.org/show_bug.cgi?id=1439814
Following up on this issue, the current issue presented here is the "slow" conditional injection of content scripts. The reason for this "slowness" is that the content scripts need to know whether they should inject themselves into the page. A case where a content script should not inject itself is when the current site is whitelisted by the user.
The way this is currently achieved is using synchronous message passing with chrome.runtime.sendMessage
. The proposed solutions above aim to address this, though the optimal solution is to use the new browser.contentScripts
API. However, this API is currently only supported in Firefox 59+.
In order to fully leverage this new API, we must either (a) adjust how all current content scripts are declared and injected to avoid duplicate injection, or (b) duplicate all the current scripts, making necessary tweaks to support both methods and avoiding duplicate injection.
Both of these approaches have downsides, though given the limitations presented to content scripts and the requirements of our content scripts (i.e. injected as close to document_start
as possible), there doesn't appear to be much room if any for flexibility outside these two options.
I just pushed a work-in-progress using the
contentScripts
API. A few things to note:
- This code currently does not work on Chrome.
You can use the Chrome polyfill for contentScripts.register
. If there's interest it can probably be adjusted to work in Firefox 58- (but it might already work there as is)
Currently we inject content scripts conditionally with message passing, where the content script will query the background page as to whether it should inject itself into the page. This has the potential for the content script to be injected after a page script has already executed. In the case of fingerprinting.js, this means we may not catch an instance of fingerprinting because the fingerprinting occurred before our content script was run.
Mozilla has released a new API (https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contentScripts/register) which looks promising. It currently only works for Firefox 59+.
Another alternative is
tabs.executeScript()
(https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/executeScript), which may provide faster injection of content scripts than our current message passing approach.A final(?) contender is
webNavigation.onCommitted
(https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webNavigation/onCommitted), which, according to Adguard is the fastest means of conditionally injecting a content script: https://github.com/gorhill/uBlock/issues/1930#issuecomment-294486152