Skip to content

Commit

Permalink
feat: use browser.contentScripts API in Firefox
Browse files Browse the repository at this point in the history
This change enables Firefox users to disable creation of window.ipfs,
solving fingerprinting issue raised in:
#451

The key difference between tabs.executeScript and contentScripts API
is that the latter provides guarantee to execute before anything else.

Chrome does not provide contentScripts API and we need to statically
load content_script via  manifest.

More info on the underlying issue:
#368
#362 (comment)
  • Loading branch information
lidel committed Jun 8, 2018
1 parent f3ab73c commit 7f22455
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
1 change: 1 addition & 0 deletions add-on/manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"default_title": "__MSG_pageAction_titleNonIpfs__",
"default_popup": "dist/popup/page-action/index.html"
},
"content_scripts": null,
"protocol_handlers": [
{
"protocol": "web+dweb",
Expand Down
38 changes: 37 additions & 1 deletion add-on/src/lib/ipfs-companion.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module.exports = async function init () {
var contextMenus
var apiStatusUpdateInterval
var ipfsProxy
var ipfsProxyContentScript
const idleInSecs = 5 * 60
const browserActionPortName = 'browser-action-port'

Expand Down Expand Up @@ -60,6 +61,7 @@ module.exports = async function init () {
})
modifyRequest = createRequestModifier(getState, dnsLink, ipfsPathValidator, runtime)
ipfsProxy = createIpfsProxy(() => ipfs, getState)
ipfsProxyContentScript = await registerIpfsProxyContentScript()
registerListeners()
await setApiStatusUpdateInterval(options.ipfsApiPollMs)
await storeMissingOptions(
Expand Down Expand Up @@ -95,6 +97,33 @@ module.exports = async function init () {
}
}

// Register Content Script responsible for loading window.ipfs (ipfsProxy)
//
// The key difference between tabs.executeScript and contentScripts API
// is the latter provides guarantee to execute before anything else.
// https://github.com/ipfs-shipyard/ipfs-companion/issues/451#issuecomment-382669093
async function registerIpfsProxyContentScript (previousHandle) {
previousHandle = previousHandle || ipfsProxyContentScript
if (previousHandle) {
previousHandle.unregister()
}
if (!state.ipfsProxy || !browser.contentScripts) {
// no-op if window.ipfs is disabled in Preferences
// or if runtime has no contentScript API
// (Chrome loads content script via manifest)
return
}
const newHandle = await browser.contentScripts.register({
matches: ['<all_urls>'],
js: [
{file: '/dist/contentScripts/ipfs-proxy/content.js'}
],
allFrames: true,
runAt: 'document_start'
})
return newHandle
}

// HTTP Request Hooks
// ===================================================================

Expand Down Expand Up @@ -553,13 +582,16 @@ module.exports = async function init () {
case 'useCustomGateway':
state.redirect = change.newValue
break
case 'ipfsProxy':
state[key] = change.newValue
ipfsProxyContentScript = await registerIpfsProxyContentScript()
break
case 'linkify':
case 'catchUnhandledProtocols':
case 'displayNotifications':
case 'automaticMode':
case 'dnslink':
case 'preloadAtPublicGateway':
case 'ipfsProxy':
state[key] = change.newValue
break
}
Expand Down Expand Up @@ -625,6 +657,10 @@ module.exports = async function init () {
contextMenus = null
ipfsProxy.destroy()
ipfsProxy = null
if (ipfsProxyContentScript) {
ipfsProxyContentScript.unregister()
ipfsProxyContentScript = null
}
await destroyIpfsClient()
}
}
Expand Down

0 comments on commit 7f22455

Please sign in to comment.