Skip to content

Commit 4d74274

Browse files
authoredJul 12, 2021
fix: decode more multibase types (#152)
* fix: decode more multibase types PeerIds used by ipns pubsub are base36 encoded so support parsing peer IDs out of base36 encoded strings. In fact, just support every default encoding supported by multiformats. Needs base36 support landing in multiformats. Depends on - [ ] multiformats/js-multiformats#101 * chore: upgrade multiformats and aegir
1 parent bc04a25 commit 4d74274

File tree

6 files changed

+130
-112
lines changed

6 files changed

+130
-112
lines changed
 

‎.aegir.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
module.exports = {
4-
bundlesize: {
5-
maxSize: '140kB'
4+
build: {
5+
bundlesizeMax: '121KB'
66
}
77
}

‎package.json

+8-3
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,27 @@
4141
"@types/chai": "^4.2.14",
4242
"@types/dirty-chai": "^2.0.2",
4343
"@types/mocha": "^8.2.0",
44-
"aegir": "^33.0.0",
45-
"multihashes": "^4.0.2",
44+
"aegir": "^34.0.2",
4645
"util": "^0.12.3"
4746
},
4847
"dependencies": {
4948
"class-is": "^1.1.0",
5049
"libp2p-crypto": "^0.19.0",
5150
"minimist": "^1.2.5",
52-
"multiformats": "^9.0.0",
51+
"multiformats": "^9.3.0",
5352
"protobufjs": "^6.10.2",
5453
"uint8arrays": "^2.0.5"
5554
},
5655
"repository": {
5756
"type": "git",
5857
"url": "https://github.com/libp2p/js-peer-id.git"
5958
},
59+
"eslintConfig": {
60+
"extends": "ipfs",
61+
"ignorePatterns": [
62+
"proto.d.ts"
63+
]
64+
},
6065
"contributors": [
6166
"David Dias <daviddias.p@gmail.com>",
6267
"Vasco Santos <vasco.santos@moxy.studio>",

‎src/index.d.ts

+68-53
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,214 @@
1-
import { PrivateKey, PublicKey, KeyType } from "libp2p-crypto";
1+
import { PrivateKey, PublicKey, KeyType } from 'libp2p-crypto'
22
import { CID } from 'multiformats/cid'
33

44
declare namespace PeerId {
55
/**
66
* Options for PeerId creation.
77
*/
8-
type CreateOptions = {
8+
interface CreateOptions {
99
/**
1010
* The number of bits to use.
1111
*/
12-
bits?: number;
12+
bits?: number
1313
/**
1414
* The type of key to use.
1515
*/
16-
keyType?: KeyType;
17-
};
16+
keyType?: KeyType
17+
}
1818

1919
/**
2020
* PeerId JSON format.
2121
*/
22-
type JSONPeerId = {
22+
interface JSONPeerId {
2323
/**
2424
* String representation of PeerId.
2525
*/
26-
id: string;
26+
id: string
2727
/**
2828
* Public key.
2929
*/
30-
pubKey?: string;
30+
pubKey?: string
3131
/**
3232
* Private key.
3333
*/
34-
privKey?: string;
35-
};
34+
privKey?: string
35+
}
3636

3737
/**
3838
* Checks if a value is an instance of PeerId.
39-
* @param id The value to check.
39+
*
40+
* @param id - The value to check.
4041
*/
41-
function isPeerId(id: any): id is PeerId
42+
function isPeerId (id: any): id is PeerId
4243

4344
/**
4445
* Create a new PeerId.
45-
* @param opts Options.
46+
*
47+
* @param opts - Options.
4648
*/
47-
function create(opts?: PeerId.CreateOptions): Promise<PeerId>;
49+
function create (opts?: PeerId.CreateOptions): Promise<PeerId>
4850

4951
/**
5052
* Create PeerId from hex string.
51-
* @param str The input hex string.
53+
*
54+
* @param str - The input hex string.
5255
*/
53-
function createFromHexString(str: string): PeerId;
56+
function createFromHexString (str: string): PeerId
5457

5558
/**
5659
* Create PeerId from raw bytes.
57-
* @param buf The raw bytes.
60+
*
61+
* @param buf - The raw bytes.
5862
*/
59-
function createFromBytes(buf: Uint8Array): PeerId;
63+
function createFromBytes (buf: Uint8Array): PeerId
6064

6165
/**
6266
* Create PeerId from base58-encoded string.
63-
* @param str The base58-encoded string.
67+
*
68+
* @param str - The base58-encoded string.
6469
*/
65-
function createFromB58String(str: string): PeerId;
70+
function createFromB58String (str: string): PeerId
6671

6772
/**
6873
* Create PeerId from CID.
69-
* @param cid The CID.
74+
*
75+
* @param cid - The CID.
7076
*/
71-
function createFromCID(cid: CID): PeerId;
77+
function createFromCID (cid: CID): PeerId
7278

7379
/**
7480
* Create PeerId from public key.
75-
* @param key Public key, as Uint8Array or base64-encoded string.
81+
*
82+
* @param key - Public key, as Uint8Array or base64-encoded string.
7683
*/
77-
function createFromPubKey(key: Uint8Array | string): Promise<PeerId>;
84+
function createFromPubKey (key: Uint8Array | string): Promise<PeerId>
7885

7986
/**
8087
* Create PeerId from private key.
81-
* @param key Private key, as Uint8Array or base64-encoded string.
88+
*
89+
* @param key - Private key, as Uint8Array or base64-encoded string.
8290
*/
83-
function createFromPrivKey(key: Uint8Array | string): Promise<PeerId>;
91+
function createFromPrivKey (key: Uint8Array | string): Promise<PeerId>
8492

8593
/**
8694
* Create PeerId from PeerId JSON formatted object.
95+
*
8796
* @see {@link PeerId#toJSON}
88-
* @param json PeerId in JSON format.
97+
* @param json - PeerId in JSON format.
8998
*/
90-
function createFromJSON(json: JSONPeerId): Promise<PeerId>;
99+
function createFromJSON (json: JSONPeerId): Promise<PeerId>
91100

92101
/**
93102
* Create PeerId from Protobuf bytes.
94-
* @param buf Protobuf bytes, as Uint8Array or hex-encoded string.
103+
*
104+
* @param buf - Protobuf bytes, as Uint8Array or hex-encoded string.
95105
*/
96-
function createFromProtobuf(buf: Uint8Array | string): Promise<PeerId>;
106+
function createFromProtobuf (buf: Uint8Array | string): Promise<PeerId>
97107

98108
/**
99109
* Parse a PeerId from a string.
100-
* @param str encoded public key string.
110+
*
111+
* @param str - encoded public key string.
101112
*/
102-
function parse(str: string): PeerId;
113+
function parse (str: string): PeerId
103114
}
104115

105116
/**
106117
* PeerId is an object representation of a peer identifier.
107118
*/
108119
declare class PeerId {
109-
constructor(id: Uint8Array, privKey?: PrivateKey, pubKey?: PublicKey);
120+
constructor (id: Uint8Array, privKey?: PrivateKey, pubKey?: PublicKey);
110121

111122
/**
112123
* Raw id.
113124
*/
114-
readonly id: Uint8Array;
125+
readonly id: Uint8Array
115126

116127
/**
117128
* Private key.
118129
*/
119-
privKey: PrivateKey;
130+
privKey: PrivateKey
120131

121132
/**
122133
* Public key.
123134
*/
124-
pubKey: PublicKey;
135+
pubKey: PublicKey
125136

126137
/**
127138
* Return the protobuf version of the public key, matching go ipfs formatting.
128139
*/
129-
marshalPubKey(): Uint8Array;
140+
marshalPubKey (): Uint8Array;
130141

131142
/**
132143
* Return the protobuf version of the private key, matching go ipfs formatting.
133144
*/
134-
marshalPrivKey(): Uint8Array;
145+
marshalPrivKey (): Uint8Array;
135146

136147
/**
137148
* Return the protobuf version of the peer-id.
138-
* @param excludePriv Whether to exclude the private key information from the output.
149+
*
150+
* @param excludePriv - Whether to exclude the private key information from the output.
139151
*/
140-
marshal(excludePriv?: boolean): Uint8Array;
152+
marshal (excludePriv?: boolean): Uint8Array;
141153

142154
/**
143155
* String representation.
144156
*/
145-
toPrint(): string;
157+
toPrint (): string;
146158

147159
/**
148160
* Return the jsonified version of the key.
149161
* Matches the formatting of go-ipfs for its config file.
162+
*
150163
* @see {@link PeerId.createFromJSON}
151164
*/
152-
toJSON(): PeerId.JSONPeerId;
165+
toJSON (): PeerId.JSONPeerId;
153166

154167
/**
155168
* Encode to hex.
156169
*/
157-
toHexString(): string;
170+
toHexString (): string;
158171

159172
/**
160173
* Return raw id bytes.
161174
*/
162-
toBytes(): Uint8Array;
175+
toBytes (): Uint8Array;
163176

164177
/**
165178
* Encode to base58 string.
166179
*/
167-
toB58String(): string;
180+
toB58String (): string;
168181

169182
/**
170183
* Return self-describing string representation.
171184
* Uses default format from RFC 0001: https://github.com/libp2p/specs/pull/209
172185
*/
173-
toString(): string;
186+
toString (): string;
174187

175188
/**
176189
* Checks the equality of `this` peer against a given PeerId.
177-
* @param id The other PeerId.
190+
*
191+
* @param id - The other PeerId.
178192
*/
179-
equals(id: PeerId | Uint8Array): boolean;
193+
equals (id: PeerId | Uint8Array): boolean;
180194

181195
/**
182196
* Checks the equality of `this` peer against a given PeerId.
197+
*
183198
* @deprecated Use {.equals}
184-
* @param id The other PeerId.
199+
* @param id - The other PeerId.
185200
*/
186-
isEqual(id: PeerId | Uint8Array): boolean;
201+
isEqual (id: PeerId | Uint8Array): boolean;
187202

188203
/**
189204
* Check if this PeerId instance is valid (privKey -> pubKey -> Id)
190205
*/
191-
isValid(): boolean;
206+
isValid (): boolean;
192207

193208
/**
194209
* Check if the PeerId has an inline public key.
195210
*/
196-
hasInlinePublicKey(): boolean;
211+
hasInlinePublicKey (): boolean;
197212
}
198213

199-
export = PeerId;
214+
export = PeerId

‎src/index.js

+21-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@
55
'use strict'
66

77
const { CID } = require('multiformats/cid')
8+
const b32 = require('multiformats/bases/base32')
9+
const b36 = require('multiformats/bases/base36')
10+
const b58 = require('multiformats/bases/base58')
11+
const b64 = require('multiformats/bases/base64')
812
const { base58btc } = require('multiformats/bases/base58')
13+
const { base32 } = require('multiformats/bases/base32')
914
const { base16 } = require('multiformats/bases/base16')
1015
const Digest = require('multiformats/hashes/digest')
1116
const cryptoKeys = require('libp2p-crypto/src/keys')
@@ -16,6 +21,17 @@ const uint8ArrayFromString = require('uint8arrays/from-string')
1621
const uint8ArrayToString = require('uint8arrays/to-string')
1722
const { identity } = require('multiformats/hashes/identity')
1823

24+
const bases = {
25+
...b32,
26+
...b36,
27+
...b58,
28+
...b64
29+
}
30+
const baseDecoder = Object.keys(bases).reduce(
31+
(acc, curr) => acc.or(bases[curr]),
32+
base32.decoder
33+
)
34+
1935
// these values are from https://github.com/multiformats/multicodec/blob/master/table.csv
2036
const DAG_PB_CODE = 0x70
2137
const LIBP2P_KEY_CODE = 0x72
@@ -389,13 +405,13 @@ exports.createFromProtobuf = async (buf) => {
389405
}
390406

391407
exports.parse = (str) => {
392-
if (str.charAt(0) === '1') {
393-
// base58btc encoded public key
394-
return exports.createFromBytes(base58btc.decode(`z${str}`))
408+
if (str.charAt(0) === '1' || str.charAt(0) === 'Q') {
409+
// identity hash ed25519 key or sha2-256 hash of rsa public key
410+
// base58btc encoded either way
411+
str = `z${str}`
395412
}
396413

397-
// try to parse it as a regular base58btc multihash or base32 encoded CID
398-
return exports.createFromCID(CID.parse(str))
414+
return exports.createFromBytes(baseDecoder.decode(str))
399415
}
400416

401417
exports.isPeerId = (peerId) => {

‎test/peer-id.spec.js

+20-10
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44

55
const { expect } = require('aegir/utils/chai')
66
const crypto = require('libp2p-crypto')
7-
const mh = require('multihashes')
87
const { CID } = require('multiformats/cid')
98
const Digest = require('multiformats/hashes/digest')
9+
const { base16 } = require('multiformats/bases/base16')
10+
const { base36 } = require('multiformats/bases/base36')
11+
const { base58btc } = require('multiformats/bases/base58')
12+
const { identity } = require('multiformats/hashes/identity')
1013
const uint8ArrayFromString = require('uint8arrays/from-string')
1114
const uint8ArrayToString = require('uint8arrays/to-string')
1215

@@ -20,9 +23,10 @@ const RAW_CODE = 0x55
2023

2124
const testId = require('./fixtures/sample-id')
2225
const testIdHex = testId.id
23-
const testIdBytes = mh.fromHexString(testId.id)
26+
const testIdBytes = base16.decode(`f${testId.id}`)
2427
const testIdDigest = Digest.decode(testIdBytes)
25-
const testIdB58String = mh.toB58String(testIdBytes)
28+
const testIdB58String = base58btc.encode(testIdBytes).substring(1)
29+
const testIdB36String = base36.encode(testIdBytes)
2630
const testIdCID = CID.createV1(LIBP2P_KEY_CODE, testIdDigest)
2731
const testIdCIDString = testIdCID.toString()
2832

@@ -46,7 +50,7 @@ describe('PeerId', () => {
4650

4751
it('can be created for a Secp256k1 key', async () => {
4852
const id = await PeerId.create({ keyType: 'secp256k1', bits: 256 })
49-
const expB58 = mh.toB58String(mh.encode(id.pubKey.bytes, 'identity'))
53+
const expB58 = base58btc.encode((await identity.digest(id.pubKey.bytes)).bytes).slice(1)
5054
expect(id.toB58String()).to.equal(expB58)
5155
})
5256

@@ -95,12 +99,18 @@ describe('PeerId', () => {
9599
expect(testIdBytes).to.deep.equal(id.toBytes())
96100
})
97101

98-
it('recreate from Base58 String (CIDv0))', () => {
102+
it('recreate from Base58 String (CIDv0)', () => {
99103
const id = PeerId.createFromCID(CID.parse(testIdB58String))
100104
expect(testIdCIDString).to.equal(id.toString())
101105
expect(testIdBytes).to.deep.equal(id.toBytes())
102106
})
103107

108+
it('recreate from Base36 String', () => {
109+
const id = PeerId.parse(testIdB36String)
110+
expect(testIdCIDString).to.equal(id.toString())
111+
expect(testIdBytes).to.deep.equal(id.toBytes())
112+
})
113+
104114
it('recreate from CIDv1 Base32 (libp2p-key multicodec)', () => {
105115
const cid = CID.createV1(LIBP2P_KEY_CODE, testIdDigest)
106116
const id = PeerId.createFromCID(cid)
@@ -176,15 +186,15 @@ describe('PeerId', () => {
176186
const key = '12D3KooWRm8J3iL796zPFi2EtGGtUJn58AG67gcqzMFHZnnsTzqD'
177187
const id = await PeerId.parse(key)
178188
expect(id.toB58String()).to.equal(key)
179-
const expB58 = mh.toB58String(mh.encode(id.pubKey.bytes, 'identity'))
189+
const expB58 = base58btc.encode((await identity.digest(id.pubKey.bytes)).bytes).slice(1)
180190
expect(id.toB58String()).to.equal(expB58)
181191
})
182192

183193
it('recreate from embedded secp256k1 key', async () => {
184194
const key = '16Uiu2HAm5qw8UyXP2RLxQUx5KvtSN8DsTKz8quRGqGNC3SYiaB8E'
185195
const id = await PeerId.parse(key)
186196
expect(id.toB58String()).to.equal(key)
187-
const expB58 = mh.toB58String(mh.encode(id.pubKey.bytes, 'identity'))
197+
const expB58 = base58btc.encode((await identity.digest(id.pubKey.bytes)).bytes).slice(1)
188198
expect(id.toB58String()).to.equal(expB58)
189199
})
190200

@@ -197,14 +207,14 @@ describe('PeerId', () => {
197207
it('can be created from a Secp256k1 public key', async () => {
198208
const privKey = await crypto.keys.generateKeyPair('secp256k1', 256)
199209
const id = await PeerId.createFromPubKey(privKey.public.bytes)
200-
const expB58 = mh.toB58String(mh.encode(id.pubKey.bytes, 'identity'))
210+
const expB58 = base58btc.encode((await identity.digest(id.pubKey.bytes)).bytes).slice(1)
201211
expect(id.toB58String()).to.equal(expB58)
202212
})
203213

204214
it('can be created from a Secp256k1 private key', async () => {
205215
const privKey = await crypto.keys.generateKeyPair('secp256k1', 256)
206216
const id = await PeerId.createFromPrivKey(privKey.bytes)
207-
const expB58 = mh.toB58String(mh.encode(id.pubKey.bytes, 'identity'))
217+
const expB58 = base58btc.encode((await identity.digest(id.pubKey.bytes)).bytes).slice(1)
208218
expect(id.toB58String()).to.equal(expB58)
209219
})
210220

@@ -298,7 +308,7 @@ describe('PeerId', () => {
298308
it('go interop', async () => {
299309
const id = await PeerId.createFromJSON(goId)
300310
const digest = await id.privKey.public.hash()
301-
expect(mh.toB58String(digest)).to.eql(goId.id)
311+
expect(base58btc.encode(digest).slice(1)).to.eql(goId.id)
302312
})
303313
})
304314

‎tsconfig.json

+11-39
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,12 @@
11
{
2-
"compilerOptions": {
3-
"module": "commonjs",
4-
"lib": [
5-
"es6"
6-
],
7-
"target": "ES5",
8-
"noImplicitAny": false,
9-
"noImplicitThis": true,
10-
"strictFunctionTypes": true,
11-
"strictNullChecks": true,
12-
"esModuleInterop": true,
13-
"resolveJsonModule": true,
14-
"allowJs": true,
15-
"checkJs": true,
16-
"baseUrl": ".",
17-
"paths": {
18-
"peer-id": [
19-
"./src",
20-
"../src",
21-
]
22-
},
23-
"types": [
24-
"node",
25-
"mocha",
26-
"chai"
27-
],
28-
"noEmit": true,
29-
"forceConsistentCasingInFileNames": true
30-
},
31-
"files": [
32-
"./src/index.d.ts",
33-
],
34-
"include": [
35-
"./test/**/*.spec.js"
36-
],
37-
"exclude": [
38-
"src/proto.js" // generated file
39-
]
40-
}
2+
"extends": "aegir/src/config/tsconfig.aegir.json",
3+
"compilerOptions": {
4+
"outDir": "dist"
5+
},
6+
"include": [
7+
"./test/**/*.spec.js"
8+
],
9+
"exclude": [
10+
"src/proto.js" // generated file
11+
]
12+
}

0 commit comments

Comments
 (0)
Please sign in to comment.