Skip to content

Commit

Permalink
feat: normalize dweb: in href and src
Browse files Browse the repository at this point in the history
Content script detects IPFS-related protocols in `href` and `src` attributes of
Elements such as `<a>` or `<img>` and replaces them with URL at the
user-specified public HTTP gateway.  Note that if IPFS API is online, HTTP
request will be redirected to custom gateway.

Closes #286
  • Loading branch information
lidel committed Oct 9, 2017
1 parent 7759546 commit e710a90
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 2 deletions.
26 changes: 24 additions & 2 deletions add-on/src/lib/common.js
Expand Up @@ -460,8 +460,8 @@ function isIpfsPageActionsContext (url) {
}

async function onUpdatedTab (tabId, changeInfo, tab) {
if (tab && tab.url && !tab.url.startsWith('chrome://')) {
if (state.linkify && changeInfo.status === 'complete') {
if (changeInfo.status === 'complete' && tab.url && tab.url.startsWith('http')) {
if (state.linkify) {
console.log(`[ipfs-companion] Running linkfyDOM for ${tab.url}`)
try {
await browser.tabs.executeScript(tabId, {
Expand All @@ -480,6 +480,28 @@ async function onUpdatedTab (tabId, changeInfo, tab) {
console.error(`Unable to linkify DOM at '${tab.url}' due to`, error)
}
}
if (state.catchUnhandledProtocols) {
// console.log(`[ipfs-companion] Normalizing links with unhandled protocols at ${tab.url}`)
// See: https://github.com/ipfs/ipfs-companion/issues/286
try {
// pass the URL of user-preffered public gateway
await browser.tabs.executeScript(tabId, {
code: `window.ipfsCompanionPubGwURL = '${state.pubGwURLString}'`,
matchAboutBlank: false,
allFrames: true,
runAt: 'document_start'
})
// inject script that normalizes `href` and `src` containing unhandled protocols
await browser.tabs.executeScript(tabId, {
file: '/src/lib/normalizeLinksWithUnhandledProtocols.js',
matchAboutBlank: false,
allFrames: true,
runAt: 'document_end'
})
} catch (error) {
console.error(`Unable to normalize links at '${tab.url}' due to`, error)
}
}
}
}

Expand Down
93 changes: 93 additions & 0 deletions add-on/src/lib/normalizeLinksWithUnhandledProtocols.js
@@ -0,0 +1,93 @@
'use strict'
/* eslint-env browser, webextensions */

/*
* This content script detects IPFS-related protocols in `href` and `src`
* attributes and replaces them with URL at the user-specified public HTTP gateway.
* Note that if IPFS API is online, HTTP request will be redirected to custom gateway.
*
* For more background see: https://github.com/ipfs/ipfs-companion/issues/286
*
* Test page: http://bit.ly/2hXiuUz
*/

;(function (alreadyLoaded) {
if (alreadyLoaded) {
return
}

// Limit contentType to "text/plain" or "text/html"
if (document.contentType !== undefined && document.contentType !== 'text/plain' && document.contentType !== 'text/html') {
return
}

// prevent double init
window.ipfsCompanionNormalizedUnhandledProtocols = true

// XPath selects all elements that have `href` of `src` attribute starting with one of IPFS-related protocols
const xpath = ".//*[starts-with(@href, 'ipfs://') or starts-with(@href, 'ipns://') or starts-with(@href, 'dweb:') " +
" or starts-with(@src, 'ipfs://') or starts-with(@src, 'ipns://') or starts-with(@src, 'dweb:')]"

const pubGwURL = window.ipfsCompanionPubGwURL

function init () {
// initial run
normalizeTree(document.body)

// listen for future DOM changes
new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.type === 'childList') {
for (let addedNode of mutation.addedNodes) {
if (addedNode.nodeType === Node.ELEMENT_NODE) {
setTimeout(() => normalizeTree(addedNode), 0)
}
}
}
})
}).observe(document.body, {
characterData: false,
childList: true,
subtree: true
})
}

function normalizeElement (element) {
if (element.href) {
// console.log('normalizeElement.href: ' + element.href)
element.href = normalizeAddress(element.href)
} else if (element.src) {
// console.log('normalizeElement.src: ' + element.src)
element.src = normalizeAddress(element.src)
}
}

// replaces unhandled protocol with a regular URL at a public gateway
function normalizeAddress (addr) {
return addr
.replace(/^dweb:\//i, pubGwURL) // dweb:/ipfs/Qm → /ipfs/Qm
.replace(/^ipfs:\/\//i, `${pubGwURL}ipfs/`) // ipfs://Qm → /ipfs/Qm
.replace(/^ipns:\/\//i, `${pubGwURL}ipns/`) // ipns://Qm → /ipns/Qm
}

function normalizeTree (root) {
const xpathResult = document.evaluate(xpath, root, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
let i = 0
function continuation () {
let node = null
let counter = 0
while ((node = xpathResult.snapshotItem(i++))) {
const parent = node.parentNode
// Skip if no longer in visible DOM
if (!parent || !document.body.contains(node)) continue
normalizeElement(node)
if (++counter > 10) {
return setTimeout(continuation, 0)
}
}
}
window.requestAnimationFrame(continuation)
}

init()
}(window.ipfsCompanionNormalizedUnhandledProtocols))

0 comments on commit e710a90

Please sign in to comment.