mirror of
https://github.com/fluencelabs/js-peer-id
synced 2025-04-25 06:22:24 +00:00
feat: support Peer ID represented as CID (#105)
* feat: support Peer ID represented as CID This change adds two functions: - createFromCID accepts CID as String|CID|Buffer and creates PeerId from the multihash value inside of it - toCIDString serializes PeerId multihash into a CIDv1 in Base32, as agreed in https://github.com/libp2p/specs/pull/209 License: MIT Signed-off-by: Marcin Rataj <lidel@lidel.org> * refactor: rename toCIDString to toString CIDv1 is self describing, and toString was not defined. Makes sense to use generic toString in this case. This change also: - remembers string with CID, so it is lazily generated only once - switches createFromB58String to createFromCID (b58 is CIDv0), making it easier to migrate existing codebases. License: MIT Signed-off-by: Marcin Rataj <lidel@lidel.org> * docs: comment tests License: MIT Signed-off-by: Marcin Rataj <lidel@lidel.org> * feat: validate CID multicodec - require CID with 'libp2p-key' (CIDv1) or 'dag-pb' (CIDv0 converted to CIDv1) - delegate CID validation to CID constructor License: MIT Signed-off-by: Marcin Rataj <lidel@lidel.org>
This commit is contained in:
parent
11d4ec10bd
commit
544ca7d74b
23
README.md
23
README.md
@ -32,14 +32,16 @@
|
|||||||
- [Import](#import)
|
- [Import](#import)
|
||||||
- [`createFromHexString(str)`](#createfromhexstringstr)
|
- [`createFromHexString(str)`](#createfromhexstringstr)
|
||||||
- [`createFromBytes(buf)`](#createfrombytesbuf)
|
- [`createFromBytes(buf)`](#createfrombytesbuf)
|
||||||
|
- [`createFromCID(cid)`](#createfromcidcid)
|
||||||
- [`createFromB58String(str)`](#createfromb58stringstr)
|
- [`createFromB58String(str)`](#createfromb58stringstr)
|
||||||
- [`createFromPubKey(pubKey)`](#createfrompubkeypubkey)
|
- [`createFromPubKey(pubKey)`](#createfrompubkeypubkey)
|
||||||
- [`createFromPrivKey(privKey)`](#createfromprivkeyprivkey)
|
- [`createFromPrivKey(privKey)`](#createfromprivkeyprivkey)
|
||||||
- [`createFromJSON(obj)`](#createfromjsonobj)
|
- [`createFromJSON(obj)`](#createfromjsonobj)
|
||||||
- [Export](#export)
|
- [Export](#export)
|
||||||
- [`toHexString()`](#tohexstring)
|
|
||||||
- [`toBytes()`](#tobytes)
|
- [`toBytes()`](#tobytes)
|
||||||
|
- [`toString()`](#tostring)
|
||||||
- [`toB58String()`](#tob58string)
|
- [`toB58String()`](#tob58string)
|
||||||
|
- [`toHexString()`](#tohexstring)
|
||||||
- [`toJSON()`](#tojson)
|
- [`toJSON()`](#tojson)
|
||||||
- [`toPrint()`](#toprint)
|
- [`toPrint()`](#toprint)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
@ -145,6 +147,14 @@ Creates a Peer ID from a buffer representing the key's multihash.
|
|||||||
|
|
||||||
Returns `PeerId`.
|
Returns `PeerId`.
|
||||||
|
|
||||||
|
### `createFromCID(cid)`
|
||||||
|
|
||||||
|
- `cid: CID|String|Buffer` - The multihash encoded as [CID](https://github.com/ipld/js-cid) (object, `String` or `Buffer`)
|
||||||
|
|
||||||
|
Creates a Peer ID from a CID representation of the key's multihash ([RFC 0001](https://github.com/libp2p/specs/blob/master/RFC/0001-text-peerid-cid.md)).
|
||||||
|
|
||||||
|
Returns `PeerId`.
|
||||||
|
|
||||||
### `createFromB58String(str)`
|
### `createFromB58String(str)`
|
||||||
|
|
||||||
Creates a Peer ID from a Base58 string representing the key's multihash.
|
Creates a Peer ID from a Base58 string representing the key's multihash.
|
||||||
@ -197,9 +207,18 @@ Returns the Peer ID's `id` as a buffer.
|
|||||||
<Buffer 12 20 d6 24 39 98 f2 fc 56 34 3a d7 ed 03 42 ab 78 86 a4 eb 18 d7 36 f1 b6 7d 44 b3 7f cc 81 e0 f3 9f>
|
<Buffer 12 20 d6 24 39 98 f2 fc 56 34 3a d7 ed 03 42 ab 78 86 a4 eb 18 d7 36 f1 b6 7d 44 b3 7f cc 81 e0 f3 9f>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### `toString()`
|
||||||
|
|
||||||
|
Returns the Peer ID's `id` as a self-describing CIDv1 in Base32 ([RFC 0001](https://github.com/libp2p/specs/blob/master/RFC/0001-text-peerid-cid.md))
|
||||||
|
|
||||||
|
```
|
||||||
|
bafzbeigweq4zr4x4ky2dvv7nanbkw6egutvrrvzw6g3h2rftp7gidyhtt4
|
||||||
|
```
|
||||||
|
|
||||||
### `toB58String()`
|
### `toB58String()`
|
||||||
|
|
||||||
Returns the Peer ID's `id` as a base58 string.
|
Returns the Peer ID's `id` as a base58 string (multihash/CIDv0).
|
||||||
|
|
||||||
```
|
```
|
||||||
QmckZzdVd72h9QUFuJJpQqhsZqGLwjhh81qSvZ9BhB2FQi
|
QmckZzdVd72h9QUFuJJpQqhsZqGLwjhh81qSvZ9BhB2FQi
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
"dirty-chai": "^2.0.1"
|
"dirty-chai": "^2.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cids": "~0.7.1",
|
||||||
"class-is": "^1.1.0",
|
"class-is": "^1.1.0",
|
||||||
"libp2p-crypto": "~0.17.0",
|
"libp2p-crypto": "~0.17.0",
|
||||||
"multihashes": "~0.4.15",
|
"multihashes": "~0.4.15",
|
||||||
|
24
src/index.js
24
src/index.js
@ -5,6 +5,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const mh = require('multihashes')
|
const mh = require('multihashes')
|
||||||
|
const CID = require('cids')
|
||||||
const cryptoKeys = require('libp2p-crypto/src/keys')
|
const cryptoKeys = require('libp2p-crypto/src/keys')
|
||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const withIs = require('class-is')
|
const withIs = require('class-is')
|
||||||
@ -122,6 +123,16 @@ class PeerId {
|
|||||||
return this._idB58String
|
return this._idB58String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return self-describing String representation
|
||||||
|
// in default format from RFC 0001: https://github.com/libp2p/specs/pull/209
|
||||||
|
toString () {
|
||||||
|
if (!this._idCIDString) {
|
||||||
|
const cid = new CID(1, 'libp2p-key', this.id, 'base32')
|
||||||
|
this._idCIDString = cid.toBaseEncodedString('base32')
|
||||||
|
}
|
||||||
|
return this._idCIDString
|
||||||
|
}
|
||||||
|
|
||||||
isEqual (id) {
|
isEqual (id) {
|
||||||
if (Buffer.isBuffer(id)) {
|
if (Buffer.isBuffer(id)) {
|
||||||
return this.id.equals(id)
|
return this.id.equals(id)
|
||||||
@ -184,7 +195,18 @@ exports.createFromBytes = (buf) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exports.createFromB58String = (str) => {
|
exports.createFromB58String = (str) => {
|
||||||
return new PeerIdWithIs(mh.fromB58String(str))
|
return exports.createFromCID(str) // B58String is CIDv0
|
||||||
|
}
|
||||||
|
|
||||||
|
const validMulticodec = (cid) => {
|
||||||
|
// supported: 'libp2p-key' (CIDv1) and 'dag-pb' (CIDv0 converted to CIDv1)
|
||||||
|
return cid.codec === 'libp2p-key' || cid.codec === 'dag-pb'
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.createFromCID = (cid) => {
|
||||||
|
cid = CID.isCID(cid) ? cid : new CID(cid)
|
||||||
|
if (!validMulticodec(cid)) throw new Error('Supplied PeerID CID has invalid multicodec: ' + cid.codec)
|
||||||
|
return new PeerIdWithIs(cid.multihash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Key input will be a buffer
|
// Public Key input will be a buffer
|
||||||
|
@ -8,6 +8,7 @@ chai.use(dirtyChai)
|
|||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
const crypto = require('libp2p-crypto')
|
const crypto = require('libp2p-crypto')
|
||||||
const mh = require('multihashes')
|
const mh = require('multihashes')
|
||||||
|
const CID = require('cids')
|
||||||
|
|
||||||
const PeerId = require('../src')
|
const PeerId = require('../src')
|
||||||
|
|
||||||
@ -17,6 +18,8 @@ const testId = require('./fixtures/sample-id')
|
|||||||
const testIdHex = testId.id
|
const testIdHex = testId.id
|
||||||
const testIdBytes = mh.fromHexString(testId.id)
|
const testIdBytes = mh.fromHexString(testId.id)
|
||||||
const testIdB58String = mh.toB58String(testIdBytes)
|
const testIdB58String = mh.toB58String(testIdBytes)
|
||||||
|
const testIdCID = new CID(1, 'libp2p-key', testIdBytes)
|
||||||
|
const testIdCIDString = testIdCID.toBaseEncodedString('base32')
|
||||||
|
|
||||||
const goId = require('./fixtures/go-private-key')
|
const goId = require('./fixtures/go-private-key')
|
||||||
|
|
||||||
@ -63,27 +66,96 @@ describe('PeerId', () => {
|
|||||||
}).to.throw(/immutable/)
|
}).to.throw(/immutable/)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('recreate an Id from Hex string', () => {
|
it('recreate from Hex string', () => {
|
||||||
const id = PeerId.createFromHexString(testIdHex)
|
const id = PeerId.createFromHexString(testIdHex)
|
||||||
expect(testIdBytes).to.deep.equal(id.id)
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Recreate an Id from a Buffer', () => {
|
it('recreate from a Buffer', () => {
|
||||||
const id = PeerId.createFromBytes(testIdBytes)
|
const id = PeerId.createFromBytes(testIdBytes)
|
||||||
expect(testId.id).to.equal(id.toHexString())
|
expect(testId.id).to.equal(id.toHexString())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Recreate a B58 String', () => {
|
it('recreate from a B58 String', () => {
|
||||||
const id = PeerId.createFromB58String(testIdB58String)
|
const id = PeerId.createFromB58String(testIdB58String)
|
||||||
expect(testIdB58String).to.equal(id.toB58String())
|
expect(testIdB58String).to.equal(id.toB58String())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Recreate from a Public Key', async () => {
|
it('recreate from CID object', () => {
|
||||||
|
const id = PeerId.createFromCID(testIdCID)
|
||||||
|
expect(testIdCIDString).to.equal(id.toString())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recreate from Base58 String (CIDv0))', () => {
|
||||||
|
const id = PeerId.createFromCID(testIdB58String)
|
||||||
|
expect(testIdCIDString).to.equal(id.toString())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recreate from CIDv1 Base32 (libp2p-key multicodec)', () => {
|
||||||
|
const cid = new CID(1, 'libp2p-key', testIdBytes)
|
||||||
|
const cidString = cid.toBaseEncodedString('base32')
|
||||||
|
const id = PeerId.createFromCID(cidString)
|
||||||
|
expect(cidString).to.equal(id.toString())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recreate from CIDv1 Base32 (dag-pb multicodec)', () => {
|
||||||
|
const cid = new CID(1, 'dag-pb', testIdBytes)
|
||||||
|
const cidString = cid.toBaseEncodedString('base32')
|
||||||
|
const id = PeerId.createFromCID(cidString)
|
||||||
|
// toString should return CID with multicodec set to libp2p-key
|
||||||
|
expect(new CID(id.toString()).codec).to.equal('libp2p-key')
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recreate from CID Buffer', () => {
|
||||||
|
const id = PeerId.createFromCID(testIdCID.buffer)
|
||||||
|
expect(testIdCIDString).to.equal(id.toString())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid CID multicodec', () => {
|
||||||
|
// only libp2p and dag-pb are supported
|
||||||
|
const invalidCID = new CID(1, 'raw', testIdBytes).toBaseEncodedString('base32')
|
||||||
|
expect(() => {
|
||||||
|
PeerId.createFromCID(invalidCID)
|
||||||
|
}).to.throw(/Supplied PeerID CID has invalid multicodec: raw/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid CID value', () => {
|
||||||
|
// using function code that does not represent valid hash function
|
||||||
|
// https://github.com/multiformats/js-multihash/blob/b85999d5768bf06f1b0f16b926ef2cb6d9c14265/src/constants.js#L345
|
||||||
|
const invalidCID = 'QmaozNR7DZHQK1ZcU9p7QdrshMvXqWK6gpu5rmrkPdT3L'
|
||||||
|
expect(() => {
|
||||||
|
PeerId.createFromCID(invalidCID)
|
||||||
|
}).to.throw(/multihash unknown function code: 0x50/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid CID object', () => {
|
||||||
|
const invalidCID = {}
|
||||||
|
expect(() => {
|
||||||
|
PeerId.createFromCID(invalidCID)
|
||||||
|
}).to.throw(/Invalid version, must be a number equal to 1 or 0/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws on invalid CID object', () => {
|
||||||
|
const invalidCID = {}
|
||||||
|
expect(() => {
|
||||||
|
PeerId.createFromCID(invalidCID)
|
||||||
|
}).to.throw(/Invalid version, must be a number equal to 1 or 0/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('recreate from a Public Key', async () => {
|
||||||
const id = await PeerId.createFromPubKey(testId.pubKey)
|
const id = await PeerId.createFromPubKey(testId.pubKey)
|
||||||
expect(testIdB58String).to.equal(id.toB58String())
|
expect(testIdB58String).to.equal(id.toB58String())
|
||||||
|
expect(testIdBytes).to.deep.equal(id.toBytes())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Recreate from a Private Key', async () => {
|
it('recreate from a Private Key', async () => {
|
||||||
const id = await PeerId.createFromPrivKey(testId.privKey)
|
const id = await PeerId.createFromPrivKey(testId.privKey)
|
||||||
expect(testIdB58String).to.equal(id.toB58String())
|
expect(testIdB58String).to.equal(id.toB58String())
|
||||||
const encoded = Buffer.from(testId.privKey, 'base64')
|
const encoded = Buffer.from(testId.privKey, 'base64')
|
||||||
@ -92,7 +164,7 @@ describe('PeerId', () => {
|
|||||||
expect(id.marshalPubKey()).to.deep.equal(id2.marshalPubKey())
|
expect(id.marshalPubKey()).to.deep.equal(id2.marshalPubKey())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Recreate from Protobuf', async () => {
|
it('recreate from Protobuf', async () => {
|
||||||
const id = await PeerId.createFromProtobuf(testId.marshaled)
|
const id = await PeerId.createFromProtobuf(testId.marshaled)
|
||||||
expect(testIdB58String).to.equal(id.toB58String())
|
expect(testIdB58String).to.equal(id.toB58String())
|
||||||
const encoded = Buffer.from(testId.privKey, 'base64')
|
const encoded = Buffer.from(testId.privKey, 'base64')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user