Skip to content

Commit

Permalink
feat(firefox>59): no prefix for redir protocols
Browse files Browse the repository at this point in the history
  • Loading branch information
lidel committed Mar 2, 2018
1 parent 2af5578 commit 70e630d
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 36 deletions.
29 changes: 22 additions & 7 deletions add-on/manifest.json
Expand Up @@ -14,7 +14,7 @@
"applications": {
"gecko": {
"id": "ipfs-firefox-addon@lidel.org",
"strict_min_version": "58.0"
"strict_min_version": "59.0"
}
},
"permissions": [
Expand Down Expand Up @@ -67,18 +67,33 @@
"protocol_handlers": [
{
"protocol": "web+dweb",
"name": "IPFS Add-On: DWEB protocol handler",
"uriTemplate": "https://ipfs.io/%s"
"name": "IPFS Companion: DWEB Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
},
{
"protocol": "web+ipns",
"name": "IPFS Add-On: IPNS protocol handler",
"uriTemplate": "https://ipfs.io/%s"
"name": "IPFS Companion: IPNS Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
},
{
"protocol": "web+ipfs",
"name": "IPFS Add-On: IPFS protocol handler",
"uriTemplate": "https://ipfs.io/%s"
"name": "IPFS Companion: IPFS Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
},
{
"protocol": "dweb",
"name": "IPFS Companion: DWEB Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
},
{
"protocol": "ipns",
"name": "IPFS Companion: IPNS Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
},
{
"protocol": "ipfs",
"name": "IPFS Companion: IPFS Protocol Handler",
"uriTemplate": "https://ipfs.io/#redirect/%s"
}
],
"content_security_policy": "script-src 'self'; object-src 'self'; frame-src 'self';",
Expand Down
36 changes: 24 additions & 12 deletions add-on/src/lib/ipfs-request.js
Expand Up @@ -27,9 +27,9 @@ function createRequestModifier (getState, dnsLink, ipfsPathValidator) {
}

// handler for protocol_handlers from manifest.json
if (webPlusProtocolRequest(request)) {
if (redirectingProtocolRequest(request)) {
// fix path passed via custom protocol
const fix = normalizedWebPlusRequest(request, state.pubGwURLString)
const fix = normalizedRedirectingProtocolRequest(request, state.pubGwURLString)
if (fix) {
return fix
}
Expand Down Expand Up @@ -71,28 +71,40 @@ function redirectToGateway (requestUrl, state) {
return { redirectUrl: url.toString() }
}

// PROTOCOL HANDLERS: web+ in Firefox (protocol_handlers from manifest.json)
// REDIRECT-BASED PROTOCOL HANDLERS
// This API is available only Firefox (protocol_handlers from manifest.json)
// Background: https://github.com/ipfs-shipyard/ipfs-companion/issues/164#issuecomment-282513891
// Notes on removal of web+ in Firefox 59: https://github.com/ipfs-shipyard/ipfs-companion/issues/164#issuecomment-355708883
// ===================================================================

const webPlusProtocolHandler = 'https://ipfs.io/web%2B'
// This is just a placeholder that we had to provide -- removed in normalizedRedirectingProtocolRequest()
const redirectingProtocolHandler = 'https://ipfs.io/#redirect/'

function webPlusProtocolRequest (request) {
return request.url.startsWith(webPlusProtocolHandler)
function redirectingProtocolRequest (request) {
return request.url.startsWith(redirectingProtocolHandler)
}

function normalizedWebPlusRequest (request, pubGwUrl) {
const oldPath = decodeURIComponent(new URL(request.url).pathname)
function normalizedRedirectingProtocolRequest (request, pubGwUrl) {
const oldPath = decodeURIComponent(new URL(request.url).hash)
let path = oldPath
path = path.replace(/^\/web\+dweb:\//i, '/') // web+dweb:/ipfs/Qm → /ipfs/Qm
path = path.replace(/^\/web\+ipfs:\/\//i, '/ipfs/') // web+ipfs://Qm → /ipfs/Qm
path = path.replace(/^\/web\+ipns:\/\//i, '/ipns/') // web+ipns://Qm → /ipns/Qm
// prefixed (Firefox < 59)
path = path.replace(/^#redirect\/web\+dweb:\//i, '/') // web+dweb:/ipfs/Qm → /ipfs/Qm
path = path.replace(/^#redirect\/web\+ipfs:\/\//i, '/ipfs/') // web+ipfs://Qm → /ipfs/Qm
path = path.replace(/^#redirect\/web\+ipns:\/\//i, '/ipns/') // web+ipns://Qm → /ipns/Qm
// without prefix (Firefox >= 59)
path = path.replace(/^#redirect\/dweb:\//i, '/') // dweb:/ipfs/Qm → /ipfs/Qm
path = path.replace(/^#redirect\/ipfs:\/\//i, '/ipfs/') // ipfs://Qm → /ipfs/Qm
path = path.replace(/^#redirect\/ipns:\/\//i, '/ipns/') // ipns://Qm → /ipns/Qm
// console.log(`oldPath: '${oldPath}' new: '${path}'`)
if (oldPath !== path && IsIpfs.path(path)) {
return { redirectUrl: urlAtPublicGw(path, pubGwUrl) }
}
return null
}

// PROTOCOL HANDLERS: UNIVERSAL FALLBACK FOR UNHANDLED PROTOCOLS
// 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
// ===================================================================

const unhandledIpfsRE = /=(?:web%2B|)(ipfs(?=%3A%2F%2F)|ipns(?=%3A%2F%2F)|dweb(?=%3A%2Fip[f|n]s))%3A(?:%2F%2F|%2F)([^&]+)/
Expand Down
60 changes: 48 additions & 12 deletions test/functional/lib/ipfs-request.test.js
Expand Up @@ -153,47 +153,83 @@ describe('modifyRequest', function () {
state.ipfsNodeType = nodeType
})
describe(`with ${nodeType} node:`, function () {
describe('request made via "web+" handler from manifest.json/protocol_handlers', function () {
// requests done with custom protocol handler are always normalized to public gateway
describe('request made via redirect-based protocol handler from manifest.json/protocol_handlers', function () {
// Note: requests done with custom protocol handler are always normalized to public gateway
// (if external node is enabled, redirect will happen in next iteration of modifyRequest)

// without web+ prefix (Firefox > 59: https://github.com/ipfs-shipyard/ipfs-companion/issues/164#issuecomment-356301174)
it('should not be normalized if ipfs:/{CID}', function () {
const request = url2request('https://ipfs.io/#redirect/ipfs%3A%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if ipfs://{CID}', function () {
const request = url2request('https://ipfs.io/#redirect/ipfs%3A%2F%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
})
it('should not be normalized if ipns:/{foo}', function () {
const request = url2request('https://ipfs.io/#redirect/ipns%3A%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if ipns://{foo}', function () {
const request = url2request('https://ipfs.io/#redirect/ipns%3A%2F%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest(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://ipfs.io/#redirect/dweb%3A%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
})
it('should not be normalized if dweb://ipfs/{CID}', function () {
const request = url2request('https://ipfs.io/#redirect/dweb%3A%2F%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if dweb:/ipns/{foo}', function () {
const request = url2request('https://ipfs.io/#redirect/dweb%3A%2Fipns/ipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).equal('https://ipfs.io/ipns/ipfs.io?argTest#hashTest')
})
it('should not be normalized if dweb://ipns/{foo}', function () {
const request = url2request('https://ipfs.io/#redirect/dweb%3A%2F%2Fipns/ipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})

// web+ prefixed versions (Firefox < 59 and Chrome)
it('should not be normalized if web+ipfs:/{CID}', function () {
const request = url2request('https://ipfs.io/web%2Bipfs%3A%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bipfs%3A%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if web+ipfs://{CID}', function () {
const request = url2request('https://ipfs.io/web%2Bipfs%3A%2F%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bipfs%3A%2F%2FQmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
})
it('should not be normalized if web+ipns:/{foo}', function () {
const request = url2request('https://ipfs.io/web%2Bipns%3A%2Fipfs.io%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bipns%3A%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if web+ipns://{foo}', function () {
const request = url2request('https://ipfs.io/web%2Bipns%3A%2F%2Fipfs.io%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bipns%3A%2F%2Fipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).to.equal('https://ipfs.io/ipns/ipfs.io?argTest#hashTest')
})
it('should be normalized if web+dweb:/ipfs/{CID}', function () {
const request = url2request('https://ipfs.io/web%2Bdweb%3A%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bdweb%3A%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).to.equal('https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest')
})
it('should not be normalized if web+dweb://ipfs/{CID}', function () {
const request = url2request('https://ipfs.io/web%2Bdweb%3A%2F%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bdweb%3A%2F%2Fipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should be normalized if web+dweb:/ipns/{foo}', function () {
const request = url2request('https://ipfs.io/web%2Bdweb%3A%2Fipns/ipfs.io%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bdweb%3A%2Fipns/ipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request).redirectUrl).equal('https://ipfs.io/ipns/ipfs.io?argTest#hashTest')
})
it('should not be normalized if web+dweb://ipns/{foo}', function () {
const request = url2request('https://ipfs.io/web%2Bdweb%3A%2F%2Fipns/ipfs.io%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bdweb%3A%2F%2Fipns/ipfs.io%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should not be normalized if web+{foo}:/bar', function () {
const request = url2request('https://ipfs.io/web%2Bfoo%3A%2Fbar%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bfoo%3A%2Fbar%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
it('should not be normalized if web+{foo}://bar', function () {
const request = url2request('https://ipfs.io/web%2Bfoo%3A%2F%2Fbar%3FargTest%23hashTest')
const request = url2request('https://ipfs.io/#redirect/web%2Bfoo%3A%2F%2Fbar%3FargTest%23hashTest')
expect(modifyRequest(request)).to.equal(undefined)
})
})
Expand Down
14 changes: 9 additions & 5 deletions yarn.lock
Expand Up @@ -112,10 +112,14 @@ acorn@^4.0.3:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"

acorn@^5.0.0, acorn@^5.2.1, acorn@^5.4.0, acorn@^5.4.1:
acorn@^5.0.0, acorn@^5.4.0, acorn@^5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102"

acorn@^5.2.1:
version "5.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822"

adbkit-logcat@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/adbkit-logcat/-/adbkit-logcat-1.1.0.tgz#01d7f9b0cef9093a30bcb3b007efff301508962f"
Expand Down Expand Up @@ -2343,8 +2347,8 @@ epimetheus@^1.0.55:
prom-client "^10.0.0"

errno@^0.1.3, errno@~0.1.1:
version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
version "0.1.6"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.6.tgz#c386ce8a6283f14fc09563b71560908c9bf53026"
dependencies:
prr "~1.0.1"

Expand Down Expand Up @@ -9065,11 +9069,11 @@ trough@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.1.tgz#a9fd8b0394b0ae8fff82e0633a0a36ccad5b5f86"

tty-browserify@0.0.0:
tty-browserify@0.0.0, tty-browserify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"

tty-browserify@0.0.1, tty-browserify@~0.0.0:
tty-browserify@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"

Expand Down

0 comments on commit 70e630d

Please sign in to comment.