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

Implement Key API #1133

Merged
merged 42 commits into from
Jan 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
5b5e890
feat: construct the keychain when starting up
richardschneider Dec 7, 2017
5ac6be2
feat: key is a core component
richardschneider Dec 7, 2017
21ae698
fix: the keychain is always available
richardschneider Dec 7, 2017
ba82f7f
feat: key is a cli command
richardschneider Dec 7, 2017
67dd69b
feat: http api routes for key
richardschneider Dec 7, 2017
9951dd2
fix: core and http api should agree on names
richardschneider Dec 7, 2017
32aa3dc
fix: key gen options
richardschneider Dec 7, 2017
7bcdbc3
fix: remove nasty CRLFs
richardschneider Dec 7, 2017
6af95b1
test(commands): less brittle
richardschneider Dec 8, 2017
50b1af7
fix: key/rm returns key info
richardschneider Dec 8, 2017
dfd9198
chore: disable the keychain
richardschneider Dec 13, 2017
aa1f7f3
fix: lint errors
richardschneider Dec 13, 2017
9ac70d3
rebasing with master
richardschneider Dec 22, 2017
788597e
test: add core/interface/key
richardschneider Dec 20, 2017
a60f47c
test: add http-api/interface/key
richardschneider Dec 20, 2017
bb0ac88
test: add cli/key
richardschneider Dec 20, 2017
4db92ec
feat: add --pass to command line #1135
richardschneider Dec 21, 2017
6b2d15e
docs(readme): mention --pass and ipfs.key...
richardschneider Dec 21, 2017
ccac973
docs(readme): review changes
richardschneider Dec 21, 2017
9799d99
test: --pass is listed in options
richardschneider Dec 22, 2017
c54be1c
feat: init creates the keychain with --pass
richardschneider Dec 22, 2017
cffdc80
fix: initing without --pass
richardschneider Dec 22, 2017
69e1889
test: remove debug code
richardschneider Dec 22, 2017
2805b04
feat(core.key): export and import of a key
richardschneider Dec 23, 2017
bbba773
feat(cli.key): export and import of a key
richardschneider Dec 23, 2017
9cd7b7c
feat(http.api.key): export and import of a key
richardschneider Dec 23, 2017
27b1529
test(http-api): create a keychain for the tests
richardschneider Dec 24, 2017
637b241
fix: if no --pass, then no key management
richardschneider Dec 24, 2017
f8d4812
feat: create the keychain on init #1135
richardschneider Dec 24, 2017
9c7813c
feat: auto upgrade to keychain
richardschneider Dec 24, 2017
300fb7d
feat: print key ID then name, its easier to read
richardschneider Dec 24, 2017
694518e
docs(readme): review change
richardschneider Dec 28, 2017
3a648cd
chore: key cli normalisation
richardschneider Jan 27, 2018
d65aac3
chore: key core normalisation
richardschneider Jan 27, 2018
d26d38d
test: key cli output has changed
richardschneider Jan 27, 2018
14de389
test: use DaemonFactory
richardschneider Jan 27, 2018
5874d22
test: key normalisation
richardschneider Jan 27, 2018
5d31eba
test: get working
richardschneider Jan 27, 2018
ed497e4
feat: if missing, create the 'seff' key
richardschneider Jan 29, 2018
cc594dc
chore: linting
richardschneider Jan 29, 2018
47bbc30
chore: use latest keychain
richardschneider Jan 29, 2018
bab526e
fix: call to daemon factory
richardschneider Jan 30, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ const node = new IPFS({
// },
start: true, // default
// start: false,
pass: undefined // default
// pass: 'pass phrase for key access',
EXPERIMENTAL: { // enable experimental features
pubsub: true,
sharding: true, // enable dir sharding
Expand Down Expand Up @@ -275,6 +277,17 @@ 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/)

#### `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])`
Copy link
Member

@daviddias daviddias Dec 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs, nice!

- [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/)
Expand Down Expand Up @@ -523,6 +536,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) |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍



## Development

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -121,6 +121,7 @@
"libp2p-circuit": "~0.1.4",
"libp2p-floodsub": "~0.13.1",
"libp2p-kad-dht": "~0.6.0",
"libp2p-keychain": "~0.3.0",
"libp2p-mdns": "~0.9.1",
"libp2p-multiplex": "~0.5.1",
"libp2p-railing": "~0.7.1",
Expand Down
7 changes: 6 additions & 1 deletion src/cli/bin.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/cli/commands/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports = {
node.init({
bits: argv.bits,
emptyRepo: argv.emptyRepo,
pass: argv.pass,
log: print
}, (err) => {
if (err) {
Expand Down
14 changes: 14 additions & 0 deletions src/cli/commands/key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict'

module.exports = {
command: 'key',

description: 'Manage your keys',

builder (yargs) {
return yargs
.commandDir('key')
},

handler (argv) {}
}
37 changes: 37 additions & 0 deletions src/cli/commands/key/export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict'

const fs = require('fs')

module.exports = {
command: 'export <name>',

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)
}
})
}
}
35 changes: 35 additions & 0 deletions src/cli/commands/key/gen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict'

const print = require('../../utils').print

module.exports = {
command: 'gen <name>',

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) {
const opts = {
type: argv.type,
size: argv.size
}
argv.ipfs.key.gen(argv.name, opts, (err, key) => {
if (err) {
throw err
}
print(`generated ${key.id} ${key.name}`)
})
}
}
34 changes: 34 additions & 0 deletions src/cli/commands/key/import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict'

const fs = require('fs')
const print = require('../../utils').print

module.exports = {
command: 'import <name>',

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.id} ${key.name}`)
})
}
}
20 changes: 20 additions & 0 deletions src/cli/commands/key/list.js
Original file line number Diff line number Diff line change
@@ -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.id} ${ki.name}`))
})
}
}
20 changes: 20 additions & 0 deletions src/cli/commands/key/rename.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

const print = require('../../utils').print

module.exports = {
command: 'rename <name> <newName>',

describe: 'Rename a key',

builder: {},

handler (argv) {
argv.ipfs.key.rename(argv.name, argv.newName, (err, res) => {
if (err) {
throw err
}
print(`renamed to ${res.id} ${res.now}`)
})
}
}
20 changes: 20 additions & 0 deletions src/cli/commands/key/rm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

const print = require('../../utils').print

module.exports = {
command: 'rm <name>',

describe: 'Remove a key',

builder: {},

handler (argv) {
argv.ipfs.key.rm(argv.name, (err, key) => {
if (err) {
throw err
}
print(`${key.id} ${key.name}`)
})
}
}
7 changes: 4 additions & 3 deletions src/cli/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
5 changes: 3 additions & 2 deletions src/core/boot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}
Expand All @@ -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 = []
Expand Down
1 change: 1 addition & 0 deletions src/core/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ exports.bitswap = require('./bitswap')
exports.pubsub = require('./pubsub')
exports.dht = require('./dht')
exports.dns = require('./dns')
exports.key = require('./key')
18 changes: 17 additions & 1 deletion src/core/components/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')

Expand Down Expand Up @@ -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),
Expand All @@ -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)

Expand All @@ -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)
self._keychain = new Keychain(self._repo.keys, keychainOptions)
self._keychain.importPeer('self', { privKey: privateKey }, cb)
} else {
cb(null, true)
}
},
(_, 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)
Expand Down
Loading