diff --git a/src/keychain.js b/src/keychain.js index 50a67983..f4e4b0fc 100644 --- a/src/keychain.js +++ b/src/keychain.js @@ -1,11 +1,10 @@ 'use strict' const async = require('async') -const sanitize = require("sanitize-filename") +const sanitize = require('sanitize-filename') const forge = require('node-forge') const deepmerge = require('deepmerge') -const crypto = require('crypto') -const libp2pCrypto = require('libp2p-crypto') +const crypto = require('libp2p-crypto') const util = require('./util') const CMS = require('./cms') const DS = require('interface-datastore') @@ -32,7 +31,6 @@ const defaultOptions = { function validateKeyName (name) { if (!name) return false - return name === sanitize(name.trim()) } @@ -44,8 +42,9 @@ function validateKeyName (name) { * * @param {function(Error)} callback - The caller * @param {string | Error} err - The error + * @returns {undefined} */ -function _error(callback, err) { +function _error (callback, err) { const min = 200 const max = 1000 const delay = Math.random() * (max - min) + min @@ -55,6 +54,9 @@ function _error(callback, err) { /** * Converts a key name into a datastore name. + * + * @param {string} name + * @returns {DS.Key} */ function DsName (name) { return new DS.Key('/' + name) @@ -62,8 +64,11 @@ function DsName (name) { /** * Converts a datastore name into a key name. + * + * @param {DS.Key} name - A datastore name + * @returns {string} */ -function KsName(name) { +function KsName (name) { return name.toString().slice(1) } @@ -111,7 +116,7 @@ class Keychain { this.cms = new CMS(this) } - static get options() { + static get options () { return defaultOptions } @@ -123,6 +128,7 @@ class Keychain { } const dsname = DsName(name) self.store.has(dsname, (err, exists) => { + if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${name}' already exists'`) switch (type.toLowerCase()) { @@ -133,14 +139,14 @@ class Keychain { forge.pki.rsa.generateKeyPair({bits: size, workers: -1}, (err, keypair) => { if (err) return _error(callback, err) - const pem = forge.pki.encryptRsaPrivateKey(keypair.privateKey, this._()); + const pem = forge.pki.encryptRsaPrivateKey(keypair.privateKey, this._()) return self.store.put(dsname, pem, (err) => { if (err) return _error(callback, err) self._getKeyInfo(name, callback) }) }) - break; + break default: return _error(callback, `Invalid key type '${type}'`) @@ -181,13 +187,14 @@ class Keychain { } const dsname = DsName(name) self.store.has(dsname, (err, exists) => { + if (err) return _error(callback, err) if (!exists) return _error(callback, `Key '${name}' does not exist'`) self.store.delete(dsname, callback) }) } - renameKey(oldName, newName, callback) { + renameKey (oldName, newName, callback) { const self = this if (!validateKeyName(oldName) || oldName === 'self') { return _error(callback, `Invalid old key name '${oldName}'`) @@ -203,6 +210,7 @@ class Keychain { } const pem = res.toString() self.store.has(newDsname, (err, exists) => { + if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${newName}' already exists'`) const batch = self.store.batch() @@ -246,7 +254,7 @@ class Keychain { }) } - importKey(name, pem, password, callback) { + importKey (name, pem, password, callback) { const self = this if (!validateKeyName(name) || name === 'self') { return _error(callback, `Invalid key name '${name}'`) @@ -256,15 +264,16 @@ class Keychain { } const dsname = DsName(name) self.store.has(dsname, (err, exists) => { + if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${name}' already exists'`) try { const privateKey = forge.pki.decryptRsaPrivateKey(pem, password) if (privateKey === null) { return _error(callback, 'Cannot read the key, most likely the password is wrong') } - const newpem = forge.pki.encryptRsaPrivateKey(privateKey, this._()); + const newpem = forge.pki.encryptRsaPrivateKey(privateKey, this._()) return self.store.put(dsname, newpem, (err) => { - if (err) return _error(callback, err) + if (err) return _error(callback, err) this._getKeyInfo(name, callback) }) @@ -280,23 +289,25 @@ class Keychain { return _error(callback, `Invalid key name '${name}'`) } if (!peer || !peer.privKey) { - return _error(callback, 'Peer.privKey \is required') + return _error(callback, 'Peer.privKey is required') } const dsname = DsName(name) self.store.has(dsname, (err, exists) => { + if (err) return _error(callback, err) if (exists) return _error(callback, `Key '${name}' already exists'`) const privateKeyProtobuf = peer.marshalPrivKey() - libp2pCrypto.keys.unmarshalPrivateKey(privateKeyProtobuf, (err, key) => { + crypto.keys.unmarshalPrivateKey(privateKeyProtobuf, (err, key) => { + if (err) return _error(callback, err) try { const der = key.marshal() - const buf = forge.util.createBuffer(der.toString('binary')); + const buf = forge.util.createBuffer(der.toString('binary')) const obj = forge.asn1.fromDer(buf) const privateKey = forge.pki.privateKeyFromAsn1(obj) if (privateKey === null) { return _error(callback, 'Cannot read the peer private key') } - const pem = forge.pki.encryptRsaPrivateKey(privateKey, this._()); + const pem = forge.pki.encryptRsaPrivateKey(privateKey, this._()) return self.store.put(dsname, pem, (err) => { if (err) return _error(callback, err) @@ -314,9 +325,9 @@ class Keychain { * * @param {string} name * @param {function(Error, string)} callback + * @returns {undefined} */ _getPrivateKey (name, callback) { - const self = this if (!validateKeyName(name)) { return _error(callback, `Invalid key name '${name}'`) } @@ -329,7 +340,6 @@ class Keychain { } _getKeyInfo (name, callback) { - const self = this if (!validateKeyName(name)) { return _error(callback, `Invalid key name '${name}'`) } @@ -356,7 +366,6 @@ class Keychain { } }) } - } module.exports = Keychain diff --git a/src/util.js b/src/util.js index c3cd5a1f..6066c33f 100644 --- a/src/util.js +++ b/src/util.js @@ -14,7 +14,7 @@ exports.keyId = (privateKey, callback) => { try { const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e) const spki = pki.publicKeyToSubjectPublicKeyInfo(publicKey) - const der = new Buffer(forge.asn1.toDer(spki).getBytes(), 'binary') + const der = Buffer.from(forge.asn1.toDer(spki).getBytes(), 'binary') const jwk = rsaUtils.pkixToJwk(der) const rsa = new rsaClass.RsaPublicKey(jwk) rsa.hash((err, kid) => { @@ -33,12 +33,12 @@ exports.certificateForKey = (privateKey, callback) => { if (err) return callback(err) const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e) - const cert = pki.createCertificate(); - cert.publicKey = publicKey; - cert.serialNumber = '01'; - cert.validity.notBefore = new Date(); - cert.validity.notAfter = new Date(); - cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10); + const cert = pki.createCertificate() + cert.publicKey = publicKey + cert.serialNumber = '01' + cert.validity.notBefore = new Date() + cert.validity.notAfter = new Date() + cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 10) var attrs = [{ name: 'organizationName', value: 'ipfs' @@ -48,9 +48,9 @@ exports.certificateForKey = (privateKey, callback) => { }, { name: 'commonName', value: kid - }]; - cert.setSubject(attrs); - cert.setIssuer(attrs); + }] + cert.setSubject(attrs) + cert.setIssuer(attrs) cert.setExtensions([{ name: 'basicConstraints', cA: true @@ -77,7 +77,7 @@ exports.certificateForKey = (privateKey, callback) => { sslCA: true, emailCA: true, objCA: true - }]); + }]) // self-sign certificate cert.sign(privateKey) diff --git a/test/browser.js b/test/browser.js index a2633bef..4e08b137 100644 --- a/test/browser.js +++ b/test/browser.js @@ -4,12 +4,9 @@ const async = require('async') const LevelStore = require('datastore-level') -// use in the browser with level.js -const browserStore = new LevelStore('my/db/name', {db: require('level-js')}) - describe('browser', () => { - const datastore1 = new LevelStore('test-keystore-1', {db: require('level-js')}) - const datastore2 = new LevelStore('test-keystore-2', {db: require('level-js')}) + const datastore1 = new LevelStore('test-keystore-1', {db: require('level-js')}) + const datastore2 = new LevelStore('test-keystore-2', {db: require('level-js')}) before((done) => { async.series([ diff --git a/test/keychain.spec.js b/test/keychain.spec.js index cc1048cf..25cae122 100644 --- a/test/keychain.spec.js +++ b/test/keychain.spec.js @@ -1,3 +1,4 @@ +/* eslint max-nested-callbacks: ["error", 8] */ /* eslint-env mocha */ 'use strict' @@ -28,12 +29,12 @@ module.exports = (datastore1, datastore2) => { expect(() => new Keychain(datastore2)).to.throw() }) - it ('needs a NIST SP 800-132 non-weak pass phrase', () => { - expect(() => new Keychain(datastore2, { passPhrase: '< 20 character'})).to.throw() + it('needs a NIST SP 800-132 non-weak pass phrase', () => { + expect(() => new Keychain(datastore2, { passPhrase: '< 20 character' })).to.throw() }) it('needs a store to persist a key', () => { - expect(() => new Keychain(null, { passPhrase: passPhrase})).to.throw() + expect(() => new Keychain(null, { passPhrase: passPhrase })).to.throw() }) it('has default options', () => { @@ -112,7 +113,6 @@ module.exports = (datastore1, datastore2) => { }) }) }) - }) describe('query', () => { @@ -177,7 +177,7 @@ module.exports = (datastore1, datastore2) => { }) it('is a PKCS #7 message', (done) => { - ks.cms.readData("not CMS", (err) => { + ks.cms.readData('not CMS', (err) => { expect(err).to.exist() done() }) @@ -205,7 +205,6 @@ module.exports = (datastore1, datastore2) => { done() }) }) - }) describe('exported key', () => { @@ -243,7 +242,7 @@ module.exports = (datastore1, datastore2) => { done() }) }) - }) + }) describe('peer id', () => { const alicePrivKey = 'CAASpgkwggSiAgEAAoIBAQC2SKo/HMFZeBml1AF3XijzrxrfQXdJzjePBZAbdxqKR1Mc6juRHXij6HXYPjlAk01BhF1S3Ll4Lwi0cAHhggf457sMg55UWyeGKeUv0ucgvCpBwlR5cQ020i0MgzjPWOLWq1rtvSbNcAi2ZEVn6+Q2EcHo3wUvWRtLeKz+DZSZfw2PEDC+DGPJPl7f8g7zl56YymmmzH9liZLNrzg/qidokUv5u1pdGrcpLuPNeTODk0cqKB+OUbuKj9GShYECCEjaybJDl9276oalL9ghBtSeEv20kugatTvYy590wFlJkkvyl+nPxIH0EEYMKK9XRWlu9XYnoSfboiwcv8M3SlsjAgMBAAECggEAZtju/bcKvKFPz0mkHiaJcpycy9STKphorpCT83srBVQi59CdFU6Mj+aL/xt0kCPMVigJw8P3/YCEJ9J+rS8BsoWE+xWUEsJvtXoT7vzPHaAtM3ci1HZd302Mz1+GgS8Epdx+7F5p80XAFLDUnELzOzKftvWGZmWfSeDnslwVONkL/1VAzwKy7Ce6hk4SxRE7l2NE2OklSHOzCGU1f78ZzVYKSnS5Ag9YrGjOAmTOXDbKNKN/qIorAQ1bovzGoCwx3iGIatQKFOxyVCyO1PsJYT7JO+kZbhBWRRE+L7l+ppPER9bdLFxs1t5CrKc078h+wuUr05S1P1JjXk68pk3+kQKBgQDeK8AR11373Mzib6uzpjGzgNRMzdYNuExWjxyxAzz53NAR7zrPHvXvfIqjDScLJ4NcRO2TddhXAfZoOPVH5k4PJHKLBPKuXZpWlookCAyENY7+Pd55S8r+a+MusrMagYNljb5WbVTgN8cgdpim9lbbIFlpN6SZaVjLQL3J8TWH6wKBgQDSChzItkqWX11CNstJ9zJyUE20I7LrpyBJNgG1gtvz3ZMUQCn3PxxHtQzN9n1P0mSSYs+jBKPuoSyYLt1wwe10/lpgL4rkKWU3/m1Myt0tveJ9WcqHh6tzcAbb/fXpUFT/o4SWDimWkPkuCb+8j//2yiXk0a/T2f36zKMuZvujqQKBgC6B7BAQDG2H2B/ijofp12ejJU36nL98gAZyqOfpLJ+FeMz4TlBDQ+phIMhnHXA5UkdDapQ+zA3SrFk+6yGk9Vw4Hf46B+82SvOrSbmnMa+PYqKYIvUzR4gg34rL/7AhwnbEyD5hXq4dHwMNsIDq+l2elPjwm/U9V0gdAl2+r50HAoGALtsKqMvhv8HucAMBPrLikhXP/8um8mMKFMrzfqZ+otxfHzlhI0L08Bo3jQrb0Z7ByNY6M8epOmbCKADsbWcVre/AAY0ZkuSZK/CaOXNX/AhMKmKJh8qAOPRY02LIJRBCpfS4czEdnfUhYV/TYiFNnKRj57PPYZdTzUsxa/yVTmECgYBr7slQEjb5Onn5mZnGDh+72BxLNdgwBkhO0OCdpdISqk0F0Pxby22DFOKXZEpiyI9XYP1C8wPiJsShGm2yEwBPWXnrrZNWczaVuCbXHrZkWQogBDG3HGXNdU4MAWCyiYlyinIBpPpoAJZSzpGLmWbMWh28+RJS6AQX6KHrK1o2uw==' @@ -252,6 +251,7 @@ module.exports = (datastore1, datastore2) => { before(function (done) { const encoded = Buffer.from(alicePrivKey, 'base64') PeerId.createFromPrivKey(encoded, (err, id) => { + expect(err).to.not.exist() alice = id done() }) @@ -351,6 +351,5 @@ module.exports = (datastore1, datastore2) => { }) }) }) - }) } diff --git a/test/peerid.js b/test/peerid.js index 8d3063c4..7d6588cb 100644 --- a/test/peerid.js +++ b/test/peerid.js @@ -24,6 +24,7 @@ describe('peer ID', () => { before(function (done) { const encoded = Buffer.from(sample.privKey, 'base64') PeerId.createFromPrivKey(encoded, (err, id) => { + expect(err).to.not.exist() peer = id done() }) @@ -44,6 +45,7 @@ describe('peer ID', () => { // get protobuf version of the private key const privateKeyProtobuf = peer.marshalPrivKey() crypto.keys.unmarshalPrivateKey(privateKeyProtobuf, (err, key) => { + expect(err).to.not.exist() // console.log('private key', key) // console.log('\nprivate key der', key.marshal().toString('base64')) done() @@ -56,6 +58,7 @@ describe('peer ID', () => { const rsa = new rsaClass.RsaPublicKey(jwk) // console.log('rsa', rsa) rsa.hash((err, keyId) => { + expect(err).to.not.exist() // console.log('err', err) // console.log('keyId', keyId) // console.log('id decoded', multihash.decode(keyId)) @@ -78,6 +81,7 @@ describe('peer ID', () => { const rsa = new rsaClass.RsaPublicKey(jwk) // console.log('rsa', rsa) rsa.hash((err, keyId) => { + expect(err).to.not.exist() // console.log('err', err) // console.log('keyId', keyId) // console.log('id decoded', multihash.decode(keyId)) @@ -96,10 +100,10 @@ describe('peer ID', () => { // get protobuf version of the private key const privateKeyProtobuf = peer.marshalPrivKey() crypto.keys.unmarshalPrivateKey(privateKeyProtobuf, (err, key) => { + expect(err).to.not.exist() // console.log('private key', key) - //console.log('\nprivate key der', key.marshal().toString('base64')) + // console.log('\nprivate key der', key.marshal().toString('base64')) done() }) }) - })