aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts
diff options
context:
space:
mode:
authorkumavis <kumavis@users.noreply.github.com>2018-10-21 17:48:15 +0800
committerGitHub <noreply@github.com>2018-10-21 17:48:15 +0800
commit6d09f60bbfe5ee737ff7a138260cc33e3db5ca46 (patch)
treea0642d45087aca57ad3e06bd93dac6bfc042f233 /app/scripts
parentb0c649a4e3c68293e08e764bbf4d53939df88e2d (diff)
downloadtangerine-wallet-browser-6d09f60bbfe5ee737ff7a138260cc33e3db5ca46.tar.gz
tangerine-wallet-browser-6d09f60bbfe5ee737ff7a138260cc33e3db5ca46.tar.zst
tangerine-wallet-browser-6d09f60bbfe5ee737ff7a138260cc33e3db5ca46.zip
ens-ipfs - refactor for readability (#5568)
* ens-ipfs - refactor for readability * ens-ipfs - use official ipfs gateway for better performance * lint - remove unused code * ens-ipfs - support path and search * lint - gotta love that linter * ens-ipfs - improve loading page formatting * ens-ipfs - loading - redirect to 404 after 1 min timeout * ens-ipfs - destructure for cleaner code
Diffstat (limited to 'app/scripts')
-rw-r--r--app/scripts/background.js10
-rw-r--r--app/scripts/lib/ens-ipfs/contracts/registrar.js (renamed from app/scripts/lib/contracts/registrar.js)0
-rw-r--r--app/scripts/lib/ens-ipfs/contracts/resolver.js (renamed from app/scripts/lib/contracts/resolver.js)0
-rw-r--r--app/scripts/lib/ens-ipfs/resolver.js54
-rw-r--r--app/scripts/lib/ens-ipfs/setup.js63
-rw-r--r--app/scripts/lib/ipfsContent.js46
-rw-r--r--app/scripts/lib/resolver.js71
7 files changed, 120 insertions, 124 deletions
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 509a0001d..6b3ac2664 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -29,7 +29,7 @@ const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
const EdgeEncryptor = require('./edge-encryptor')
const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code')
const getObjStructure = require('./lib/getObjStructure')
-const ipfsContent = require('./lib/ipfsContent.js')
+const setupEnsIpfsResolver = require('./lib/ens-ipfs/setup')
const {
ENVIRONMENT_TYPE_POPUP,
@@ -58,7 +58,6 @@ const isIE = !!document.documentMode
// Edge 20+
const isEdge = !isIE && !!window.StyleMedia
-let ipfsHandle
let popupIsOpen = false
let notificationIsOpen = false
const openMetamaskTabsIDs = {}
@@ -164,7 +163,6 @@ async function initialize () {
const initLangCode = await getFirstPreferredLangCode()
await setupController(initState, initLangCode)
log.debug('MetaMask initialization complete.')
- ipfsHandle = ipfsContent(initState.NetworkController.provider)
}
//
@@ -269,10 +267,8 @@ function setupController (initState, initLangCode) {
})
global.metamaskController = controller
- controller.networkController.on('networkDidChange', () => {
- ipfsHandle && ipfsHandle.remove()
- ipfsHandle = ipfsContent(controller.networkController.providerStore.getState())
- })
+ const provider = controller.provider
+ setupEnsIpfsResolver({ provider })
// report failed transactions to Sentry
controller.txController.on(`tx:status-update`, (txId, status) => {
diff --git a/app/scripts/lib/contracts/registrar.js b/app/scripts/lib/ens-ipfs/contracts/registrar.js
index 99ca24458..99ca24458 100644
--- a/app/scripts/lib/contracts/registrar.js
+++ b/app/scripts/lib/ens-ipfs/contracts/registrar.js
diff --git a/app/scripts/lib/contracts/resolver.js b/app/scripts/lib/ens-ipfs/contracts/resolver.js
index 1bf3f90ce..1bf3f90ce 100644
--- a/app/scripts/lib/contracts/resolver.js
+++ b/app/scripts/lib/ens-ipfs/contracts/resolver.js
diff --git a/app/scripts/lib/ens-ipfs/resolver.js b/app/scripts/lib/ens-ipfs/resolver.js
new file mode 100644
index 000000000..fe2dc1134
--- /dev/null
+++ b/app/scripts/lib/ens-ipfs/resolver.js
@@ -0,0 +1,54 @@
+const namehash = require('eth-ens-namehash')
+const multihash = require('multihashes')
+const Eth = require('ethjs-query')
+const EthContract = require('ethjs-contract')
+const registrarAbi = require('./contracts/registrar')
+const resolverAbi = require('./contracts/resolver')
+
+module.exports = resolveEnsToIpfsContentId
+
+
+async function resolveEnsToIpfsContentId ({ provider, name }) {
+ const eth = new Eth(provider)
+ const hash = namehash.hash(name)
+ const contract = new EthContract(eth)
+ // lookup registrar
+ const chainId = Number.parseInt(await eth.net_version(), 10)
+ const registrarAddress = getRegistrarForChainId(chainId)
+ if (!registrarAddress) {
+ throw new Error(`EnsIpfsResolver - no known ens-ipfs registrar for chainId "${chainId}"`)
+ }
+ const Registrar = contract(registrarAbi).at(registrarAddress)
+ // lookup resolver
+ const resolverLookupResult = await Registrar.resolver(hash)
+ const resolverAddress = resolverLookupResult[0]
+ if (hexValueIsEmpty(resolverAddress)) {
+ throw new Error(`EnsIpfsResolver - no resolver found for name "${name}"`)
+ }
+ const Resolver = contract(resolverAbi).at(resolverAddress)
+ // lookup content id
+ const contentLookupResult = await Resolver.content(hash)
+ const contentHash = contentLookupResult[0]
+ if (hexValueIsEmpty(contentHash)) {
+ throw new Error(`EnsIpfsResolver - no content ID found for name "${name}"`)
+ }
+ const nonPrefixedHex = contentHash.slice(2)
+ const buffer = multihash.fromHexString(nonPrefixedHex)
+ const contentId = multihash.toB58String(multihash.encode(buffer, 'sha2-256'))
+ return contentId
+}
+
+function hexValueIsEmpty(value) {
+ return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value)
+}
+
+function getRegistrarForChainId (chainId) {
+ switch (chainId) {
+ // mainnet
+ case 1:
+ return '0x314159265dd8dbb310642f98f50c066173c1259b'
+ // ropsten
+ case 3:
+ return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
+ }
+}
diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js
new file mode 100644
index 000000000..45eb1ce14
--- /dev/null
+++ b/app/scripts/lib/ens-ipfs/setup.js
@@ -0,0 +1,63 @@
+const urlUtil = require('url')
+const extension = require('extensionizer')
+const resolveEnsToIpfsContentId = require('./resolver.js')
+
+const supportedTopLevelDomains = ['eth']
+
+module.exports = setupEnsIpfsResolver
+
+function setupEnsIpfsResolver({ provider }) {
+
+ // install listener
+ const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
+ extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns })
+
+ // return api object
+ return {
+ // uninstall listener
+ remove () {
+ extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail)
+ },
+ }
+
+ async function webRequestDidFail (details) {
+ const { tabId, url } = details
+ // ignore requests that are not associated with tabs
+ if (tabId === -1) return
+ // parse ens name
+ const urlData = urlUtil.parse(url)
+ const { hostname: name, path, search } = urlData
+ const domainParts = name.split('.')
+ const topLevelDomain = domainParts[domainParts.length - 1]
+ // if unsupported TLD, abort
+ if (!supportedTopLevelDomains.includes(topLevelDomain)) return
+ // otherwise attempt resolve
+ attemptResolve({ tabId, name, path, search })
+ }
+
+ async function attemptResolve({ tabId, name, path, search }) {
+ extension.tabs.update(tabId, { url: `loading.html` })
+ try {
+ const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name })
+ let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}`
+ try {
+ // check if ipfs gateway has result
+ const response = await fetch(url, { method: 'HEAD' })
+ // if failure, redirect to 404 page
+ if (response.status !== 200) {
+ extension.tabs.update(tabId, { url: '404.html' })
+ return
+ }
+ // otherwise redirect to the correct page
+ extension.tabs.update(tabId, { url })
+ } catch (err) {
+ console.warn(err)
+ // if HEAD fetch failed, redirect so user can see relevant error page
+ extension.tabs.update(tabId, { url })
+ }
+ } catch (err) {
+ console.warn(err)
+ extension.tabs.update(tabId, { url: `error.html?name=${name}` })
+ }
+ }
+}
diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js
deleted file mode 100644
index 8b08453c4..000000000
--- a/app/scripts/lib/ipfsContent.js
+++ /dev/null
@@ -1,46 +0,0 @@
-const extension = require('extensionizer')
-const resolver = require('./resolver.js')
-
-module.exports = function (provider) {
- function ipfsContent (details) {
- const name = details.url.substring(7, details.url.length - 1)
- let clearTime = null
- if (/^.+\.eth$/.test(name) === false) return
-
- extension.tabs.query({active: true}, tab => {
- extension.tabs.update(tab.id, { url: 'loading.html' })
-
- clearTime = setTimeout(() => {
- return extension.tabs.update(tab.id, { url: '404.html' })
- }, 60000)
-
- resolver.resolve(name, provider).then(ipfsHash => {
- clearTimeout(clearTime)
- let url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
- return fetch(url, { method: 'HEAD' }).then(response => response.status).then(statusCode => {
- if (statusCode !== 200) return extension.tabs.update(tab.id, { url: '404.html' })
- extension.tabs.update(tab.id, { url: url })
- })
- .catch(err => {
- url = 'https://ipfs.infura.io/ipfs/' + ipfsHash
- extension.tabs.update(tab.id, {url: url})
- return err
- })
- })
- .catch(err => {
- clearTimeout(clearTime)
- const url = err === 'unsupport' ? 'unsupport' : 'error'
- extension.tabs.update(tab.id, {url: `${url}.html?name=${name}`})
- })
- })
- return { cancel: true }
- }
-
- extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']})
-
- return {
- remove () {
- extension.webRequest.onErrorOccurred.removeListener(ipfsContent)
- },
- }
-}
diff --git a/app/scripts/lib/resolver.js b/app/scripts/lib/resolver.js
deleted file mode 100644
index ff0fed161..000000000
--- a/app/scripts/lib/resolver.js
+++ /dev/null
@@ -1,71 +0,0 @@
-const namehash = require('eth-ens-namehash')
-const multihash = require('multihashes')
-const HttpProvider = require('ethjs-provider-http')
-const Eth = require('ethjs-query')
-const EthContract = require('ethjs-contract')
-const registrarAbi = require('./contracts/registrar')
-const resolverAbi = require('./contracts/resolver')
-
-function ens (name, provider) {
- const eth = new Eth(new HttpProvider(getProvider(provider.type)))
- const hash = namehash.hash(name)
- const contract = new EthContract(eth)
- const Registrar = contract(registrarAbi).at(getRegistrar(provider.type))
- return new Promise((resolve, reject) => {
- if (provider.type === 'mainnet' || provider.type === 'ropsten') {
- Registrar.resolver(hash).then((address) => {
- if (address === '0x0000000000000000000000000000000000000000') {
- reject(null)
- } else {
- const Resolver = contract(resolverAbi).at(address['0'])
- return Resolver.content(hash)
- }
- }).then((contentHash) => {
- if (contentHash['0'] === '0x0000000000000000000000000000000000000000000000000000000000000000') reject(null)
- if (contentHash.ret !== '0x') {
- const hex = contentHash['0'].substring(2)
- const buf = multihash.fromHexString(hex)
- resolve(multihash.toB58String(multihash.encode(buf, 'sha2-256')))
- } else {
- reject(null)
- }
- })
- } else {
- return reject('unsupport')
- }
- })
-}
-
-function getProvider (type) {
- switch (type) {
- case 'mainnet':
- return 'https://mainnet.infura.io/'
- case 'ropsten':
- return 'https://ropsten.infura.io/'
- default:
- return 'http://localhost:8545/'
- }
-}
-
-function getRegistrar (type) {
- switch (type) {
- case 'mainnet':
- return '0x314159265dd8dbb310642f98f50c066173c1259b'
- case 'ropsten':
- return '0x112234455c3a32fd11230c42e7bccd4a84e02010'
- default:
- return '0x0000000000000000000000000000000000000000'
- }
-}
-
-module.exports.resolve = function (name, provider) {
- const path = name.split('.')
- const topLevelDomain = path[path.length - 1]
- if (topLevelDomain === 'eth' || topLevelDomain === 'test') {
- return ens(name, provider)
- } else {
- return new Promise((resolve, reject) => {
- reject(null)
- })
- }
-}