Skip to content

Commit

Permalink
feat: support ipfs://{dnslink} (#748)
Browse files Browse the repository at this point in the history
* fix: redirect-based handler vs no redirect on ipfs.io

Disabling redirect does it for all subdomains.
We use gateway.ipfs.io as intermediate step when handling
`ipfs://` in firefox, which resulted in a bizzarre edge case.

This change restores `ipfs://` handler when redirect on ipfs.io is
disabled.

* feat: support ipfs://{dnslink}

This adds support for resolving DNSLink via ipfs:// protocol handler
For now it is just a redirect to proper /ipns/ path, but should improve
UX in the long run.

Closes #534
  • Loading branch information
lidel authored Sep 11, 2019
1 parent 18be6b8 commit 7ba096d
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 7 deletions.
21 changes: 17 additions & 4 deletions add-on/src/lib/ipfs-request.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ log.error = debug('ipfs-companion:request:error')

const LRU = require('lru-cache')
const IsIpfs = require('is-ipfs')
const isFQDN = require('is-fqdn')
const { pathAtHttpGateway } = require('./ipfs-path')
const redirectOptOutHint = 'x-ipfs-companion-no-redirect'
const recoverableErrors = new Set([
Expand Down Expand Up @@ -74,7 +75,7 @@ function createRequestModifier (getState, dnslinkResolver, ipfsPathValidator, ru
const fqdn = new URL(request.url).hostname
const parentFqdn = parentUrl && parentUrl !== 'null' && request.url !== parentUrl ? new URL(parentUrl).hostname : null
if (state.noRedirectHostnames.some(optout =>
fqdn.endsWith(optout) || (parentFqdn && parentFqdn.endsWith(optout)
fqdn !== 'gateway.ipfs.io' && (fqdn.endsWith(optout) || (parentFqdn && parentFqdn.endsWith(optout))
))) {
ignore(request.requestId)
}
Expand Down Expand Up @@ -492,13 +493,24 @@ function normalizedRedirectingProtocolRequest (request, pubGwUrl) {
path = path.replace(/^#dweb:\//i, '/') // dweb:/ipfs/Qm → /ipfs/Qm
path = path.replace(/^#ipfs:\/\//i, '/ipfs/') // ipfs://Qm → /ipfs/Qm
path = path.replace(/^#ipns:\/\//i, '/ipns/') // ipns://Qm → /ipns/Qm
// console.log(`oldPath: '${oldPath}' new: '${path}'`)
// additional fixups of the final path
path = fixupDnslinkPath(path) // /ipfs/example.com → /ipns/example.com
if (oldPath !== path && IsIpfs.path(path)) {
return { redirectUrl: pathAtHttpGateway(path, pubGwUrl) }
}
return null
}

// idempotent /ipfs/example.com → /ipns/example.com
function fixupDnslinkPath (path) {
if (!(path && path.startsWith('/ipfs/'))) return path
const [, root] = path.match(/^\/ipfs\/([^/?#]+)/)
if (root && !IsIpfs.cid(root) && isFQDN(root)) {
return path.replace(/^\/ipfs\//, '/ipns/')
}
return path
}

// SEARCH-HIJACK HANDLERS: UNIVERSAL FALLBACK FOR UNHANDLED PROTOCOLS
// (Used in Chrome and other browsers that do not provide better alternatives)
// Background: https://github.com/ipfs-shipyard/ipfs-companion/issues/164#issuecomment-328374052
Expand All @@ -521,9 +533,10 @@ function unhandledIpfsPath (requestUrl) {
}

function normalizedUnhandledIpfsProtocol (request, pubGwUrl) {
const path = unhandledIpfsPath(request.url)
let path = unhandledIpfsPath(request.url)
path = fixupDnslinkPath(path) // /ipfs/example.com → /ipns/example.com
if (IsIpfs.path(path)) {
// replace search query with fake request to the public gateway
// replace search query with a request to a public gateway
// (will be redirected later, if needed)
return { redirectUrl: pathAtHttpGateway(path, pubGwUrl) }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use strict'
const { describe, it, before, beforeEach, after } = require('mocha')
// const sinon = require('sinon')
const { expect } = require('chai')
const { URL } = require('url')
const browser = require('sinon-chrome')
Expand Down Expand Up @@ -30,6 +29,7 @@ describe('modifyRequest.onBeforeRequest:', function () {
ipfsNodeType: 'external',
peerCount: 1,
redirect: true,
dnslinkPolicy: false, // dnslink test suite is in ipfs-request-dnslink.test.js
catchUnhandledProtocols: true,
gwURLString: 'http://127.0.0.1:8080',
pubGwURLString: 'https://ipfs.io'
Expand Down Expand Up @@ -66,14 +66,18 @@ describe('modifyRequest.onBeforeRequest:', function () {
const request = url2request('https://gateway.ipfs.io/ipfs/QmXQY7mKr28B964Uj4ouq3fPgkNLqzaKiajTA7surAiQuD#ipfs%3A%2F%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
})
it('should not be normalized if ipns:/{foo}', function () {
it('should not be normalized if ipns:/{fqdn}', function () {
const request = url2request('https://gateway.ipfs.io/ipfs/QmXQY7mKr28B964Uj4ouq3fPgkNLqzaKiajTA7surAiQuD#ipns%3A%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest.onBeforeRequest(request)).to.equal(undefined)
})
it('should be normalized if ipns://{foo}', function () {
it('should be normalized if ipns://{fqdn}', function () {
const request = url2request('https://gateway.ipfs.io/ipfs/QmXQY7mKr28B964Uj4ouq3fPgkNLqzaKiajTA7surAiQuD#ipns%3A%2F%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipns/ipfs.io?argTest#hashTest')
})
it('should be normalized if ipfs://{fqdn}', function () {
const request = url2request('https://gateway.ipfs.io/ipfs/QmXQY7mKr28B964Uj4ouq3fPgkNLqzaKiajTA7surAiQuD#ipfs%3A%2F%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipns/ipfs.io?argTest#hashTest')
})
it('should be normalized if dweb:/ipfs/{CID}', function () {
const request = url2request('https://gateway.ipfs.io/ipfs/QmXQY7mKr28B964Uj4ouq3fPgkNLqzaKiajTA7surAiQuD#dweb%3A%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
Expand Down Expand Up @@ -151,6 +155,10 @@ describe('modifyRequest.onBeforeRequest:', function () {
const request = url2request('https://duckduckgo.com/?q=ipns%3A%2F%2Fipns.io%2Findex.html%3Farg%3Dfoo%26bar%3Dbuzz%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipns/ipns.io/index.html?arg=foo&bar=buzz#hashTest')
})
it('should be normalized if ipfs://{fqdn}', function () {
const request = url2request('https://duckduckgo.com/?q=ipfs%3A%2F%2Fipns.io%2Findex.html%3Farg%3Dfoo%26bar%3Dbuzz%23hashTest')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipns/ipns.io/index.html?arg=foo&bar=buzz#hashTest')
})
it('should be normalized if dweb:/ipfs/{CID}', function () {
const request = url2request('https://duckduckgo.com/?q=dweb%3A%2Fipfs%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3Farg%3Dfoo%26bar%3Dbuzz%23hash&ia=software')
expect(modifyRequest.onBeforeRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?arg=foo&bar=buzz#hash')
Expand Down

0 comments on commit 7ba096d

Please sign in to comment.