js-peer-id/src/index.js

265 lines
5.7 KiB
JavaScript
Raw Normal View History

2015-07-08 14:51:49 -07:00
/*
* Id is an object representation of a peer Id. a peer Id is a multihash
*/
2016-05-23 14:16:30 +01:00
2016-03-22 17:01:46 +01:00
'use strict'
2015-07-08 14:51:49 -07:00
const mh = require('multihashes')
const crypto = require('libp2p-crypto')
const assert = require('assert')
const waterfall = require('async/waterfall')
class PeerId {
constructor (id, privKey, pubKey) {
assert(Buffer.isBuffer(id), 'invalid id provided')
2016-02-10 13:55:59 -08:00
if (privKey && pubKey) {
assert(privKey.public.bytes.equals(pubKey.bytes), 'inconsistent arguments')
}
2015-07-08 14:51:49 -07:00
2016-12-14 09:05:07 +01:00
this._id = id
this._idB58String = mh.toB58String(this.id)
this._privKey = privKey
this._pubKey = pubKey
2015-07-08 14:51:49 -07:00
}
2016-12-14 09:05:07 +01:00
get id () {
return this._id
}
set id (val) {
throw new Error('Id is immutable')
}
get privKey () {
return this._privKey
}
2017-04-02 20:06:26 -04:00
set privKey (privKey) {
this._privKey = privKey
}
get pubKey () {
if (this._pubKey) {
return this._pubKey
}
2015-07-08 14:51:49 -07:00
2017-04-02 20:06:26 -04:00
if (this._privKey) {
return this._privKey.public
2015-07-08 14:51:49 -07:00
}
}
2017-04-02 20:06:26 -04:00
set pubKey (pubKey) {
this._pubKey = pubKey
}
// Return the protobuf version of the public key, matching go ipfs formatting
marshalPubKey () {
if (this.pubKey) {
return crypto.keys.marshalPublicKey(this.pubKey)
}
}
2017-04-02 20:06:26 -04:00
// Return the protobuf version of the private key, matching go ipfs formatting
marshalPrivKey () {
if (this.privKey) {
return crypto.keys.marshalPrivateKey(this.privKey)
}
2015-07-08 14:51:49 -07:00
}
// pretty print
toPrint () {
return this.toJSON()
2015-07-08 14:51:49 -07:00
}
// return the jsonified version of the key, matching the formatting
// of go-ipfs for its config file
toJSON () {
return {
2016-12-14 09:05:07 +01:00
id: this.toB58String(),
privKey: toB64Opt(this.marshalPrivKey()),
pubKey: toB64Opt(this.marshalPubKey())
}
2015-07-08 14:51:49 -07:00
}
2015-11-05 18:51:53 +00:00
// encode/decode functions
toHexString () {
return mh.toHexString(this.id)
}
toBytes () {
return this.id
}
2015-07-08 14:51:49 -07:00
toB58String () {
2016-12-14 09:05:07 +01:00
return this._idB58String
}
2017-03-30 09:43:00 +01:00
isEqual (id) {
if (Buffer.isBuffer(id)) {
return this.id.equals(id)
} else if (id.id) {
return this.id.equals(id.id)
} else {
throw new Error('not valid Id')
}
}
2017-04-02 20:06:26 -04:00
/*
* Check if this PeerId instance is valid (privKey -> pubKey -> Id)
*/
isValid (callback) {
// TODO Needs better checking
if (this.privKey &&
this.privKey.public &&
this.privKey.public.bytes &&
Buffer.isBuffer(this.pubKey.bytes) &&
this.privKey.public.bytes.equals(this.pubKey.bytes)) {
callback()
} else {
callback(new Error('Keys not match'))
}
}
}
exports = module.exports = PeerId
2016-02-10 13:55:59 -08:00
// generation
exports.create = function (opts, callback) {
if (typeof opts === 'function') {
callback = opts
opts = {}
}
2016-03-14 17:10:02 -07:00
opts = opts || {}
opts.bits = opts.bits || 2048
waterfall([
(cb) => crypto.keys.generateKeyPair('RSA', opts.bits, cb),
(privKey, cb) => privKey.public.hash((err, digest) => {
cb(err, digest, privKey)
})
], (err, digest, privKey) => {
if (err) {
return callback(err)
}
callback(null, new PeerId(digest, privKey))
})
2015-07-08 14:51:49 -07:00
}
exports.createFromHexString = function (str) {
return new PeerId(mh.fromHexString(str))
2015-07-08 14:51:49 -07:00
}
exports.createFromBytes = function (buf) {
return new PeerId(buf)
2015-07-08 14:51:49 -07:00
}
exports.createFromB58String = function (str) {
return new PeerId(mh.fromB58String(str))
2015-07-08 14:51:49 -07:00
}
2016-03-10 10:32:48 -08:00
// Public Key input will be a buffer
exports.createFromPubKey = function (key, callback) {
2017-04-02 20:06:26 -04:00
if (typeof callback !== 'function') {
throw new Error('callback is required')
}
let buf = key
if (typeof buf === 'string') {
buf = Buffer.from(key, 'base64')
}
const pubKey = crypto.keys.unmarshalPublicKey(buf)
2017-04-02 20:06:26 -04:00
pubKey.hash((err, digest) => {
if (err) {
return callback(err)
}
callback(null, new PeerId(digest, null, pubKey))
})
2015-07-08 14:51:49 -07:00
}
2016-03-10 10:32:48 -08:00
// Private key input will be a string
exports.createFromPrivKey = function (key, callback) {
let buf = key
if (typeof buf === 'string') {
buf = Buffer.from(key, 'base64')
}
if (typeof callback !== 'function') {
throw new Error('callback is required')
}
waterfall([
(cb) => crypto.keys.unmarshalPrivateKey(buf, cb),
(privKey, cb) => privKey.public.hash((err, digest) => {
cb(err, digest, privKey)
})
], (err, digest, privKey) => {
if (err) {
return callback(err)
}
callback(null, new PeerId(digest, privKey))
})
}
exports.createFromJSON = function (obj, callback) {
if (typeof callback !== 'function') {
throw new Error('callback is required')
}
2016-03-10 10:32:48 -08:00
const id = mh.fromB58String(obj.id)
const rawPrivKey = obj.privKey && Buffer.from(obj.privKey, 'base64')
const rawPubKey = obj.pubKey && Buffer.from(obj.pubKey, 'base64')
const pub = rawPubKey && crypto.keys.unmarshalPublicKey(rawPubKey)
if (rawPrivKey) {
waterfall([
(cb) => crypto.keys.unmarshalPrivateKey(rawPrivKey, cb),
(priv, cb) => priv.public.hash((err, digest) => {
cb(err, digest, priv)
}),
(privDigest, priv, cb) => {
if (pub) {
pub.hash((err, pubDigest) => {
cb(err, privDigest, priv, pubDigest)
})
} else {
cb(null, privDigest, priv)
}
}
], (err, privDigest, priv, pubDigest) => {
if (err) {
return callback(err)
}
if (pub && !privDigest.equals(pubDigest)) {
return callback(new Error('Public and private key do not match'))
}
if (id && !privDigest.equals(id)) {
return callback(new Error('Id and private key do not match'))
}
callback(null, new PeerId(id, priv, pub))
})
} else {
callback(null, new PeerId(id, null, pub))
}
}
2017-03-27 13:23:18 +01:00
exports.isPeerId = function (peerId) {
2017-03-27 13:58:21 +01:00
return Boolean(typeof peerId === 'object' &&
peerId._id &&
peerId._idB58String)
2017-03-27 13:23:18 +01:00
}
function toB64Opt (val) {
if (val) {
return val.toString('base64')
}
2015-07-08 14:51:49 -07:00
}