Skip to content

Commit

Permalink
refactor: use HTTP proxy for subdomains only on Firefox
Browse files Browse the repository at this point in the history
Chromium 80 already hardcodes localhost to loopback IPs, and we don't
want to add unnecessary permission as it may cause us fail review at
Chrome Web Store.

I also renamed the setting as its about overall Subdomain support on
localhost, even when HTTP proxy is not used.
  • Loading branch information
lidel committed Apr 3, 2020
1 parent c7d36b0 commit bfa59c3
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 52 deletions.
12 changes: 6 additions & 6 deletions add-on/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,13 @@
"message": "Redirect requests for IPFS resources to the Custom gateway",
"description": "An option description on the Preferences screen (option_useCustomGateway_description)"
},
"option_useSubdomainProxy_title": {
"message": "Use Subdomain Proxy",
"description": "An option title on the Preferences screen (option_useSubdomainProxy_title)"
"option_useSubdomains_title": {
"message": "Use Subdomains",
"description": "An option title on the Preferences screen (option_useSubdomains_title)"
},
"option_useSubdomainProxy_description": {
"message": "Use Custom Gateway as HTTP Proxy to enable Origin isolation per content root at *.ipfs.localhost",
"description": "An option description on the Preferences screen (option_useSubdomainProxy_description)"
"option_useSubdomains_description": {
"message": "Isolate content roots from each other by loading them from subdomains at *.localhost and creating a unique Origin for each CID, IPNS or DNSLink record. Requires a local go-ipfs 0.5.0 or later.",
"description": "An option description on the Preferences screen (option_useSubdomains_description)"
},
"option_dnslinkRedirect_title": {
"message": "Load websites from Custom Gateway",
Expand Down
13 changes: 13 additions & 0 deletions add-on/manifest.chromium.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
{
"minimum_chrome_version": "72",
"permissions": [
"<all_urls>",
"idle",
"tabs",
"notifications",
"storage",
"unlimitedStorage",
"contextMenus",
"clipboardWrite",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"incognito": "not_allowed"
}
14 changes: 0 additions & 14 deletions add-on/manifest.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,6 @@
"38": "icons/png/ipfs-logo-on_38.png",
"128": "icons/png/ipfs-logo-on_128.png"
},
"permissions": [
"<all_urls>",
"idle",
"tabs",
"notifications",
"storage",
"unlimitedStorage",
"contextMenus",
"clipboardWrite",
"proxy",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"background": {
"page": "dist/background/background.html"
},
Expand Down
14 changes: 14 additions & 0 deletions add-on/manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@
"default_title": "__MSG_pageAction_titleNonIpfs__",
"default_popup": "dist/popup/page-action/index.html"
},
"permissions": [
"<all_urls>",
"idle",
"tabs",
"notifications",
"proxy",
"storage",
"unlimitedStorage",
"contextMenus",
"clipboardWrite",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"content_scripts": [ ],
"protocol_handlers": [
{
Expand Down
19 changes: 14 additions & 5 deletions add-on/src/lib/http-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ log.error = debug('ipfs-companion:http-proxy:error')
//
// State in Q2 2020:
// - Chromium hardcodes `localhost` name to point at local IP and proxy is not
// really necessary, but we do it just to be safe.
// really necessary. The code is here (inactivE) in case we need it in the future.
// - Firefox requires proxy to avoid DNS lookup, but there is an open issue
// that will remove that need at some point:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1220810
async function registerSubdomainProxy (getState, runtime, notify) {
// At the moment only firefox requires proxy registration
if (!runtime.isFirefox) return

try {
const { active, useSubdomainProxy, gwURLString } = getState()
const enable = active && useSubdomainProxy
const { active, useSubdomains, gwURLString } = getState()
const enable = active && useSubdomains

// HTTP Proxy feature is exposed on the gateway port
// Just ensure we use localhost IP to remove any dependency on DNS
Expand All @@ -44,8 +47,9 @@ async function registerSubdomainProxy (getState, runtime, notify) {
return await registerSubdomainProxyFirefox(enable, hostname, port)
}

// at this point we asume Chromium
return await registerSubdomainProxyChromium(enable, hostname, port)
// At this point we would asume Chromium, but its not needed atm
// Uncomment below if ever needed (+ add 'proxy' permission to manifest.json)
// return await registerSubdomainProxyChromium(enable, hostname, port)
} catch (err) {
// registerSubdomainProxy is just a failsafe, not necessary in most cases,
// so we should not break init when it fails.
Expand Down Expand Up @@ -97,6 +101,10 @@ async function registerSubdomainProxyFirefox (enable, hostname, port) {
log('disabled HTTP proxy for *.localhost')
}

/*
* Chromium 80 does not need proxy, so below is not used.
* Uncomment below if ever needed (+ add 'proxy' permission to manifest.json)
// Helpers for converting callback chrome.* API to promises
const cb = (resolve, reject) => (result) => {
const err = chrome.runtime.lastError
Expand Down Expand Up @@ -142,5 +150,6 @@ async function registerSubdomainProxyChromium (enable, hostname, port) {
log('disabled HTTP proxy for *.localhost')
}
}
*/

module.exports.registerSubdomainProxy = registerSubdomainProxy
19 changes: 9 additions & 10 deletions add-on/src/lib/ipfs-companion.js
Original file line number Diff line number Diff line change
Expand Up @@ -637,18 +637,17 @@ module.exports = async function init () {
case 'useCustomGateway':
state.redirect = change.newValue
break
case 'useSubdomainProxy':
case 'useSubdomains':
state[key] = change.newValue
// Normalize hostname if enabled
if (state.useSubdomainProxy) {
await browser.storage.local.set({
// We need to update the hostname in customGatewayUrl because:
// 127.0.0.1 - path gateway
// localhost - subdomain gateway
// and we need to use the latter
customGatewayUrl: guiURLString(state.gwURLString, { useLocalhostName: true })
await browser.storage.local.set({
// We need to update the hostname in customGatewayUrl because:
// 127.0.0.1 - path gateway
// localhost - subdomain gateway
// and we need to use the latter
customGatewayUrl: guiURLString(state.gwURLString, {
useLocalhostName: state.useSubdomains
})
}
})
// Finally, update proxy settings based on the state
await registerSubdomainProxy(getState, runtime)
break
Expand Down
2 changes: 1 addition & 1 deletion add-on/src/lib/ipfs-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru
// to the local gateway and replace raw IP with 'localhost' hostname to
// take advantage of subdomain redirect provided by go-ipfs >= 0.5
if (state.redirect && request.type === 'main_frame' && sameGateway(request.url, state.gwURL)) {
const redirectUrl = safeURL(request.url, { useLocalhostName: state.useSubdomainProxy }).toString()
const redirectUrl = safeURL(request.url, { useLocalhostName: state.useSubdomains }).toString()
if (redirectUrl !== request.url) return { redirectUrl }
}

Expand Down
6 changes: 3 additions & 3 deletions add-on/src/lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports.optionDefaults = Object.freeze({
publicGatewayUrl: 'https://ipfs.io',
publicSubdomainGatewayUrl: 'https://dweb.link',
useCustomGateway: true,
useSubdomainProxy: true,
useSubdomains: true,
noIntegrationsHostnames: [],
automaticMode: true,
linkify: false,
Expand Down Expand Up @@ -169,8 +169,8 @@ exports.migrateOptions = async (storage) => {
// migrate old default 127.0.0.1 to localhost hostname
const { customGatewayUrl: gwUrl } = await storage.get('customGatewayUrl')
if (gwUrl && (localhostIpUrl(gwUrl) || localhostNameUrl(gwUrl))) {
const { useSubdomainProxy } = await storage.get('useSubdomainProxy')
const newUrl = guiURLString(gwUrl, { useLocalhostName: useSubdomainProxy })
const { useSubdomains } = await storage.get('useSubdomains')
const newUrl = guiURLString(gwUrl, { useLocalhostName: useSubdomains })
if (gwUrl !== newUrl) {
await storage.set({ customGatewayUrl: newUrl })
}
Expand Down
2 changes: 1 addition & 1 deletion add-on/src/lib/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function initState (options, overrides) {
state.apiURL = safeURL(options.ipfsApiUrl, { useLocalhostName: false }) // go-ipfs returns 403 if IP is beautified to 'localhost'
state.apiURLString = state.apiURL.toString()
delete state.ipfsApiUrl
state.gwURL = safeURL(options.customGatewayUrl, { useLocalhostName: state.useSubdomainProxy })
state.gwURL = safeURL(options.customGatewayUrl, { useLocalhostName: state.useSubdomains })
state.gwURLString = state.gwURL.toString()
delete state.customGatewayUrl
state.dnslinkPolicy = String(options.dnslinkPolicy) === 'false' ? false : options.dnslinkPolicy
Expand Down
14 changes: 7 additions & 7 deletions add-on/src/options/forms/gateways-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ function gatewaysForm ({
ipfsNodeType,
customGatewayUrl,
useCustomGateway,
useSubdomainProxy,
useSubdomains,
noIntegrationsHostnames,
publicGatewayUrl,
publicSubdomainGatewayUrl,
onOptionChange
}) {
const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', (url) => guiURLString(url, { useLocalhostName: useSubdomainProxy }))
const onCustomGatewayUrlChange = onOptionChange('customGatewayUrl', (url) => guiURLString(url, { useLocalhostName: useSubdomains }))
const onUseCustomGatewayChange = onOptionChange('useCustomGateway')
const onUseSubdomainProxyChange = onOptionChange('useSubdomainProxy')
const onUseSubdomainProxyChange = onOptionChange('useSubdomains')
const onPublicGatewayUrlChange = onOptionChange('publicGatewayUrl', guiURLString)
const onPublicSubdomainGatewayUrlChange = onOptionChange('publicSubdomainGatewayUrl', guiURLString)
const onNoIntegrationsHostnamesChange = onOptionChange('noIntegrationsHostnames', hostTextToArray)
Expand Down Expand Up @@ -113,18 +113,18 @@ function gatewaysForm ({
` : null}
${supportRedirectToCustomGateway ? html`
<div>
<label for="useSubdomainProxy">
<label for="useSubdomains">
<dl>
<dt>${browser.i18n.getMessage('option_useSubdomainProxy_title')}</dt>
<dt>${browser.i18n.getMessage('option_useSubdomains_title')}</dt>
<dd>
${browser.i18n.getMessage('option_useSubdomainProxy_description')}
${browser.i18n.getMessage('option_useSubdomains_description')}
<p><a href="https://docs.ipfs.io/guides/guides/addressing/#subdomain-gateway" target="_blank">
${browser.i18n.getMessage('option_legend_readMore')}
</a></p>
</dd>
</dl>
</label>
<div>${switchToggle({ id: 'useSubdomainProxy', checked: useSubdomainProxy, onchange: onUseSubdomainProxyChange })}</div>
<div>${switchToggle({ id: 'useSubdomains', checked: useSubdomains, onchange: onUseSubdomainProxyChange })}</div>
</div>
` : null}
${supportRedirectToCustomGateway ? html`
Expand Down
2 changes: 1 addition & 1 deletion add-on/src/options/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ module.exports = function optionsPage (state, emit) {
ipfsNodeType: state.options.ipfsNodeType,
customGatewayUrl: state.options.customGatewayUrl,
useCustomGateway: state.options.useCustomGateway,
useSubdomainProxy: state.options.useSubdomainProxy,
useSubdomains: state.options.useSubdomains,
publicGatewayUrl: state.options.publicGatewayUrl,
publicSubdomainGatewayUrl: state.options.publicSubdomainGatewayUrl,
noIntegrationsHostnames: state.options.noIntegrationsHostnames,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"ipfs-postmsg-proxy": "3.1.1",
"ipfsx": "0.17.0",
"is-fqdn": "1.0.1",
"is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz",
"is-ipfs": "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz",
"is-svg": "4.2.0",
"it-to-stream": "0.1.1",
"lru-cache": "5.1.1",
Expand Down
2 changes: 1 addition & 1 deletion test/functional/lib/ipfs-request-gateway-redirect.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ describe('modifyRequest.onBeforeRequest:', function () {
})
it('should be redirected to localhost (subdomain in go-ipfs >0.5) if type=main_frame and 127.0.0.1 (path gw) is used un URL', function () {
state.redirect = true
state.useSubdomainProxy = true
state.useSubdomains = true
expect(state.gwURL.hostname).to.equal('localhost')
const cid = 'QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR'
const request = url2request(`http://127.0.0.1:8080/ipfs/${cid}?arg=val#hash`)
Expand Down
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7931,9 +7931,9 @@ is-ip@^3.1.0:
dependencies:
ip-regex "^4.0.0"

"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz":
"is-ipfs@https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz":
version "0.6.3"
resolved "https://github.com/ipfs/is-ipfs/tarball/d9e7082587595a5c7a192405342fae18865c33f9/is-ipfs.tar.gz#733850d100cb80d08d251706d4b91ab14b58bd56"
resolved "https://github.com/ipfs/is-ipfs/tarball/d5717e910d864d738faf39480897342c7cbf065d/is-ipfs.tar.gz#c3f2f4d5423be1bfff4712488c742eb89d5f7ac0"
dependencies:
bs58 "^4.0.1"
cids "~0.7.0"
Expand Down

0 comments on commit bfa59c3

Please sign in to comment.