Skip to content

Commit cab5d25

Browse files
Updated to reduce size of dependency.
1 parent f351942 commit cab5d25

7 files changed

+88
-30
lines changed

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,6 @@
167167
"dns-over-http-resolver": "^2.1.0",
168168
"err-code": "^3.0.1",
169169
"is-ip": "^4.0.0",
170-
"multibase": "^4.0.6",
171170
"multiformats": "^9.4.5",
172171
"uint8arrays": "^3.0.0",
173172
"varint": "^6.0.0"

src/convert.ts

+6-22
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
21
import * as ip from './ip.js'
32
import { getProtocol } from './protocols-table.js'
43
import { CID } from 'multiformats/cid'
54
import { base32 } from 'multiformats/bases/base32'
65
import { base58btc } from 'multiformats/bases/base58'
7-
import * as MB from 'multibase'
86
import * as Digest from 'multiformats/hashes/digest'
97
import varint from 'varint'
108
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
@@ -27,6 +25,9 @@ export function convert (proto: string, a: string | Uint8Array) {
2725
*/
2826
export function convertToString (proto: number | string, buf: Uint8Array) {
2927
const protocol = getProtocol(proto)
28+
if (protocol.convertor) {
29+
return protocol.convertor.bytesToString(buf);
30+
}
3031
switch (protocol.code) {
3132
case 4: // ipv4
3233
case 41: // ipv6
@@ -52,15 +53,16 @@ export function convertToString (proto: number | string, buf: Uint8Array) {
5253
return bytes2onion(buf)
5354
case 445: // onion3
5455
return bytes2onion(buf)
55-
case 466: //certhash
56-
return bytes2mb(buf)
5756
default:
5857
return uint8ArrayToString(buf, 'base16') // no clue. convert to hex
5958
}
6059
}
6160

6261
export function convertToBytes (proto: string | number, str: string) {
6362
const protocol = getProtocol(proto)
63+
if (protocol.convertor) {
64+
return protocol.convertor.stringToBytes(str);
65+
}
6466
switch (protocol.code) {
6567
case 4: // ipv4
6668
return ip2bytes(str)
@@ -87,8 +89,6 @@ export function convertToBytes (proto: string | number, str: string) {
8789
return onion2bytes(str)
8890
case 445: // onion3
8991
return onion32bytes(str)
90-
case 466: //certhash
91-
return mb2bytes(str)
9292
default:
9393
return uint8ArrayFromString(str, 'base16') // no clue. convert from hex
9494
}
@@ -153,22 +153,6 @@ function mh2bytes (hash: string) {
153153
return uint8ArrayConcat([size, mh], size.length + mh.length)
154154
}
155155

156-
function mb2bytes(mbstr: string) {
157-
let mb = MB.decode(mbstr)
158-
const size = Uint8Array.from(varint.encode(mb.length))
159-
return uint8ArrayConcat([size, mb], size.length + mb.length)
160-
}
161-
function bytes2mb(buf: Uint8Array) {
162-
const size = varint.decode(buf)
163-
const hash = buf.slice(varint.decode.bytes)
164-
165-
if (hash.length !== size) {
166-
throw new Error('inconsistent lengths')
167-
}
168-
169-
return 'm' + uint8ArrayToString(hash, 'base64')
170-
}
171-
172156
/**
173157
* Converts bytes to bas58btc string
174158
*/

src/default-certhash-codec.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { ParseError } from './codec.js'
2+
import type { Codec } from './protocols-table'
3+
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
4+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
5+
import varint from 'varint'
6+
import { base16 } from 'multiformats/bases/base16'
7+
import { base58btc } from 'multiformats/bases/base58'
8+
import { base64url } from 'multiformats/bases/base64'
9+
import type { BaseDecoder } from 'multiformats/bases/interface'
10+
11+
const encodings: {[prefix: string]: BaseDecoder} = {
12+
'f': base16,
13+
'u': base64url,
14+
'z': base58btc,
15+
};
16+
17+
export class DefaultCerthashCodec implements Codec {
18+
stringToBytes(stringRepresentation: string): Uint8Array {
19+
if (stringRepresentation.length < 2) {
20+
throw ParseError('Not enough length to be a multibase: ' + stringRepresentation);
21+
}
22+
let prefix = stringRepresentation[0];
23+
let encoded = stringRepresentation.slice(1);
24+
let encoding = encodings[prefix];
25+
let decoded: Uint8Array;
26+
if (encoding) {
27+
decoded = encoding.baseDecode(encoded);
28+
} else {
29+
throw new Error('certhash is in a multibase encoding that is not supported by default. Please provide a custom decoder: '+stringRepresentation);
30+
}
31+
const size = Uint8Array.from(varint.encode(decoded.length))
32+
return uint8ArrayConcat([size, decoded], size.length + decoded.length)
33+
}
34+
bytesToString(byteRepresentation: Uint8Array): string {
35+
const size = varint.decode(byteRepresentation)
36+
const hash = byteRepresentation.slice(varint.decode.bytes)
37+
38+
if (hash.length !== size) {
39+
throw new Error('inconsistent lengths')
40+
}
41+
42+
return 'z' + uint8ArrayToString(hash, 'base58btc')
43+
}
44+
45+
}

src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as codec from './codec.js'
2-
import { getProtocol, names } from './protocols-table.js'
2+
import { setProtocolCodec, getProtocol, names } from './protocols-table.js'
33
import varint from 'varint'
44
import { CID } from 'multiformats/cid'
55
import { base58btc } from 'multiformats/bases/base58'
@@ -647,4 +647,5 @@ export function multiaddr (addr: MultiaddrInput) {
647647
}
648648

649649
export { getProtocol as protocols }
650+
export { setProtocolCodec }
650651
export { resolvers }

src/protocols-table.ts

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
1+
import { DefaultCerthashCodec } from "./default-certhash-codec.js";
2+
3+
export interface Codec {
4+
stringToBytes(stringRepresentation: string): Uint8Array;
5+
bytesToString(byteRepresentation: Uint8Array): string;
6+
}
7+
18
export interface Protocol {
29
code: number
310
size: number
411
name: string
512
resolvable?: boolean
613
path?: boolean
14+
convertor?: Codec
715
}
816

917
const V = -1
1018
export const names: Record<string, Protocol> = {}
1119
export const codes: Record<number, Protocol> = {}
1220

13-
export const table: Array<[number, number, string, boolean?, boolean?]> = [
21+
export const table: Array<[number, number, string, boolean?, boolean?, Codec?]> = [
1422
[4, 32, 'ip4'],
1523
[6, 16, 'tcp'],
1624
[33, 16, 'dccp'],
@@ -41,7 +49,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [
4149
[445, 296, 'onion3'],
4250
[446, V, 'garlic64'],
4351
[460, 0, 'quic'],
44-
[466, V, 'certhash'],
52+
[466, V, 'certhash', false, false, new DefaultCerthashCodec()],
4553
[477, 0, 'ws'],
4654
[478, 0, 'wss'],
4755
[479, 0, 'p2p-websocket-star'],
@@ -56,13 +64,14 @@ table.forEach(row => {
5664
names[proto.name] = proto
5765
})
5866

59-
export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any): Protocol {
67+
export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any, convertor?: Codec): Protocol {
6068
return {
6169
code,
6270
size,
6371
name,
6472
resolvable: Boolean(resolvable),
65-
path: Boolean(path)
73+
path: Boolean(path),
74+
convertor: convertor
6675
}
6776
}
6877

@@ -83,3 +92,10 @@ export function getProtocol (proto: number | string) {
8392

8493
throw new Error(`invalid protocol id type: ${typeof proto}`)
8594
}
95+
96+
export function setProtocolCodec(proto: number | string, codec: Codec) {
97+
let protocol = getProtocol(proto)
98+
protocol.convertor = codec
99+
codes[protocol.code] = protocol
100+
names[protocol.name] = protocol
101+
}

test/convert.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ describe('convert', () => {
9797
let bytes = convert.convertToBytes('certhash',mb);
9898
let outcome = convert.convertToString(466, bytes);
9999
//Although I sent hex encoding in, base64 always comes out
100-
expect(outcome).to.equal('m9DKgRTRiheDY13U2hHKOsqqecWTk6/4GUWRCZP4EqNA');
100+
expect(outcome).to.equal('zHSFFdP8jLt9o6HXnz5bBYoE7JACNqVcFNnCnDyd5Ynyu');
101101
let bytesOut = convert.convertToBytes(466,outcome);
102102
expect(bytesOut.toString()).to.equal(bytes.toString());
103103
})

test/index.spec.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -540,12 +540,14 @@ describe('helpers', () => {
540540
expect(new Multiaddr('/ip4/0.0.0.0/utp').protos())
541541
.to.eql([{
542542
code: 4,
543+
convertor: undefined,
543544
name: 'ip4',
544545
path: false,
545546
size: 32,
546-
resolvable: false
547+
resolvable: false,
547548
}, {
548549
code: 302,
550+
convertor: undefined,
549551
name: 'utp',
550552
path: false,
551553
size: 0,
@@ -558,18 +560,21 @@ describe('helpers', () => {
558560
new Multiaddr('/ip4/0.0.0.0/utp/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos()
559561
).to.be.eql([{
560562
code: 4,
563+
convertor: undefined,
561564
name: 'ip4',
562565
path: false,
563566
size: 32,
564567
resolvable: false
565568
}, {
566569
code: 302,
570+
convertor: undefined,
567571
name: 'utp',
568572
path: false,
569573
size: 0,
570574
resolvable: false
571575
}, {
572576
code: 421,
577+
convertor: undefined,
573578
name: 'p2p',
574579
path: false,
575580
size: -1,
@@ -582,18 +587,21 @@ describe('helpers', () => {
582587
new Multiaddr('/ip4/0.0.0.0/utp/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos()
583588
).to.be.eql([{
584589
code: 4,
590+
convertor: undefined,
585591
name: 'ip4',
586592
path: false,
587593
size: 32,
588594
resolvable: false
589595
}, {
590596
code: 302,
597+
convertor: undefined,
591598
name: 'utp',
592599
path: false,
593600
size: 0,
594601
resolvable: false
595602
}, {
596603
code: 421,
604+
convertor: undefined,
597605
name: 'p2p',
598606
path: false,
599607
size: -1,
@@ -606,18 +614,21 @@ describe('helpers', () => {
606614
new Multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos()
607615
).to.be.eql([{
608616
code: 4,
617+
convertor: undefined,
609618
name: 'ip4',
610619
path: false,
611620
size: 32,
612621
resolvable: false
613622
}, {
614623
code: 6,
624+
convertor: undefined,
615625
name: 'tcp',
616626
path: false,
617627
size: 16,
618628
resolvable: false
619629
}, {
620630
code: 400,
631+
convertor: undefined,
621632
name: 'unix',
622633
path: true,
623634
size: -1,
@@ -630,12 +641,14 @@ describe('helpers', () => {
630641
new Multiaddr('/memory/test/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6').protos()
631642
).to.be.eql([{
632643
code: 777,
644+
convertor: undefined,
633645
name: 'memory',
634646
path: false,
635647
size: -1,
636648
resolvable: false
637649
}, {
638650
code: 421,
651+
convertor: undefined,
639652
name: 'p2p',
640653
path: false,
641654
size: -1,

0 commit comments

Comments
 (0)