Skip to content

Commit

Permalink
Updated to reduce size of dependency.
Browse files Browse the repository at this point in the history
  • Loading branch information
John-LittleBearLabs committed Aug 17, 2022
1 parent f351942 commit cab5d25
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 30 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@
"dns-over-http-resolver": "^2.1.0",
"err-code": "^3.0.1",
"is-ip": "^4.0.0",
"multibase": "^4.0.6",
"multiformats": "^9.4.5",
"uint8arrays": "^3.0.0",
"varint": "^6.0.0"
Expand Down
28 changes: 6 additions & 22 deletions src/convert.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@

import * as ip from './ip.js'
import { getProtocol } from './protocols-table.js'
import { CID } from 'multiformats/cid'
import { base32 } from 'multiformats/bases/base32'
import { base58btc } from 'multiformats/bases/base58'
import * as MB from 'multibase'
import * as Digest from 'multiformats/hashes/digest'
import varint from 'varint'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
Expand All @@ -27,6 +25,9 @@ export function convert (proto: string, a: string | Uint8Array) {
*/
export function convertToString (proto: number | string, buf: Uint8Array) {
const protocol = getProtocol(proto)
if (protocol.convertor) {
return protocol.convertor.bytesToString(buf);
}
switch (protocol.code) {
case 4: // ipv4
case 41: // ipv6
Expand All @@ -52,15 +53,16 @@ export function convertToString (proto: number | string, buf: Uint8Array) {
return bytes2onion(buf)
case 445: // onion3
return bytes2onion(buf)
case 466: //certhash
return bytes2mb(buf)
default:
return uint8ArrayToString(buf, 'base16') // no clue. convert to hex
}
}

export function convertToBytes (proto: string | number, str: string) {
const protocol = getProtocol(proto)
if (protocol.convertor) {
return protocol.convertor.stringToBytes(str);
}
switch (protocol.code) {
case 4: // ipv4
return ip2bytes(str)
Expand All @@ -87,8 +89,6 @@ export function convertToBytes (proto: string | number, str: string) {
return onion2bytes(str)
case 445: // onion3
return onion32bytes(str)
case 466: //certhash
return mb2bytes(str)
default:
return uint8ArrayFromString(str, 'base16') // no clue. convert from hex
}
Expand Down Expand Up @@ -153,22 +153,6 @@ function mh2bytes (hash: string) {
return uint8ArrayConcat([size, mh], size.length + mh.length)
}

function mb2bytes(mbstr: string) {
let mb = MB.decode(mbstr)
const size = Uint8Array.from(varint.encode(mb.length))
return uint8ArrayConcat([size, mb], size.length + mb.length)
}
function bytes2mb(buf: Uint8Array) {
const size = varint.decode(buf)
const hash = buf.slice(varint.decode.bytes)

if (hash.length !== size) {
throw new Error('inconsistent lengths')
}

return 'm' + uint8ArrayToString(hash, 'base64')
}

/**
* Converts bytes to bas58btc string
*/
Expand Down
45 changes: 45 additions & 0 deletions src/default-certhash-codec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ParseError } from './codec.js'
import type { Codec } from './protocols-table'
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import varint from 'varint'
import { base16 } from 'multiformats/bases/base16'
import { base58btc } from 'multiformats/bases/base58'
import { base64url } from 'multiformats/bases/base64'
import type { BaseDecoder } from 'multiformats/bases/interface'

const encodings: {[prefix: string]: BaseDecoder} = {
'f': base16,
'u': base64url,
'z': base58btc,
};

export class DefaultCerthashCodec implements Codec {
stringToBytes(stringRepresentation: string): Uint8Array {
if (stringRepresentation.length < 2) {
throw ParseError('Not enough length to be a multibase: ' + stringRepresentation);
}
let prefix = stringRepresentation[0];
let encoded = stringRepresentation.slice(1);
let encoding = encodings[prefix];
let decoded: Uint8Array;
if (encoding) {
decoded = encoding.baseDecode(encoded);
} else {
throw new Error('certhash is in a multibase encoding that is not supported by default. Please provide a custom decoder: '+stringRepresentation);
}
const size = Uint8Array.from(varint.encode(decoded.length))
return uint8ArrayConcat([size, decoded], size.length + decoded.length)
}
bytesToString(byteRepresentation: Uint8Array): string {
const size = varint.decode(byteRepresentation)
const hash = byteRepresentation.slice(varint.decode.bytes)

if (hash.length !== size) {
throw new Error('inconsistent lengths')
}

return 'z' + uint8ArrayToString(hash, 'base58btc')
}

}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as codec from './codec.js'
import { getProtocol, names } from './protocols-table.js'
import { setProtocolCodec, getProtocol, names } from './protocols-table.js'
import varint from 'varint'
import { CID } from 'multiformats/cid'
import { base58btc } from 'multiformats/bases/base58'
Expand Down Expand Up @@ -647,4 +647,5 @@ export function multiaddr (addr: MultiaddrInput) {
}

export { getProtocol as protocols }
export { setProtocolCodec }
export { resolvers }
24 changes: 20 additions & 4 deletions src/protocols-table.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { DefaultCerthashCodec } from "./default-certhash-codec.js";

export interface Codec {
stringToBytes(stringRepresentation: string): Uint8Array;
bytesToString(byteRepresentation: Uint8Array): string;
}

export interface Protocol {
code: number
size: number
name: string
resolvable?: boolean
path?: boolean
convertor?: Codec
}

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

export const table: Array<[number, number, string, boolean?, boolean?]> = [
export const table: Array<[number, number, string, boolean?, boolean?, Codec?]> = [
[4, 32, 'ip4'],
[6, 16, 'tcp'],
[33, 16, 'dccp'],
Expand Down Expand Up @@ -41,7 +49,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [
[445, 296, 'onion3'],
[446, V, 'garlic64'],
[460, 0, 'quic'],
[466, V, 'certhash'],
[466, V, 'certhash', false, false, new DefaultCerthashCodec()],
[477, 0, 'ws'],
[478, 0, 'wss'],
[479, 0, 'p2p-websocket-star'],
Expand All @@ -56,13 +64,14 @@ table.forEach(row => {
names[proto.name] = proto
})

export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any): Protocol {
export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any, convertor?: Codec): Protocol {
return {
code,
size,
name,
resolvable: Boolean(resolvable),
path: Boolean(path)
path: Boolean(path),
convertor: convertor
}
}

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

throw new Error(`invalid protocol id type: ${typeof proto}`)
}

export function setProtocolCodec(proto: number | string, codec: Codec) {
let protocol = getProtocol(proto)
protocol.convertor = codec
codes[protocol.code] = protocol
names[protocol.name] = protocol
}
2 changes: 1 addition & 1 deletion test/convert.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('convert', () => {
let bytes = convert.convertToBytes('certhash',mb);
let outcome = convert.convertToString(466, bytes);
//Although I sent hex encoding in, base64 always comes out
expect(outcome).to.equal('m9DKgRTRiheDY13U2hHKOsqqecWTk6/4GUWRCZP4EqNA');
expect(outcome).to.equal('zHSFFdP8jLt9o6HXnz5bBYoE7JACNqVcFNnCnDyd5Ynyu');
let bytesOut = convert.convertToBytes(466,outcome);
expect(bytesOut.toString()).to.equal(bytes.toString());
})
Expand Down
15 changes: 14 additions & 1 deletion test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -540,12 +540,14 @@ describe('helpers', () => {
expect(new Multiaddr('/ip4/0.0.0.0/utp').protos())
.to.eql([{
code: 4,
convertor: undefined,
name: 'ip4',
path: false,
size: 32,
resolvable: false
resolvable: false,
}, {
code: 302,
convertor: undefined,
name: 'utp',
path: false,
size: 0,
Expand All @@ -558,18 +560,21 @@ describe('helpers', () => {
new Multiaddr('/ip4/0.0.0.0/utp/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos()
).to.be.eql([{
code: 4,
convertor: undefined,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 302,
convertor: undefined,
name: 'utp',
path: false,
size: 0,
resolvable: false
}, {
code: 421,
convertor: undefined,
name: 'p2p',
path: false,
size: -1,
Expand All @@ -582,18 +587,21 @@ describe('helpers', () => {
new Multiaddr('/ip4/0.0.0.0/utp/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC').protos()
).to.be.eql([{
code: 4,
convertor: undefined,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 302,
convertor: undefined,
name: 'utp',
path: false,
size: 0,
resolvable: false
}, {
code: 421,
convertor: undefined,
name: 'p2p',
path: false,
size: -1,
Expand All @@ -606,18 +614,21 @@ describe('helpers', () => {
new Multiaddr('/ip4/0.0.0.0/tcp/8000/unix/tmp/p2p.sock').protos()
).to.be.eql([{
code: 4,
convertor: undefined,
name: 'ip4',
path: false,
size: 32,
resolvable: false
}, {
code: 6,
convertor: undefined,
name: 'tcp',
path: false,
size: 16,
resolvable: false
}, {
code: 400,
convertor: undefined,
name: 'unix',
path: true,
size: -1,
Expand All @@ -630,12 +641,14 @@ describe('helpers', () => {
new Multiaddr('/memory/test/p2p/QmZR5a9AAXGqQF2ADqoDdGS8zvqv8n3Pag6TDDnTNMcFW6').protos()
).to.be.eql([{
code: 777,
convertor: undefined,
name: 'memory',
path: false,
size: -1,
resolvable: false
}, {
code: 421,
convertor: undefined,
name: 'p2p',
path: false,
size: -1,
Expand Down

0 comments on commit cab5d25

Please sign in to comment.