From 5ea7b52c8efde5cfce765141f4ca4fa864f8b92c Mon Sep 17 00:00:00 2001 From: John Turpish Date: Tue, 9 Aug 2022 16:31:57 -0400 Subject: [PATCH 1/7] fix: Add support for webrtc and certhash (#261) --- package.json | 1 + src/convert.ts | 11 +++++++++++ src/protocols-table.ts | 2 ++ 3 files changed, 14 insertions(+) diff --git a/package.json b/package.json index 0cd636bc..cdd7dd53 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "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" diff --git a/src/convert.ts b/src/convert.ts index e35613d2..2256c35c 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -4,6 +4,7 @@ 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' @@ -51,6 +52,8 @@ export function convertToString (proto: number | string, buf: Uint8Array) { return bytes2onion(buf) case 445: // onion3 return bytes2onion(buf) + case 466: //certhash + return bytes2mh(buf) default: return uint8ArrayToString(buf, 'base16') // no clue. convert to hex } @@ -84,6 +87,8 @@ 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 } @@ -148,6 +153,12 @@ 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) +} + /** * Converts bytes to bas58btc string */ diff --git a/src/protocols-table.ts b/src/protocols-table.ts index 0e839cc9..657003c6 100644 --- a/src/protocols-table.ts +++ b/src/protocols-table.ts @@ -25,6 +25,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [ [275, 0, 'p2p-webrtc-star'], [276, 0, 'p2p-webrtc-direct'], [277, 0, 'p2p-stardust'], + [280, 0, 'webrtc'], [290, 0, 'p2p-circuit'], [301, 0, 'udt'], [302, 0, 'utp'], @@ -40,6 +41,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [ [445, 296, 'onion3'], [446, V, 'garlic64'], [460, 0, 'quic'], + [466, V, 'certhash'], [477, 0, 'ws'], [478, 0, 'wss'], [479, 0, 'p2p-websocket-star'], From f351942fae55da1ebe5af7ffd498eccfa60b0815 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Wed, 10 Aug 2022 13:18:56 -0400 Subject: [PATCH 2/7] Added a test for certhash encoding. --- src/convert.ts | 12 +++++++++++- test/convert.spec.ts | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/convert.ts b/src/convert.ts index 2256c35c..7d3767b9 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -53,7 +53,7 @@ export function convertToString (proto: number | string, buf: Uint8Array) { case 445: // onion3 return bytes2onion(buf) case 466: //certhash - return bytes2mh(buf) + return bytes2mb(buf) default: return uint8ArrayToString(buf, 'base16') // no clue. convert to hex } @@ -158,6 +158,16 @@ function mb2bytes(mbstr: string) { 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 diff --git a/test/convert.spec.ts b/test/convert.spec.ts index 15bf40cd..e20cfb79 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -87,4 +87,18 @@ describe('convert', () => { expect(convert.convertToString('sctp', buffer.subarray(5))).to.equal('1234') }) }) + + it('can round-trip certhash, though encoding base may change', ()=>{ + let myCertFingerprint = { + "algorithm": "sha-256", + "value": "f4:32:a0:45:34:62:85:e0:d8:d7:75:36:84:72:8e:b2:aa:9e:71:64:e4:eb:fe:06:51:64:42:64:fe:04:a8:d0" + }; + let mb = 'f' + myCertFingerprint.value.replaceAll(':',''); + 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'); + let bytesOut = convert.convertToBytes(466,outcome); + expect(bytesOut.toString()).to.equal(bytes.toString()); + }) }) From cab5d2574c7eef797d64711d15756d637431e523 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Wed, 17 Aug 2022 01:01:21 -0400 Subject: [PATCH 3/7] Updated to reduce size of dependency. --- package.json | 1 - src/convert.ts | 28 +++++----------------- src/default-certhash-codec.ts | 45 +++++++++++++++++++++++++++++++++++ src/index.ts | 3 ++- src/protocols-table.ts | 24 +++++++++++++++---- test/convert.spec.ts | 2 +- test/index.spec.ts | 15 +++++++++++- 7 files changed, 88 insertions(+), 30 deletions(-) create mode 100644 src/default-certhash-codec.ts diff --git a/package.json b/package.json index cdd7dd53..0cd636bc 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/src/convert.ts b/src/convert.ts index 7d3767b9..b45dbc08 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -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' @@ -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 @@ -52,8 +53,6 @@ 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 } @@ -61,6 +60,9 @@ export function convertToString (proto: number | string, buf: Uint8Array) { 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) @@ -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 } @@ -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 */ diff --git a/src/default-certhash-codec.ts b/src/default-certhash-codec.ts new file mode 100644 index 00000000..ce33221a --- /dev/null +++ b/src/default-certhash-codec.ts @@ -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') + } + +} diff --git a/src/index.ts b/src/index.ts index 0ba8a868..fb2b7f0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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' @@ -647,4 +647,5 @@ export function multiaddr (addr: MultiaddrInput) { } export { getProtocol as protocols } +export { setProtocolCodec } export { resolvers } diff --git a/src/protocols-table.ts b/src/protocols-table.ts index 657003c6..31eb33ab 100644 --- a/src/protocols-table.ts +++ b/src/protocols-table.ts @@ -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 = {} export const codes: Record = {} -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'], @@ -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'], @@ -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 } } @@ -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 +} diff --git a/test/convert.spec.ts b/test/convert.spec.ts index e20cfb79..f1e780bf 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -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()); }) diff --git a/test/index.spec.ts b/test/index.spec.ts index 225a89a0..e94d7598 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, From 178b6602f746403d4d0241b8186e03dd332a61da Mon Sep 17 00:00:00 2001 From: John Turpish Date: Wed, 17 Aug 2022 12:15:08 -0400 Subject: [PATCH 4/7] Revert "Updated to reduce size of dependency." This reverts commit cab5d2574c7eef797d64711d15756d637431e523. --- package.json | 1 + src/convert.ts | 28 +++++++++++++++++----- src/default-certhash-codec.ts | 45 ----------------------------------- src/index.ts | 3 +-- src/protocols-table.ts | 24 ++++--------------- test/convert.spec.ts | 2 +- test/index.spec.ts | 15 +----------- 7 files changed, 30 insertions(+), 88 deletions(-) delete mode 100644 src/default-certhash-codec.ts diff --git a/package.json b/package.json index 0cd636bc..cdd7dd53 100644 --- a/package.json +++ b/package.json @@ -167,6 +167,7 @@ "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" diff --git a/src/convert.ts b/src/convert.ts index b45dbc08..7d3767b9 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -1,8 +1,10 @@ + 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' @@ -25,9 +27,6 @@ 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 @@ -53,6 +52,8 @@ 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 } @@ -60,9 +61,6 @@ export function convertToString (proto: number | string, buf: Uint8Array) { 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) @@ -89,6 +87,8 @@ 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 } @@ -153,6 +153,22 @@ 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 */ diff --git a/src/default-certhash-codec.ts b/src/default-certhash-codec.ts deleted file mode 100644 index ce33221a..00000000 --- a/src/default-certhash-codec.ts +++ /dev/null @@ -1,45 +0,0 @@ -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') - } - -} diff --git a/src/index.ts b/src/index.ts index fb2b7f0e..0ba8a868 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ import * as codec from './codec.js' -import { setProtocolCodec, getProtocol, names } from './protocols-table.js' +import { getProtocol, names } from './protocols-table.js' import varint from 'varint' import { CID } from 'multiformats/cid' import { base58btc } from 'multiformats/bases/base58' @@ -647,5 +647,4 @@ export function multiaddr (addr: MultiaddrInput) { } export { getProtocol as protocols } -export { setProtocolCodec } export { resolvers } diff --git a/src/protocols-table.ts b/src/protocols-table.ts index 31eb33ab..657003c6 100644 --- a/src/protocols-table.ts +++ b/src/protocols-table.ts @@ -1,24 +1,16 @@ -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 = {} export const codes: Record = {} -export const table: Array<[number, number, string, boolean?, boolean?, Codec?]> = [ +export const table: Array<[number, number, string, boolean?, boolean?]> = [ [4, 32, 'ip4'], [6, 16, 'tcp'], [33, 16, 'dccp'], @@ -49,7 +41,7 @@ export const table: Array<[number, number, string, boolean?, boolean?, Codec?]> [445, 296, 'onion3'], [446, V, 'garlic64'], [460, 0, 'quic'], - [466, V, 'certhash', false, false, new DefaultCerthashCodec()], + [466, V, 'certhash'], [477, 0, 'ws'], [478, 0, 'wss'], [479, 0, 'p2p-websocket-star'], @@ -64,14 +56,13 @@ table.forEach(row => { names[proto.name] = proto }) -export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any, convertor?: Codec): Protocol { +export function createProtocol (code: number, size: number, name: string, resolvable?: any, path?: any): Protocol { return { code, size, name, resolvable: Boolean(resolvable), - path: Boolean(path), - convertor: convertor + path: Boolean(path) } } @@ -92,10 +83,3 @@ 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 -} diff --git a/test/convert.spec.ts b/test/convert.spec.ts index f1e780bf..e20cfb79 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -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('zHSFFdP8jLt9o6HXnz5bBYoE7JACNqVcFNnCnDyd5Ynyu'); + expect(outcome).to.equal('m9DKgRTRiheDY13U2hHKOsqqecWTk6/4GUWRCZP4EqNA'); let bytesOut = convert.convertToBytes(466,outcome); expect(bytesOut.toString()).to.equal(bytes.toString()); }) diff --git a/test/index.spec.ts b/test/index.spec.ts index e94d7598..225a89a0 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -540,14 +540,12 @@ 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, @@ -560,21 +558,18 @@ 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, @@ -587,21 +582,18 @@ 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, @@ -614,21 +606,18 @@ 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, @@ -641,14 +630,12 @@ 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, From 344e8f81aa87355b86c25817fdce62547676d506 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Wed, 17 Aug 2022 13:41:08 -0400 Subject: [PATCH 5/7] Supporting the others, removed custom proto-specific codecs. --- package.json | 1 - src/convert.ts | 13 ++++++++++--- test/convert.spec.ts | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index cdd7dd53..0cd636bc 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/src/convert.ts b/src/convert.ts index 7d3767b9..141891b5 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -4,7 +4,7 @@ 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 { bases } from 'multiformats/basics' import * as Digest from 'multiformats/hashes/digest' import varint from 'varint' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' @@ -94,6 +94,13 @@ export function convertToBytes (proto: string | number, str: string) { } } +const decoders = Object.values(bases).map( (c) => c.decoder ); +const anybaseDecoder = (function () { + let acc = decoders[0].or(decoders[1]); + decoders.slice(2).forEach((d) => (acc = acc.or(d))); + return acc; +})(); + function ip2bytes (ipString: string) { if (!ip.isIP(ipString)) { throw new Error('invalid ip address') @@ -154,7 +161,7 @@ function mh2bytes (hash: string) { } function mb2bytes(mbstr: string) { - let mb = MB.decode(mbstr) + let mb = anybaseDecoder.decode(mbstr) const size = Uint8Array.from(varint.encode(mb.length)) return uint8ArrayConcat([size, mb], size.length + mb.length) } @@ -166,7 +173,7 @@ function bytes2mb(buf: Uint8Array) { throw new Error('inconsistent lengths') } - return 'm' + uint8ArrayToString(hash, 'base64') + return 'z' + uint8ArrayToString(hash, 'base58btc') } /** diff --git a/test/convert.spec.ts b/test/convert.spec.ts index e20cfb79..d690abdf 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -96,8 +96,8 @@ describe('convert', () => { let mb = 'f' + myCertFingerprint.value.replaceAll(':',''); 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'); + //Although I sent hex encoding in, base58btc always comes out + expect(outcome).to.equal('zHSFFdP8jLt9o6HXnz5bBYoE7JACNqVcFNnCnDyd5Ynyu'); let bytesOut = convert.convertToBytes(466,outcome); expect(bytesOut.toString()).to.equal(bytes.toString()); }) From 33e5b30f46c5fdae4366b63241e94e77e9ba2fc1 Mon Sep 17 00:00:00 2001 From: John Turpish Date: Thu, 18 Aug 2022 23:24:48 -0400 Subject: [PATCH 6/7] Back to base64url as the default base for ToString --- src/convert.ts | 2 +- test/convert.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/convert.ts b/src/convert.ts index 141891b5..5365cac8 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -173,7 +173,7 @@ function bytes2mb(buf: Uint8Array) { throw new Error('inconsistent lengths') } - return 'z' + uint8ArrayToString(hash, 'base58btc') + return 'u' + uint8ArrayToString(hash, 'base64url') } /** diff --git a/test/convert.spec.ts b/test/convert.spec.ts index d690abdf..5f766d82 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -97,7 +97,7 @@ describe('convert', () => { let bytes = convert.convertToBytes('certhash',mb); let outcome = convert.convertToString(466, bytes); //Although I sent hex encoding in, base58btc always comes out - expect(outcome).to.equal('zHSFFdP8jLt9o6HXnz5bBYoE7JACNqVcFNnCnDyd5Ynyu'); + expect(outcome).to.equal('u9DKgRTRiheDY13U2hHKOsqqecWTk6_4GUWRCZP4EqNA'); let bytesOut = convert.convertToBytes(466,outcome); expect(bytesOut.toString()).to.equal(bytes.toString()); }) From 561bf9bb28d0f6424d7503403e75f680fdcabe7c Mon Sep 17 00:00:00 2001 From: John Turpish Date: Tue, 30 Aug 2022 12:20:33 -0400 Subject: [PATCH 7/7] Updated for PR comments. --- src/convert.ts | 20 ++++++++++---------- test/convert.spec.ts | 23 +++++++++++------------ 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/convert.ts b/src/convert.ts index 5365cac8..c38a64b0 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -52,7 +52,7 @@ export function convertToString (proto: number | string, buf: Uint8Array) { return bytes2onion(buf) case 445: // onion3 return bytes2onion(buf) - case 466: //certhash + case 466: // certhash return bytes2mb(buf) default: return uint8ArrayToString(buf, 'base16') // no clue. convert to hex @@ -87,19 +87,19 @@ export function convertToBytes (proto: string | number, str: string) { return onion2bytes(str) case 445: // onion3 return onion32bytes(str) - case 466: //certhash + case 466: // certhash return mb2bytes(str) default: return uint8ArrayFromString(str, 'base16') // no clue. convert from hex } } -const decoders = Object.values(bases).map( (c) => c.decoder ); +const decoders = Object.values(bases).map((c) => c.decoder) const anybaseDecoder = (function () { - let acc = decoders[0].or(decoders[1]); - decoders.slice(2).forEach((d) => (acc = acc.or(d))); - return acc; -})(); + let acc = decoders[0].or(decoders[1]) + decoders.slice(2).forEach((d) => (acc = acc.or(d))) + return acc +})() function ip2bytes (ipString: string) { if (!ip.isIP(ipString)) { @@ -160,12 +160,12 @@ function mh2bytes (hash: string) { return uint8ArrayConcat([size, mh], size.length + mh.length) } -function mb2bytes(mbstr: string) { - let mb = anybaseDecoder.decode(mbstr) +function mb2bytes (mbstr: string) { + const mb = anybaseDecoder.decode(mbstr) const size = Uint8Array.from(varint.encode(mb.length)) return uint8ArrayConcat([size, mb], size.length + mb.length) } -function bytes2mb(buf: Uint8Array) { +function bytes2mb (buf: Uint8Array) { const size = varint.decode(buf) const hash = buf.slice(varint.decode.bytes) diff --git a/test/convert.spec.ts b/test/convert.spec.ts index 5f766d82..5d395c1e 100644 --- a/test/convert.spec.ts +++ b/test/convert.spec.ts @@ -88,17 +88,16 @@ describe('convert', () => { }) }) - it('can round-trip certhash, though encoding base may change', ()=>{ - let myCertFingerprint = { - "algorithm": "sha-256", - "value": "f4:32:a0:45:34:62:85:e0:d8:d7:75:36:84:72:8e:b2:aa:9e:71:64:e4:eb:fe:06:51:64:42:64:fe:04:a8:d0" - }; - let mb = 'f' + myCertFingerprint.value.replaceAll(':',''); - let bytes = convert.convertToBytes('certhash',mb); - let outcome = convert.convertToString(466, bytes); - //Although I sent hex encoding in, base58btc always comes out - expect(outcome).to.equal('u9DKgRTRiheDY13U2hHKOsqqecWTk6_4GUWRCZP4EqNA'); - let bytesOut = convert.convertToBytes(466,outcome); - expect(bytesOut.toString()).to.equal(bytes.toString()); + it('can round-trip certhash, though encoding base may change', () => { + const myCertFingerprint = { + algorithm: 'sha-256', + value: 'f4:32:a0:45:34:62:85:e0:d8:d7:75:36:84:72:8e:b2:aa:9e:71:64:e4:eb:fe:06:51:64:42:64:fe:04:a8:d0' + } + const mb = 'f' + myCertFingerprint.value.replaceAll(':', '') + const bytes = convert.convertToBytes('certhash', mb) + const outcome = convert.convertToString(466, bytes) + expect(outcome).to.equal('u9DKgRTRiheDY13U2hHKOsqqecWTk6_4GUWRCZP4EqNA') + const bytesOut = convert.convertToBytes(466, outcome) + expect(bytesOut.toString()).to.equal(bytes.toString()) }) })