diff --git a/doc/API.md b/doc/API.md index eb0c4d69..325809d9 100644 --- a/doc/API.md +++ b/doc/API.md @@ -418,7 +418,7 @@ const latency = await libp2p.ping(otherPeerId) ## multiaddrs -Gets the multiaddrs the libp2p node announces to the network. This computes the advertising multiaddrs +Gets the multiaddrs the libp2p node announces to the network. This computes the advertising multiaddrs of the peer by joining the multiaddrs that libp2p transports are listening on with the announce multiaddrs provided in the libp2p config. Configured no announce multiaddrs will be filtered out of the advertised addresses. @@ -1454,7 +1454,7 @@ Create a key in the keychain. |------|------|-------------| | name | `string` | The local key name. It cannot already exist. | | type | `string` | One of the key types; 'rsa' | -| size | `number` | The key size in bits. | +| [size] | `number` | The key size in bits. Must be provided for rsa keys. | #### Returns @@ -1801,7 +1801,7 @@ console.log(peerStats.toJSON()) ## Events -Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events. +Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events. ### libp2p diff --git a/package.json b/package.json index 23ce0826..79d80bdc 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "it-length-prefixed": "^3.0.1", "it-pipe": "^1.1.0", "it-protocol-buffers": "^0.2.0", - "libp2p-crypto": "^0.17.8", + "libp2p-crypto": "^0.17.9", "libp2p-interfaces": "^0.3.1", "libp2p-utils": "^0.1.2", "mafmt": "^7.0.0", diff --git a/src/keychain/index.js b/src/keychain/index.js index 9af46d26..c5009a54 100644 --- a/src/keychain/index.js +++ b/src/keychain/index.js @@ -7,6 +7,9 @@ const crypto = require('libp2p-crypto') const DS = require('interface-datastore') const CMS = require('./cms') const errcode = require('err-code') +const { Number } = require('ipfs-utils/src/globalthis') + +require('node-forge/lib/sha512') const keyPrefix = '/pkcs8/' const infoPrefix = '/info/' @@ -171,8 +174,8 @@ class Keychain { * * @param {string} name - The local key name; cannot already exist. * @param {string} type - One of the key types; 'rsa'. - * @param {int} size - The key size in bits. - * @returns {KeyInfo} + * @param {int} [size] - The key size in bits. Used for rsa keys only. + * @returns {KeyInfo} */ async createKey (name, type, size) { const self = this @@ -185,17 +188,13 @@ class Keychain { return throwDelayed(errcode(new Error(`Invalid key type '${type}'`), 'ERR_INVALID_KEY_TYPE')) } - if (!Number.isSafeInteger(size)) { - return throwDelayed(errcode(new Error(`Invalid key size '${size}'`), 'ERR_INVALID_KEY_SIZE')) - } - const dsname = DsName(name) const exists = await self.store.has(dsname) if (exists) return throwDelayed(errcode(new Error(`Key '${name}' already exists`), 'ERR_KEY_ALREADY_EXISTS')) switch (type.toLowerCase()) { case 'rsa': - if (size < 2048) { + if (!Number.isSafeInteger(size) || size < 2048) { return throwDelayed(errcode(new Error(`Invalid RSA key size ${size}`), 'ERR_INVALID_KEY_SIZE')) } break diff --git a/test/keychain/keychain.spec.js b/test/keychain/keychain.spec.js index 5ba0e8c3..73ff15bd 100644 --- a/test/keychain/keychain.spec.js +++ b/test/keychain/keychain.spec.js @@ -149,6 +149,70 @@ describe('keychain', () => { }) }) + describe('ed25519 keys', () => { + const keyName = 'my custom key' + it('can be an ed25519 key', async () => { + const keyInfo = await ks.createKey(keyName, 'ed25519') + expect(keyInfo).to.exist() + expect(keyInfo).to.have.property('name', keyName) + expect(keyInfo).to.have.property('id') + }) + + it('does not overwrite existing key', async () => { + const err = await ks.createKey(keyName, 'ed25519').then(fail, err => err) + expect(err).to.have.property('code', 'ERR_KEY_ALREADY_EXISTS') + }) + + it('can export/import a key', async () => { + const keyName = 'a new key' + const password = 'my sneaky password' + const keyInfo = await ks.createKey(keyName, 'ed25519') + const exportedKey = await ks.exportKey(keyName, password) + // remove it so we can import it + await ks.removeKey(keyName) + const importedKey = await ks.importKey(keyName, exportedKey, password) + expect(importedKey.id).to.eql(keyInfo.id) + }) + + it('cannot create the "self" key', async () => { + const err = await ks.createKey('self', 'ed25519').then(fail, err => err) + expect(err).to.exist() + expect(err).to.have.property('code', 'ERR_INVALID_KEY_NAME') + }) + }) + + describe('secp256k1 keys', () => { + const keyName = 'my secp256k1 key' + it('can be an secp256k1 key', async () => { + const keyInfo = await ks.createKey(keyName, 'secp256k1') + expect(keyInfo).to.exist() + expect(keyInfo).to.have.property('name', keyName) + expect(keyInfo).to.have.property('id') + }) + + it('does not overwrite existing key', async () => { + const err = await ks.createKey(keyName, 'secp256k1').then(fail, err => err) + expect(err).to.have.property('code', 'ERR_KEY_ALREADY_EXISTS') + }) + + it('can export/import a key', async () => { + const keyName = 'a new secp256k1 key' + const password = 'my sneaky password' + const keyInfo = await ks.createKey(keyName, 'secp256k1') + const exportedKey = await ks.exportKey(keyName, password) + // remove it so we can import it + await ks.removeKey(keyName) + const importedKey = await ks.importKey(keyName, exportedKey, password) + expect(importedKey.id).to.eql(keyInfo.id) + }) + + it('cannot create the "self" key', async () => { + const err = await ks.createKey('self', 'secp256k1').then(fail, err => err) + expect(err).to.exist() + expect(err).to.have.property('code', 'ERR_INVALID_KEY_NAME') + }) + }) + describe('query', () => { it('finds all existing keys', async () => { const keys = await ks.listKeys()