Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 088e578

Browse files
committed
feat: enable recursive lookups on ipfs.dns
1 parent dd38867 commit 088e578

File tree

5 files changed

+101
-6
lines changed

5 files changed

+101
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,7 @@ The core API is grouped into several areas:
639639
- [`ipfs.stop([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#stop)
640640
- `ipfs.isOnline()`
641641
- [`ipfs.resolve(name, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#resolve)
642+
- [`ipfs.dns(name, [options], [callback]`](https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#dns)
642643
643644
- [repo](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/REPO.md)
644645
- `ipfs.repo.init`

src/cli/commands/dns.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,21 @@ module.exports = {
77
describe: 'Resolve DNS links',
88

99
builder: {
10+
recursive: {
11+
type: 'boolean',
12+
default: false,
13+
alias: 'r',
14+
desc: 'Resolve until the result is not a DNS link'
15+
},
1016
format: {
1117
type: 'string'
1218
}
1319
},
1420

15-
handler ({ getIpfs, domain, resolve }) {
21+
handler ({ getIpfs, domain, resolve, ...opts }) {
1622
resolve((async () => {
1723
const ipfs = await getIpfs()
18-
const path = await ipfs.dns(domain)
24+
const path = await ipfs.dns(domain, opts)
1925
print(path)
2026
})())
2127
}

src/core/runtime/dns-nodejs.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,27 @@
22

33
const dns = require('dns')
44
const _ = require('lodash')
5+
const isIPFS = require('is-ipfs')
56
const errcode = require('err-code')
67

8+
const maxRecursiveDepth = 32
9+
710
module.exports = (domain, opts, callback) => {
8-
resolveDnslink(domain)
11+
const recursive = opts.recursive && opts.recursive.toString() === 'true'
12+
let depth
13+
if (recursive) {
14+
depth = maxRecursiveDepth
15+
}
16+
17+
return recursiveResolveDnslink(domain, depth, callback)
18+
}
19+
20+
function recursiveResolveDnslink (domain, depth, callback) {
21+
if (depth === 0) {
22+
return callback(errcode(`recursion limit exceeded`, 'ERR_DNSLINK_RECURSION_LIMIT'))
23+
}
24+
25+
return resolveDnslink(domain)
926
.catch(err => {
1027
// If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND or ENODATA then throw the error
1128
if (err.code !== 'ENOTFOUND' && err.code !== 'ERR_DNSLINK_NOT_FOUND' && err.code !== 'ENODATA') throw err
@@ -22,7 +39,14 @@ module.exports = (domain, opts, callback) => {
2239
return resolveDnslink(_dnslinkDomain)
2340
})
2441
.then(dnslinkRecord => {
25-
callback(null, dnslinkRecord.replace('dnslink=', ''))
42+
const result = dnslinkRecord.replace('dnslink=', '')
43+
const domainOrCID = result.split('/')[2]
44+
const isIPFSCID = isIPFS.cid(domainOrCID)
45+
46+
if (isIPFSCID || !depth) {
47+
return callback(null, result)
48+
}
49+
return recursiveResolveDnslink(domainOrCID, depth - 1, callback)
2650
})
2751
.catch(callback)
2852
}

src/http/api/resources/dns.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
const Boom = require('boom')
44

55
module.exports = async (request, h) => {
6-
if (!request.query.arg) {
6+
const { arg: domain, ...opts } = request.query
7+
8+
if (!domain) {
79
throw Boom.badRequest("Argument 'domain' is required")
810
}
911

10-
const path = await request.server.app.ipfs.dns(request.query.arg)
12+
const path = await request.server.app.ipfs.dns(domain, opts)
1113
return h.response({
1214
Path: path
1315
})

test/core/dns.spec.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const chai = require('chai')
5+
const dirtyChai = require('dirty-chai')
6+
const expect = chai.expect
7+
chai.use(dirtyChai)
8+
9+
const IPFSFactory = require('ipfsd-ctl')
10+
const IPFS = require('../../src/core')
11+
12+
describe('.dns', () => {
13+
let ipfsd, ipfs
14+
15+
before(function (done) {
16+
this.timeout(20 * 1000)
17+
18+
const factory = IPFSFactory.create({ type: 'proc' })
19+
20+
factory.spawn({
21+
exec: IPFS,
22+
initOptions: { bits: 512 },
23+
config: { Bootstrap: [] }
24+
}, (err, _ipfsd) => {
25+
expect(err).to.not.exist()
26+
ipfsd = _ipfsd
27+
ipfs = _ipfsd.api
28+
done()
29+
})
30+
})
31+
32+
after((done) => {
33+
if (ipfsd) {
34+
ipfsd.stop(done)
35+
} else {
36+
done()
37+
}
38+
})
39+
40+
// skipping because there is an error in https://ipfs.io/api/v0/dns?arg=ipfs.io
41+
// unskip once this is resolved: https://github.com/ipfs/go-ipfs/issues/6086
42+
it.skip('should resolve ipfs.io', () => {
43+
return ipfs.dns('ipfs.io').then(res => {
44+
// matches pattern /ipns/<ipnsaddress>
45+
expect(res).to.match(/\/ipns\/.+$/)
46+
})
47+
})
48+
49+
it('should recursively resolve ipfs.io', () => {
50+
return ipfs.dns('ipfs.io', { recursive: true }).then(res => {
51+
// matches pattern /ipfs/<hash>
52+
expect(res).to.match(/\/ipfs\/.+$/)
53+
})
54+
})
55+
56+
it('should resolve subdomain docs.ipfs.io', () => {
57+
return ipfs.dns('docs.ipfs.io').then(res => {
58+
// matches pattern /ipfs/<hash>
59+
expect(res).to.match(/\/ipfs\/.+$/)
60+
})
61+
})
62+
})

0 commit comments

Comments
 (0)