From 24869d5258e89bc4ec66fb43ec5c638ba156666c Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 5 Dec 2019 23:16:34 +0100 Subject: [PATCH 1/3] feat: opt-in DNSLink redirect In past, it was opt-out via redirect opt-out per hostname. This changes default behavior and disables redirect of DNSLink websites to local gateway, as noted in https://github.com/ipfs-shipyard/ipfs-companion/issues/701 Adds DNSLink section to Preferences screen. Closes #701, #667 --- add-on/_locales/en/messages.json | 20 +++++- add-on/src/lib/ipfs-companion.js | 1 + add-on/src/lib/ipfs-request.js | 7 +- add-on/src/lib/options.js | 1 + add-on/src/options/forms/dnslink-form.js | 70 +++++++++++++++++++ add-on/src/options/forms/experiments-form.js | 32 --------- add-on/src/options/page.js | 7 +- .../lib/ipfs-request-dnslink.test.js | 3 +- 8 files changed, 101 insertions(+), 40 deletions(-) create mode 100644 add-on/src/options/forms/dnslink-form.js diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index 047bd360e..863117a48 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -275,6 +275,18 @@ "message": "Redirect requests for IPFS resources to the Custom gateway", "description": "An option description on the Preferences screen (option_useCustomGateway_description)" }, + "option_dnslinkRedirect_title": { + "message": "Force load from Custom Gateway", + "description": "An option title on the Preferences screen (option_dnslinkRedirect_title)" + }, + "option_dnslinkRedirect_description": { + "message": "If global redirect is enabled, this will include DNSLink websites and redirect them to respective /ipns/{fqdn} paths at Custom Gateway", + "description": "An option description on the Preferences screen (option_dnslinkRedirect_description)" + }, + "option_dnslinkRedirect_warning": { + "message": "Redirecting to a path-based gateway breaks Origin-based security isolation of DNSLink website! Please leave this disabled unless you are aware of (and ok with) related risks.", + "description": "A warning on the Preferences screen, displayed when URL does not belong to Secure Context (option_customGatewayUrl_warning)" + }, "option_noRedirectHostnames_title": { "message": "Redirect Opt-Outs", "description": "An option title on the Preferences screen (option_noRedirectHostnames_title)" @@ -327,6 +339,10 @@ "message": "Toggle use of Custom Gateway when IPFS API availability changes", "description": "An option description on the Preferences screen (option_automaticMode_description)" }, + "option_header_dnslink": { + "message": "DNSLink", + "description": "A section header on the Preferences screen (option_header_dnslink)" + }, "option_header_experiments": { "message": "Experiments", "description": "A section header on the Preferences screen (option_header_experiments)" @@ -364,11 +380,11 @@ "description": "An option description on the Preferences screen (option_linkify_description)" }, "option_dnslinkPolicy_title": { - "message": "DNSLink Support", + "message": "DNSLink Lookup", "description": "An option title on the Preferences screen (option_dnslinkPolicy_title)" }, "option_dnslinkPolicy_description": { - "message": "Select DNS TXT lookup policy to load IPFS hosted sites over IPFS where possible", + "message": "Lookup policy for displaying context actions on websites with DNSLink", "description": "An option description on the Preferences screen (option_dnslinkPolicy_description)" }, "option_dnslinkPolicy_disabled": { diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 759a53222..da17bd7d4 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -676,6 +676,7 @@ module.exports = async function init () { case 'preloadAtPublicGateway': case 'openViaWebUI': case 'noRedirectHostnames': + case 'dnslinkRedirect': state[key] = change.newValue break } diff --git a/add-on/src/lib/ipfs-request.js b/add-on/src/lib/ipfs-request.js index 28ae1c2f8..76fb317f3 100644 --- a/add-on/src/lib/ipfs-request.js +++ b/add-on/src/lib/ipfs-request.js @@ -142,7 +142,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru return redirectToGateway(request.url, state, ipfsPathValidator) } // Detect dnslink using heuristics enabled in Preferences - if (state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { + if (state.dnslinkRedirect && state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { const dnslinkRedirect = dnslinkResolver.dnslinkRedirect(request.url) if (dnslinkRedirect && isSafeToRedirect(request, runtime)) { // console.log('onBeforeRequest.dnslinkRedirect', dnslinkRedirect) @@ -339,10 +339,9 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (header.name.toLowerCase() === 'x-ipfs-path' && isSafeToRedirect(request, runtime)) { // console.log('onHeadersReceived.request.responseHeaders', request.responseHeaders.length) const xIpfsPath = header.value - log(`detected x-ipfs-path for ${request.url}: ${xIpfsPath}`) // First: Check if dnslink heuristic yields any results // Note: this depends on which dnslink lookup policy is selecten in Preferences - if (state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { + if (state.dnslinkRedirect && state.dnslinkPolicy && dnslinkResolver.canLookupURL(request.url)) { // x-ipfs-path is a strong indicator of IPFS support // so we force dnslink lookup to pre-populate dnslink cache // in a way that works even when state.dnslinkPolicy !== 'enabled' @@ -358,7 +357,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru if (IsIpfs.ipnsPath(xIpfsPath)) { // Ignore unhandled IPNS path by this point // (means DNSLink is disabled so we don't want to make a redirect that works like DNSLink) - log(`onHeadersReceived: ignoring x-ipfs-path=${xIpfsPath} (dnslinkPolicy=false or missing DNS TXT record)`) + // log(`onHeadersReceived: ignoring x-ipfs-path=${xIpfsPath} (dnslinkRedirect=false, dnslinkPolicy=false or missing DNS TXT record)`) } else if (IsIpfs.ipfsPath(xIpfsPath)) { // It is possible that someone exposed /ipfs// under / // and our path-based onBeforeRequest heuristics were unable diff --git a/add-on/src/lib/options.js b/add-on/src/lib/options.js index dfc31076a..3dc5dad41 100644 --- a/add-on/src/lib/options.js +++ b/add-on/src/lib/options.js @@ -17,6 +17,7 @@ exports.optionDefaults = Object.freeze({ automaticMode: true, linkify: false, dnslinkPolicy: 'best-effort', + dnslinkRedirect: false, recoverFailedHttpRequests: true, detectIpfsPathHeader: true, preloadAtPublicGateway: true, diff --git a/add-on/src/options/forms/dnslink-form.js b/add-on/src/options/forms/dnslink-form.js new file mode 100644 index 000000000..dfbf77399 --- /dev/null +++ b/add-on/src/options/forms/dnslink-form.js @@ -0,0 +1,70 @@ +'use strict' +/* eslint-env browser, webextensions */ + +const browser = require('webextension-polyfill') +const html = require('choo/html') +const switchToggle = require('../../pages/components/switch-toggle') + +function dnslinkForm ({ + dnslinkPolicy, + dnslinkRedirect, + onOptionChange +}) { + const onDnslinkPolicyChange = onOptionChange('dnslinkPolicy') + const onDnslinkRedirectChange = onOptionChange('dnslinkRedirect') + + return html` +
+
+ ${browser.i18n.getMessage('option_header_dnslink')} +
+ + +
+
+ +
${switchToggle({ id: 'dnslinkRedirect', checked: dnslinkRedirect, onchange: onDnslinkRedirectChange })}
+
+
+
+ ` +} + +module.exports = dnslinkForm diff --git a/add-on/src/options/forms/experiments-form.js b/add-on/src/options/forms/experiments-form.js index c5e2a5e95..74150d50e 100644 --- a/add-on/src/options/forms/experiments-form.js +++ b/add-on/src/options/forms/experiments-form.js @@ -9,7 +9,6 @@ function experimentsForm ({ displayNotifications, catchUnhandledProtocols, linkify, - dnslinkPolicy, recoverFailedHttpRequests, detectIpfsPathHeader, ipfsProxy, @@ -20,7 +19,6 @@ function experimentsForm ({ const onDisplayNotificationsChange = onOptionChange('displayNotifications') const onCatchUnhandledProtocolsChange = onOptionChange('catchUnhandledProtocols') const onLinkifyChange = onOptionChange('linkify') - const onDnslinkPolicyChange = onOptionChange('dnslinkPolicy') const onrecoverFailedHttpRequestsChange = onOptionChange('recoverFailedHttpRequests') const onDetectIpfsPathHeaderChange = onOptionChange('detectIpfsPathHeader') const onIpfsProxyChange = onOptionChange('ipfsProxy') @@ -66,36 +64,6 @@ function experimentsForm ({
${switchToggle({ id: 'linkify', checked: linkify, onchange: onLinkifyChange })}
-
- - -
` } - // TODO: change "redirect on {fqdn}" to "disable on {fqdn}" and disable all integrations + /* TODO: change "redirect on {fqdn}" to "disable on {fqdn}" and disable all integrations + // removed per site toggle for now: ${renderSiteRedirectToggle()} const renderSiteRedirectToggle = () => { if (!isRedirectContext) return return html` @@ -83,10 +84,10 @@ function contextActions ({ })} ` } + */ return html`
${renderIpfsContextItems()} - ${renderSiteRedirectToggle()}
` }