Skip to content

Commit e5a8e27

Browse files
feat: add support for webrtc and certhash (#261) (#262)
For use with the js implementation of the webrtc transport The most relevant point of info, from [the draft spec](https://github.com/libp2p/specs/blob/4b8e890c49061eb62c9d16a9afd3aa0a738e6285/webrtc/README.md#addressing): > The TLS certificate fingerprint in /certhash is a [multibase](https://github.com/multiformats/multibase) encoded [multihash](https://github.com/multiformats/multihash).
1 parent bcb0503 commit e5a8e27

File tree

3 files changed

+43
-0
lines changed

3 files changed

+43
-0
lines changed

src/convert.ts

+28
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getProtocol } from './protocols-table.js'
44
import { CID } from 'multiformats/cid'
55
import { base32 } from 'multiformats/bases/base32'
66
import { base58btc } from 'multiformats/bases/base58'
7+
import { bases } from 'multiformats/basics'
78
import * as Digest from 'multiformats/hashes/digest'
89
import varint from 'varint'
910
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
@@ -51,6 +52,8 @@ export function convertToString (proto: number | string, buf: Uint8Array) {
5152
return bytes2onion(buf)
5253
case 445: // onion3
5354
return bytes2onion(buf)
55+
case 466: // certhash
56+
return bytes2mb(buf)
5457
default:
5558
return uint8ArrayToString(buf, 'base16') // no clue. convert to hex
5659
}
@@ -84,11 +87,20 @@ export function convertToBytes (proto: string | number, str: string) {
8487
return onion2bytes(str)
8588
case 445: // onion3
8689
return onion32bytes(str)
90+
case 466: // certhash
91+
return mb2bytes(str)
8792
default:
8893
return uint8ArrayFromString(str, 'base16') // no clue. convert from hex
8994
}
9095
}
9196

97+
const decoders = Object.values(bases).map((c) => c.decoder)
98+
const anybaseDecoder = (function () {
99+
let acc = decoders[0].or(decoders[1])
100+
decoders.slice(2).forEach((d) => (acc = acc.or(d)))
101+
return acc
102+
})()
103+
92104
function ip2bytes (ipString: string) {
93105
if (!ip.isIP(ipString)) {
94106
throw new Error('invalid ip address')
@@ -148,6 +160,22 @@ function mh2bytes (hash: string) {
148160
return uint8ArrayConcat([size, mh], size.length + mh.length)
149161
}
150162

163+
function mb2bytes (mbstr: string) {
164+
const mb = anybaseDecoder.decode(mbstr)
165+
const size = Uint8Array.from(varint.encode(mb.length))
166+
return uint8ArrayConcat([size, mb], size.length + mb.length)
167+
}
168+
function bytes2mb (buf: Uint8Array) {
169+
const size = varint.decode(buf)
170+
const hash = buf.slice(varint.decode.bytes)
171+
172+
if (hash.length !== size) {
173+
throw new Error('inconsistent lengths')
174+
}
175+
176+
return 'u' + uint8ArrayToString(hash, 'base64url')
177+
}
178+
151179
/**
152180
* Converts bytes to bas58btc string
153181
*/

src/protocols-table.ts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [
2525
[275, 0, 'p2p-webrtc-star'],
2626
[276, 0, 'p2p-webrtc-direct'],
2727
[277, 0, 'p2p-stardust'],
28+
[280, 0, 'webrtc'],
2829
[290, 0, 'p2p-circuit'],
2930
[301, 0, 'udt'],
3031
[302, 0, 'utp'],
@@ -40,6 +41,7 @@ export const table: Array<[number, number, string, boolean?, boolean?]> = [
4041
[445, 296, 'onion3'],
4142
[446, V, 'garlic64'],
4243
[460, 0, 'quic'],
44+
[466, V, 'certhash'],
4345
[477, 0, 'ws'],
4446
[478, 0, 'wss'],
4547
[479, 0, 'p2p-websocket-star'],

test/convert.spec.ts

+13
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,17 @@ describe('convert', () => {
8787
expect(convert.convertToString('sctp', buffer.subarray(5))).to.equal('1234')
8888
})
8989
})
90+
91+
it('can round-trip certhash, though encoding base may change', () => {
92+
const myCertFingerprint = {
93+
algorithm: 'sha-256',
94+
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'
95+
}
96+
const mb = 'f' + myCertFingerprint.value.replaceAll(':', '')
97+
const bytes = convert.convertToBytes('certhash', mb)
98+
const outcome = convert.convertToString(466, bytes)
99+
expect(outcome).to.equal('u9DKgRTRiheDY13U2hHKOsqqecWTk6_4GUWRCZP4EqNA')
100+
const bytesOut = convert.convertToBytes(466, outcome)
101+
expect(bytesOut.toString()).to.equal(bytes.toString())
102+
})
90103
})

0 commit comments

Comments
 (0)