Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for webrtc and certhash (#261) #262

Merged
merged 7 commits into from
Aug 30, 2022
28 changes: 28 additions & 0 deletions src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 { bases } from 'multiformats/basics'
import * as Digest from 'multiformats/hashes/digest'
import varint from 'varint'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
Expand Down Expand Up @@ -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 bytes2mb(buf)
default:
return uint8ArrayToString(buf, 'base16') // no clue. convert to hex
}
Expand Down Expand Up @@ -84,11 +87,20 @@ 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
}
}

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')
Expand Down Expand Up @@ -148,6 +160,22 @@ function mh2bytes (hash: string) {
return uint8ArrayConcat([size, mh], size.length + mh.length)
}

function mb2bytes(mbstr: string) {
let mb = anybaseDecoder.decode(mbstr)
const size = Uint8Array.from(varint.encode(mb.length))
return uint8ArrayConcat([size, mb], size.length + mb.length)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any verification required that the decoded multibase contains a valid multihash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure there's an easy way to verify that. The existing multihash function does one validation I did not replicate here,

https://github.com/multiformats/js-multiaddr/blob/master/src/convert.ts#L158-L160

That it reports a size that is correct. I could (maybe should) do that. But to go beyond that I think we'd have to be aware of all the supported encryption schemes, correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@achingbrain - thoughts on this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine, otherwise as you say it would have to know about all the available hash algorithms.

}
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 'u' + uint8ArrayToString(hash, 'base64url')
}

/**
* Converts bytes to bas58btc string
*/
Expand Down
2 changes: 2 additions & 0 deletions src/protocols-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand All @@ -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'],
Expand Down
14 changes: 14 additions & 0 deletions test/convert.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, base58btc always comes out
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment valid? Looks like base64url has come out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The comment is out-of-date.

expect(outcome).to.equal('u9DKgRTRiheDY13U2hHKOsqqecWTk6_4GUWRCZP4EqNA');
let bytesOut = convert.convertToBytes(466,outcome);
expect(bytesOut.toString()).to.equal(bytes.toString());
})
})