Skip to content

Commit

Permalink
feat: support page actions for CID subdomains
Browse files Browse the repository at this point in the history
  • Loading branch information
lidel committed Jul 23, 2018
1 parent 0b5635a commit a0c0ca8
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 18 deletions.
2 changes: 1 addition & 1 deletion add-on/src/lib/ipfs-companion.js
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ module.exports = async function init () {
async function updatePageActionIndicator (tabId, url) {
// Chrome does not permit for both pageAction and browserAction to be enabled at the same time
// https://github.com/ipfs-shipyard/ipfs-companion/issues/398
if (runtime.isFirefox && ipfsPathValidator.validIpfsOrIpnsUrl(url)) {
if (runtime.isFirefox && ipfsPathValidator.isIpfsPageActionsContext(url)) {
if (url.startsWith(state.gwURLString) || url.startsWith(state.apiURLString)) {
await browser.pageAction.setIcon({ tabId: tabId, path: '/icons/ipfs-logo-on.svg' })
await browser.pageAction.setTitle({ tabId: tabId, title: browser.i18n.getMessage('pageAction_titleIpfsAtCustomGateway') })
Expand Down
14 changes: 12 additions & 2 deletions add-on/src/lib/ipfs-path.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,21 @@
const IsIpfs = require('is-ipfs')

function safeIpfsPath (urlOrPath) {
if (IsIpfs.subdomain(urlOrPath)) {
urlOrPath = subdomainToIpfsPath(urlOrPath)
}
// better safe than sorry: https://github.com/ipfs/ipfs-companion/issues/303
return decodeURIComponent(urlOrPath.replace(/^.*(\/ip(f|n)s\/.+)$/, '$1'))
}

function subdomainToIpfsPath (urlString) {
const url = new URL(urlString)
const fqdn = url.hostname.split('.')
const cid = fqdn[0]
const protocol = fqdn[1]
return `/${protocol}/${cid}${url.pathname}`
}

exports.safeIpfsPath = safeIpfsPath

function urlAtPublicGw (path, pubGwUrl) {
Expand Down Expand Up @@ -41,9 +52,8 @@ function createIpfsPathValidator (getState, dnsLink) {
},

// Test if actions such as 'copy URL', 'pin/unpin' should be enabled for the URL
// (we explicitly disable IPNS for now as there is no support for pins)
isIpfsPageActionsContext (url) {
return IsIpfs.url(url) && !url.startsWith(getState().apiURLString)
return (IsIpfs.url(url) && !url.startsWith(getState().apiURLString)) || IsIpfs.subdomain(url)
}
}

Expand Down
10 changes: 5 additions & 5 deletions add-on/src/popup/browser-action/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ module.exports = (state, emitter) => {

try {
const ipfs = await getIpfsApi()
const currentPath = await resolveToIPFS(ipfs, new URL(state.currentTab.url).pathname)
const currentPath = await resolveToIPFS(ipfs, state.currentTab.url)
const pinResult = await ipfs.pin.add(currentPath, { recursive: true })
console.log('ipfs.pin.add result', pinResult)
state.isPinned = true
Expand All @@ -90,7 +90,7 @@ module.exports = (state, emitter) => {

try {
const ipfs = await getIpfsApi()
const currentPath = await resolveToIPFS(ipfs, new URL(state.currentTab.url).pathname)
const currentPath = await resolveToIPFS(ipfs, state.currentTab.url)
const result = await ipfs.pin.rm(currentPath, {recursive: true})
state.isPinned = false
console.log('ipfs.pin.rm result', result)
Expand Down Expand Up @@ -244,7 +244,7 @@ module.exports = (state, emitter) => {
// skip update if there is an ongoing pin or unpin
if (state.isPinning || state.isUnPinning) return
try {
const currentPath = await resolveToIPFS(ipfs, new URL(status.currentTab.url).pathname)
const currentPath = await resolveToIPFS(ipfs, status.currentTab.url)
const response = await ipfs.pin.ls(currentPath, {quiet: true})
console.log(`positive ipfs.pin.ls for ${currentPath}: ${JSON.stringify(response)}`)
state.isPinned = true
Expand Down Expand Up @@ -273,8 +273,8 @@ async function getIpfsApi () {
return (bg && bg.ipfsCompanion) ? bg.ipfsCompanion.ipfs : null
}

async function resolveToIPFS (ipfs, path) {
path = safeIpfsPath(path) // https://github.com/ipfs/ipfs-companion/issues/303
async function resolveToIPFS (ipfs, urlOrPath) {
let path = safeIpfsPath(urlOrPath) // https://github.com/ipfs/ipfs-companion/issues/303
if (/^\/ipns/.test(path)) {
const response = await ipfs.name.resolve(path, {recursive: true, nocache: false})
return response.Path
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
"ipfs-css": "0.5.2",
"ipfs-http-response": "0.1.2",
"ipfs-postmsg-proxy": "3.0.0",
"is-ipfs": "0.3.2",
"is-ipfs": "0.4.2",
"is-svg": "3.0.0",
"lru_map": "0.3.3",
"mime-types": "2.1.18",
Expand Down
20 changes: 20 additions & 0 deletions test/functional/lib/ipfs-path.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,24 @@ describe('ipfs-path.js', function () {
})
})
})
describe('isIpfsPageActionsContext', function () {
it('should return true for URL at IPFS Gateway', function () {
const url = 'https://ipfs.io/ipfs/QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR?argTest#hashTest'
expect(ipfsPathValidator.isIpfsPageActionsContext(url)).to.equal(true)
})
it('should return true for URL at IPFS Gateway with Base32 CIDv1 in subdomain', function () {
// context-actions are shown on publick gateways that use CID in subdomain as well
const url = 'http://bafkreigh2akiscaildcqabsyg3dfr6chu3fgpregiymsck7e7aqa4s52zy.ipfs.dweb.link/'
expect(ipfsPathValidator.isIpfsPageActionsContext(url)).to.equal(true)
})
it('should return false for URL at IPFS Gateway with Base58 CIDv0 in subdomain', function () {
// context-actions are shown on publick gateways that use CID in subdomain as well
const url = 'http://QmbWqxBEKC3P8tqsKc98xmWNzrzDtRLMiMPL8wBuTGsMnR.ipfs.dweb.link/'
expect(ipfsPathValidator.isIpfsPageActionsContext(url)).to.equal(false)
})
it('should return false for non-IPFS URL', function () {
const url = 'https://ipfs.io/ipfs/NotACid?argTest#hashTest'
expect(ipfsPathValidator.isIpfsPageActionsContext(url)).to.equal(false)
})
})
})
15 changes: 15 additions & 0 deletions test/functional/lib/ipfs-request.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,21 @@ describe('modifyRequest.onBeforeRequest', function () {
})
})

describe('request to FQDN with valid CID in subdomain', function () {
// we do not touch such requests for now, as HTTP-based local node usually can't provide the same origin-based guarantees
// we will redirect subdomains to ipfs:// when native handler is available
it('should be left untouched for IPFS', function () {
state.redirect = true
const request = url2request('http://bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge.ipfs.dweb.link/')
expect(modifyRequest.onBeforeRequest(request)).to.equal(undefined)
})
it('should be left untouched for IPNS', function () {
state.redirect = true
const request = url2request('http://bafybeigxjv2o4jse2lajbd5c7xxl5rluhyqg5yupln42252e5tcao7hbge.ipns.dweb.link/')
expect(modifyRequest.onBeforeRequest(request)).to.equal(undefined)
})
})

describe('request to FQDN with dnslink experiment enabled', function () {
let activeGateway
beforeEach(function () {
Expand Down
27 changes: 18 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1602,16 +1602,16 @@ browserslist@^3.2.6:
caniuse-lite "^1.0.30000844"
electron-to-chromium "^1.3.47"

bs58@=2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.0.tgz#72b713bed223a0ac518bbda0e3ce3f4817f39eb5"

bs58@^4.0.0, bs58@^4.0.1:
bs58@4.0.1, bs58@^4.0.0, bs58@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
dependencies:
base-x "^3.0.2"

bs58@=2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-2.0.0.tgz#72b713bed223a0ac518bbda0e3ce3f4817f39eb5"

bs58check@<3.0.0, bs58check@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.1.tgz#8a5d0e587af97b784bf9cbf1b29f454d82bc0222"
Expand Down Expand Up @@ -1994,7 +1994,7 @@ ci-info@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"

cids@^0.5.2, cids@^0.5.3, cids@~0.5.1, cids@~0.5.2, cids@~0.5.3:
cids@0.5.3, cids@^0.5.2, cids@^0.5.3, cids@~0.5.1, cids@~0.5.2, cids@~0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/cids/-/cids-0.5.3.tgz#9a25b697eb76faf807afcec35c4ab936edfbd0a4"
dependencies:
Expand Down Expand Up @@ -5329,7 +5329,16 @@ is-installed-globally@^0.1.0:
global-dirs "^0.1.0"
is-path-inside "^1.0.0"

is-ipfs@0.3.2, is-ipfs@~0.3.2:
is-ipfs@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-0.4.2.tgz#06a858769cbfdac39a3e0ed1ca157e3f3fcc84fc"
dependencies:
bs58 "4.0.1"
cids "0.5.3"
multibase "0.4.0"
multihashes "0.4.13"

is-ipfs@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-ipfs/-/is-ipfs-0.3.2.tgz#c4650b838e36fd0151de5896b2ff319fe8936182"
dependencies:
Expand Down Expand Up @@ -7016,7 +7025,7 @@ multiaddr@^5.0.0:
varint "^5.0.0"
xtend "^4.0.1"

multibase@~0.4.0:
multibase@0.4.0, multibase@~0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.4.0.tgz#1bdb62c82de0114f822a1d8751bcbee91cd2efba"
dependencies:
Expand All @@ -7041,7 +7050,7 @@ multicodec@~0.2.7:
dependencies:
varint "^5.0.0"

multihashes@^0.4.13, multihashes@~0.4.12, multihashes@~0.4.13, multihashes@~0.4.9:
multihashes@0.4.13, multihashes@^0.4.13, multihashes@~0.4.12, multihashes@~0.4.13, multihashes@~0.4.9:
version "0.4.13"
resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.13.tgz#d10bd71bd51d24aa894e2a6f1457146bb7bac125"
dependencies:
Expand Down

0 comments on commit a0c0ca8

Please sign in to comment.