From 8645c3e57493f45ee9602ad6f34f68c99a871f7e Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Jan 2018 09:53:51 +0000 Subject: [PATCH 1/7] feat: /api/v0/dns --- .gitignore | 1 + package.json | 1 + src/cli/commands/dns.js | 24 ++++++++++++++++++++++++ src/core/components/dns.js | 20 ++++++++++++++++++++ src/core/components/index.js | 1 + src/core/index.js | 1 + src/core/runtime/dns-browser.js | 25 +++++++++++++++++++++++++ src/core/runtime/dns-nodejs.js | 21 +++++++++++++++++++++ src/http/api/resources/dns.js | 24 ++++++++++++++++++++++++ src/http/api/resources/index.js | 1 + src/http/api/routes/dns.js | 13 +++++++++++++ src/http/api/routes/index.js | 1 + test/cli/commands.js | 2 +- test/cli/dns.js | 22 ++++++++++++++++++++++ test/http-api/extra/dns.js | 19 +++++++++++++++++++ test/http-api/spec/dns.js | 24 ++++++++++++++++++++++++ 16 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 src/cli/commands/dns.js create mode 100644 src/core/components/dns.js create mode 100644 src/core/runtime/dns-browser.js create mode 100644 src/core/runtime/dns-nodejs.js create mode 100644 src/http/api/resources/dns.js create mode 100644 src/http/api/routes/dns.js create mode 100644 test/cli/dns.js create mode 100644 test/http-api/extra/dns.js create mode 100644 test/http-api/spec/dns.js diff --git a/.gitignore b/.gitignore index 18ddbab6a9..7455bdffdb 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ test/test-data/go-ipfs-repo/LOG.old # while testing npm5 package-lock.json +yarn.lock diff --git a/package.json b/package.json index 52fa0192ff..747dba1347 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "./src/core/runtime/config-nodejs.json": "./src/core/runtime/config-browser.json", "./src/core/runtime/libp2p-nodejs.js": "./src/core/runtime/libp2p-browser.js", "./src/core/runtime/repo-nodejs.js": "./src/core/runtime/repo-browser.js", + "./src/core/runtime/dns-nodejs.js": "./src/core/runtime/dns-browser.js", "./test/utils/create-repo-nodejs.js": "./test/utils/create-repo-browser.js", "stream": "readable-stream" }, diff --git a/src/cli/commands/dns.js b/src/cli/commands/dns.js new file mode 100644 index 0000000000..5be09d12e1 --- /dev/null +++ b/src/cli/commands/dns.js @@ -0,0 +1,24 @@ +'use strict' +const print = require('../utils').print + +module.exports = { + command: 'dns ', + + describe: 'Resolve DNS links', + + builder: { + format: { + type: 'string' + } + }, + + handler (argv) { + argv.ipfs.dns(argv['domain'], (err, path) => { + if (err) { + throw err + } + + print(path) + }) + } +} diff --git a/src/core/components/dns.js b/src/core/components/dns.js new file mode 100644 index 0000000000..4895f01667 --- /dev/null +++ b/src/core/components/dns.js @@ -0,0 +1,20 @@ +'use strict' + +// dns-nodejs gets replaced by dns-browser when webpacked/browserified +const dns = require('../runtime/dns-nodejs') +const promisify = require('promisify-es6') + +module.exports = () => { + return promisify((domain, opts, callback) => { + if (typeof domain !== 'string') { + return callback(new Error('Invalid arguments, domain must be a string')) + } + + if (typeof opts === 'function') { + callback = opts + opts = {} + } + + dns(domain, opts, callback) + }) +} diff --git a/src/core/components/index.js b/src/core/components/index.js index e4fb45464f..248243a88e 100644 --- a/src/core/components/index.js +++ b/src/core/components/index.js @@ -20,3 +20,4 @@ exports.files = require('./files') exports.bitswap = require('./bitswap') exports.pubsub = require('./pubsub') exports.dht = require('./dht') +exports.dns = require('./dns') diff --git a/src/core/index.js b/src/core/index.js index 2fb4825e54..fa60876061 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -94,6 +94,7 @@ class IPFS extends EventEmitter { this.ping = components.ping(this) this.pubsub = components.pubsub(this) this.dht = components.dht(this) + this.dns = components.dns(this) if (this._options.EXPERIMENTAL.pubsub) { this.log('EXPERIMENTAL pubsub is enabled') diff --git a/src/core/runtime/dns-browser.js b/src/core/runtime/dns-browser.js new file mode 100644 index 0000000000..adfe926886 --- /dev/null +++ b/src/core/runtime/dns-browser.js @@ -0,0 +1,25 @@ +'use strict' + +module.exports = (domain, opts, callback) => { + domain = encodeURIComponent(domain) + let url = `https://ipfs.io/api/v0/dns?arg=${domain}` + + for (const prop in opts) { + url += `&${prop}=${opts[prop]}` + } + + window.fetch(url, {mode: 'cors'}) + .then((response) => { + return response.json() + }) + .then((response) => { + if (response.Path) { + return callback(null, response.Path) + } else { + return callback(new Error(response.Message)) + } + }) + .catch((error) => { + callback(error) + }) +} diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js new file mode 100644 index 0000000000..8f6bb132bd --- /dev/null +++ b/src/core/runtime/dns-nodejs.js @@ -0,0 +1,21 @@ +'use strict' + +const dns = require('dns') + +module.exports = (domain, opts, callback) => { + dns.resolveTxt(domain, (err, records) => { + if (err) { + return callback(err, null) + } + + // TODO: implement recursive option + + for (const record of records) { + if (record[0].startsWith('dnslink=')) { + return callback(null, record[0].substr(8, record[0].length - 1)) + } + } + + callback(new Error('domain does not have a txt dnslink entry')) + }) +} diff --git a/src/http/api/resources/dns.js b/src/http/api/resources/dns.js new file mode 100644 index 0000000000..92549e68b7 --- /dev/null +++ b/src/http/api/resources/dns.js @@ -0,0 +1,24 @@ +'use strict' + +const boom = require('boom') + +exports = module.exports + +exports.get = (request, reply) => { + if (!request.query.arg) { + return reply({ + Message: "Argument 'domain' is required", + Code: 0 + }).code(400).takeover() + } + + request.server.app.ipfs.dns(request.query.arg, (err, path) => { + if (err) { + return reply(boom.badRequest(err)) + } + + return reply({ + Path: path + }) + }) +} diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index 37bb316cab..16b0f17128 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -12,3 +12,4 @@ exports.bitswap = require('./bitswap') exports.file = require('./file') exports.files = require('./files') exports.pubsub = require('./pubsub') +exports.dns = require('./dns') diff --git a/src/http/api/routes/dns.js b/src/http/api/routes/dns.js new file mode 100644 index 0000000000..dd3f074025 --- /dev/null +++ b/src/http/api/routes/dns.js @@ -0,0 +1,13 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/dns', + handler: resources.dns.get + }) +} diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index 08756fc91c..908c0c0878 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -15,4 +15,5 @@ module.exports = (server) => { require('./pubsub')(server) require('./debug')(server) require('./webui')(server) + require('./dns')(server) } diff --git a/test/cli/commands.js b/test/cli/commands.js index 558cbcc8b4..3a2d85a418 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,7 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 59 +const commandCount = 60 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/cli/dns.js b/test/cli/dns.js new file mode 100644 index 0000000000..2a90dae444 --- /dev/null +++ b/test/cli/dns.js @@ -0,0 +1,22 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const runOnAndOff = require('../utils/on-and-off') + +describe('dns', () => runOnAndOff((thing) => { + let ipfs + + before(function () { + this.timeout(60 * 1000) + ipfs = thing.ipfs + }) + + it('dns record for ipfs.io', function () { + this.timeout(60 * 1000) + + return ipfs('ipfs.io').then((res) => { + expect(res.substr(0, 6)).to.eql('/ipfs/') + }) + }) +})) diff --git a/test/http-api/extra/dns.js b/test/http-api/extra/dns.js new file mode 100644 index 0000000000..2368378a87 --- /dev/null +++ b/test/http-api/extra/dns.js @@ -0,0 +1,19 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) + +module.exports = (ctl) => { + describe('.dns', () => { + it('get dns for ipfs.io', (done) => { + ctl.dns('ipfs.io', (err, result) => { + expect(err).to.not.exist() + expect(result).to.exist() + done() + }) + }) + }) +} diff --git a/test/http-api/spec/dns.js b/test/http-api/spec/dns.js new file mode 100644 index 0000000000..cd64feb3bd --- /dev/null +++ b/test/http-api/spec/dns.js @@ -0,0 +1,24 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect + +module.exports = (http) => { + describe('/dns', () => { + let api + + before(() => { + api = http.api.server.select('API') + }) + + it('get the id', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/dns?arg=ipfs.io' + }, (res) => { + expect(res).to.have.property('Path') + done() + }) + }) + }) +} From fbf648d22f66324f8835c222f9afa8a66a41e9ad Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Jan 2018 12:42:13 +0000 Subject: [PATCH 2/7] fix some tests --- test/cli/dns.js | 5 +++-- test/http-api/extra/dns.js | 2 +- test/http-api/spec/dns.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test/cli/dns.js b/test/cli/dns.js index 2a90dae444..ae3cb0091d 100644 --- a/test/cli/dns.js +++ b/test/cli/dns.js @@ -12,10 +12,11 @@ describe('dns', () => runOnAndOff((thing) => { ipfs = thing.ipfs }) - it('dns record for ipfs.io', function () { + it('resolve ipfs.io dns', function () { this.timeout(60 * 1000) - return ipfs('ipfs.io').then((res) => { + return ipfs('dns ipfs.io').then((res) => { + console.log(res) expect(res.substr(0, 6)).to.eql('/ipfs/') }) }) diff --git a/test/http-api/extra/dns.js b/test/http-api/extra/dns.js index 2368378a87..bb6ab6046f 100644 --- a/test/http-api/extra/dns.js +++ b/test/http-api/extra/dns.js @@ -8,7 +8,7 @@ chai.use(dirtyChai) module.exports = (ctl) => { describe('.dns', () => { - it('get dns for ipfs.io', (done) => { + it('resolve ipfs.io dns', (done) => { ctl.dns('ipfs.io', (err, result) => { expect(err).to.not.exist() expect(result).to.exist() diff --git a/test/http-api/spec/dns.js b/test/http-api/spec/dns.js index cd64feb3bd..b73bb3e7ef 100644 --- a/test/http-api/spec/dns.js +++ b/test/http-api/spec/dns.js @@ -11,7 +11,7 @@ module.exports = (http) => { api = http.api.server.select('API') }) - it('get the id', (done) => { + it('resolve ipfs.io dns', (done) => { api.inject({ method: 'GET', url: '/api/v0/dns?arg=ipfs.io' From 860b5a380659c4888fa66cff9655be6490495aaf Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Jan 2018 14:28:46 +0000 Subject: [PATCH 3/7] fix test --- test/http-api/spec/dns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/http-api/spec/dns.js b/test/http-api/spec/dns.js index b73bb3e7ef..bf84eb6b07 100644 --- a/test/http-api/spec/dns.js +++ b/test/http-api/spec/dns.js @@ -16,7 +16,7 @@ module.exports = (http) => { method: 'GET', url: '/api/v0/dns?arg=ipfs.io' }, (res) => { - expect(res).to.have.property('Path') + expect(res.result).to.have.property('Path') done() }) }) From 6db81386969d2744666b72608999a26c552c8786 Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 12 Jan 2018 14:05:50 +0000 Subject: [PATCH 4/7] chore: update deps --- package.json | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 747dba1347..eba49c8516 100644 --- a/package.json +++ b/package.json @@ -67,14 +67,14 @@ "dir-compare": "^1.4.0", "dirty-chai": "^2.0.1", "eslint-plugin-react": "^7.5.1", - "execa": "^0.8.0", + "execa": "^0.9.0", "expose-loader": "^0.7.4", "form-data": "^2.3.1", "hat": "0.0.3", - "interface-ipfs-core": "~0.36.15", + "interface-ipfs-core": "~0.40.0", "left-pad": "^1.2.0", "lodash": "^4.17.4", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "ncp": "^2.0.0", "nexpect": "^0.5.0", "pre-commit": "^1.2.2", @@ -92,28 +92,28 @@ "boom": "^7.1.1", "bs58": "^4.0.1", "byteman": "^1.3.5", - "cids": "^0.5.2", + "cids": "~0.5.2", "debug": "^3.1.0", "file-type": "^7.4.0", "filesize": "^3.5.11", "fsm-event": "^2.1.0", - "get-folder-size": "^1.0.0", + "get-folder-size": "^1.0.1", "glob": "^7.1.2", - "hapi": "^16.2.2", + "hapi": "^16.6.2", "hapi-set-header": "^1.0.2", "hoek": "^5.0.2", - "ipfs-api": "^17.2.4", + "ipfs-api": "^17.2.7", "ipfs-bitswap": "~0.18.0", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", "ipfs-multipart": "~0.1.0", - "ipfs-repo": "~0.18.4", + "ipfs-repo": "~0.18.5", "ipfs-unixfs": "~0.1.14", - "ipfs-unixfs-engine": "~0.24.1", + "ipfs-unixfs-engine": "~0.24.2", "ipld-resolver": "~0.14.1", "is-ipfs": "^0.3.2", "is-stream": "^1.1.0", - "joi": "^13.0.2", + "joi": "^13.1.0", "libp2p": "~0.15.0", "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", @@ -122,7 +122,7 @@ "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", "libp2p-secio": "~0.9.0", - "libp2p-tcp": "~0.11.1", + "libp2p-tcp": "~0.11.2", "libp2p-webrtc-star": "~0.13.3", "libp2p-websocket-star": "~0.7.2", "libp2p-websockets": "~0.10.4", @@ -133,13 +133,13 @@ "mafmt": "^3.0.2", "mime-types": "^2.1.17", "mkdirp": "~0.5.1", - "multiaddr": "^3.0.1", - "multihashes": "~0.4.12", + "multiaddr": "^3.0.2", + "multihashes": "~0.4.13", "once": "^1.4.0", "path-exists": "^3.0.0", "peer-book": "~0.5.2", - "peer-id": "~0.10.3", - "peer-info": "~0.11.3", + "peer-id": "~0.10.4", + "peer-info": "~0.11.4", "progress": "^2.0.0", "promisify-es6": "^1.0.3", "pull-abortable": "^4.1.1", @@ -147,7 +147,7 @@ "pull-file": "^1.1.0", "pull-ndjson": "^0.1.1", "pull-paramap": "^1.2.2", - "pull-pushable": "^2.1.1", + "pull-pushable": "^2.1.2", "pull-sort": "^1.0.1", "pull-stream": "^3.6.1", "pull-stream-to-stream": "^1.3.4", @@ -160,8 +160,8 @@ "temp": "~0.8.3", "through2": "^2.0.3", "update-notifier": "^2.3.0", - "yargs": "^10.0.3", - "yargs-parser": "^8.0.0" + "yargs": "^10.1.1", + "yargs-parser": "^8.1.0" }, "optionalDependencies": { "prom-client": "^10.2.2", From 7f90c3b3baf5f949e45b164e60356cbef7327e35 Mon Sep 17 00:00:00 2001 From: David Dias Date: Fri, 12 Jan 2018 14:50:15 +0000 Subject: [PATCH 5/7] updat deps --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eba49c8516..7ec29b7b17 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "hapi": "^16.6.2", "hapi-set-header": "^1.0.2", "hoek": "^5.0.2", - "ipfs-api": "^17.2.7", + "ipfs-api": "^17.3.0", "ipfs-bitswap": "~0.18.0", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", From 38a7bd9afe050eb9bbb39199fdaaee5c14ed38df Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 12 Jan 2018 14:56:39 +0000 Subject: [PATCH 6/7] fix: remove console.log --- test/cli/dns.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cli/dns.js b/test/cli/dns.js index ae3cb0091d..ae66c6c8c3 100644 --- a/test/cli/dns.js +++ b/test/cli/dns.js @@ -16,7 +16,6 @@ describe('dns', () => runOnAndOff((thing) => { this.timeout(60 * 1000) return ipfs('dns ipfs.io').then((res) => { - console.log(res) expect(res.substr(0, 6)).to.eql('/ipfs/') }) }) From 5738e7a39032d4cb3ddc2cd44cc39561916f103a Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 13 Jan 2018 11:04:21 +0000 Subject: [PATCH 7/7] fix: replace window by self --- src/core/runtime/dns-browser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/runtime/dns-browser.js b/src/core/runtime/dns-browser.js index adfe926886..c68de233fe 100644 --- a/src/core/runtime/dns-browser.js +++ b/src/core/runtime/dns-browser.js @@ -8,7 +8,7 @@ module.exports = (domain, opts, callback) => { url += `&${prop}=${opts[prop]}` } - window.fetch(url, {mode: 'cors'}) + self.fetch(url, {mode: 'cors'}) .then((response) => { return response.json() })