From a4c9dce38fa4f23169874eb0952e6fc2ed65da4f Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 3 Apr 2020 02:05:48 +0200 Subject: [PATCH] refactor: use HTTP proxy for subdomains only on Firefox 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. --- add-on/_locales/en/messages.json | 12 ++++++------ add-on/manifest.chromium.json | 13 +++++++++++++ add-on/manifest.common.json | 14 -------------- add-on/manifest.firefox.json | 14 ++++++++++++++ add-on/src/lib/http-proxy.js | 14 +++++++++----- add-on/src/lib/ipfs-companion.js | 19 +++++++++---------- add-on/src/lib/ipfs-request.js | 2 +- add-on/src/lib/options.js | 6 +++--- add-on/src/lib/state.js | 2 +- add-on/src/options/forms/gateways-form.js | 14 +++++++------- add-on/src/options/page.js | 2 +- .../lib/ipfs-request-gateway-redirect.test.js | 2 +- 12 files changed, 65 insertions(+), 49 deletions(-) diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index 4434db2ac..0b8dcf243 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -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", diff --git a/add-on/manifest.chromium.json b/add-on/manifest.chromium.json index 81a8f2767..9949e6e1d 100644 --- a/add-on/manifest.chromium.json +++ b/add-on/manifest.chromium.json @@ -1,4 +1,17 @@ { "minimum_chrome_version": "72", + "permissions": [ + "", + "idle", + "tabs", + "notifications", + "storage", + "unlimitedStorage", + "contextMenus", + "clipboardWrite", + "webNavigation", + "webRequest", + "webRequestBlocking" + ], "incognito": "not_allowed" } diff --git a/add-on/manifest.common.json b/add-on/manifest.common.json index 8aa8f9f80..947138058 100644 --- a/add-on/manifest.common.json +++ b/add-on/manifest.common.json @@ -11,20 +11,6 @@ "38": "icons/png/ipfs-logo-on_38.png", "128": "icons/png/ipfs-logo-on_128.png" }, - "permissions": [ - "", - "idle", - "tabs", - "notifications", - "storage", - "unlimitedStorage", - "contextMenus", - "clipboardWrite", - "proxy", - "webNavigation", - "webRequest", - "webRequestBlocking" - ], "background": { "page": "dist/background/background.html" }, diff --git a/add-on/manifest.firefox.json b/add-on/manifest.firefox.json index f3229ccd5..1cb644983 100644 --- a/add-on/manifest.firefox.json +++ b/add-on/manifest.firefox.json @@ -18,6 +18,20 @@ "default_title": "__MSG_pageAction_titleNonIpfs__", "default_popup": "dist/popup/page-action/index.html" }, + "permissions": [ + "", + "idle", + "tabs", + "notifications", + "proxy", + "storage", + "unlimitedStorage", + "contextMenus", + "clipboardWrite", + "webNavigation", + "webRequest", + "webRequestBlocking" + ], "content_scripts": [ ], "protocol_handlers": [ { diff --git a/add-on/src/lib/http-proxy.js b/add-on/src/lib/http-proxy.js index 1e7c553b5..0427147bd 100644 --- a/add-on/src/lib/http-proxy.js +++ b/add-on/src/lib/http-proxy.js @@ -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 @@ -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. diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 08e7b54df..47ef9fa25 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -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 diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index 3645ef958..7dca61366 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -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 } } diff --git a/add-on/src/lib/options.js b/add-on/src/lib/options.js index 8e7be5c7f..64c56f22e 100644 --- a/add-on/src/lib/options.js +++ b/add-on/src/lib/options.js @@ -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, @@ -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 }) } diff --git a/add-on/src/lib/state.js b/add-on/src/lib/state.js index 48523a76b..992271ee4 100644 --- a/add-on/src/lib/state.js +++ b/add-on/src/lib/state.js @@ -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 diff --git a/add-on/src/options/forms/gateways-form.js b/add-on/src/options/forms/gateways-form.js index dbeec8cb1..ab4c2bdc0 100644 --- a/add-on/src/options/forms/gateways-form.js +++ b/add-on/src/options/forms/gateways-form.js @@ -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) @@ -113,18 +113,18 @@ function gatewaysForm ({ ` : null} ${supportRedirectToCustomGateway ? html`
-
` : null} ${supportRedirectToCustomGateway ? html` diff --git a/add-on/src/options/page.js b/add-on/src/options/page.js index e3173fae0..57a17a71a 100644 --- a/add-on/src/options/page.js +++ b/add-on/src/options/page.js @@ -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, diff --git a/test/functional/lib/ipfs-request-gateway-redirect.test.js b/test/functional/lib/ipfs-request-gateway-redirect.test.js index 7eb61cdae..81b8ccdeb 100644 --- a/test/functional/lib/ipfs-request-gateway-redirect.test.js +++ b/test/functional/lib/ipfs-request-gateway-redirect.test.js @@ -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`)