Skip to content

Commit

Permalink
feat: add support to ipns resolve /ipns/<fqdn>
Browse files Browse the repository at this point in the history
fixes: ipfs#1918
  • Loading branch information
hugomrdias authored and lidel committed May 6, 2019
1 parent 752e904 commit 4901718
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 22 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
"ipld-raw": "^2.0.1",
"ipld-zcash": "~0.1.6",
"ipns": "~0.5.0",
"is-domain-name": "^1.0.1",
"is-ipfs": "~0.6.0",
"is-pull-stream": "~0.0.0",
"is-stream": "^1.1.0",
Expand Down
55 changes: 38 additions & 17 deletions src/core/components/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const parallel = require('async/parallel')
const human = require('human-to-milliseconds')
const crypto = require('libp2p-crypto')
const errcode = require('err-code')
const mergeOptions = require('merge-options')
const mh = require('multihashes')
const isDomain = require('is-domain-name')

const log = debug('ipfs:name')
log.error = debug('ipfs:name:error')
Expand Down Expand Up @@ -35,6 +38,16 @@ const keyLookup = (ipfsNode, kname, callback) => {
})
}

/**
* @typedef { import("../index") } IPFS
*/

/**
* IPNS - Inter-Planetary Naming System
*
* @param {IPFS} self
* @returns {Function}
*/
module.exports = function name (self) {
return {
/**
Expand Down Expand Up @@ -125,22 +138,15 @@ module.exports = function name (self) {
options = {}
}

options = options || {}
const nocache = options.nocache && options.nocache.toString() === 'true'
const recursive = options.recursive && options.recursive.toString() === 'true'
options = mergeOptions({
nocache: false,
recursive: false
}, options)

const offline = self._options.offline

if (!self.isOnline() && !offline) {
const errMsg = utils.OFFLINE_ERROR

log.error(errMsg)
return callback(errcode(errMsg, 'OFFLINE_ERROR'))
}

// TODO: params related logic should be in the core implementation

if (offline && nocache) {
if (offline && options.nocache) {
const error = 'cannot specify both offline and nocache'

log.error(error)
Expand All @@ -156,12 +162,27 @@ module.exports = function name (self) {
name = `/ipns/${name}`
}

const resolveOptions = {
nocache,
recursive
}
const [ , hash ] = name.slice(1).split('/')
try {
mh.fromB58String(hash)

// ipns resolve needs a online daemon
if (!self.isOnline() && !offline) {
const errMsg = utils.OFFLINE_ERROR

self._ipns.resolve(name, resolveOptions, callback)
log.error(errMsg)
return callback(errcode(errMsg, 'OFFLINE_ERROR'))
}
self._ipns.resolve(name, options, callback)
} catch (err) {
// lets check if we have a domain ex. /ipns/ipfs.io and resolve with dns
if (isDomain(hash)) {
return self.dns(hash, options, callback)
}

log.error(err)
callback(errcode(new Error('Invalid IPNS name.'), 'ERR_IPNS_INVALID_NAME'))
}
}),
pubsub: namePubsub(self)
}
Expand Down
12 changes: 11 additions & 1 deletion src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@ const defaultRepo = require('./runtime/repo-nodejs')
const preload = require('./preload')
const mfsPreload = require('./mfs-preload')
const ipldOptions = require('./runtime/ipld-nodejs')

/**
* @typedef { import("./ipns/index") } IPNS
*/

/**
*
*
* @class IPFS
* @extends {EventEmitter}
*/
class IPFS extends EventEmitter {
constructor (options) {
super()
Expand Down Expand Up @@ -76,6 +85,7 @@ class IPFS extends EventEmitter {
this._ipld = new Ipld(ipldOptions(this._blockService, this._options.ipld, this.log))
this._preload = preload(this)
this._mfsPreload = mfsPreload(this)
/** @type {IPNS} */
this._ipns = undefined
// eslint-disable-next-line no-console
this._print = this._options.silent ? this.log : console.log
Expand Down
5 changes: 3 additions & 2 deletions src/core/ipns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ class IPNS {
}
}

exports = module.exports = IPNS
exports.path = path
IPNS.path = path

module.exports = IPNS
43 changes: 41 additions & 2 deletions test/core/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ describe('name', function () {
})
})

it('should not recursively resolve to an IPFS hash if the option recursive is not provided', function (done) {
it('should not recursively resolve to an IPFS hash', function (done) {
this.timeout(90 * 1000)
const keyName = hat()

Expand All @@ -132,7 +132,7 @@ describe('name', function () {
series([
(cb) => node.name.publish(ipfsRef, { resolve: false }, cb),
(cb) => node.name.publish(`/ipns/${nodeId}`, { resolve: false, key: keyName }, cb),
(cb) => node.name.resolve(key.id, cb)
(cb) => node.name.resolve(key.id, { recursive: false }, cb)
], (err, res) => {
expect(err).to.not.exist()
expect(res[2]).to.exist()
Expand Down Expand Up @@ -618,4 +618,43 @@ describe('name', function () {
done()
})
})

describe('working with dns', function () {
let node
let ipfsd

before(function (done) {
df.spawn({
exec: IPFS,
args: [`--pass ${hat()}`, '--offline'],
config: { Bootstrap: [] }
}, (err, _ipfsd) => {
expect(err).to.not.exist()
ipfsd = _ipfsd
node = _ipfsd.api
done()
})
})

after((done) => ipfsd.stop(done))

it('should resolve ipfs.io', async () => {
const r = await node.name.resolve('ipfs.io', { recursive: false })
return expect(r).to.eq('/ipns/website.ipfs.io')
})

it('should resolve /ipns/ipfs.io recursive', async () => {
const r = await node.name.resolve('ipfs.io', { recursive: true })

return expect(r.substr(0, 6)).to.eql('/ipfs/')
})

it('should fail to resolve /ipns/ipfs.a', async () => {
try {
await node.name.resolve('ipfs.a')
} catch (err) {
expect(err).to.exist()
}
})
})
})

0 comments on commit 4901718

Please sign in to comment.