From 5b5e8902141d1e64d41c8407329764a4d21efe7d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 7 Dec 2017 13:55:03 +1300 Subject: [PATCH 01/42] feat: construct the keychain when starting up --- package.json | 1 + src/core/components/start.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/package.json b/package.json index de9635ca59..16ebe89092 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", + "libp2p-keychain": "github:libp2p/js-libp2p-keychain", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", diff --git a/src/core/components/start.js b/src/core/components/start.js index 9575c3e3c6..985325c7e2 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -4,6 +4,7 @@ const series = require('async/series') const Bitswap = require('ipfs-bitswap') const FloodSub = require('libp2p-floodsub') const NoFloodSub = require('./no-floodsub') +const Keychain = require('libp2p-keychain') const setImmediate = require('async/setImmediate') const promisify = require('promisify-es6') @@ -51,6 +52,8 @@ module.exports = (self) => { self._bitswap.start() self._blockService.setExchange(self._bitswap) + self._keychain = new Keychain(self._repo.keys, { passPhrase: 'todo do not hardcode the pass phrase' }) + self._pubsub = self._options.EXPERIMENTAL.pubsub ? new FloodSub(self._libp2pNode) : new NoFloodSub() From 5ac6be2f3eb31b49d2a49ef76d73dcbf45488400 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 7 Dec 2017 14:01:59 +1300 Subject: [PATCH 02/42] feat: key is a core component --- src/core/components/index.js | 1 + src/core/components/key.js | 29 +++++++++++++++++++++++++++++ src/core/index.js | 1 + 3 files changed, 31 insertions(+) create mode 100644 src/core/components/key.js diff --git a/src/core/components/index.js b/src/core/components/index.js index 248243a88e..4aea90db9e 100644 --- a/src/core/components/index.js +++ b/src/core/components/index.js @@ -21,3 +21,4 @@ exports.bitswap = require('./bitswap') exports.pubsub = require('./pubsub') exports.dht = require('./dht') exports.dns = require('./dns') +exports.key = require('./key') diff --git a/src/core/components/key.js b/src/core/components/key.js new file mode 100644 index 0000000000..ca3b036ebd --- /dev/null +++ b/src/core/components/key.js @@ -0,0 +1,29 @@ +'use strict' + +// See https://github.com/ipfs/specs/tree/master/keystore + +const promisify = require('promisify-es6') + +module.exports = function key (self) { + return { + generate: promisify((name, type, size, callback) => { + self._keychain.createKey(name, type, size, callback) + }), + + info: promisify((name, callback) => { + self._keychain.findKeyByName(name, callback) + }), + + list: promisify((callback) => { + self._keychain.listKeys(callback) + }), + + remove: promisify((name, callback) => { + self._keychain.removeKey(name, callback) + }), + + rename: promisify((oldName, newName, callback) => { + self._keychain.put(oldName, newName, callback) + }) + } +} diff --git a/src/core/index.js b/src/core/index.js index fa60876061..b0e5719b2f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -95,6 +95,7 @@ class IPFS extends EventEmitter { this.pubsub = components.pubsub(this) this.dht = components.dht(this) this.dns = components.dns(this) + this.key = components.key(this) if (this._options.EXPERIMENTAL.pubsub) { this.log('EXPERIMENTAL pubsub is enabled') From 21ae69878dd08750a740e7f43da505b0f65a4798 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 7 Dec 2017 16:52:30 +1300 Subject: [PATCH 03/42] fix: the keychain is always available --- src/core/components/pre-start.js | 3 +++ src/core/components/start.js | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 32017bd4f0..eb8e2d8f4d 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -2,6 +2,7 @@ const peerId = require('peer-id') const PeerInfo = require('peer-info') +const Keychain = require('libp2p-keychain') const multiaddr = require('multiaddr') const waterfall = require('async/waterfall') @@ -12,6 +13,8 @@ module.exports = function preStart (self) { return (callback) => { self.log('pre-start') + self._keychain = new Keychain(self._repo.keys, { passPhrase: 'todo do not hardcode the pass phrase' }) + waterfall([ (cb) => self._repo.config.get(cb), (config, cb) => { diff --git a/src/core/components/start.js b/src/core/components/start.js index 985325c7e2..5e392a0cb9 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -52,8 +52,6 @@ module.exports = (self) => { self._bitswap.start() self._blockService.setExchange(self._bitswap) - self._keychain = new Keychain(self._repo.keys, { passPhrase: 'todo do not hardcode the pass phrase' }) - self._pubsub = self._options.EXPERIMENTAL.pubsub ? new FloodSub(self._libp2pNode) : new NoFloodSub() From ba82f7f60792cef4b54bdac657cf4ed71a6121f0 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 7 Dec 2017 17:23:23 +1300 Subject: [PATCH 04/42] feat: key is a cli command --- src/cli/commands/key.js | 14 ++++++++++++++ src/cli/commands/key/gen.js | 31 +++++++++++++++++++++++++++++++ src/cli/commands/key/list.js | 20 ++++++++++++++++++++ src/cli/commands/key/rename.js | 20 ++++++++++++++++++++ src/cli/commands/key/rm.js | 20 ++++++++++++++++++++ src/core/components/key.js | 2 +- src/core/components/start.js | 1 - 7 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 src/cli/commands/key.js create mode 100644 src/cli/commands/key/gen.js create mode 100644 src/cli/commands/key/list.js create mode 100644 src/cli/commands/key/rename.js create mode 100644 src/cli/commands/key/rm.js diff --git a/src/cli/commands/key.js b/src/cli/commands/key.js new file mode 100644 index 0000000000..c6d620dc61 --- /dev/null +++ b/src/cli/commands/key.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = { + command: 'key', + + description: 'Manage your keys', + + builder (yargs) { + return yargs + .commandDir('key') + }, + + handler (argv) {} +} diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js new file mode 100644 index 0000000000..64fc5eb557 --- /dev/null +++ b/src/cli/commands/key/gen.js @@ -0,0 +1,31 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'gen ', + + describe: 'Create a new key', + + builder: { + type: { + alias: 't', + describe: 'type of the key to create [rsa, ed25519].', + default: 'rsa' + }, + size: { + alias: 's', + describe: 'size of the key to generate.', + default: '2048' + } + }, + + handler (argv) { + argv.ipfs.key.generate(argv.name, argv.type, argv.size, (err, key) => { + if (err) { + throw err + } + print(`generated ${key.name} ${key.id}`) + }) + } +} diff --git a/src/cli/commands/key/list.js b/src/cli/commands/key/list.js new file mode 100644 index 0000000000..e15cc47f96 --- /dev/null +++ b/src/cli/commands/key/list.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'list', + + describe: 'List all local keys', + + builder: {}, + + handler (argv) { + argv.ipfs.key.list((err, keys) => { + if (err) { + throw err + } + keys.forEach((ki) => print(`${ki.name} ${ki.id}`)) + }) + } +} diff --git a/src/cli/commands/key/rename.js b/src/cli/commands/key/rename.js new file mode 100644 index 0000000000..d3af8ce36f --- /dev/null +++ b/src/cli/commands/key/rename.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'rename ', + + describe: 'Rename a key', + + builder: {}, + + handler (argv) { + argv.ipfs.key.rename(argv.name, argv.newName, (err, key) => { + if (err) { + throw err + } + print(`renamed to ${key.name} ${key.id}`) + }) + } +} diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js new file mode 100644 index 0000000000..21ca5c3af3 --- /dev/null +++ b/src/cli/commands/key/rm.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'rm ', + + describe: 'Remove a key', + + builder: {}, + + handler (argv) { + argv.ipfs.key.remove(argv.name, (err) => { + if (err) { + throw err + } + print(`removed ${argv.name}`) + }) + } +} diff --git a/src/core/components/key.js b/src/core/components/key.js index ca3b036ebd..3131872a06 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -23,7 +23,7 @@ module.exports = function key (self) { }), rename: promisify((oldName, newName, callback) => { - self._keychain.put(oldName, newName, callback) + self._keychain.renameKey(oldName, newName, callback) }) } } diff --git a/src/core/components/start.js b/src/core/components/start.js index 5e392a0cb9..9575c3e3c6 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -4,7 +4,6 @@ const series = require('async/series') const Bitswap = require('ipfs-bitswap') const FloodSub = require('libp2p-floodsub') const NoFloodSub = require('./no-floodsub') -const Keychain = require('libp2p-keychain') const setImmediate = require('async/setImmediate') const promisify = require('promisify-es6') From 67dd69b023f7ca762b8775f07011fe359cbe7fa9 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 10:29:20 +1300 Subject: [PATCH 05/42] feat: http api routes for key --- src/http/api/resources/index.js | 1 + src/http/api/resources/key.js | 76 +++++++++++++++++++++++++++++++++ src/http/api/routes/index.js | 1 + src/http/api/routes/key.js | 31 ++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/http/api/resources/key.js create mode 100644 src/http/api/routes/key.js diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index 16b0f17128..42eec1d0b0 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -13,3 +13,4 @@ exports.file = require('./file') exports.files = require('./files') exports.pubsub = require('./pubsub') exports.dns = require('./dns') +exports.key = require('./key') diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js new file mode 100644 index 0000000000..3422485ece --- /dev/null +++ b/src/http/api/resources/key.js @@ -0,0 +1,76 @@ +'use strict' + +exports = module.exports + +function applyError (reply, err) { + reply({ + Message: err.message, + Code: 0 + }).code(500).takeover() +} + +function toKeyInfo (key) { + return { + Name: key.name, + Id: key.id + } +} + +exports.list = (request, reply) => { + const ipfs = request.server.app.ipfs + + ipfs._keychain.listKeys((err, keys) => { + if (err) { + return applyError(reply, err) + } + + keys = keys.map(toKeyInfo) + return reply({ Keys: keys }) + }) +} + +exports.remove = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + ipfs._keychain.removeKey(name, (err, key) => { + if (err) { + return applyError(reply, err) + } + + // TODO: need key info from keychain + return reply({ Keys: [] }) + }) +} + +exports.rename = (request, reply) => { + const ipfs = request.server.app.ipfs + const oldName = request.query.arg[0] + const newName = request.query.arg[1] + ipfs._keychain.renameKey(oldName, newName, (err, key) => { + if (err) { + return applyError(reply, err) + } + + const result = { + Was: oldName, + Now: key.name, + Id: key.id, + Overwrite: false + } + return reply(result) + }) +} + +exports.generate = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const type = request.query.type + const size = request.query.size + ipfs._keychain.createKey(name, type, size, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply(toKeyInfo(key)) + }) +} diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index 908c0c0878..9e405ae6b5 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -16,4 +16,5 @@ module.exports = (server) => { require('./debug')(server) require('./webui')(server) require('./dns')(server) + require('./key')(server) } diff --git a/src/http/api/routes/key.js b/src/http/api/routes/key.js new file mode 100644 index 0000000000..0af40970a2 --- /dev/null +++ b/src/http/api/routes/key.js @@ -0,0 +1,31 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/key/list', + handler: resources.key.list + }) + + api.route({ + method: '*', + path: '/api/v0/key/gen', + handler: resources.key.generate + }) + + api.route({ + method: '*', + path: '/api/v0/key/rm', + handler: resources.key.remove + }) + + api.route({ + method: '*', + path: '/api/v0/key/rename', + handler: resources.key.rename + }) +} From 9951dd21e54338b7a6eef2fe6e695e777fc3318d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 10:59:03 +1300 Subject: [PATCH 06/42] fix: core and http api should agree on names --- src/cli/commands/key/gen.js | 4 ++-- src/cli/commands/key/list.js | 4 ++-- src/cli/commands/key/rename.js | 4 ++-- src/cli/commands/key/rm.js | 2 +- src/core/components/key.js | 38 ++++++++++++++++++++++++++++------ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js index 64fc5eb557..963a2e8f2e 100644 --- a/src/cli/commands/key/gen.js +++ b/src/cli/commands/key/gen.js @@ -21,11 +21,11 @@ module.exports = { }, handler (argv) { - argv.ipfs.key.generate(argv.name, argv.type, argv.size, (err, key) => { + argv.ipfs.key.gen(argv.name, argv.type, argv.size, (err, key) => { if (err) { throw err } - print(`generated ${key.name} ${key.id}`) + print(`generated ${key.Name} ${key.Id}`) }) } } diff --git a/src/cli/commands/key/list.js b/src/cli/commands/key/list.js index e15cc47f96..577719cb77 100644 --- a/src/cli/commands/key/list.js +++ b/src/cli/commands/key/list.js @@ -10,11 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.list((err, keys) => { + argv.ipfs.key.list((err, res) => { if (err) { throw err } - keys.forEach((ki) => print(`${ki.name} ${ki.id}`)) + res.Keys.forEach((ki) => print(`${ki.Name} ${ki.Id}`)) }) } } diff --git a/src/cli/commands/key/rename.js b/src/cli/commands/key/rename.js index d3af8ce36f..130a25fa9a 100644 --- a/src/cli/commands/key/rename.js +++ b/src/cli/commands/key/rename.js @@ -10,11 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.rename(argv.name, argv.newName, (err, key) => { + argv.ipfs.key.rename(argv.name, argv.newName, (err, res) => { if (err) { throw err } - print(`renamed to ${key.name} ${key.id}`) + print(`renamed to ${res.Now} ${res.Id}`) }) } } diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js index 21ca5c3af3..8dfce84027 100644 --- a/src/cli/commands/key/rm.js +++ b/src/cli/commands/key/rm.js @@ -10,7 +10,7 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.remove(argv.name, (err) => { + argv.ipfs.key.rm(argv.name, (err) => { if (err) { throw err } diff --git a/src/core/components/key.js b/src/core/components/key.js index 3131872a06..9ace8ec0c2 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -4,26 +4,52 @@ const promisify = require('promisify-es6') +function toKeyInfo (key) { + return { + Name: key.name, + Id: key.id + } +} + module.exports = function key (self) { return { - generate: promisify((name, type, size, callback) => { - self._keychain.createKey(name, type, size, callback) + gen: promisify((name, type, size, callback) => { + self._keychain.createKey(name, type, size, (err, key) => { + if (err) return callback(err) + callback(null, toKeyInfo(key)) + }) }), info: promisify((name, callback) => { - self._keychain.findKeyByName(name, callback) + self._keychain.findKeyByName(name, (err, key) => { + if (err) return callback(err) + callback(null, toKeyInfo(key)) + }) }), list: promisify((callback) => { - self._keychain.listKeys(callback) + self._keychain.listKeys((err, keys) => { + if (err) return callback(err) + keys = keys.map(toKeyInfo) + callback(null, { Keys: keys }) + }) }), - remove: promisify((name, callback) => { + rm: promisify((name, callback) => { self._keychain.removeKey(name, callback) }), rename: promisify((oldName, newName, callback) => { - self._keychain.renameKey(oldName, newName, callback) + self._keychain.renameKey(oldName, newName, (err, key) => { + if (err) return callback(err) + const result = { + Was: oldName, + Now: key.name, + Id: key.id, + Overwrite: false + } + callback(null, result) + }) }) } } From 32aa3dcbb982359f7e94c9b8713d78b062964894 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 11:20:38 +1300 Subject: [PATCH 07/42] fix: key gen options --- src/cli/commands/key/gen.js | 6 +++++- src/core/components/key.js | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js index 963a2e8f2e..ef645d284f 100644 --- a/src/cli/commands/key/gen.js +++ b/src/cli/commands/key/gen.js @@ -21,7 +21,11 @@ module.exports = { }, handler (argv) { - argv.ipfs.key.gen(argv.name, argv.type, argv.size, (err, key) => { + const opts = { + type: argv.type, + size: argv.size + } + argv.ipfs.key.gen(argv.name, opts, (err, key) => { if (err) { throw err } diff --git a/src/core/components/key.js b/src/core/components/key.js index 9ace8ec0c2..e91ca4d887 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -13,8 +13,8 @@ function toKeyInfo (key) { module.exports = function key (self) { return { - gen: promisify((name, type, size, callback) => { - self._keychain.createKey(name, type, size, (err, key) => { + gen: promisify((name, opts, callback) => { + self._keychain.createKey(name, opts.type, opts.size, (err, key) => { if (err) return callback(err) callback(null, toKeyInfo(key)) }) From 7bcdbc32d773ebf35cfad393aa1d8634003f51fb Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 12:49:50 +1300 Subject: [PATCH 08/42] fix: remove nasty CRLFs --- src/http/api/resources/key.js | 152 +++++++++++++++++----------------- src/http/api/routes/key.js | 62 +++++++------- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js index 3422485ece..6d95e62049 100644 --- a/src/http/api/resources/key.js +++ b/src/http/api/resources/key.js @@ -1,76 +1,76 @@ -'use strict' - -exports = module.exports - -function applyError (reply, err) { - reply({ - Message: err.message, - Code: 0 - }).code(500).takeover() -} - -function toKeyInfo (key) { - return { - Name: key.name, - Id: key.id - } -} - -exports.list = (request, reply) => { - const ipfs = request.server.app.ipfs - - ipfs._keychain.listKeys((err, keys) => { - if (err) { - return applyError(reply, err) - } - - keys = keys.map(toKeyInfo) - return reply({ Keys: keys }) - }) -} - -exports.remove = (request, reply) => { - const ipfs = request.server.app.ipfs - const name = request.query.arg - ipfs._keychain.removeKey(name, (err, key) => { - if (err) { - return applyError(reply, err) - } - - // TODO: need key info from keychain - return reply({ Keys: [] }) - }) -} - -exports.rename = (request, reply) => { - const ipfs = request.server.app.ipfs - const oldName = request.query.arg[0] - const newName = request.query.arg[1] - ipfs._keychain.renameKey(oldName, newName, (err, key) => { - if (err) { - return applyError(reply, err) - } - - const result = { - Was: oldName, - Now: key.name, - Id: key.id, - Overwrite: false - } - return reply(result) - }) -} - -exports.generate = (request, reply) => { - const ipfs = request.server.app.ipfs - const name = request.query.arg - const type = request.query.type - const size = request.query.size - ipfs._keychain.createKey(name, type, size, (err, key) => { - if (err) { - return applyError(reply, err) - } - - return reply(toKeyInfo(key)) - }) -} +'use strict' + +exports = module.exports + +function applyError (reply, err) { + reply({ + Message: err.message, + Code: 0 + }).code(500).takeover() +} + +function toKeyInfo (key) { + return { + Name: key.name, + Id: key.id + } +} + +exports.list = (request, reply) => { + const ipfs = request.server.app.ipfs + + ipfs._keychain.listKeys((err, keys) => { + if (err) { + return applyError(reply, err) + } + + keys = keys.map(toKeyInfo) + return reply({ Keys: keys }) + }) +} + +exports.remove = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + ipfs._keychain.removeKey(name, (err, key) => { + if (err) { + return applyError(reply, err) + } + + // TODO: need key info from keychain + return reply({ Keys: [] }) + }) +} + +exports.rename = (request, reply) => { + const ipfs = request.server.app.ipfs + const oldName = request.query.arg[0] + const newName = request.query.arg[1] + ipfs._keychain.renameKey(oldName, newName, (err, key) => { + if (err) { + return applyError(reply, err) + } + + const result = { + Was: oldName, + Now: key.name, + Id: key.id, + Overwrite: false + } + return reply(result) + }) +} + +exports.generate = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const type = request.query.type + const size = request.query.size + ipfs._keychain.createKey(name, type, size, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply(toKeyInfo(key)) + }) +} diff --git a/src/http/api/routes/key.js b/src/http/api/routes/key.js index 0af40970a2..7351807aef 100644 --- a/src/http/api/routes/key.js +++ b/src/http/api/routes/key.js @@ -1,31 +1,31 @@ -'use strict' - -const resources = require('./../resources') - -module.exports = (server) => { - const api = server.select('API') - - api.route({ - method: '*', - path: '/api/v0/key/list', - handler: resources.key.list - }) - - api.route({ - method: '*', - path: '/api/v0/key/gen', - handler: resources.key.generate - }) - - api.route({ - method: '*', - path: '/api/v0/key/rm', - handler: resources.key.remove - }) - - api.route({ - method: '*', - path: '/api/v0/key/rename', - handler: resources.key.rename - }) -} +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/key/list', + handler: resources.key.list + }) + + api.route({ + method: '*', + path: '/api/v0/key/gen', + handler: resources.key.generate + }) + + api.route({ + method: '*', + path: '/api/v0/key/rm', + handler: resources.key.remove + }) + + api.route({ + method: '*', + path: '/api/v0/key/rename', + handler: resources.key.rename + }) +} From 6af95b1132c8426fc40aa18a3cbc32b48be5f33e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 13:09:29 +1300 Subject: [PATCH 09/42] test(commands): less brittle --- test/cli/commands.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cli/commands.js b/test/cli/commands.js index 3a2d85a418..913d1da059 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -5,7 +5,6 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') const commandCount = 60 - describe('commands', () => runOnAndOff((thing) => { let ipfs From 50b1af743e2e6471f6710641d090997f5d1bd2da Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 8 Dec 2017 15:22:35 +1300 Subject: [PATCH 10/42] fix: key/rm returns key info --- src/cli/commands/key/rm.js | 4 ++-- src/core/components/key.js | 5 ++++- src/http/api/resources/key.js | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js index 8dfce84027..e31abe5dd7 100644 --- a/src/cli/commands/key/rm.js +++ b/src/cli/commands/key/rm.js @@ -10,11 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.rm(argv.name, (err) => { + argv.ipfs.key.rm(argv.name, (err, res) => { if (err) { throw err } - print(`removed ${argv.name}`) + res.Keys.forEach((ki) => print(`${ki.Name} ${ki.Id}`)) }) } } diff --git a/src/core/components/key.js b/src/core/components/key.js index e91ca4d887..903bcad398 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -36,7 +36,10 @@ module.exports = function key (self) { }), rm: promisify((name, callback) => { - self._keychain.removeKey(name, callback) + self._keychain.removeKey(name, (err, key) => { + if (err) return callback(err) + callback(null, { Keys: [ toKeyInfo(key) ] }) + }) }), rename: promisify((oldName, newName, callback) => { diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js index 6d95e62049..b4e1f67076 100644 --- a/src/http/api/resources/key.js +++ b/src/http/api/resources/key.js @@ -37,8 +37,7 @@ exports.remove = (request, reply) => { return applyError(reply, err) } - // TODO: need key info from keychain - return reply({ Keys: [] }) + return reply({ Keys: [ toKeyInfo(key) ] }) }) } From dfd919830f724141bbeff3dad6084e77b91f1973 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Wed, 13 Dec 2017 21:37:40 +1300 Subject: [PATCH 11/42] chore: disable the keychain --- package.json | 1 - src/core/components/no-keychain.js | 24 ++++++++++++++++++++++++ src/core/components/pre-start.js | 4 +++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/core/components/no-keychain.js diff --git a/package.json b/package.json index 16ebe89092..de9635ca59 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,6 @@ "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", - "libp2p-keychain": "github:libp2p/js-libp2p-keychain", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", diff --git a/src/core/components/no-keychain.js b/src/core/components/no-keychain.js new file mode 100644 index 0000000000..39402a1933 --- /dev/null +++ b/src/core/components/no-keychain.js @@ -0,0 +1,24 @@ +'use strict' + +function fail () { + throw new Error('Key management is not yet implemented') +} + +class NoKeychain { + constructor () { } + + static get options () { return {} } + + createKey () { fail() } + listKeys () { fail() } + findKeyById () { fail() } + findKeyByName () { fail() } + renameKey () { fail() } + exportKey () { fail() } + importKey () { fail() } + importPeer () { fail() } + + get cms () { fail() } +} + +module.exports = NoKeychain diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index eb8e2d8f4d..8549efd28d 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -2,10 +2,12 @@ const peerId = require('peer-id') const PeerInfo = require('peer-info') -const Keychain = require('libp2p-keychain') const multiaddr = require('multiaddr') const waterfall = require('async/waterfall') +// See https://github.com/ipfs/js-ipfs/pull/1133#issuecomment-351310534 +const Keychain = require('./no-keychain') + /* * Load stuff from Repo into memory */ From aa1f7f3adef12cf43e5e9291d752c4048217047f Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Wed, 13 Dec 2017 21:44:11 +1300 Subject: [PATCH 12/42] fix: lint errors --- src/core/components/no-keychain.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/components/no-keychain.js b/src/core/components/no-keychain.js index 39402a1933..bae80d21c4 100644 --- a/src/core/components/no-keychain.js +++ b/src/core/components/no-keychain.js @@ -5,8 +5,6 @@ function fail () { } class NoKeychain { - constructor () { } - static get options () { return {} } createKey () { fail() } @@ -17,7 +15,7 @@ class NoKeychain { exportKey () { fail() } importKey () { fail() } importPeer () { fail() } - + get cms () { fail() } } From 9ac70d30858b9fd03509e9fceaddeb142c679fe0 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 03:50:40 +1300 Subject: [PATCH 13/42] rebasing with master --- package.json | 1 + src/core/components/pre-start.js | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index de9635ca59..3303699aa8 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", + "libp2p-keychain": "~0.2.0", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 8549efd28d..8fc2e18d81 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -4,9 +4,7 @@ const peerId = require('peer-id') const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') const waterfall = require('async/waterfall') - -// See https://github.com/ipfs/js-ipfs/pull/1133#issuecomment-351310534 -const Keychain = require('./no-keychain') +const Keychain = require('libp2p-keychain') /* * Load stuff from Repo into memory From 788597e7df00dba47f1a6f1d0e5550bfaec0ed57 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 21 Dec 2017 03:54:06 +1300 Subject: [PATCH 14/42] test: add core/interface/key --- test/core/interface/interface.spec.js | 1 + test/core/interface/key.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 test/core/interface/key.js diff --git a/test/core/interface/interface.spec.js b/test/core/interface/interface.spec.js index 96815d2596..3d8e370981 100644 --- a/test/core/interface/interface.spec.js +++ b/test/core/interface/interface.spec.js @@ -12,6 +12,7 @@ describe('interface-ipfs-core tests', () => { require('./object') require('./dag') require('./stats') + require('./key') if (isNode) { require('./swarm') require('./pubsub') diff --git a/test/core/interface/key.js b/test/core/interface/key.js new file mode 100644 index 0000000000..3953cf8b00 --- /dev/null +++ b/test/core/interface/key.js @@ -0,0 +1,20 @@ +/* eslint-env mocha */ + +'use strict' + +const test = require('interface-ipfs-core') +const IPFSFactory = require('../../utils/ipfs-factory-instance') + +let factory + +const common = { + setup: function (cb) { + factory = new IPFSFactory() + cb(null, factory) + }, + teardown: function (cb) { + factory.dismantle(cb) + } +} + +test.key(common) From a60f47c6458d3a949772ccbef32b679ea1e56f86 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 21 Dec 2017 09:44:29 +1300 Subject: [PATCH 15/42] test: add http-api/interface/key --- src/http/api/resources/key.js | 4 ++-- src/http/api/routes/key.js | 4 ++-- test/http-api/interface/key.js | 20 ++++++++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 test/http-api/interface/key.js diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js index b4e1f67076..be91a8a5f8 100644 --- a/src/http/api/resources/key.js +++ b/src/http/api/resources/key.js @@ -29,7 +29,7 @@ exports.list = (request, reply) => { }) } -exports.remove = (request, reply) => { +exports.rm = (request, reply) => { const ipfs = request.server.app.ipfs const name = request.query.arg ipfs._keychain.removeKey(name, (err, key) => { @@ -60,7 +60,7 @@ exports.rename = (request, reply) => { }) } -exports.generate = (request, reply) => { +exports.gen = (request, reply) => { const ipfs = request.server.app.ipfs const name = request.query.arg const type = request.query.type diff --git a/src/http/api/routes/key.js b/src/http/api/routes/key.js index 7351807aef..2b6f47ee16 100644 --- a/src/http/api/routes/key.js +++ b/src/http/api/routes/key.js @@ -14,13 +14,13 @@ module.exports = (server) => { api.route({ method: '*', path: '/api/v0/key/gen', - handler: resources.key.generate + handler: resources.key.gen }) api.route({ method: '*', path: '/api/v0/key/rm', - handler: resources.key.remove + handler: resources.key.rm }) api.route({ diff --git a/test/http-api/interface/key.js b/test/http-api/interface/key.js new file mode 100644 index 0000000000..cf43f694a0 --- /dev/null +++ b/test/http-api/interface/key.js @@ -0,0 +1,20 @@ +/* eslint-env mocha */ + +'use strict' + +const test = require('interface-ipfs-core') +const FactoryClient = require('./../../utils/ipfs-factory-daemon') + +let fc + +const common = { + setup: function (callback) { + fc = new FactoryClient() + callback(null, fc) + }, + teardown: function (callback) { + fc.dismantle(callback) + } +} + +test.key(common) From bb0ac884219cd5f56307738ba5325db5bdc42b80 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 21 Dec 2017 12:10:35 +1300 Subject: [PATCH 16/42] test: add cli/key --- test/cli/key.js | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 test/cli/key.js diff --git a/test/cli/key.js b/test/cli/key.js new file mode 100644 index 0000000000..076225ab7e --- /dev/null +++ b/test/cli/key.js @@ -0,0 +1,52 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const runOnAndOff = require('../utils/on-and-off') +const hat = require('hat') + +describe('key', () => runOnAndOff.off((thing) => { + const name = 'test-key-' + hat() + const newName = 'test-key-' + hat() + let ipfs + + before(() => { + ipfs = thing.ipfs + }) + + it('gen', function () { + this.timeout(40 * 1000) + + return ipfs(`key gen ${name} --type rsa --size 2048`) + .then((out) => { + expect(out).to.include(`generated ${name}`) + }) + }) + + it('list', function () { + this.timeout(20 * 1000) + + return ipfs('key list') + .then((out) => { + expect(out).to.include(name) + }) + }) + + it('rename', function () { + this.timeout(20 * 1000) + + return ipfs(`key rename ${name} ${newName}`) + .then((out) => { + expect(out).to.include(`renamed to ${newName}`) + }) + }) + + it('rm', function () { + this.timeout(20 * 1000) + + return ipfs(`key rm ${newName}`) + .then((out) => { + expect(out).to.include(newName) + }) + }) +})) From 4db92ecab7361e80c1e6695b3d6f3294cbce2d33 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 22 Dec 2017 11:00:49 +1300 Subject: [PATCH 17/42] feat: add --pass to command line #1135 Allow the pass phrase to specified on the jsipfs command line. --- src/cli/bin.js | 7 ++++++- src/cli/utils.js | 7 ++++--- src/core/components/pre-start.js | 2 +- src/http/index.js | 1 + 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/cli/bin.js b/src/cli/bin.js index 3ea4ecc812..67e60f8362 100755 --- a/src/cli/bin.js +++ b/src/cli/bin.js @@ -21,6 +21,11 @@ const cli = yargs default: false, coerce: ('silent', silent => silent ? utils.disablePrinting() : silent) }) + .option('pass', { + desc: 'Pass phrase for the keys', + type: 'string', + default: '' + }) .commandDir('commands') .demandCommand(1) .fail((msg, err, yargs) => { @@ -59,7 +64,7 @@ if (args[0] === 'daemon' || args[0] === 'init') { if (err) { throw err } - utils.getIPFS(argv.api, (err, ipfs, cleanup) => { + utils.getIPFS(argv, (err, ipfs, cleanup) => { if (err) { throw err } cli diff --git a/src/cli/utils.js b/src/cli/utils.js index b3f2f85e9f..37cd49010f 100644 --- a/src/cli/utils.js +++ b/src/cli/utils.js @@ -38,15 +38,16 @@ function getAPICtl (apiAddr) { return APIctl(apiAddr) } -exports.getIPFS = (apiAddr, callback) => { - if (apiAddr || isDaemonOn()) { - return callback(null, getAPICtl(apiAddr), (cb) => cb()) +exports.getIPFS = (argv, callback) => { + if (argv.api || isDaemonOn()) { + return callback(null, getAPICtl(argv.api), (cb) => cb()) } const node = new IPFS({ repo: exports.getRepoPath(), init: false, start: false, + pass: argv.pass, EXPERIMENTAL: { pubsub: true } diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 8fc2e18d81..8e478b5d3d 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -13,7 +13,7 @@ module.exports = function preStart (self) { return (callback) => { self.log('pre-start') - self._keychain = new Keychain(self._repo.keys, { passPhrase: 'todo do not hardcode the pass phrase' }) + self._keychain = new Keychain(self._repo.keys, { passPhrase: self._options.pass || 'todo do not hardcode the pass phrase' }) waterfall([ (cb) => self._repo.config.get(cb), diff --git a/src/http/index.js b/src/http/index.js index 2df407dd5d..4a985ce3c6 100644 --- a/src/http/index.js +++ b/src/http/index.js @@ -67,6 +67,7 @@ function HttpApi (repo, config, cliArgs) { init: init, start: true, config: config, + pass: cliArgs && cliArgs.pass, EXPERIMENTAL: { pubsub: cliArgs && cliArgs.enablePubsubExperiment, sharding: cliArgs && cliArgs.enableShardingExperiment From 6b2d15e139e8217864b5a3dd32e3b7eeb94e8a0c Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 22 Dec 2017 11:18:20 +1300 Subject: [PATCH 18/42] docs(readme): mention --pass and ipfs.key... --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index bef1e12285..87f4ddf880 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,8 @@ const node = new IPFS({ // }, start: true, // default // start: false, + pass: '' // default + // pass: 'pass phrase for key access', EXPERIMENTAL: { // enable experimental features pubsub: true, sharding: true, // enable dir sharding @@ -275,6 +277,14 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.object.patch.setData(multihash, data, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md#objectpatchsetdata) - [pin (not implemented, yet!)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) +#### `Security` + +- [key](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/KEY.md) + - `ipfs.key.gen(name, options, [callback])` + - `ipfs.key.list([callback])` + - `ipfs.key.rename(oldName, newName, [callback])` + - `ipfs.key.rm(name, [callback])` + #### `Network` - [bootstrap](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) From ccac9735e5450dd569a392bed885fb8d6b23753f Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Fri, 22 Dec 2017 12:03:56 +1300 Subject: [PATCH 19/42] docs(readme): review changes --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 87f4ddf880..48e9b8f36f 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.object.patch.setData(multihash, data, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md#objectpatchsetdata) - [pin (not implemented, yet!)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) -#### `Security` +#### `Crypto and Key Management` - [key](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/KEY.md) - `ipfs.key.gen(name, options, [callback])` @@ -285,6 +285,8 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.key.rename(oldName, newName, [callback])` - `ipfs.key.rm(name, [callback])` +- [crypto (not yet implemented)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC) + #### `Network` - [bootstrap](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) From 9799d99122a714bf870dbe127757693911b75c23 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 04:46:43 +1300 Subject: [PATCH 20/42] test: --pass is listed in options --- README.md | 4 ++++ test/cli/files.js | 1 + 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 48e9b8f36f..c7fb043564 100644 --- a/README.md +++ b/README.md @@ -535,6 +535,10 @@ If you find any other issue, please check the [`Electron Support` issue](https:/ | [`is-ipfs`](https://github.com/ipfs/is-ipfs) | [![npm](https://img.shields.io/npm/v/is-ipfs.svg?maxAge=86400&style=flat-square)](//github.com/ipfs/is-ipfs/releases) | [![Dep](https://david-dm.org/ipfs/is-ipfs.svg?style=flat-square)](https://david-dm.org/ipfs/is-ipfs) | [![devDep](https://david-dm.org/ipfs/is-ipfs/dev-status.svg?style=flat-square)](https://david-dm.org/ipfs/is-ipfs?type=dev) | [![Travis](https://travis-ci.org/ipfs/is-ipfs.svg?branch=master)](https://travis-ci.org/ipfs/is-ipfs) | | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/ipfs/is-ipfs?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/ipfs/is-ipfs/badge.svg?branch=master)](https://coveralls.io/github/ipfs/is-ipfs?branch=master) | | [`multihashing`](//github.com/multiformats/js-multihashing) | [![npm](https://img.shields.io/npm/v/multihashing.svg?maxAge=86400&style=flat-square)](//github.com/multiformats/js-multihashing/releases) | [![Dep](https://david-dm.org/multiformats/js-multihashing.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing) | [![devDep](https://david-dm.org/multiformats/js-multihashing/dev-status.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing?type=dev) | [![Travis](https://travis-ci.org/multiformats/js-multihashing.svg?branch=master)](https://travis-ci.org/multiformats/js-multihashing) | [![Circle CI](https://circleci.com/gh/multiformats/js-multihashing.svg?style=svg)](https://circleci.com/gh/jbenet/js-multihashing) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/multiformats/js-multihashing?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/jbenet/js-multihashing/badge.svg?branch=master)](https://coveralls.io/github/jbenet/js-multihashing?branch=master) | | [`mafmt`](//github.com/whyrusleeping/js-mafmt) | [![npm](https://img.shields.io/npm/v/mafmt.svg?maxAge=86400&style=flat-square)](//github.com/whyrusleeping/js-mafmt/releases) | [![Dep](https://david-dm.org/whyrusleeping/js-mafmt.svg?style=flat-square)](https://david-dm.org/whyrusleeping/js-mafmt) | [![devDep](https://david-dm.org/whyrusleeping/js-mafmt/dev-status.svg?style=flat-square)](https://david-dm.org/whyrusleeping/js-mafmt?type=dev) | [![Travis](https://travis-ci.org/whyrusleeping/js-mafmt.svg?branch=master)](https://travis-ci.org/whyrusleeping/js-mafmt) | [![Circle CI](https://circleci.com/gh/whyrusleeping/js-mafmt.svg?style=svg)](https://circleci.com/gh/whyrusleeping/js-mafmt) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/whyrusleeping/js-mafmt?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/whyrusleeping/js-mafmt/badge.svg?branch=master)](https://coveralls.io/github/whyrusleeping/js-mafmt?branch=master) | +| **Crypto** +| [`libp2p-crypto`](https://github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Dep](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![devDep](https://david-dm.org/libp2p/js-libp2p-crypto/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto?type=dev) | [![Travis](https://travis-ci.org/libp2p/js-libp2p-crypto.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-crypto) | [![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-crypto.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-crypto) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/libp2p/js-libp2p-crypto?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-crypto/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-crypto?branch=master) | +| [`libp2p-keychain`](https://github.com/libp2p/js-libp2p-keychain) | [![npm](https://img.shields.io/npm/v/libp2p-keychain.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-keychain/releases) | [![Dep](https://david-dm.org/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain) | [![devDep](https://david-dm.org/libp2p/js-libp2p-keychain/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain?type=dev) | [![Travis](https://travis-ci.org/libp2p/js-libp2p-keychain.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-keychain) | [![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-keychain.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-keychain) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/libp2p/js-libp2p-keychain?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-keychain/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-keychain?branch=master) | + ## Development diff --git a/test/cli/files.js b/test/cli/files.js index 5a36f52a4e..738b07e317 100644 --- a/test/cli/files.js +++ b/test/cli/files.js @@ -353,6 +353,7 @@ describe('files', () => runOnAndOff((thing) => { 'Options:', ' --version Show version number [boolean]', ' --silent Write no output [boolean] [default: false]', + ' --pass Pass phrase for the keys [string] [default: ""]', ' --help Show help [boolean]', ' -v, --headers Print table headers (Hash, Size, Name).', ' [boolean] [default: false]', From c54be1cb25334821e1a6cda127f02721b4e6673a Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 11:13:29 +1300 Subject: [PATCH 21/42] feat: init creates the keychain with --pass Creates the 'self' key, #1138 Fixes #1139 --- src/cli/commands/init.js | 1 + src/core/components/init.js | 18 +++++++++++++++++- src/core/components/pre-start.js | 8 ++++++-- test/core/init.spec.js | 9 ++++++--- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/cli/commands/init.js b/src/cli/commands/init.js index b53639fec0..741a313750 100644 --- a/src/cli/commands/init.js +++ b/src/cli/commands/init.js @@ -38,6 +38,7 @@ module.exports = { node.init({ bits: argv.bits, emptyRepo: argv.emptyRepo, + pass: argv.pass, log: print }, (err) => { if (err) { diff --git a/src/core/components/init.js b/src/core/components/init.js index 87e9072811..1364aee782 100644 --- a/src/core/components/init.js +++ b/src/core/components/init.js @@ -5,6 +5,7 @@ const waterfall = require('async/waterfall') const parallel = require('async/parallel') const promisify = require('promisify-es6') const config = require('../runtime/config-nodejs.json') +const Keychain = require('libp2p-keychain') const addDefaultAssets = require('./init-assets') @@ -36,7 +37,7 @@ module.exports = function init (self) { opts.emptyRepo = opts.emptyRepo || false opts.bits = Number(opts.bits) || 2048 opts.log = opts.log || function () {} - + let privateKey waterfall([ // Verify repo does not yet exist. (cb) => self._repo.exists(cb), @@ -57,6 +58,10 @@ module.exports = function init (self) { PeerID: keys.toB58String(), PrivKey: keys.privKey.bytes.toString('base64') } + if (opts.pass) { + privateKey = keys.privKey + config.Keychain = Keychain.generateOptions() + } opts.log('done') opts.log('peer identity: ' + config.Identity.PeerID) @@ -65,10 +70,21 @@ module.exports = function init (self) { (_, cb) => self._repo.open(cb), (cb) => { self.log('repo opened') + if (opts.pass) { + self.log('creating keychain') + const keychainOptions = Object.assign({passPhrase: opts.pass}, config.Keychain) + const keychain = new Keychain(self._repo.keys, keychainOptions) + keychain.importPeer('self', { privKey: privateKey }, cb) + } else { + cb() + } + }, + (_, cb) => { if (opts.emptyRepo) { return cb(null, true) } + self.log('adding assets') const tasks = [ // add empty unixfs dir object (go-ipfs assumes this exists) (cb) => self.object.new('unixfs-dir', cb) diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 8e478b5d3d..ff7c8c7032 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -13,10 +13,14 @@ module.exports = function preStart (self) { return (callback) => { self.log('pre-start') - self._keychain = new Keychain(self._repo.keys, { passPhrase: self._options.pass || 'todo do not hardcode the pass phrase' }) - waterfall([ (cb) => self._repo.config.get(cb), + (config, cb) => { + const pass = self._options.pass || 'todo do not hardcode the pass phrase' + const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + cb(null, config) + }, (config, cb) => { const privKey = config.Identity.PrivKey diff --git a/test/core/init.spec.js b/test/core/init.spec.js index 07990027f2..8adaad85e8 100644 --- a/test/core/init.spec.js +++ b/test/core/init.spec.js @@ -7,6 +7,7 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const isNode = require('detect-node') +const hat = require('hat') const PeerId = require('peer-id') const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') @@ -36,7 +37,7 @@ describe('init', () => { afterEach((done) => repo.teardown(done)) it('basic', (done) => { - ipfs.init({ bits: 512 }, (err) => { + ipfs.init({ bits: 512, pass: hat() }, (err) => { expect(err).to.not.exist() repo.exists((err, res) => { @@ -45,7 +46,9 @@ describe('init', () => { repo.config.get((err, config) => { expect(err).to.not.exist() + console.log(config) expect(config.Identity).to.exist() + expect(config.Keychain).to.exist() done() }) }) @@ -55,7 +58,7 @@ describe('init', () => { it('set # of bits in key', function (done) { this.timeout(40 * 1000) - ipfs.init({ bits: 1024 }, (err) => { + ipfs.init({ bits: 1024, pass: hat() }, (err) => { expect(err).to.not.exist() repo.config.get((err, config) => { @@ -67,7 +70,7 @@ describe('init', () => { }) it('init docs are written', (done) => { - ipfs.init({ bits: 512 }, (err) => { + ipfs.init({ bits: 512, pass: hat() }, (err) => { expect(err).to.not.exist() const multihash = 'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB' From cffdc8085692cd4c3a8d0ca3395090f250dc4d8d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 11:50:02 +1300 Subject: [PATCH 22/42] fix: initing without --pass --- src/core/components/init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/init.js b/src/core/components/init.js index 1364aee782..d245e5fe33 100644 --- a/src/core/components/init.js +++ b/src/core/components/init.js @@ -76,7 +76,7 @@ module.exports = function init (self) { const keychain = new Keychain(self._repo.keys, keychainOptions) keychain.importPeer('self', { privKey: privateKey }, cb) } else { - cb() + cb(null, true) } }, (_, cb) => { From 69e188965e83065a094d25dfdedec0dcb9fd1b8e Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 12:51:16 +1300 Subject: [PATCH 23/42] test: remove debug code --- test/core/init.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/core/init.spec.js b/test/core/init.spec.js index 8adaad85e8..58916ecbe4 100644 --- a/test/core/init.spec.js +++ b/test/core/init.spec.js @@ -46,7 +46,6 @@ describe('init', () => { repo.config.get((err, config) => { expect(err).to.not.exist() - console.log(config) expect(config.Identity).to.exist() expect(config.Keychain).to.exist() done() From 2805b040510fe955d02ea98956fa959d4cc03f00 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 16:42:22 +1300 Subject: [PATCH 24/42] feat(core.key): export and import of a key --- README.md | 7 ++++- src/core/boot.js | 2 +- src/core/components/key.js | 11 ++++++++ test/core/key-exchange.js | 53 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 test/core/key-exchange.js diff --git a/README.md b/README.md index c7fb043564..7c7f252a63 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ const node = new IPFS({ // }, start: true, // default // start: false, - pass: '' // default + pass: undefined // default // pass: 'pass phrase for key access', EXPERIMENTAL: { // enable experimental features pubsub: true, @@ -284,6 +284,11 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.key.list([callback])` - `ipfs.key.rename(oldName, newName, [callback])` - `ipfs.key.rm(name, [callback])` + + For security reasons, the following are not available when using http-api + + - `ipfs.key.export(name, password, [callback])` + - `ipfs.key.import(name, pem, password, [callback])` - [crypto (not yet implemented)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC) diff --git a/src/core/boot.js b/src/core/boot.js index 64f62ca631..1958a3329e 100644 --- a/src/core/boot.js +++ b/src/core/boot.js @@ -15,7 +15,7 @@ module.exports = (self) => { const repoOpen = !self._repo.closed const customInitOptions = typeof options.init === 'object' ? options.init : {} - const initOptions = Object.assign({ bits: 2048 }, customInitOptions) + const initOptions = Object.assign({ bits: 2048, pass: self._options.pass }, customInitOptions) // Checks if a repo exists, and if so opens it // Will return callback with a bool indicating the existence diff --git a/src/core/components/key.js b/src/core/components/key.js index 903bcad398..e99b1b432f 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -53,6 +53,17 @@ module.exports = function key (self) { } callback(null, result) }) + }), + + import: promisify((name, pem, password, callback) => { + self._keychain.importKey(name, pem, password, (err, key) => { + if (err) return callback(err) + callback(null, toKeyInfo(key)) + }) + }), + + export: promisify((name, password, callback) => { + self._keychain.exportKey(name, password, callback) }) } } diff --git a/test/core/key-exchange.js b/test/core/key-exchange.js new file mode 100644 index 0000000000..8d7713f993 --- /dev/null +++ b/test/core/key-exchange.js @@ -0,0 +1,53 @@ +/* eslint max-nested-callbacks: ["error", 8] */ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const hat = require('hat') +const IPFS = require('../../src/core') + +// This gets replaced by `create-repo-browser.js` in the browser +const createTempRepo = require('../utils/create-repo-nodejs.js') + +describe('key exchange', () => { + + let ipfs + let repo + let selfPem + let passwordPem = hat() + + before(function (done) { + this.timeout(20 * 1000) + repo = createTempRepo() + ipfs = new IPFS({ + repo: repo, + pass: hat() + }) + ipfs.on('ready', () => done()) + }) + + after((done) => repo.teardown(done)) + + it('exports', (done) => { + ipfs.key.export('self', passwordPem, (err, pem) => { + expect(err).to.not.exist() + expect(pem).to.exist() + selfPem = pem + console.log(pem) + done() + }) + }) + + it('imports', (done) => { + ipfs.key.import('clone', selfPem, passwordPem, (err, key) => { + expect(err).to.not.exist() + expect(key).to.exist() + expect(key).to.have.property('Name', 'clone') + expect(key).to.have.property('Id') + done() + }) + }) +}) From bbba773b3bc4c5849c141ccf6142266a40b6e53d Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Dec 2017 22:46:46 +1300 Subject: [PATCH 25/42] feat(cli.key): export and import of a key --- src/cli/commands/key/export.js | 37 ++++++++++++++++++++++++++++++++ src/cli/commands/key/import.js | 34 +++++++++++++++++++++++++++++ src/core/boot.js | 3 ++- src/core/components/pre-start.js | 2 ++ test/core/key-exchange.js | 3 +-- 5 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/cli/commands/key/export.js create mode 100644 src/cli/commands/key/import.js diff --git a/src/cli/commands/key/export.js b/src/cli/commands/key/export.js new file mode 100644 index 0000000000..66adde248c --- /dev/null +++ b/src/cli/commands/key/export.js @@ -0,0 +1,37 @@ +'use strict' + +const fs = require('fs') + +module.exports = { + command: 'export ', + + describe: 'Export the key as a password protected PKCS #8 PEM file', + + builder: { + passout: { + alias: 'p', + describe: 'Password for the PEM', + type: 'string', + demandOption: true + }, + output: { + alias: 'o', + describe: 'Output file', + type: 'string', + default: 'stdout' + } + }, + + handler (argv) { + argv.ipfs.key.export(argv.name, argv.passout, (err, pem) => { + if (err) { + throw err + } + if (argv.output === 'stdout') { + process.stdout.write(pem) + } else { + fs.writeFileSync(argv.output, pem) + } + }) + } +} diff --git a/src/cli/commands/key/import.js b/src/cli/commands/key/import.js new file mode 100644 index 0000000000..875eaaa18a --- /dev/null +++ b/src/cli/commands/key/import.js @@ -0,0 +1,34 @@ +'use strict' + +const fs = require('fs') +const print = require('../../utils').print + +module.exports = { + command: 'import ', + + describe: 'Import the key from a PKCS #8 PEM file', + + builder: { + passin: { + alias: 'p', + describe: 'Password for the PEM', + type: 'string' + }, + input: { + alias: 'i', + describe: 'Input PEM file', + type: 'string', + demandOption: true, + coerce: ('input', input => fs.readFileSync(input, 'utf8')) + } + }, + + handler (argv) { + argv.ipfs.key.import(argv.name, argv.input, argv.passin, (err, key) => { + if (err) { + throw err + } + print(`imported ${key.Name} ${key.Id}`) + }) + } +} diff --git a/src/core/boot.js b/src/core/boot.js index 1958a3329e..cc7c14970e 100644 --- a/src/core/boot.js +++ b/src/core/boot.js @@ -30,6 +30,7 @@ module.exports = (self) => { (cb) => self._repo.open(cb), (cb) => self.preStart(cb), (cb) => { + self.log('initialized') self.state.initialized() cb(null, true) } @@ -56,8 +57,8 @@ module.exports = (self) => { if (err) { return self.emit('error', err) } + self.log('boot:done') self.emit('ready') - self.log('boot:done', err) } const tasks = [] diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index ff7c8c7032..738949edd8 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -19,6 +19,7 @@ module.exports = function preStart (self) { const pass = self._options.pass || 'todo do not hardcode the pass phrase' const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) self._keychain = new Keychain(self._repo.keys, keychainOptions) + self.log('keychain constructed') cb(null, config) }, (config, cb) => { @@ -27,6 +28,7 @@ module.exports = function preStart (self) { peerId.createFromPrivKey(privKey, (err, id) => cb(err, config, id)) }, (config, id, cb) => { + self.log('peer created') self._peerInfo = new PeerInfo(id) if (config.Addresses && config.Addresses.Swarm) { diff --git a/test/core/key-exchange.js b/test/core/key-exchange.js index 8d7713f993..373c7f3fe2 100644 --- a/test/core/key-exchange.js +++ b/test/core/key-exchange.js @@ -13,12 +13,11 @@ const IPFS = require('../../src/core') const createTempRepo = require('../utils/create-repo-nodejs.js') describe('key exchange', () => { - let ipfs let repo let selfPem let passwordPem = hat() - + before(function (done) { this.timeout(20 * 1000) repo = createTempRepo() From 9cd7b7ca6b574b1e23e9d2c0e4526ec63fac29a8 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 11:29:54 +1300 Subject: [PATCH 26/42] feat(http.api.key): export and import of a key --- README.md | 7 ++----- src/http/api/resources/key.js | 29 +++++++++++++++++++++++++++++ src/http/api/routes/key.js | 12 ++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7c7f252a63..170973733d 100644 --- a/README.md +++ b/README.md @@ -280,15 +280,12 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u #### `Crypto and Key Management` - [key](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/KEY.md) + - `ipfs.key.export(name, password, [callback])` - `ipfs.key.gen(name, options, [callback])` + - `ipfs.key.import(name, pem, password, [callback])` - `ipfs.key.list([callback])` - `ipfs.key.rename(oldName, newName, [callback])` - `ipfs.key.rm(name, [callback])` - - For security reasons, the following are not available when using http-api - - - `ipfs.key.export(name, password, [callback])` - - `ipfs.key.import(name, pem, password, [callback])` - [crypto (not yet implemented)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC) diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js index be91a8a5f8..98c7c823fc 100644 --- a/src/http/api/resources/key.js +++ b/src/http/api/resources/key.js @@ -73,3 +73,32 @@ exports.gen = (request, reply) => { return reply(toKeyInfo(key)) }) } + +exports.export = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const password = request.query.password + ipfs._keychain.exportKey(name, password, (err, pem) => { + if (err) { + return applyError(reply, err) + } + + return reply(pem).type('application/x-pem-file') + }) +} + +exports.import = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const pem = request.query.pem + const password = request.query.password + console.log('import psd', password) + console.log('import pem', pem) + ipfs._keychain.importKey(name, pem, password, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply(toKeyInfo(key)) + }) +} diff --git a/src/http/api/routes/key.js b/src/http/api/routes/key.js index 2b6f47ee16..4493bdab39 100644 --- a/src/http/api/routes/key.js +++ b/src/http/api/routes/key.js @@ -28,4 +28,16 @@ module.exports = (server) => { path: '/api/v0/key/rename', handler: resources.key.rename }) + + api.route({ + method: '*', + path: '/api/v0/key/export', + handler: resources.key.export + }) + + api.route({ + method: '*', + path: '/api/v0/key/import', + handler: resources.key.import + }) } From 27b1529aef2bbf81be4e6adcd831db564ade271a Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 13:07:09 +1300 Subject: [PATCH 27/42] test(http-api): create a keychain for the tests --- src/http/api/resources/key.js | 2 -- test/core/key-exchange.js | 1 - test/http-api/index.js | 6 +++++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js index 98c7c823fc..15de675c8e 100644 --- a/src/http/api/resources/key.js +++ b/src/http/api/resources/key.js @@ -92,8 +92,6 @@ exports.import = (request, reply) => { const name = request.query.arg const pem = request.query.pem const password = request.query.password - console.log('import psd', password) - console.log('import pem', pem) ipfs._keychain.importKey(name, pem, password, (err, key) => { if (err) { return applyError(reply, err) diff --git a/test/core/key-exchange.js b/test/core/key-exchange.js index 373c7f3fe2..f1d73529b5 100644 --- a/test/core/key-exchange.js +++ b/test/core/key-exchange.js @@ -35,7 +35,6 @@ describe('key exchange', () => { expect(err).to.not.exist() expect(pem).to.exist() selfPem = pem - console.log(pem) done() }) }) diff --git a/test/http-api/index.js b/test/http-api/index.js index 374f50485c..1fa11622ad 100644 --- a/test/http-api/index.js +++ b/test/http-api/index.js @@ -6,6 +6,7 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) +const hat = require('hat') const API = require('../../src/http') const APIctl = require('ipfs-api') const ncp = require('ncp').ncp @@ -21,7 +22,10 @@ describe('HTTP API', () => { before(function (done) { this.timeout(60 * 1000) - const options = { enablePubsubExperiment: true } + const options = { + pass: hat(), + enablePubsubExperiment: true + } http.api = new API(repoTests, null, options) ncp(repoExample, repoTests, (err) => { From 637b241558b9ec1e4ef65f35812ab3236c448b56 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 16:21:38 +1300 Subject: [PATCH 28/42] fix: if no --pass, then no key management Helps #1135 --- src/core/components/no-keychain.js | 6 ++++-- src/core/components/pre-start.js | 15 ++++++++++----- test/cli/key.js | 9 +++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/core/components/no-keychain.js b/src/core/components/no-keychain.js index bae80d21c4..ced2f142dc 100644 --- a/src/core/components/no-keychain.js +++ b/src/core/components/no-keychain.js @@ -1,17 +1,19 @@ 'use strict' function fail () { - throw new Error('Key management is not yet implemented') + throw new Error('Key management requires the daemon to run with \'--pass ...\'') } class NoKeychain { - static get options () { return {} } + static get options () { fail() } + static generateOptions () { fail() } createKey () { fail() } listKeys () { fail() } findKeyById () { fail() } findKeyByName () { fail() } renameKey () { fail() } + removeKey () { fail() } exportKey () { fail() } importKey () { fail() } importPeer () { fail() } diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 738949edd8..76f94cf052 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -5,7 +5,7 @@ const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') const waterfall = require('async/waterfall') const Keychain = require('libp2p-keychain') - +const NoKeychain = require('./no-keychain') /* * Load stuff from Repo into memory */ @@ -16,10 +16,15 @@ module.exports = function preStart (self) { waterfall([ (cb) => self._repo.config.get(cb), (config, cb) => { - const pass = self._options.pass || 'todo do not hardcode the pass phrase' - const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) - self._keychain = new Keychain(self._repo.keys, keychainOptions) - self.log('keychain constructed') + const pass = self._options.pass + if (pass) { + const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + self.log('keychain constructed') + } else { + self._keychain = new NoKeychain() + self.log('no keychain, use --pass') + } cb(null, config) }, (config, cb) => { diff --git a/test/cli/key.js b/test/cli/key.js index 076225ab7e..e2eb6e53aa 100644 --- a/test/cli/key.js +++ b/test/cli/key.js @@ -8,6 +8,7 @@ const hat = require('hat') describe('key', () => runOnAndOff.off((thing) => { const name = 'test-key-' + hat() const newName = 'test-key-' + hat() + const pass = '--pass ' + hat() let ipfs before(() => { @@ -17,7 +18,7 @@ describe('key', () => runOnAndOff.off((thing) => { it('gen', function () { this.timeout(40 * 1000) - return ipfs(`key gen ${name} --type rsa --size 2048`) + return ipfs(`${pass} key gen ${name} --type rsa --size 2048`) .then((out) => { expect(out).to.include(`generated ${name}`) }) @@ -26,7 +27,7 @@ describe('key', () => runOnAndOff.off((thing) => { it('list', function () { this.timeout(20 * 1000) - return ipfs('key list') + return ipfs(`${pass} key list`) .then((out) => { expect(out).to.include(name) }) @@ -35,7 +36,7 @@ describe('key', () => runOnAndOff.off((thing) => { it('rename', function () { this.timeout(20 * 1000) - return ipfs(`key rename ${name} ${newName}`) + return ipfs(`${pass} key rename ${name} ${newName}`) .then((out) => { expect(out).to.include(`renamed to ${newName}`) }) @@ -44,7 +45,7 @@ describe('key', () => runOnAndOff.off((thing) => { it('rm', function () { this.timeout(20 * 1000) - return ipfs(`key rm ${newName}`) + return ipfs(`${pass} key rm ${newName}`) .then((out) => { expect(out).to.include(newName) }) From f8d48129a3a9310e62039f89077c8b0c598313cc Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 16:54:43 +1300 Subject: [PATCH 29/42] feat: create the keychain on init #1135 --- src/core/components/init.js | 4 ++-- src/core/components/pre-start.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/components/init.js b/src/core/components/init.js index d245e5fe33..21504c9128 100644 --- a/src/core/components/init.js +++ b/src/core/components/init.js @@ -73,8 +73,8 @@ module.exports = function init (self) { if (opts.pass) { self.log('creating keychain') const keychainOptions = Object.assign({passPhrase: opts.pass}, config.Keychain) - const keychain = new Keychain(self._repo.keys, keychainOptions) - keychain.importPeer('self', { privKey: privateKey }, cb) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + self._keychain.importPeer('self', { privKey: privateKey }, cb) } else { cb(null, true) } diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 76f94cf052..9a7c6eadf1 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -17,7 +17,9 @@ module.exports = function preStart (self) { (cb) => self._repo.config.get(cb), (config, cb) => { const pass = self._options.pass - if (pass) { + if (self._keychain) { + // most likely an init has happened + } else if (pass) { const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) self._keychain = new Keychain(self._repo.keys, keychainOptions) self.log('keychain constructed') From 9c7813cf7538595391619998235a2745a4d6b8c6 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 18:17:36 +1300 Subject: [PATCH 30/42] feat: auto upgrade to keychain Older repos are automatically upgraded to a keychain when the '--pass' is present. Helps #1138 --- src/core/components/no-keychain.js | 2 +- src/core/components/pre-start.js | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/core/components/no-keychain.js b/src/core/components/no-keychain.js index ced2f142dc..6f07f4068e 100644 --- a/src/core/components/no-keychain.js +++ b/src/core/components/no-keychain.js @@ -1,7 +1,7 @@ 'use strict' function fail () { - throw new Error('Key management requires the daemon to run with \'--pass ...\'') + throw new Error('Key management requires \'--pass ...\' option') } class NoKeychain { diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 9a7c6eadf1..386b6e1702 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -13,12 +13,28 @@ module.exports = function preStart (self) { return (callback) => { self.log('pre-start') + const pass = self._options.pass + let importSelf = false waterfall([ (cb) => self._repo.config.get(cb), (config, cb) => { - const pass = self._options.pass + // Upgrade to keychain? + if (!pass || config.Keychain) { + return cb(null, config) + } + config.Keychain = Keychain.generateOptions() + self.config.set('Keychain', config.Keychain, (err) => { + if (err) return cb(err) + const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + importSelf = true + self.log('Upgrade repo for a keychain') + cb(null, config) + }) + }, + (config, cb) => { if (self._keychain) { - // most likely an init has happened + // most likely an init or upgrade has happened } else if (pass) { const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) self._keychain = new Keychain(self._repo.keys, keychainOptions) @@ -32,7 +48,12 @@ module.exports = function preStart (self) { (config, cb) => { const privKey = config.Identity.PrivKey - peerId.createFromPrivKey(privKey, (err, id) => cb(err, config, id)) + peerId.createFromPrivKey(privKey, (err, id) => { + if (!err && importSelf) { + return self._keychain.importPeer('self', id, (err) => cb(err, config, id)) + } + cb(err, config, id) + }) }, (config, id, cb) => { self.log('peer created') From 300fb7da64c31933c753d11f315921b21ed581a2 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sun, 24 Dec 2017 18:29:01 +1300 Subject: [PATCH 31/42] feat: print key ID then name, its easier to read --- src/cli/commands/key/gen.js | 2 +- src/cli/commands/key/import.js | 2 +- src/cli/commands/key/list.js | 2 +- src/cli/commands/key/rename.js | 2 +- src/cli/commands/key/rm.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js index ef645d284f..7a80ac255b 100644 --- a/src/cli/commands/key/gen.js +++ b/src/cli/commands/key/gen.js @@ -29,7 +29,7 @@ module.exports = { if (err) { throw err } - print(`generated ${key.Name} ${key.Id}`) + print(`generated ${key.Id} ${key.Name}`) }) } } diff --git a/src/cli/commands/key/import.js b/src/cli/commands/key/import.js index 875eaaa18a..c4446172fb 100644 --- a/src/cli/commands/key/import.js +++ b/src/cli/commands/key/import.js @@ -28,7 +28,7 @@ module.exports = { if (err) { throw err } - print(`imported ${key.Name} ${key.Id}`) + print(`imported ${key.Id} ${key.Name}`) }) } } diff --git a/src/cli/commands/key/list.js b/src/cli/commands/key/list.js index 577719cb77..c6bc1cb64e 100644 --- a/src/cli/commands/key/list.js +++ b/src/cli/commands/key/list.js @@ -14,7 +14,7 @@ module.exports = { if (err) { throw err } - res.Keys.forEach((ki) => print(`${ki.Name} ${ki.Id}`)) + res.Keys.forEach((ki) => print(`${ki.Id} ${ki.Name}`)) }) } } diff --git a/src/cli/commands/key/rename.js b/src/cli/commands/key/rename.js index 130a25fa9a..922b40f5fb 100644 --- a/src/cli/commands/key/rename.js +++ b/src/cli/commands/key/rename.js @@ -14,7 +14,7 @@ module.exports = { if (err) { throw err } - print(`renamed to ${res.Now} ${res.Id}`) + print(`renamed to ${res.Id} ${res.Now}`) }) } } diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js index e31abe5dd7..088ede54b4 100644 --- a/src/cli/commands/key/rm.js +++ b/src/cli/commands/key/rm.js @@ -14,7 +14,7 @@ module.exports = { if (err) { throw err } - res.Keys.forEach((ki) => print(`${ki.Name} ${ki.Id}`)) + res.Keys.forEach((ki) => print(`${ki.Id} ${ki.Name}`)) }) } } From 694518e5993fbc72435cf102abfcea8d157428ed Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 28 Dec 2017 22:24:32 +1300 Subject: [PATCH 32/42] docs(readme): review change --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 170973733d..4d3ccc8f52 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,6 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.key.list([callback])` - `ipfs.key.rename(oldName, newName, [callback])` - `ipfs.key.rm(name, [callback])` - - [crypto (not yet implemented)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC) #### `Network` From 3a648cdde6fd5ac91056afcde2a370618fd811f3 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 14:44:28 +1300 Subject: [PATCH 33/42] chore: key cli normalisation --- src/cli/commands/key/gen.js | 2 +- src/cli/commands/key/import.js | 2 +- src/cli/commands/key/list.js | 4 ++-- src/cli/commands/key/rename.js | 2 +- src/cli/commands/key/rm.js | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js index 7a80ac255b..a3f108eeaa 100644 --- a/src/cli/commands/key/gen.js +++ b/src/cli/commands/key/gen.js @@ -29,7 +29,7 @@ module.exports = { if (err) { throw err } - print(`generated ${key.Id} ${key.Name}`) + print(`generated ${key.id} ${key.name}`) }) } } diff --git a/src/cli/commands/key/import.js b/src/cli/commands/key/import.js index c4446172fb..ae0363b25d 100644 --- a/src/cli/commands/key/import.js +++ b/src/cli/commands/key/import.js @@ -28,7 +28,7 @@ module.exports = { if (err) { throw err } - print(`imported ${key.Id} ${key.Name}`) + print(`imported ${key.id} ${key.name}`) }) } } diff --git a/src/cli/commands/key/list.js b/src/cli/commands/key/list.js index c6bc1cb64e..d50db99697 100644 --- a/src/cli/commands/key/list.js +++ b/src/cli/commands/key/list.js @@ -10,11 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.list((err, res) => { + argv.ipfs.key.list((err, keys) => { if (err) { throw err } - res.Keys.forEach((ki) => print(`${ki.Id} ${ki.Name}`)) + keys.forEach((ki) => print(`${ki.id} ${ki.name}`)) }) } } diff --git a/src/cli/commands/key/rename.js b/src/cli/commands/key/rename.js index 922b40f5fb..9126dbbb36 100644 --- a/src/cli/commands/key/rename.js +++ b/src/cli/commands/key/rename.js @@ -14,7 +14,7 @@ module.exports = { if (err) { throw err } - print(`renamed to ${res.Id} ${res.Now}`) + print(`renamed to ${res.id} ${res.now}`) }) } } diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js index 088ede54b4..a7a5daf658 100644 --- a/src/cli/commands/key/rm.js +++ b/src/cli/commands/key/rm.js @@ -10,11 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.key.rm(argv.name, (err, res) => { + argv.ipfs.key.rm(argv.name, (err, key) => { if (err) { throw err } - res.Keys.forEach((ki) => print(`${ki.Id} ${ki.Name}`)) + print(`${key.id} ${key.name}`) }) } } From d65aac38f80374614a84563227366f28afdb68ff Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 14:52:06 +1300 Subject: [PATCH 34/42] chore: key core normalisation --- src/core/components/key.js | 41 +++++++++----------------------------- 1 file changed, 9 insertions(+), 32 deletions(-) diff --git a/src/core/components/key.js b/src/core/components/key.js index e99b1b432f..b5bc5cd434 100644 --- a/src/core/components/key.js +++ b/src/core/components/key.js @@ -4,62 +4,39 @@ const promisify = require('promisify-es6') -function toKeyInfo (key) { - return { - Name: key.name, - Id: key.id - } -} - module.exports = function key (self) { return { gen: promisify((name, opts, callback) => { - self._keychain.createKey(name, opts.type, opts.size, (err, key) => { - if (err) return callback(err) - callback(null, toKeyInfo(key)) - }) + self._keychain.createKey(name, opts.type, opts.size, callback) }), info: promisify((name, callback) => { - self._keychain.findKeyByName(name, (err, key) => { - if (err) return callback(err) - callback(null, toKeyInfo(key)) - }) + self._keychain.findKeyByName(name, callback) }), list: promisify((callback) => { - self._keychain.listKeys((err, keys) => { - if (err) return callback(err) - keys = keys.map(toKeyInfo) - callback(null, { Keys: keys }) - }) + self._keychain.listKeys(callback) }), rm: promisify((name, callback) => { - self._keychain.removeKey(name, (err, key) => { - if (err) return callback(err) - callback(null, { Keys: [ toKeyInfo(key) ] }) - }) + self._keychain.removeKey(name, callback) }), rename: promisify((oldName, newName, callback) => { self._keychain.renameKey(oldName, newName, (err, key) => { if (err) return callback(err) const result = { - Was: oldName, - Now: key.name, - Id: key.id, - Overwrite: false + was: oldName, + now: key.name, + id: key.id, + overwrite: false } callback(null, result) }) }), import: promisify((name, pem, password, callback) => { - self._keychain.importKey(name, pem, password, (err, key) => { - if (err) return callback(err) - callback(null, toKeyInfo(key)) - }) + self._keychain.importKey(name, pem, password, callback) }), export: promisify((name, password, callback) => { From d26d38dac40f7c199c3cec3d8bc83cae0d9eba62 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 15:01:17 +1300 Subject: [PATCH 35/42] test: key cli output has changed --- test/cli/key.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cli/key.js b/test/cli/key.js index e2eb6e53aa..8a39c4919c 100644 --- a/test/cli/key.js +++ b/test/cli/key.js @@ -20,7 +20,7 @@ describe('key', () => runOnAndOff.off((thing) => { return ipfs(`${pass} key gen ${name} --type rsa --size 2048`) .then((out) => { - expect(out).to.include(`generated ${name}`) + expect(out).to.include(name) }) }) @@ -38,7 +38,7 @@ describe('key', () => runOnAndOff.off((thing) => { return ipfs(`${pass} key rename ${name} ${newName}`) .then((out) => { - expect(out).to.include(`renamed to ${newName}`) + expect(out).to.include(newName) }) }) From 14de3892922db834dc981ccf0f9f61ab78abbea1 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 16:01:00 +1300 Subject: [PATCH 36/42] test: use DaemonFactory --- test/core/interface/key.js | 30 +++++++++++++++++++++++------- test/http-api/interface/key.js | 25 ++++++++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/test/core/interface/key.js b/test/core/interface/key.js index 3953cf8b00..737d412743 100644 --- a/test/core/interface/key.js +++ b/test/core/interface/key.js @@ -3,17 +3,33 @@ 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') -let factory +const IPFS = require('../../../src') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const options = { + args: ['--pass ipfs-is-awesome-software'] +} +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn(options, (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/key.js b/test/http-api/interface/key.js index cf43f694a0..dd7143b0ab 100644 --- a/test/http-api/interface/key.js +++ b/test/http-api/interface/key.js @@ -3,17 +3,32 @@ 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const options = { + //args: ['--pass ipfs-is-awesome-software'] +} +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } From 5874d22b1c5f365d15f29d06bd0a20cab58f8ac3 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 16:01:50 +1300 Subject: [PATCH 37/42] test: key normalisation --- test/core/key-exchange.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/key-exchange.js b/test/core/key-exchange.js index f1d73529b5..86a2781ad6 100644 --- a/test/core/key-exchange.js +++ b/test/core/key-exchange.js @@ -43,8 +43,8 @@ describe('key exchange', () => { ipfs.key.import('clone', selfPem, passwordPem, (err, key) => { expect(err).to.not.exist() expect(key).to.exist() - expect(key).to.have.property('Name', 'clone') - expect(key).to.have.property('Id') + expect(key).to.have.property('name', 'clone') + expect(key).to.have.property('id') done() }) }) From 5d31ebaa1159ac54c7c8f2b3e2fc12e3d6a22d9a Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 27 Jan 2018 17:01:18 +1300 Subject: [PATCH 38/42] test: get working --- test/cli/commands.js | 2 +- test/http-api/interface/key.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/cli/commands.js b/test/cli/commands.js index 913d1da059..1fabdc857f 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 = 60 +const commandCount = 67 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/http-api/interface/key.js b/test/http-api/interface/key.js index dd7143b0ab..45335aefc0 100644 --- a/test/http-api/interface/key.js +++ b/test/http-api/interface/key.js @@ -8,7 +8,7 @@ const parallel = require('async/parallel') const DaemonFactory = require('ipfsd-ctl') const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) const options = { - //args: ['--pass ipfs-is-awesome-software'] + args: ['--pass ipfs-is-awesome-software'] } const nodes = [] @@ -16,7 +16,7 @@ const common = { setup: function (callback) { callback(null, { spawnNode: (cb) => { - df.spawn((err, _ipfsd) => { + df.spawn(options, (err, _ipfsd) => { if (err) { return cb(err) } From ed497e4d7016b2455a7799e84931d595b45fd642 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Mon, 29 Jan 2018 14:42:29 +1300 Subject: [PATCH 39/42] feat: if missing, create the 'seff' key --- src/core/components/pre-start.js | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 386b6e1702..af4498bf15 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -18,21 +18,18 @@ module.exports = function preStart (self) { waterfall([ (cb) => self._repo.config.get(cb), (config, cb) => { - // Upgrade to keychain? - if (!pass || config.Keychain) { + // Create keychain configuration, if needed. + if (config.Keychain) { return cb(null, config) } config.Keychain = Keychain.generateOptions() self.config.set('Keychain', config.Keychain, (err) => { - if (err) return cb(err) - const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) - self._keychain = new Keychain(self._repo.keys, keychainOptions) - importSelf = true - self.log('Upgrade repo for a keychain') - cb(null, config) + self.log('using default keychain options') + cb(err, config) }) }, (config, cb) => { + // Construct the keychain if (self._keychain) { // most likely an init or upgrade has happened } else if (pass) { @@ -49,12 +46,22 @@ module.exports = function preStart (self) { const privKey = config.Identity.PrivKey peerId.createFromPrivKey(privKey, (err, id) => { - if (!err && importSelf) { - return self._keychain.importPeer('self', id, (err) => cb(err, config, id)) - } cb(err, config, id) }) }, + (config, id, cb) => { + // Import the private key as 'self', if needed. + if (!pass) { + return cb(null, config, id) + } + self._keychain.findKeyByName('self', (err) => { + if (err) { + self.log('Creating "self" key') + return self._keychain.importPeer('self', id, (err) => cb(err, config, id)) + } + cb(null, config, id) + }); + }, (config, id, cb) => { self.log('peer created') self._peerInfo = new PeerInfo(id) From cc594dc524b0b1697913db91cddd51c93b25d795 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Mon, 29 Jan 2018 16:12:32 +1300 Subject: [PATCH 40/42] chore: linting --- src/core/components/pre-start.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index af4498bf15..2121ff6e22 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -14,7 +14,6 @@ module.exports = function preStart (self) { self.log('pre-start') const pass = self._options.pass - let importSelf = false waterfall([ (cb) => self._repo.config.get(cb), (config, cb) => { @@ -60,7 +59,7 @@ module.exports = function preStart (self) { return self._keychain.importPeer('self', id, (err) => cb(err, config, id)) } cb(null, config, id) - }); + }) }, (config, id, cb) => { self.log('peer created') From 47bbc306027f16a0dc267a38f75c9f067a21e0b3 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Mon, 29 Jan 2018 19:35:52 +1300 Subject: [PATCH 41/42] chore: use latest keychain --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3303699aa8..e24f59c912 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,7 @@ "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", - "libp2p-keychain": "~0.2.0", + "libp2p-keychain": "~0.3.0", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", From bab526ee1512ecdbd0467cd7dfa79f8c143c4c92 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Tue, 30 Jan 2018 17:14:26 +1300 Subject: [PATCH 42/42] fix: call to daemon factory --- package.json | 2 +- test/http-api/interface/key.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e24f59c912..fa3e7acf7e 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", "interface-ipfs-core": "~0.42.1", - "ipfsd-ctl": "^0.27.0", + "ipfsd-ctl": "~0.27.2", "left-pad": "^1.2.0", "lodash": "^4.17.4", "mocha": "^4.1.0", diff --git a/test/http-api/interface/key.js b/test/http-api/interface/key.js index 45335aefc0..75d5cf5769 100644 --- a/test/http-api/interface/key.js +++ b/test/http-api/interface/key.js @@ -8,7 +8,7 @@ const parallel = require('async/parallel') const DaemonFactory = require('ipfsd-ctl') const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) const options = { - args: ['--pass ipfs-is-awesome-software'] + args: ['--pass', 'ipfs-is-awesome-software'] } const nodes = []