From 071df1ba73c918f2239f56bfc7af08b4ff7af498 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 19 Jul 2018 15:07:21 +0100 Subject: [PATCH 1/5] test: add tests and docs for ipfs.resolve License: MIT Signed-off-by: Alan Shaw --- SPEC/MISCELLANEOUS.md | 71 ++++++++++++++++++++ js/src/miscellaneous/index.js | 3 +- js/src/miscellaneous/resolve.js | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 js/src/miscellaneous/resolve.js diff --git a/SPEC/MISCELLANEOUS.md b/SPEC/MISCELLANEOUS.md index a45a4af06..b2b57d0dd 100644 --- a/SPEC/MISCELLANEOUS.md +++ b/SPEC/MISCELLANEOUS.md @@ -7,6 +7,7 @@ * [ping](#ping) * [pingPullStream](#pingpullstream) * [pingReadableStream](#pingreadablestream) +* [resolve](#resolve) #### `id` @@ -242,6 +243,76 @@ stream.on('data', (res) => { A great source of [examples][] can be found in the tests for this API. +#### `resolve` + +> Resolve the value of names to IPFS + +There are a number of mutable name protocols that can link among themselves and into IPNS. For example IPNS references can (currently) point at an IPFS object, and DNS links can point at other DNS links, IPNS entries, or IPFS objects. This command accepts any of these identifiers and resolves them to the referenced item. + +##### `Go` **WIP** + +##### `JavaScript` - ipfs.resolve(name, [options], [callback]) + +Where: + +- `name` (string): The name to resolve +- `options` is an optional object that might include the following properties: + - `recursive` (boolean, default false): Resolve until the result is an IPFS name + +`callback` must follow `function (err, res) {}` signature, where `err` is an error if the operation was not successful. `res` is a string, the resolved name. + +If no `callback` is passed, a promise is returned. + +**Examples:** + +Resolve the value of your identity: + +```JavaScript +const name = '/ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy' + +ipfs.resolve(name, (err, res) => { + if (err) { + throw err + } + console.log(res) // /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj +}) +``` + +Resolve the value of another name recursively: + +```JavaScript +const name = '/ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n' + +// Where: +// /ipns/QmbCMUZw6JFeZ7Wp9jkzbye3Fzp2GGcPgC3nmeUjfVF87n +// ...resolves to: +// /ipns/QmatmE9msSfkKxoffpHwNLNKgwZG8eT9Bud6YoPab52vpy +// ...which in turn resolves to: +// /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj + +ipfs.resolve(name, { recursive: true }, (err, res) => { + if (err) { + throw err + } + console.log(res) // /ipfs/Qmcqtw8FfrVSBaRmbWwHxt3AuySBhJLcvmFYi3Lbc4xnwj +}) +``` + +Resolve the value of an IPFS path: + +```JavaScript +const name = '/ipfs/QmeZy1fGbwgVSrqbfh9fKQrAWgeyRnj7h8fsHS1oy3k99x/beep/boop' + +ipfs.resolve(name, (err, res) => { + if (err) { + throw err + } + console.log(res) // /ipfs/QmYRMjyvAiHKN9UTi8Bzt1HUspmSRD8T8DwxfSMzLgBon1 +}) +``` + +A great source of [examples][] can be found in the tests for this API. + [examples]: https://github.com/ipfs/interface-ipfs-core/blob/master/js/src/miscellaneous [rs]: https://www.npmjs.com/package/readable-stream [ps]: https://www.npmjs.com/package/pull-stream diff --git a/js/src/miscellaneous/index.js b/js/src/miscellaneous/index.js index b3a5dc603..82f7f08ec 100644 --- a/js/src/miscellaneous/index.js +++ b/js/src/miscellaneous/index.js @@ -5,7 +5,8 @@ const tests = { id: require('./id'), version: require('./version'), dns: require('./dns'), - stop: require('./stop') + stop: require('./stop'), + resolve: require('./resolve') } module.exports = createSuite(tests) diff --git a/js/src/miscellaneous/resolve.js b/js/src/miscellaneous/resolve.js new file mode 100644 index 000000000..d4dd9bc7e --- /dev/null +++ b/js/src/miscellaneous/resolve.js @@ -0,0 +1,112 @@ +/* eslint-env mocha */ +'use strict' + +const isIpfs = require('is-ipfs') +const loadFixture = require('aegir/fixtures') +const { getDescribe, getIt, expect } = require('../utils/mocha') + +module.exports = (createCommon, options) => { + const describe = getDescribe(options) + const it = getIt(options) + const common = createCommon() + + describe('.resolve', () => { + let ipfs + + before(function (done) { + // CI takes longer to instantiate the daemon, so we need to increase the + // timeout for the before step + this.timeout(60 * 1000) + + common.setup((err, factory) => { + expect(err).to.not.exist() + factory.spawnNode((err, node) => { + expect(err).to.not.exist() + ipfs = node + done() + }) + }) + }) + + after((done) => { + common.teardown(done) + }) + + it('should resolve an IPFS hash', (done) => { + const content = loadFixture('js/test/fixtures/testfile.txt', 'interface-ipfs-core') + + ipfs.add(content, (err, res) => { + expect(err).to.not.exist() + expect(isIpfs.cid(res[0].hash)).to.be.true() + + ipfs.resolve(`/ipfs/${res[0].hash}`, (err, path) => { + expect(err).to.not.exist() + expect(path).to.equal(`/ipfs/${res[0].hash}`) + done() + }) + }) + }) + + // Test resolve turns /ipfs/QmRootHash/path/to/file into /ipfs/QmFileHash + it('should resolve an IPFS path link', (done) => { + const path = '/path/to/testfile.txt' + const content = loadFixture('js/test/fixtures/testfile.txt', 'interface-ipfs-core') + + ipfs.add([{ path, content }], { wrapWithDirectory: true }, (err, res) => { + expect(err).to.not.exist() + + const rootHash = res.find(r => r.path === '').hash + const fileHash = res.find(r => r.path === path).hash + + ipfs.resolve(`/ipfs/${rootHash}${path}`, (err, path) => { + expect(err).to.not.exist() + expect(path).to.equal(`/ipfs/${fileHash}`) + done() + }) + }) + }) + + it('should not resolve an IPFS path non-link', (done) => { + const content = { path: { to: { file: 'hello world' } } } + const options = { format: 'dag-cbor', hashAlg: 'sha2-256' } + + ipfs.dag.put(content, options, (err, cid) => { + expect(err).to.not.exist() + + const path = `/ipfs/${cid.toBaseEncodedString()}/path/to/file` + ipfs.resolve(path, (err, path) => { + expect(err).to.exist() + expect(err.message).to.equal('found non-link at given path') + done() + }) + }) + }) + + // Test resolve turns /ipns/domain.com into /ipfs/QmHash + it('should resolve an IPNS DNS link', function (done) { + this.timeout(20 * 1000) + + ipfs.resolve('/ipns/ipfs.io', (err, path) => { + expect(err).to.not.exist() + expect(isIpfs.path(path)).to.be.true() + done() + }) + }) + + // Test resolve turns /ipns/QmPeerHash into /ipns/domain.com into /ipfs/QmHash + it('should resolve IPNS link recursively', function (done) { + this.timeout(2 * 60 * 1000) + + ipfs.name.publish('/ipns/ipfs.io', { resolve: false }, (err, res) => { + expect(err).to.not.exist() + + ipfs.resolve(`/ipns/${res.name}`, { recursive: true }, (err, res) => { + expect(err).to.not.exist() + expect(res).to.not.equal('/ipns/ipfs.io') + expect(isIpfs.path(res)).to.be.true() + done() + }) + }) + }) + }) +} From 4c25a4e227337e627fdb69110a07d26e4bdfa10f Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 19 Jul 2018 15:19:47 +0100 Subject: [PATCH 2/5] fix: use ipfs.files.add License: MIT Signed-off-by: Alan Shaw --- js/src/miscellaneous/resolve.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/miscellaneous/resolve.js b/js/src/miscellaneous/resolve.js index d4dd9bc7e..97fce488c 100644 --- a/js/src/miscellaneous/resolve.js +++ b/js/src/miscellaneous/resolve.js @@ -35,7 +35,7 @@ module.exports = (createCommon, options) => { it('should resolve an IPFS hash', (done) => { const content = loadFixture('js/test/fixtures/testfile.txt', 'interface-ipfs-core') - ipfs.add(content, (err, res) => { + ipfs.files.add(content, (err, res) => { expect(err).to.not.exist() expect(isIpfs.cid(res[0].hash)).to.be.true() @@ -52,7 +52,7 @@ module.exports = (createCommon, options) => { const path = '/path/to/testfile.txt' const content = loadFixture('js/test/fixtures/testfile.txt', 'interface-ipfs-core') - ipfs.add([{ path, content }], { wrapWithDirectory: true }, (err, res) => { + ipfs.files.add([{ path, content }], { wrapWithDirectory: true }, (err, res) => { expect(err).to.not.exist() const rootHash = res.find(r => r.path === '').hash From f88d99f62c4e51bc6a3e59cc8d573226e37f6ce0 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 19 Jul 2018 15:39:34 +0100 Subject: [PATCH 3/5] fix: use ipfsPath instead of path License: MIT Signed-off-by: Alan Shaw --- js/src/miscellaneous/resolve.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/miscellaneous/resolve.js b/js/src/miscellaneous/resolve.js index 97fce488c..d789f3ad0 100644 --- a/js/src/miscellaneous/resolve.js +++ b/js/src/miscellaneous/resolve.js @@ -88,7 +88,7 @@ module.exports = (createCommon, options) => { ipfs.resolve('/ipns/ipfs.io', (err, path) => { expect(err).to.not.exist() - expect(isIpfs.path(path)).to.be.true() + expect(isIpfs.ipfsPath(path)).to.be.true() done() }) }) @@ -103,7 +103,7 @@ module.exports = (createCommon, options) => { ipfs.resolve(`/ipns/${res.name}`, { recursive: true }, (err, res) => { expect(err).to.not.exist() expect(res).to.not.equal('/ipns/ipfs.io') - expect(isIpfs.path(res)).to.be.true() + expect(isIpfs.ipfsPath(res)).to.be.true() done() }) }) From 91eef62ec3cedc9381c47c28f8113dd4d91c7e37 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 20 Jul 2018 10:02:27 +0100 Subject: [PATCH 4/5] fix: skip DNS tests temporarily License: MIT Signed-off-by: Alan Shaw --- js/src/miscellaneous/resolve.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/js/src/miscellaneous/resolve.js b/js/src/miscellaneous/resolve.js index d789f3ad0..0fd8e868d 100644 --- a/js/src/miscellaneous/resolve.js +++ b/js/src/miscellaneous/resolve.js @@ -3,6 +3,7 @@ const isIpfs = require('is-ipfs') const loadFixture = require('aegir/fixtures') +const hat = require('hat') const { getDescribe, getIt, expect } = require('../utils/mocha') module.exports = (createCommon, options) => { @@ -67,7 +68,7 @@ module.exports = (createCommon, options) => { }) it('should not resolve an IPFS path non-link', (done) => { - const content = { path: { to: { file: 'hello world' } } } + const content = { path: { to: { file: hat() } } } const options = { format: 'dag-cbor', hashAlg: 'sha2-256' } ipfs.dag.put(content, options, (err, cid) => { @@ -83,7 +84,8 @@ module.exports = (createCommon, options) => { }) // Test resolve turns /ipns/domain.com into /ipfs/QmHash - it('should resolve an IPNS DNS link', function (done) { + // TODO skipped until we can find a way to remove dependency on external service + it.skip('should resolve an IPNS DNS link', function (done) { this.timeout(20 * 1000) ipfs.resolve('/ipns/ipfs.io', (err, path) => { @@ -94,7 +96,8 @@ module.exports = (createCommon, options) => { }) // Test resolve turns /ipns/QmPeerHash into /ipns/domain.com into /ipfs/QmHash - it('should resolve IPNS link recursively', function (done) { + // TODO skipped until we can find a way to remove dependency on external service + it.skip('should resolve IPNS link recursively', function (done) { this.timeout(2 * 60 * 1000) ipfs.name.publish('/ipns/ipfs.io', { resolve: false }, (err, res) => { From e585a0009f67dd60f1c2ae65f27d5b57d23a83c1 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Mon, 23 Jul 2018 11:52:15 +0100 Subject: [PATCH 5/5] refactor: unskip License: MIT Signed-off-by: Alan Shaw --- js/src/miscellaneous/resolve.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/js/src/miscellaneous/resolve.js b/js/src/miscellaneous/resolve.js index 0fd8e868d..f9a0f3c9b 100644 --- a/js/src/miscellaneous/resolve.js +++ b/js/src/miscellaneous/resolve.js @@ -84,8 +84,7 @@ module.exports = (createCommon, options) => { }) // Test resolve turns /ipns/domain.com into /ipfs/QmHash - // TODO skipped until we can find a way to remove dependency on external service - it.skip('should resolve an IPNS DNS link', function (done) { + it('should resolve an IPNS DNS link', function (done) { this.timeout(20 * 1000) ipfs.resolve('/ipns/ipfs.io', (err, path) => { @@ -96,8 +95,7 @@ module.exports = (createCommon, options) => { }) // Test resolve turns /ipns/QmPeerHash into /ipns/domain.com into /ipfs/QmHash - // TODO skipped until we can find a way to remove dependency on external service - it.skip('should resolve IPNS link recursively', function (done) { + it('should resolve IPNS link recursively', function (done) { this.timeout(2 * 60 * 1000) ipfs.name.publish('/ipns/ipfs.io', { resolve: false }, (err, res) => {