From d30f3c283c4ab65b2565c0c2f0b32a24c03c42d9 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 4 Aug 2022 17:27:38 +0400 Subject: [PATCH 01/48] wasm-node: modify index-browser to support webrtc Refs #1712 --- bin/wasm-node/javascript/src/index-browser.ts | 177 ++++++++++++++++-- 1 file changed, 158 insertions(+), 19 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index b58f27ae7e..c0c82cbfb8 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -86,14 +86,16 @@ function trustedBase64Decode(base64: string): Uint8Array { * @see Connection * @throws ConnectionError If the multiaddress couldn't be parsed or contains an invalid protocol. */ - function connect(config: ConnectionConfig, forbidWs: boolean, forbidNonLocalWs: boolean, forbidWss: boolean): Connection { - let connection: WebSocket; - + function connect(config: ConnectionConfig, forbidWs: boolean, forbidNonLocalWs: boolean, forbidWss: boolean, forbidWebRTC: boolean): Connection { // Attempt to parse the multiaddress. // TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940) const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/); + const webRTCParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/udp\/(.*?)\/(x-webrtc)\/(.*?)\/$/); + if (wsParsed != null) { + let connection: WebSocket; + const proto = (wsParsed[4] == 'ws') ? 'ws' : 'wss'; if ( (proto == 'ws' && forbidWs) || @@ -121,23 +123,160 @@ function trustedBase64Decode(base64: string): Uint8Array { config.onMessage(new Uint8Array(msg.data as ArrayBuffer)); }; - } else { - throw new ConnectionError('Unrecognized multiaddr format'); - } + return { + close: (): void => { + connection.onopen = null; + connection.onclose = null; + connection.onmessage = null; + connection.onerror = null; + connection.close(); + }, - return { - close: (): void => { - connection.onopen = null; - connection.onclose = null; - connection.onmessage = null; - connection.onerror = null; - connection.close(); - }, + send: (data: Uint8Array): void => { + connection.send(data); + }, - send: (data: Uint8Array): void => { - connection.send(data); - }, + openOutSubstream: () => { throw new Error('Wrong connection type') } + }; + } else if (webRTCParsed != null) { + let pc: RTCPeerConnection; + + const proto = webRTCParsed[4]; + if (proto == 'x-webrtc' && forbidWebRTC) { + throw new ConnectionError('Connection type not allowed'); + } + + // Create a new peer connection. + pc = new RTCPeerConnection(); + + pc.onconnectionstatechange = (_event) => { + switch(pc.connectionState) { + case "connected": + config.onOpen({ type: 'multi-stream', peerId: new Uint8Array([0]) }); + case "disconnected": + config.onConnectionClose(""); + } + }; + + // Create a new data channel. This will trigger a new negotiation (see + // `negotiationneeded` handler below). + const dataChannel = pc.createDataChannel("data", { id: 1 }); + + // When a new negotion is triggered, set both local and remote descriptions. + pc.onnegotiationneeded = async (_event) => { + // Create a new offer and set it as local description. + var sdpOffer = (await pc.createOffer()).sdp!; + await pc.setLocalDescription({ type: 'offer', sdp: sdpOffer }); - openOutSubstream: () => { throw new Error('Wrong connection type') } - }; + console.log("LOCAL OFFER: " + pc.localDescription!.sdp); + + // Note that the trailing line feed is important, as otherwise Chrome + // fails to parse the payload. + const remoteSdp = + // Version of the SDP protocol. Always 0. (RFC8866) + "v=0" + "\n" + + // Identifies the creator of the SDP document. We are allowed to use dummy values + // (`-` and `0.0.0.0`) to remain anonymous, which we do. Note that "IN" means + // "Internet". (RFC8866) + "o=- " + (Date.now() / 1000).toFixed() + " 0 IN IP" + ipVersion + " " + targetIp + "\n" + + // Name for the session. We are allowed to pass a dummy `-`. (RFC8866) + "s=-" + "\n" + + // Start and end of the validity of the session. `0 0` means that the session never + // expires. (RFC8866) + "t=0 0" + "\n" + + // A lite implementation is only appropriate for devices that will + // *always* be connected to the public Internet and have a public + // IP address at which it can receive packets from any + // correspondent. ICE will not function when a lite implementation + // is placed behind a NAT (RFC8445). + "a=ice-lite" + "\n" + + // A `m=` line describes a request to establish a certain protocol. + // The protocol in this line (i.e. `TCP/DTLS/SCTP` or `UDP/DTLS/SCTP`) must always be + // the same as the one in the offer. We know that this is true because we tweak the + // offer to match the protocol. + // The `` component must always be `pc-datachannel` for WebRTC. + // The rest of the SDP payload adds attributes to this specific media stream. + // RFCs: 8839, 8866, 8841 + "m=application " + targetPort + " " + (protocol == 'tcp' ? "TCP" : "UDP") + "/DTLS/SCTP webrtc-datachannel" + "\n" + + // Indicates the IP address of the remote. + // Note that "IN" means "Internet". + "c=IN IP" + ipVersion + " " + targetIp + "\n" + + // Media ID - uniquely identifies this media stream (RFC9143). + "a=mid:0" + "\n" + + // Indicates that we are complying with RFC8839 (as oppposed to the legacy RFC5245). + "a=ice-options:ice2" + "\n" + + // ICE username and password, which are used for establishing and + // maintaining the ICE connection. (RFC8839) + // MUST match ones used by the answerer (server). + "a=ice-ufrag:aIGX" + "\n" + + "a=ice-pwd:ndajecaXt6vPIt6VYcUL8wpW" + "\n" + + // Fingerprint of the certificate that the server will use during the TLS + // handshake. (RFC8122) + // As explained at the top-level documentation, we use a hardcoded certificate. + // MUST be derived from the certificate used by the answerer (server). + // TODO: proper certificate and fingerprint + "a=fingerprint:sha-256 AC:D1:E5:33:EC:27:1F:CD:E0:27:59:47:F4:D6:2A:2B:23:31:FF:10:C9:DD:E0:29:8E:B7:B3:99:B4:BF:F6:0B" + "\n" + + + // "TLS ID" uniquely identifies a TLS association. + // The ICE protocol uses a "TLS ID" system to indicate whether a fresh DTLS connection + // must be reopened in case of ICE renegotiation. Considering that ICE renegotiations + // never happen in our use case, we can simply put a random value and not care about + // it. Note however that the TLS ID in the answer must be present if and only if the + // offer contains one. (RFC8842) + // TODO: is it true that renegotiations never happen? what about a connection closing? + // TODO: right now browsers don't send it "a=tls-id:" + genRandomPayload(120) + "\n" + + // "tls-id" attribute MUST be present in the initial offer and respective answer (RFC8839). + + // Indicates that the remote DTLS server will only listen for incoming + // connections. (RFC5763) + // The answerer (server) MUST not be located behind a NAT (RFC6135). + "a=setup:passive" + "\n" + + // The SCTP port (RFC8841) + // Note it's different from the "m=" line port value, which + // indicates the port of the underlying transport-layer protocol + // (UDP or TCP) + "a=sctp-port:5000" + "\n" + + // The maximum SCTP user message size (in bytes) (RFC8841) + "a=max-message-size:100000" + "\n" + + // A transport address for a candidate that can be used for connectivity checks (RFC8839). + "a=candidate:1 1 " + (protocol == 'tcp' ? "TCP" : "UDP") + " 2113667327 " + targetIp + " " + targetPort + " typ host" + "\n"; + + await pc.setRemoteDescription({ type: "answer", sdp: remoteSdp }); + + console.log("REMOTE ANSWER: " + pc.remoteDescription!.sdp); + }; + + dataChannel.onopen = () => { + console.log(`'${dataChannel.label}' opened`); + }; + + dataChannel.onerror = (error) => { + console.log(`'${dataChannel.label}' errored: ${error}`); + }; + + dataChannel.onclose = () => { + console.log(`'${dataChannel.label}' closed`); + }; + + dataChannel.onmessage = (m) => { + console.log(`new message on '${dataChannel.label}': '${m.data}'`); + } + + return { + close: (): void => { + pc.onconnectionstatechange = null; + pc.onmessage = null; + pc.onerror = null; + pc.close(); + }, + + send: (data: Uint8Array): void => { + connection.send(data); + }, + + openOutSubstream: () => { throw new Error('Wrong connection type') } + }; + } else { + throw new ConnectionError('Unrecognized multiaddr format'); + } } From 81b8c4f133659db83787b3dc393e631de13a7a02 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 4 Aug 2022 18:24:56 +0400 Subject: [PATCH 02/48] correct URL pattern --- bin/wasm-node/javascript/src/index-browser.ts | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c0c82cbfb8..5fbdf44c87 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -91,7 +91,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940) const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/); - const webRTCParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/udp\/(.*?)\/(x-webrtc)\/(.*?)\/$/); + const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/x-webrtc\/(.*?)\/$/); if (wsParsed != null) { let connection: WebSocket; @@ -141,8 +141,8 @@ function trustedBase64Decode(base64: string): Uint8Array { } else if (webRTCParsed != null) { let pc: RTCPeerConnection; - const proto = webRTCParsed[4]; - if (proto == 'x-webrtc' && forbidWebRTC) { + const targetPort = webRTCParsed[3]; + if (forbidWebRTC || targetPort == '0') { throw new ConnectionError('Connection type not allowed'); } @@ -158,18 +158,21 @@ function trustedBase64Decode(base64: string): Uint8Array { } }; - // Create a new data channel. This will trigger a new negotiation (see + // Create a new data channel with id=1. This will trigger a new negotiation (see // `negotiationneeded` handler below). const dataChannel = pc.createDataChannel("data", { id: 1 }); // When a new negotion is triggered, set both local and remote descriptions. pc.onnegotiationneeded = async (_event) => { - // Create a new offer and set it as local description. - var sdpOffer = (await pc.createOffer()).sdp!; + // Create a new offer and set it as local description. + const sdpOffer = (await pc.createOffer()).sdp!; await pc.setLocalDescription({ type: 'offer', sdp: sdpOffer }); console.log("LOCAL OFFER: " + pc.localDescription!.sdp); + const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; + const targetIp = webRTCParsed[2]; + // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. const remoteSdp = @@ -197,7 +200,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // The `` component must always be `pc-datachannel` for WebRTC. // The rest of the SDP payload adds attributes to this specific media stream. // RFCs: 8839, 8866, 8841 - "m=application " + targetPort + " " + (protocol == 'tcp' ? "TCP" : "UDP") + "/DTLS/SCTP webrtc-datachannel" + "\n" + + "m=application " + targetPort + " " + "UDP/DTLS/SCTP webrtc-datachannel" + "\n" + // Indicates the IP address of the remote. // Note that "IN" means "Internet". "c=IN IP" + ipVersion + " " + targetIp + "\n" + @@ -239,7 +242,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // The maximum SCTP user message size (in bytes) (RFC8841) "a=max-message-size:100000" + "\n" + // A transport address for a candidate that can be used for connectivity checks (RFC8839). - "a=candidate:1 1 " + (protocol == 'tcp' ? "TCP" : "UDP") + " 2113667327 " + targetIp + " " + targetPort + " typ host" + "\n"; + "a=candidate:1 1 UDP 2113667327 " + targetIp + " " + targetPort + " typ host" + "\n"; await pc.setRemoteDescription({ type: "answer", sdp: remoteSdp }); @@ -248,6 +251,8 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onopen = () => { console.log(`'${dataChannel.label}' opened`); + + // TODO: noise handshake }; dataChannel.onerror = (error) => { @@ -265,16 +270,32 @@ function trustedBase64Decode(base64: string): Uint8Array { return { close: (): void => { pc.onconnectionstatechange = null; - pc.onmessage = null; - pc.onerror = null; pc.close(); }, - send: (data: Uint8Array): void => { - connection.send(data); + send: (_data: Uint8Array): void => { + // pc.send(data); }, - openOutSubstream: () => { throw new Error('Wrong connection type') } + openOutSubstream: () => { + var dataChannel = pc.createDataChannel("data"); + + dataChannel.onopen = () => { + console.log(`'${dataChannel.label}' opened`); + }; + + dataChannel.onerror = (error) => { + console.log(`'${dataChannel.label}' errored: ${error}`); + }; + + dataChannel.onclose = () => { + console.log(`'${dataChannel.label}' closed`); + }; + + dataChannel.onmessage = (m) => { + console.log(`new message on '${dataChannel.label}': '${m.data}'`); + } + } }; } else { throw new ConnectionError('Unrecognized multiaddr format'); From 4de6a30e187e7f8744ce3172df67146574b18253 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 4 Aug 2022 18:49:43 +0400 Subject: [PATCH 03/48] close and send functions --- bin/wasm-node/javascript/src/index-browser.ts | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 5fbdf44c87..7f15b0cebc 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -150,10 +150,10 @@ function trustedBase64Decode(base64: string): Uint8Array { pc = new RTCPeerConnection(); pc.onconnectionstatechange = (_event) => { + console.log(`conn state: ${pc.connectionState}`); switch(pc.connectionState) { case "connected": - config.onOpen({ type: 'multi-stream', peerId: new Uint8Array([0]) }); - case "disconnected": + case "closed": config.onConnectionClose(""); } }; @@ -253,6 +253,8 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log(`'${dataChannel.label}' opened`); // TODO: noise handshake + const peerId = ""; + config.onOpen({ type: 'multi-stream', peerId: trustedBase64Decode(peerId) }); }; dataChannel.onerror = (error) => { @@ -267,14 +269,32 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log(`new message on '${dataChannel.label}': '${m.data}'`); } + let dataChannels = new Map(); + return { - close: (): void => { + close: (streamId: number): void => { + if (streamId == null) { pc.onconnectionstatechange = null; + pc.onnegotiationneeded = null; pc.close(); + } else { + let dc = dataChannels.get(streamId); + if (dc != null) { + dc.close(); + } else { + console.log(`Data channel ${streamId} not found`); + } + } }, - send: (_data: Uint8Array): void => { - // pc.send(data); + + send: (data: Uint8Array, streamId: number): void => { + let dc = dataChannels.get(streamId); + if (dc != null) { + dc.send(data); + } else { + console.log(`Data channel ${streamId} not found`); + } }, openOutSubstream: () => { @@ -295,6 +315,8 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onmessage = (m) => { console.log(`new message on '${dataChannel.label}': '${m.data}'`); } + + dataChannels.set(dataChannel.id, dataChannel); } }; } else { From 7121f25ba2109ecbccd6859e28528c40d1aedba0 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 5 Aug 2022 12:54:43 +0400 Subject: [PATCH 04/48] correct fingerprint --- bin/wasm-node/javascript/src/index-browser.ts | 34 ++++++------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 7f15b0cebc..ba104f649d 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -151,9 +151,7 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.onconnectionstatechange = (_event) => { console.log(`conn state: ${pc.connectionState}`); - switch(pc.connectionState) { - case "connected": - case "closed": + if (pc.connectionState == "closed") { config.onConnectionClose(""); } }; @@ -172,16 +170,19 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; + const ufrag = webRTCParsed[5]; + let fingerprint = ""; + for(i=0;i<=ufrag.length;i+=2) { + fingerprint += ufrag[i] + ufrag[i+1] + ":"; + } // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. const remoteSdp = - // Version of the SDP protocol. Always 0. (RFC8866) - "v=0" + "\n" + // Identifies the creator of the SDP document. We are allowed to use dummy values // (`-` and `0.0.0.0`) to remain anonymous, which we do. Note that "IN" means // "Internet". (RFC8866) - "o=- " + (Date.now() / 1000).toFixed() + " 0 IN IP" + ipVersion + " " + targetIp + "\n" + + "o=- 0 0 IN IP" + ipVersion + " " + targetIp + "\n" + // Name for the session. We are allowed to pass a dummy `-`. (RFC8866) "s=-" + "\n" + // Start and end of the validity of the session. `0 0` means that the session never @@ -211,25 +212,12 @@ function trustedBase64Decode(base64: string): Uint8Array { // ICE username and password, which are used for establishing and // maintaining the ICE connection. (RFC8839) // MUST match ones used by the answerer (server). - "a=ice-ufrag:aIGX" + "\n" + - "a=ice-pwd:ndajecaXt6vPIt6VYcUL8wpW" + "\n" + + "a=ice-ufrag:" + ufrag + "\n" + + "a=ice-pwd:" + ufrag + "\n" + // Fingerprint of the certificate that the server will use during the TLS // handshake. (RFC8122) - // As explained at the top-level documentation, we use a hardcoded certificate. // MUST be derived from the certificate used by the answerer (server). - // TODO: proper certificate and fingerprint - "a=fingerprint:sha-256 AC:D1:E5:33:EC:27:1F:CD:E0:27:59:47:F4:D6:2A:2B:23:31:FF:10:C9:DD:E0:29:8E:B7:B3:99:B4:BF:F6:0B" + "\n" + - - // "TLS ID" uniquely identifies a TLS association. - // The ICE protocol uses a "TLS ID" system to indicate whether a fresh DTLS connection - // must be reopened in case of ICE renegotiation. Considering that ICE renegotiations - // never happen in our use case, we can simply put a random value and not care about - // it. Note however that the TLS ID in the answer must be present if and only if the - // offer contains one. (RFC8842) - // TODO: is it true that renegotiations never happen? what about a connection closing? - // TODO: right now browsers don't send it "a=tls-id:" + genRandomPayload(120) + "\n" + - // "tls-id" attribute MUST be present in the initial offer and respective answer (RFC8839). - + "a=fingerprint:sha-256 " + fingerprint + "\n" + // Indicates that the remote DTLS server will only listen for incoming // connections. (RFC5763) // The answerer (server) MUST not be located behind a NAT (RFC6135). @@ -242,7 +230,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // The maximum SCTP user message size (in bytes) (RFC8841) "a=max-message-size:100000" + "\n" + // A transport address for a candidate that can be used for connectivity checks (RFC8839). - "a=candidate:1 1 UDP 2113667327 " + targetIp + " " + targetPort + " typ host" + "\n"; + "a=candidate:1 1 UDP 1 " + targetIp + " " + targetPort + " typ host" + "\n"; await pc.setRemoteDescription({ type: "answer", sdp: remoteSdp }); From ca2ed4ff9bbb0dc26d629fec45a168e115f711e1 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 7 Sep 2022 10:20:59 +0400 Subject: [PATCH 05/48] new URL format --- bin/wasm-node/javascript/package.json | 3 ++- bin/wasm-node/javascript/src/client.ts | 6 +++++ bin/wasm-node/javascript/src/index-browser.ts | 24 ++++++++++--------- 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index 46faf4b2c5..57383b9370 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -35,7 +35,8 @@ }, "dependencies": { "pako": "^2.0.4", - "ws": "^8.8.1" + "ws": "^8.8.1", + "multiformats": "^9.8.1" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/client.ts b/bin/wasm-node/javascript/src/client.ts index ee856ac9ad..567512cc99 100644 --- a/bin/wasm-node/javascript/src/client.ts +++ b/bin/wasm-node/javascript/src/client.ts @@ -253,6 +253,12 @@ export interface ClientOptions { * connections. */ forbidWss?: boolean; + + /** + * If `true`, then the client will never open any WebRTC connection. + * Defaults to `false`. + */ + forbidWebRTC?: boolean; } /** diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index e0ae67a773..aca1abee96 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -20,6 +20,7 @@ import { Client, ClientOptions, start as innerStart } from './client.js' import { Connection, ConnectionError, ConnectionConfig } from './instance/instance.js'; import { inflate } from 'pako'; +import { base64url } from "multiformats/bases/base64url"; export { AddChainError, @@ -58,7 +59,7 @@ export function start(options?: ClientOptions): Client { crypto.getRandomValues(buffer); }, connect: (config) => { - return connect(config, options?.forbidWs || false, options?.forbidNonLocalWs || false, options?.forbidWss || false) + return connect(config, options?.forbidWs || false, options?.forbidNonLocalWs || false, options?.forbidWss || false, options?.forbidWebRTC || false) } }) } @@ -91,7 +92,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940) const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/); - const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/x-webrtc\/(.*?)\/$/); + const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)$/); if (wsParsed != null) { let connection: WebSocket; @@ -156,11 +157,10 @@ function trustedBase64Decode(base64: string): Uint8Array { } }; - // Create a new data channel with id=1. This will trigger a new negotiation (see - // `negotiationneeded` handler below). - const dataChannel = pc.createDataChannel("data", { id: 1 }); + // Create an initial data channel with a predefined `id = 1`, which is used + // to verify remote peer's identity. + const dataChannel = pc.createDataChannel("data", { id: 1, negotiated: true }); - // When a new negotion is triggered, set both local and remote descriptions. pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. const sdpOffer = (await pc.createOffer()).sdp!; @@ -170,11 +170,13 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; - const ufrag = webRTCParsed[5]; - let fingerprint = ""; - for(i=0;i<=ufrag.length;i+=2) { - fingerprint += ufrag[i] + ufrag[i+1] + ":"; - } + const ufrag = (webRTCParsed[5] || ''); + + // Transform ufrag (multibase-encoded multihash) to fingerprint (upper-hex; + // each byte separated by ":"). + // + // To add additional decoders use `or`: `base64url.decoder.or(base32.decoder)`. + const fingerprint = new Uint8Array(base64url.decode(ufrag)).join(':').toUpperCase(); // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. From 1668a7628b3a801b2e9878bc8aa9ba917af3dd13 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Wed, 7 Sep 2022 16:20:05 +0400 Subject: [PATCH 06/48] noise handshake --- bin/wasm-node/javascript/package.json | 6 ++- bin/wasm-node/javascript/src/index-browser.ts | 41 +++++++++++++++---- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index 57383b9370..590a9c0c85 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -36,7 +36,11 @@ "dependencies": { "pako": "^2.0.4", "ws": "^8.8.1", - "multiformats": "^9.8.1" + "multiformats": "^9.8.1", + "@chainsafe/libp2p-noise": "^8.0.1", // Even though this package works in browser, it will bundle around 600Kb (200Kb gzipped) of code + "@libp2p/peer-id": "^1.1.15", + "@libp2p/crypto": "^1.0.4", + "it-stream-types": "^1.0.4", }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index aca1abee96..785903b387 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -20,7 +20,14 @@ import { Client, ClientOptions, start as innerStart } from './client.js' import { Connection, ConnectionError, ConnectionConfig } from './instance/instance.js'; import { inflate } from 'pako'; + import { base64url } from "multiformats/bases/base64url"; +import { base58btc } from "multiformats/bases/base58btc"; +import { sha256 } from 'multiformats/hashes/sha2'; +import { Noise } from "@chainsafe/libp2p-noise"; +import { Ed25519PeerIdImpl, peerIdFromString } from '@libp2p/peer-id'; +import { generateKeyPair } from '@libp2p/crypto/keys'; +import type { Duplex } from 'it-stream-types'; export { AddChainError, @@ -92,7 +99,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940) const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/); - const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)$/); + const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)\/p2p\/(.*?)$/); if (wsParsed != null) { let connection: WebSocket; @@ -242,9 +249,31 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onopen = () => { console.log(`'${dataChannel.label}' opened`); - // TODO: noise handshake - const peerId = ""; - config.onOpen({ type: 'multi-stream', peerId: trustedBase64Decode(peerId) }); + const keyPair = generateKeyPair('Ed25519', 1024); + const multihash = sha256.digest(keyPair.public); + const localPeerId = new Ed25519PeerIdImpl({ multihash: multihash, privateKey: keyPair.private }); + const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); + + console.log(`noise handshake with addr='${config.address}'`); + const noise = new Noise(keyPair.private); + const conn: Duplex = { + sink: async data => { + dataChannel.send(data); + }, + source: (async function * () { + dataChannel.onmessage = (m) => { + yield * m.data + }; + }()) + }; + const secureConn = noise.secureOutbound(localPeerId, conn, remotePeerId); + + console.log(`verifying peer's identity addr='${config.address}'`); + // TODO: assert secureConn.peerId == remotePeerId + + dataChannel.close(); + + config.onOpen({ type: 'multi-stream', peerId: remotePeerId }); }; dataChannel.onerror = (error) => { @@ -255,10 +284,6 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log(`'${dataChannel.label}' closed`); }; - dataChannel.onmessage = (m) => { - console.log(`new message on '${dataChannel.label}': '${m.data}'`); - } - let dataChannels = new Map(); return { From ed39cfd4b1950ae00570e8768a4960612c32278b Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 8 Sep 2022 12:45:00 +0400 Subject: [PATCH 07/48] verify peer ID --- bin/wasm-node/javascript/src/index-browser.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 785903b387..10cbb62578 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -254,7 +254,7 @@ function trustedBase64Decode(base64: string): Uint8Array { const localPeerId = new Ed25519PeerIdImpl({ multihash: multihash, privateKey: keyPair.private }); const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); - console.log(`noise handshake with addr='${config.address}'`); + console.log(`noise handshake with addr=${config.address}`); const noise = new Noise(keyPair.private); const conn: Duplex = { sink: async data => { @@ -266,13 +266,16 @@ function trustedBase64Decode(base64: string): Uint8Array { }; }()) }; - const secureConn = noise.secureOutbound(localPeerId, conn, remotePeerId); - - console.log(`verifying peer's identity addr='${config.address}'`); - // TODO: assert secureConn.peerId == remotePeerId + const { secureConn, verifiedRemotePeerId } = noise.secureOutbound(localPeerId, conn, remotePeerId); dataChannel.close(); + console.log(`verifying peer's identity addr=${config.address}`); + if (verifiedRemotePeerId != remotePeerId) { + console.error(`invalid peer ID (expected ${verifiedRemotePeerId}, got ${remotePeerId})`); + return + } + config.onOpen({ type: 'multi-stream', peerId: remotePeerId }); }; From 1a18c3a582978056798eb79a24e3b146c330264a Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Thu, 8 Sep 2022 16:51:22 +0400 Subject: [PATCH 08/48] fix import bug --- bin/wasm-node/javascript/package-lock.json | 1193 ++++++++++++++++- bin/wasm-node/javascript/package.json | 4 +- bin/wasm-node/javascript/src/index-browser.ts | 23 +- bin/wasm-node/javascript/tsconfig.json | 3 +- 4 files changed, 1164 insertions(+), 59 deletions(-) diff --git a/bin/wasm-node/javascript/package-lock.json b/bin/wasm-node/javascript/package-lock.json index a6be84a064..56681e3b6e 100644 --- a/bin/wasm-node/javascript/package-lock.json +++ b/bin/wasm-node/javascript/package-lock.json @@ -9,6 +9,11 @@ "version": "0.6.31", "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", "dependencies": { + "@chainsafe/libp2p-noise": "^8.0.1", + "@libp2p/crypto": "^1.0.4", + "@libp2p/peer-id": "^1.1.15", + "it-stream-types": "^1.0.4", + "multiformats": "^9.8.1", "pako": "^2.0.4", "ws": "^8.8.1" }, @@ -22,6 +27,35 @@ "typescript": "^4.5.4" } }, + "node_modules/@chainsafe/libp2p-noise": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.1.tgz", + "integrity": "sha512-mr1/CMTBIfraqTY4OWBdmJ2v+0+D89vbIp1nJTHz64oDPRgU0Ah8wb7K5hgs0erU8aYMkgMtbhXeouhJK3A7wA==", + "dependencies": { + "@libp2p/crypto": "^1.0.0", + "@libp2p/interface-connection-encrypter": "^2.0.1", + "@libp2p/interface-keys": "^1.0.2", + "@libp2p/interface-peer-id": "^1.0.2", + "@libp2p/logger": "^2.0.0", + "@libp2p/peer-id": "^1.1.8", + "@stablelib/chacha20poly1305": "^1.0.1", + "@stablelib/hkdf": "^1.0.1", + "@stablelib/sha256": "^1.0.1", + "@stablelib/x25519": "^1.0.1", + "it-length-prefixed": "^8.0.2", + "it-pair": "^2.0.2", + "it-pb-stream": "^2.0.2", + "it-pipe": "^2.0.3", + "it-stream-types": "^1.0.4", + "protons-runtime": "^3.1.0", + "uint8arraylist": "^2.3.2", + "uint8arrays": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@definitelytyped/header-parser": { "version": "0.0.85", "resolved": "https://registry.npmjs.org/@definitelytyped/header-parser/-/header-parser-0.0.85.tgz", @@ -75,6 +109,112 @@ "node": ">=6 <7 || >=8" } }, + "node_modules/@libp2p/crypto": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-1.0.4.tgz", + "integrity": "sha512-3hHZvqi+vI8YoTHE+0u8nA5SYGPLZRLMvbgXQoAn0IyPjez66Taaxym/3p3Duf9QkFlvJu95nzpNzv0OdHs9Yw==", + "dependencies": { + "@libp2p/interface-keys": "^1.0.2", + "@noble/ed25519": "^1.6.0", + "@noble/secp256k1": "^1.5.4", + "err-code": "^3.0.1", + "multiformats": "^9.4.5", + "node-forge": "^1.1.0", + "protons-runtime": "^3.1.0", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/interface-connection-encrypter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@libp2p/interface-connection-encrypter/-/interface-connection-encrypter-2.0.1.tgz", + "integrity": "sha512-GtqsNJuL1q7LWX3z41t9eFFFrlLSmMH92E0rupoXeFx1dJ8Gs/Zy8b6lZro96Ld6rjU1CeZa87SmYeqQQeHRmw==", + "dependencies": { + "@libp2p/interface-peer-id": "^1.0.0", + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.1.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/interface-keys": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@libp2p/interface-keys/-/interface-keys-1.0.3.tgz", + "integrity": "sha512-K8/HlRl/swbVTWuGHNHF28EytszYfUhKgUHfv8CdbMk9ZA/bgO4uU+d9rcrg/Dhw3511U3aRz2bwl2psn6rJfg==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/interface-peer-id": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@libp2p/interface-peer-id/-/interface-peer-id-1.0.4.tgz", + "integrity": "sha512-VRnE0MqmS1kN43hyKCEdkhz0gciuDML7hpL3p8zDm0LnveNMLJsR+/VSUaugCi/muOzLaLk26WffKWbMYfnGfA==", + "dependencies": { + "multiformats": "^9.6.3" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-2.0.1.tgz", + "integrity": "sha512-Mtj7ImjRYbaANuT53QRqc7ooBYpWieLo7KbqYYGas5O2AWQeOu/zyGBMM35WbWIo7sMuhCas9XBPJdFOR7A05w==", + "dependencies": { + "@libp2p/interface-peer-id": "^1.0.2", + "debug": "^4.3.3", + "interface-datastore": "^7.0.0", + "multiformats": "^9.6.3" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@libp2p/peer-id": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-1.1.15.tgz", + "integrity": "sha512-Y33JLEfsLmLUjuC2nhQ2lBXP6PIsR892gSsNy4Vd7oILkuRhjPouIojP9BbME0m9bhVbAws+Zh9NBKtp7UH7wA==", + "dependencies": { + "@libp2p/interface-peer-id": "^1.0.0", + "err-code": "^3.0.1", + "multiformats": "^9.6.3", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", + "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -110,11 +250,190 @@ "node": ">= 8" } }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@stablelib/aead": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", + "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" + }, + "node_modules/@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "dependencies": { + "@stablelib/int": "^1.0.1" + } + }, + "node_modules/@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "node_modules/@stablelib/chacha": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", + "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/chacha20poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", + "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", + "dependencies": { + "@stablelib/aead": "^1.0.1", + "@stablelib/binary": "^1.0.1", + "@stablelib/chacha": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/poly1305": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "node_modules/@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "node_modules/@stablelib/hkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", + "dependencies": { + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "node_modules/@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "dependencies": { + "@stablelib/bytes": "^1.0.1" + } + }, + "node_modules/@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/sha256": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "node_modules/@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "dependencies": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "node_modules/@types/node": { "version": "18.7.15", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==", - "dev": true + "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" }, "node_modules/@types/pako": { "version": "2.0.0", @@ -445,29 +764,6 @@ "node": ">=8" } }, - "node_modules/ava/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/ava/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/ava/node_modules/globby": { "version": "13.1.1", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", @@ -841,6 +1137,18 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, + "node_modules/byte-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", + "integrity": "sha512-GKYa+lvxnzhgHWj9X+LCsQ4s2/C5uvib573eAOiQKywXMkzFFErY2+yQdzmdE5iWVpmqecsRx3bOtOY4/1eINw==", + "dependencies": { + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/callsites": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", @@ -1336,6 +1644,22 @@ "node": ">=6" } }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -1540,6 +1864,11 @@ "once": "^1.4.0" } }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1607,6 +1936,11 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", + "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" + }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -2018,6 +2352,29 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/interface-datastore": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-7.0.0.tgz", + "integrity": "sha512-q9OveOhexQ3Fx8h4YbuR4mZtUHwvlOynKnIwTm6x8oBTWfIyAKtlYtrOYdlHfqQztbYpdzRFcapopNJBMx36NQ==", + "dependencies": { + "interface-store": "^3.0.0", + "nanoid": "^3.0.2", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/interface-store": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-3.0.0.tgz", + "integrity": "sha512-IBJn3hE6hYutwdDcStR76mcwfV98vZc49LkEN9ANHHpsxcm6YbGMJxowO2G3FITU4U5ZH4KJPlHOT6Oe2vzTWA==", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/irregular-plurals": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", @@ -2160,6 +2517,141 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "node_modules/it-handshake": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-4.1.2.tgz", + "integrity": "sha512-Q/EvrB4KWIX5+/wO7edBK3l79Vh28+iWPGZvZSSqwAtOJnHZIvywC+JUbiXPRJVXfICBJRqFETtIJcvrqWL2Zw==", + "dependencies": { + "it-pushable": "^3.1.0", + "it-reader": "^6.0.1", + "it-stream-types": "^1.0.4", + "p-defer": "^4.0.0", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-handshake/node_modules/p-defer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", + "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/it-length-prefixed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-8.0.2.tgz", + "integrity": "sha512-qYCGZ6lTaI6lcuTXUrJmVpE6clq63ULrkq1FGTxHrzexjB2cCrS/CZ5HCRDZ5IRPw33tSDUDK91S7X5S64dPyQ==", + "dependencies": { + "err-code": "^3.0.1", + "it-stream-types": "^1.0.4", + "uint8-varint": "^1.0.1", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-merge": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-1.0.4.tgz", + "integrity": "sha512-DcL6GksTD2HQ7+5/q3JznXaLNfwjyG3/bObaF98da+oHfUiPmdo64oJlT9J8R8G5sJRU7thwaY5zxoAKCn7FJw==", + "dependencies": { + "it-pushable": "^1.4.0" + } + }, + "node_modules/it-merge/node_modules/it-pushable": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-1.4.2.tgz", + "integrity": "sha512-vVPu0CGRsTI8eCfhMknA7KIBqqGFolbRx+1mbQ6XuZ7YCz995Qj7L4XUviwClFunisDq96FdxzF5FnAbw15afg==", + "dependencies": { + "fast-fifo": "^1.0.0" + } + }, + "node_modules/it-pair": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.3.tgz", + "integrity": "sha512-heCgsbYscFCQY5YvltlGT9tjgLGYo7NxPEoJyl55X4BD2KOXpTyuwOhPLWhi9Io0y6+4ZUXCkyaQXIB6Y8xhRw==", + "dependencies": { + "it-stream-types": "^1.0.3", + "p-defer": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pair/node_modules/p-defer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", + "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/it-pb-stream": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/it-pb-stream/-/it-pb-stream-2.0.2.tgz", + "integrity": "sha512-FR1FM9W71wMTZlAij1Pq4PKNcfVb0TGhUTpNQ3tv0LMV/pJ5cDh4g3jW7jhwB+kHtr7PywD1CybBHaT8iAVpKg==", + "dependencies": { + "it-handshake": "^4.1.2", + "it-length-prefixed": "^8.0.2", + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pipe": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-2.0.4.tgz", + "integrity": "sha512-lK0BV0egwfc64DFJva+0Jh1z8UxwmYBpAHDwq21s0OenRCaEDIntx/iOyWH/jg5efBU6Xa8igzmOqm2CPPNDgg==", + "dependencies": { + "it-merge": "^1.0.4", + "it-pushable": "^3.1.0", + "it-stream-types": "^1.0.3" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pushable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.1.0.tgz", + "integrity": "sha512-sEAdT86u6aIWvLkH4hlOmgvHpRyUOUG22HD365H+Dh67zYpaPdILmT4Om7Wjdb+m/SjEB81z3nYCoIrgVYpOFA==" + }, + "node_modules/it-reader": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.1.tgz", + "integrity": "sha512-C+YRk3OTufbKSJMNEonfEw+9F38llmwwZvqhkjb0xIgob7l4L3p01Yt43+bHRI8SSppAOgk5AKLqas7ea0UTAw==", + "dependencies": { + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-stream-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-1.0.4.tgz", + "integrity": "sha512-0F3CqTIcIHwtnmIgqd03a7sw8BegAmE32N2w7anIGdALea4oAN4ltqPgDMZ7zn4XPLZifXEZlBXSzgg64L1Ebw==" + }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -2281,6 +2773,24 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "node_modules/long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + }, + "node_modules/longbits": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/longbits/-/longbits-1.1.0.tgz", + "integrity": "sha512-22U2exkkYy7sr7nuQJYx2NEZ2kEMsC69+BxM5h8auLvkVIJa+LwAB5mFIExnuW2dFuYXFOWsFMKXjaWiq/htYQ==", + "dependencies": { + "byte-access": "^1.0.1", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2445,6 +2955,35 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multiformats": { + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.8.1.tgz", + "integrity": "sha512-Cu7NfUYtCV+WN7w59WsRRF138S+um4tTo11ScYsWbNgWyCEGOu8wID1e5eMJs91gFZ0I7afodkkdxCF8NGkqZQ==" + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, "node_modules/node-gyp-build": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", @@ -2877,6 +3416,45 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/protobufjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.0.tgz", + "integrity": "sha512-rCuxKlh0UQKSMjrpIcTLbR5TtGQ52cgs1a5nUoPBAKOccdPblN67BJtjrbtudUJK6HmBvUdsmymyYOzO7lxZEA==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protons-runtime": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz", + "integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==", + "dependencies": { + "protobufjs": "^7.0.0", + "uint8arraylist": "^2.3.2" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "uint8arraylist": "^2.3.2" + } + }, "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -3574,6 +4152,41 @@ "node": ">=4.2.0" } }, + "node_modules/uint8-varint": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-1.0.3.tgz", + "integrity": "sha512-ESs/P/AYPy2wWZCT2V6Tg7RPqA6jzlhJbdsNPFvbDeIrDxj12dwTcm0rD9yFlnmgEf6vRBCZrP3d0SiRTcPwSQ==", + "dependencies": { + "byte-access": "^1.0.0", + "longbits": "^1.1.0", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.3.2.tgz", + "integrity": "sha512-4ybc/jixmtGhUrebJ0bzB95TjEbskWxBKBRrAozw7P6WcAcZdPMYSLdDuNoEEGo/Cwe+0TNic9CXzWUWzy1quw==", + "dependencies": { + "uint8arrays": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/uint8arrays": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", + "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", + "dependencies": { + "multiformats": "^9.4.2" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -3878,6 +4491,31 @@ } }, "dependencies": { + "@chainsafe/libp2p-noise": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.1.tgz", + "integrity": "sha512-mr1/CMTBIfraqTY4OWBdmJ2v+0+D89vbIp1nJTHz64oDPRgU0Ah8wb7K5hgs0erU8aYMkgMtbhXeouhJK3A7wA==", + "requires": { + "@libp2p/crypto": "^1.0.0", + "@libp2p/interface-connection-encrypter": "^2.0.1", + "@libp2p/interface-keys": "^1.0.2", + "@libp2p/interface-peer-id": "^1.0.2", + "@libp2p/logger": "^2.0.0", + "@libp2p/peer-id": "^1.1.8", + "@stablelib/chacha20poly1305": "^1.0.1", + "@stablelib/hkdf": "^1.0.1", + "@stablelib/sha256": "^1.0.1", + "@stablelib/x25519": "^1.0.1", + "it-length-prefixed": "^8.0.2", + "it-pair": "^2.0.2", + "it-pb-stream": "^2.0.2", + "it-pipe": "^2.0.3", + "it-stream-types": "^1.0.4", + "protons-runtime": "^3.1.0", + "uint8arraylist": "^2.3.2", + "uint8arrays": "^3.1.0" + } + }, "@definitelytyped/header-parser": { "version": "0.0.85", "resolved": "https://registry.npmjs.org/@definitelytyped/header-parser/-/header-parser-0.0.85.tgz", @@ -3930,6 +4568,76 @@ } } }, + "@libp2p/crypto": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-1.0.4.tgz", + "integrity": "sha512-3hHZvqi+vI8YoTHE+0u8nA5SYGPLZRLMvbgXQoAn0IyPjez66Taaxym/3p3Duf9QkFlvJu95nzpNzv0OdHs9Yw==", + "requires": { + "@libp2p/interface-keys": "^1.0.2", + "@noble/ed25519": "^1.6.0", + "@noble/secp256k1": "^1.5.4", + "err-code": "^3.0.1", + "multiformats": "^9.4.5", + "node-forge": "^1.1.0", + "protons-runtime": "^3.1.0", + "uint8arrays": "^3.0.0" + } + }, + "@libp2p/interface-connection-encrypter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@libp2p/interface-connection-encrypter/-/interface-connection-encrypter-2.0.1.tgz", + "integrity": "sha512-GtqsNJuL1q7LWX3z41t9eFFFrlLSmMH92E0rupoXeFx1dJ8Gs/Zy8b6lZro96Ld6rjU1CeZa87SmYeqQQeHRmw==", + "requires": { + "@libp2p/interface-peer-id": "^1.0.0", + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.1.1" + } + }, + "@libp2p/interface-keys": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@libp2p/interface-keys/-/interface-keys-1.0.3.tgz", + "integrity": "sha512-K8/HlRl/swbVTWuGHNHF28EytszYfUhKgUHfv8CdbMk9ZA/bgO4uU+d9rcrg/Dhw3511U3aRz2bwl2psn6rJfg==" + }, + "@libp2p/interface-peer-id": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@libp2p/interface-peer-id/-/interface-peer-id-1.0.4.tgz", + "integrity": "sha512-VRnE0MqmS1kN43hyKCEdkhz0gciuDML7hpL3p8zDm0LnveNMLJsR+/VSUaugCi/muOzLaLk26WffKWbMYfnGfA==", + "requires": { + "multiformats": "^9.6.3" + } + }, + "@libp2p/logger": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-2.0.1.tgz", + "integrity": "sha512-Mtj7ImjRYbaANuT53QRqc7ooBYpWieLo7KbqYYGas5O2AWQeOu/zyGBMM35WbWIo7sMuhCas9XBPJdFOR7A05w==", + "requires": { + "@libp2p/interface-peer-id": "^1.0.2", + "debug": "^4.3.3", + "interface-datastore": "^7.0.0", + "multiformats": "^9.6.3" + } + }, + "@libp2p/peer-id": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-1.1.15.tgz", + "integrity": "sha512-Y33JLEfsLmLUjuC2nhQ2lBXP6PIsR892gSsNy4Vd7oILkuRhjPouIojP9BbME0m9bhVbAws+Zh9NBKtp7UH7wA==", + "requires": { + "@libp2p/interface-peer-id": "^1.0.0", + "err-code": "^3.0.1", + "multiformats": "^9.6.3", + "uint8arrays": "^3.0.0" + } + }, + "@noble/ed25519": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.0.tgz", + "integrity": "sha512-LeAxFK0+181zQOhOUuKE8Jnd3duzYhDNd3iCLxpmzA5K+e4I1FdbrK3Ot0ZHBwZMeRD/6EojyUfTbpHZ+hkQHg==" + }, + "@noble/secp256k1": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", + "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3956,11 +4664,190 @@ "fastq": "^1.6.0" } }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "@stablelib/aead": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", + "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" + }, + "@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "requires": { + "@stablelib/int": "^1.0.1" + } + }, + "@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "@stablelib/chacha": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", + "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/chacha20poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", + "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", + "requires": { + "@stablelib/aead": "^1.0.1", + "@stablelib/binary": "^1.0.1", + "@stablelib/chacha": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/poly1305": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "@stablelib/hkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", + "requires": { + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "requires": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "requires": { + "@stablelib/bytes": "^1.0.1" + } + }, + "@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "requires": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/sha256": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "requires": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "@types/node": { "version": "18.7.15", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.15.tgz", - "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==", - "dev": true + "integrity": "sha512-XnjpaI8Bgc3eBag2Aw4t2Uj/49lLBSStHWfqKvIuXD7FIrZyMLWp8KuAFHAqxMZYTF9l08N1ctUn9YNybZJVmQ==" }, "@types/pako": { "version": "2.0.0", @@ -4213,23 +5100,6 @@ } } }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, "globby": { "version": "13.1.1", "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", @@ -4533,6 +5403,14 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, + "byte-access": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", + "integrity": "sha512-GKYa+lvxnzhgHWj9X+LCsQ4s2/C5uvib573eAOiQKywXMkzFFErY2+yQdzmdE5iWVpmqecsRx3bOtOY4/1eINw==", + "requires": { + "uint8arraylist": "^2.0.0" + } + }, "callsites": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", @@ -4916,6 +5794,14 @@ "time-zone": "^1.0.0" } }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -5070,6 +5956,11 @@ "once": "^1.4.0" } }, + "err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -5118,6 +6009,11 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, + "fast-fifo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", + "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -5444,6 +6340,21 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "interface-datastore": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-7.0.0.tgz", + "integrity": "sha512-q9OveOhexQ3Fx8h4YbuR4mZtUHwvlOynKnIwTm6x8oBTWfIyAKtlYtrOYdlHfqQztbYpdzRFcapopNJBMx36NQ==", + "requires": { + "interface-store": "^3.0.0", + "nanoid": "^3.0.2", + "uint8arrays": "^3.0.0" + } + }, + "interface-store": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-3.0.0.tgz", + "integrity": "sha512-IBJn3hE6hYutwdDcStR76mcwfV98vZc49LkEN9ANHHpsxcm6YbGMJxowO2G3FITU4U5ZH4KJPlHOT6Oe2vzTWA==" + }, "irregular-plurals": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", @@ -5553,6 +6464,111 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "it-handshake": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-4.1.2.tgz", + "integrity": "sha512-Q/EvrB4KWIX5+/wO7edBK3l79Vh28+iWPGZvZSSqwAtOJnHZIvywC+JUbiXPRJVXfICBJRqFETtIJcvrqWL2Zw==", + "requires": { + "it-pushable": "^3.1.0", + "it-reader": "^6.0.1", + "it-stream-types": "^1.0.4", + "p-defer": "^4.0.0", + "uint8arraylist": "^2.0.0" + }, + "dependencies": { + "p-defer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", + "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==" + } + } + }, + "it-length-prefixed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-8.0.2.tgz", + "integrity": "sha512-qYCGZ6lTaI6lcuTXUrJmVpE6clq63ULrkq1FGTxHrzexjB2cCrS/CZ5HCRDZ5IRPw33tSDUDK91S7X5S64dPyQ==", + "requires": { + "err-code": "^3.0.1", + "it-stream-types": "^1.0.4", + "uint8-varint": "^1.0.1", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^3.0.0" + } + }, + "it-merge": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-1.0.4.tgz", + "integrity": "sha512-DcL6GksTD2HQ7+5/q3JznXaLNfwjyG3/bObaF98da+oHfUiPmdo64oJlT9J8R8G5sJRU7thwaY5zxoAKCn7FJw==", + "requires": { + "it-pushable": "^1.4.0" + }, + "dependencies": { + "it-pushable": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-1.4.2.tgz", + "integrity": "sha512-vVPu0CGRsTI8eCfhMknA7KIBqqGFolbRx+1mbQ6XuZ7YCz995Qj7L4XUviwClFunisDq96FdxzF5FnAbw15afg==", + "requires": { + "fast-fifo": "^1.0.0" + } + } + } + }, + "it-pair": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.3.tgz", + "integrity": "sha512-heCgsbYscFCQY5YvltlGT9tjgLGYo7NxPEoJyl55X4BD2KOXpTyuwOhPLWhi9Io0y6+4ZUXCkyaQXIB6Y8xhRw==", + "requires": { + "it-stream-types": "^1.0.3", + "p-defer": "^4.0.0" + }, + "dependencies": { + "p-defer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", + "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==" + } + } + }, + "it-pb-stream": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/it-pb-stream/-/it-pb-stream-2.0.2.tgz", + "integrity": "sha512-FR1FM9W71wMTZlAij1Pq4PKNcfVb0TGhUTpNQ3tv0LMV/pJ5cDh4g3jW7jhwB+kHtr7PywD1CybBHaT8iAVpKg==", + "requires": { + "it-handshake": "^4.1.2", + "it-length-prefixed": "^8.0.2", + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.0.0" + } + }, + "it-pipe": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-2.0.4.tgz", + "integrity": "sha512-lK0BV0egwfc64DFJva+0Jh1z8UxwmYBpAHDwq21s0OenRCaEDIntx/iOyWH/jg5efBU6Xa8igzmOqm2CPPNDgg==", + "requires": { + "it-merge": "^1.0.4", + "it-pushable": "^3.1.0", + "it-stream-types": "^1.0.3" + } + }, + "it-pushable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.1.0.tgz", + "integrity": "sha512-sEAdT86u6aIWvLkH4hlOmgvHpRyUOUG22HD365H+Dh67zYpaPdILmT4Om7Wjdb+m/SjEB81z3nYCoIrgVYpOFA==" + }, + "it-reader": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.1.tgz", + "integrity": "sha512-C+YRk3OTufbKSJMNEonfEw+9F38llmwwZvqhkjb0xIgob7l4L3p01Yt43+bHRI8SSppAOgk5AKLqas7ea0UTAw==", + "requires": { + "it-stream-types": "^1.0.4", + "uint8arraylist": "^2.0.0" + } + }, + "it-stream-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-1.0.4.tgz", + "integrity": "sha512-0F3CqTIcIHwtnmIgqd03a7sw8BegAmE32N2w7anIGdALea4oAN4ltqPgDMZ7zn4XPLZifXEZlBXSzgg64L1Ebw==" + }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -5656,6 +6672,20 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "long": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", + "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" + }, + "longbits": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/longbits/-/longbits-1.1.0.tgz", + "integrity": "sha512-22U2exkkYy7sr7nuQJYx2NEZ2kEMsC69+BxM5h8auLvkVIJa+LwAB5mFIExnuW2dFuYXFOWsFMKXjaWiq/htYQ==", + "requires": { + "byte-access": "^1.0.1", + "uint8arraylist": "^2.0.0" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5771,6 +6801,26 @@ "minimist": "^1.2.5" } }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multiformats": { + "version": "9.8.1", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.8.1.tgz", + "integrity": "sha512-Cu7NfUYtCV+WN7w59WsRRF138S+um4tTo11ScYsWbNgWyCEGOu8wID1e5eMJs91gFZ0I7afodkkdxCF8NGkqZQ==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, "node-gyp-build": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", @@ -6084,6 +7134,34 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "protobufjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.0.tgz", + "integrity": "sha512-rCuxKlh0UQKSMjrpIcTLbR5TtGQ52cgs1a5nUoPBAKOccdPblN67BJtjrbtudUJK6HmBvUdsmymyYOzO7lxZEA==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + }, + "protons-runtime": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz", + "integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==", + "requires": { + "protobufjs": "^7.0.0", + "uint8arraylist": "^2.3.2" + } + }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -6616,6 +7694,33 @@ "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", "dev": true }, + "uint8-varint": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-1.0.3.tgz", + "integrity": "sha512-ESs/P/AYPy2wWZCT2V6Tg7RPqA6jzlhJbdsNPFvbDeIrDxj12dwTcm0rD9yFlnmgEf6vRBCZrP3d0SiRTcPwSQ==", + "requires": { + "byte-access": "^1.0.0", + "longbits": "^1.1.0", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^3.1.0" + } + }, + "uint8arraylist": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.3.2.tgz", + "integrity": "sha512-4ybc/jixmtGhUrebJ0bzB95TjEbskWxBKBRrAozw7P6WcAcZdPMYSLdDuNoEEGo/Cwe+0TNic9CXzWUWzy1quw==", + "requires": { + "uint8arrays": "^3.1.0" + } + }, + "uint8arrays": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", + "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", + "requires": { + "multiformats": "^9.4.2" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index 590a9c0c85..5b112d31b7 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -37,10 +37,10 @@ "pako": "^2.0.4", "ws": "^8.8.1", "multiformats": "^9.8.1", - "@chainsafe/libp2p-noise": "^8.0.1", // Even though this package works in browser, it will bundle around 600Kb (200Kb gzipped) of code + "@chainsafe/libp2p-noise": "^8.0.1", "@libp2p/peer-id": "^1.1.15", "@libp2p/crypto": "^1.0.4", - "it-stream-types": "^1.0.4", + "it-stream-types": "^1.0.4" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 10cbb62578..f6330a94a2 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -21,11 +21,10 @@ import { Client, ClientOptions, start as innerStart } from './client.js' import { Connection, ConnectionError, ConnectionConfig } from './instance/instance.js'; import { inflate } from 'pako'; -import { base64url } from "multiformats/bases/base64url"; -import { base58btc } from "multiformats/bases/base58btc"; +import { base64 } from 'multiformats/bases/base64'; import { sha256 } from 'multiformats/hashes/sha2'; -import { Noise } from "@chainsafe/libp2p-noise"; -import { Ed25519PeerIdImpl, peerIdFromString } from '@libp2p/peer-id'; +import { Noise } from '@chainsafe/libp2p-noise'; +import { createPeerId, peerIdFromString } from '@libp2p/peer-id'; import { generateKeyPair } from '@libp2p/crypto/keys'; import type { Duplex } from 'it-stream-types'; @@ -182,8 +181,8 @@ function trustedBase64Decode(base64: string): Uint8Array { // Transform ufrag (multibase-encoded multihash) to fingerprint (upper-hex; // each byte separated by ":"). // - // To add additional decoders use `or`: `base64url.decoder.or(base32.decoder)`. - const fingerprint = new Uint8Array(base64url.decode(ufrag)).join(':').toUpperCase(); + // To add additional decoders use `or`: `base64.decoder.or(base32.decoder)`. + const fingerprint = new Uint8Array(base64.decode(ufrag)).join(':').toUpperCase(); // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. @@ -246,16 +245,16 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log("REMOTE ANSWER: " + pc.remoteDescription!.sdp); }; - dataChannel.onopen = () => { + dataChannel.onopen = async () => { console.log(`'${dataChannel.label}' opened`); - const keyPair = generateKeyPair('Ed25519', 1024); - const multihash = sha256.digest(keyPair.public); - const localPeerId = new Ed25519PeerIdImpl({ multihash: multihash, privateKey: keyPair.private }); + const privateKey = await generateKeyPair('Ed25519', 1024); + const multihash = await sha256.digest(privateKey.bytes); + const localPeerId = createPeerId({ type: 'Ed25519', multihash: multihash, privateKey: privateKey.bytes }); const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); console.log(`noise handshake with addr=${config.address}`); - const noise = new Noise(keyPair.private); + const noise = new Noise(privateKey.bytes); const conn: Duplex = { sink: async data => { dataChannel.send(data); @@ -266,7 +265,7 @@ function trustedBase64Decode(base64: string): Uint8Array { }; }()) }; - const { secureConn, verifiedRemotePeerId } = noise.secureOutbound(localPeerId, conn, remotePeerId); + const { secureConn, verifiedRemotePeerId } = await noise.secureOutbound(localPeerId, conn, remotePeerId); dataChannel.close(); diff --git a/bin/wasm-node/javascript/tsconfig.json b/bin/wasm-node/javascript/tsconfig.json index 7a3e945da5..654c8d4d62 100644 --- a/bin/wasm-node/javascript/tsconfig.json +++ b/bin/wasm-node/javascript/tsconfig.json @@ -8,7 +8,8 @@ "noPropertyAccessFromIndexSignature": true, "noUncheckedIndexedAccess": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "moduleResolution": "node" }, "include": [ "src/**/*" From 6df37bff0ab94f9d40216ea74d0a7d69e239a020 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Fri, 9 Sep 2022 14:24:16 +0400 Subject: [PATCH 09/48] fix remaining errors except one --- bin/wasm-node/javascript/package-lock.json | 1 + bin/wasm-node/javascript/package.json | 3 +- bin/wasm-node/javascript/src/index-browser.ts | 36 +++++++++++-------- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/bin/wasm-node/javascript/package-lock.json b/bin/wasm-node/javascript/package-lock.json index 56681e3b6e..56e68355b8 100644 --- a/bin/wasm-node/javascript/package-lock.json +++ b/bin/wasm-node/javascript/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@chainsafe/libp2p-noise": "^8.0.1", "@libp2p/crypto": "^1.0.4", + "@libp2p/interface-peer-id": "^1.0.4", "@libp2p/peer-id": "^1.1.15", "it-stream-types": "^1.0.4", "multiformats": "^9.8.1", diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index 5b112d31b7..f995479f9f 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -40,7 +40,8 @@ "@chainsafe/libp2p-noise": "^8.0.1", "@libp2p/peer-id": "^1.1.15", "@libp2p/crypto": "^1.0.4", - "it-stream-types": "^1.0.4" + "it-stream-types": "^1.0.4", + "@libp2p/interface-peer-id": "^1.0.4" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index f6330a94a2..c676aa8176 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -22,11 +22,11 @@ import { Connection, ConnectionError, ConnectionConfig } from './instance/instan import { inflate } from 'pako'; import { base64 } from 'multiformats/bases/base64'; -import { sha256 } from 'multiformats/hashes/sha2'; import { Noise } from '@chainsafe/libp2p-noise'; -import { createPeerId, peerIdFromString } from '@libp2p/peer-id'; -import { generateKeyPair } from '@libp2p/crypto/keys'; +import { peerIdFromString, peerIdFromKeys } from '@libp2p/peer-id'; +import { generateKeyPair, marshalPrivateKey, marshalPublicKey } from '@libp2p/crypto/keys'; import type { Duplex } from 'it-stream-types'; +import type { PeerId } from '@libp2p/interface-peer-id'; export { AddChainError, @@ -248,34 +248,40 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onopen = async () => { console.log(`'${dataChannel.label}' opened`); - const privateKey = await generateKeyPair('Ed25519', 1024); - const multihash = await sha256.digest(privateKey.bytes); - const localPeerId = createPeerId({ type: 'Ed25519', multihash: multihash, privateKey: privateKey.bytes }); + const privateKey = await generateKeyPair('Ed25519'); + const localPeerId: PeerId = await peerIdFromKeys(marshalPublicKey(privateKey.public), marshalPrivateKey(privateKey)); const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); console.log(`noise handshake with addr=${config.address}`); const noise = new Noise(privateKey.bytes); const conn: Duplex = { - sink: async data => { - dataChannel.send(data); + sink: async source => { + for await (const v of source) { + dataChannel.send(v); + } }, source: (async function * () { dataChannel.onmessage = (m) => { - yield * m.data + // TODO: 99% this is incorrect, as I need to yield m.data (`yield + // * m.data` doesn't work). + // + // In Rust/Go, I'd create a channel and use it to pass m.data + // from this handler to the outer function. + return m.data; }; }()) }; - const { secureConn, verifiedRemotePeerId } = await noise.secureOutbound(localPeerId, conn, remotePeerId); + const secureConn = await noise.secureOutbound(localPeerId, conn, remotePeerId); dataChannel.close(); console.log(`verifying peer's identity addr=${config.address}`); - if (verifiedRemotePeerId != remotePeerId) { - console.error(`invalid peer ID (expected ${verifiedRemotePeerId}, got ${remotePeerId})`); + if (!secureConn.remotePeer.equals(remotePeerId)) { + console.error(`invalid peer ID (expected ${secureConn.remotePeer}, got ${remotePeerId})`); return } - config.onOpen({ type: 'multi-stream', peerId: remotePeerId }); + config.onOpen({ type: 'multi-stream', peerId: remotePeerId.toBytes() }); }; dataChannel.onerror = (error) => { @@ -333,7 +339,9 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log(`new message on '${dataChannel.label}': '${m.data}'`); } - dataChannels.set(dataChannel.id, dataChannel); + if (dataChannel.id != null) { + dataChannels.set(dataChannel.id, dataChannel); + } } }; } else { From 36e960ac1871d11a2933e5f029fc80e89fc28b52 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Mon, 12 Sep 2022 16:18:04 +0400 Subject: [PATCH 10/48] use array to push/pull messages --- bin/wasm-node/javascript/src/index-browser.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c676aa8176..3131220948 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -248,6 +248,11 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onopen = async () => { console.log(`'${dataChannel.label}' opened`); + let messages: Array = []; + dataChannel.onmessage = (m) => { + messages.push(m.data); + }; + const privateKey = await generateKeyPair('Ed25519'); const localPeerId: PeerId = await peerIdFromKeys(marshalPublicKey(privateKey.public), marshalPrivateKey(privateKey)); const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); @@ -261,14 +266,11 @@ function trustedBase64Decode(base64: string): Uint8Array { } }, source: (async function * () { - dataChannel.onmessage = (m) => { - // TODO: 99% this is incorrect, as I need to yield m.data (`yield - // * m.data` doesn't work). - // - // In Rust/Go, I'd create a channel and use it to pass m.data - // from this handler to the outer function. - return m.data; - }; + let m = messages.shift() + while (m != null) { + yield m; + m = messages.shift(); + } }()) }; const secureConn = await noise.secureOutbound(localPeerId, conn, remotePeerId); From 0917bf51426a8859e9e2c78369259bd28f5951fb Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 13 Sep 2022 13:14:17 +0200 Subject: [PATCH 11/48] Various minor fixes --- bin/wasm-node/javascript/src/index-browser.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 3131220948..b37cfdaddb 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -21,7 +21,7 @@ import { Client, ClientOptions, start as innerStart } from './client.js' import { Connection, ConnectionError, ConnectionConfig } from './instance/instance.js'; import { inflate } from 'pako'; -import { base64 } from 'multiformats/bases/base64'; +import { base64, base64pad, base64url, base64urlpad } from 'multiformats/bases/base64'; import { Noise } from '@chainsafe/libp2p-noise'; import { peerIdFromString, peerIdFromKeys } from '@libp2p/peer-id'; import { generateKeyPair, marshalPrivateKey, marshalPublicKey } from '@libp2p/crypto/keys'; @@ -98,7 +98,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // TODO: remove support for `/wss` in a long time (https://github.com/paritytech/smoldot/issues/1940) const wsParsed = config.address.match(/^\/(ip4|ip6|dns4|dns6|dns)\/(.*?)\/tcp\/(.*?)\/(ws|wss|tls\/ws)$/); - const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)\/p2p\/(.*?)$/); + const webRTCParsed = config.address.match(/^\/(ip4|ip6)\/(.*?)\/udp\/(.*?)\/webrtc\/certhash\/(.*?)$/); if (wsParsed != null) { let connection: WebSocket; @@ -176,17 +176,20 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; - const ufrag = (webRTCParsed[5] || ''); + const ufrag = (webRTCParsed[4] || ''); // Transform ufrag (multibase-encoded multihash) to fingerprint (upper-hex; // each byte separated by ":"). - // - // To add additional decoders use `or`: `base64.decoder.or(base32.decoder)`. - const fingerprint = new Uint8Array(base64.decode(ufrag)).join(':').toUpperCase(); + // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better + const fingerprint = Array.from(new Uint8Array( + base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(ufrag).slice(2) + )).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. const remoteSdp = + // Version of the SDP protocol. Always 0. (RFC8866) + "v=0" + "\n" + // Identifies the creator of the SDP document. We are allowed to use dummy values // (`-` and `0.0.0.0`) to remain anonymous, which we do. Note that "IN" means // "Internet". (RFC8866) From 28e86c02249dbd51ed31aaebbf9bbc77ed44ef47 Mon Sep 17 00:00:00 2001 From: Anton Kaliaev Date: Tue, 13 Sep 2022 18:24:42 +0400 Subject: [PATCH 12/48] ensure client's ufrag and pwd are equal --- bin/wasm-node/javascript/src/index-browser.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index b37cfdaddb..c9bb099c1a 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -169,7 +169,15 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. - const sdpOffer = (await pc.createOffer()).sdp!; + let sdpOffer = (await pc.createOffer()).sdp!; + // Ensure ufrag and pwd are the same (expected by the server). + const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); + if (pwd != null) { + sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); + } else { + console.error("Failed to set ufrag to pwd."); + return; + } await pc.setLocalDescription({ type: 'offer', sdp: sdpOffer }); console.log("LOCAL OFFER: " + pc.localDescription!.sdp); From 3985e8394540ed652e60ff59262ff5e6aa1f2b3e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 13 Sep 2022 16:41:11 +0200 Subject: [PATCH 13/48] Use proper ufrag/pwd in SDP --- bin/wasm-node/javascript/src/index-browser.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c9bb099c1a..e90e00da05 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -184,14 +184,16 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; - const ufrag = (webRTCParsed[4] || ''); + + // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better + const certSha256Hash = new Uint8Array( + base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(webRTCParsed[4]!).slice(2) + ); // Transform ufrag (multibase-encoded multihash) to fingerprint (upper-hex; // each byte separated by ":"). - // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better - const fingerprint = Array.from(new Uint8Array( - base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(ufrag).slice(2) - )).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); + const ufrag = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toLowerCase()).join(''); + const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); // Note that the trailing line feed is important, as otherwise Chrome // fails to parse the payload. From 85d5770c187b47149729213c16f937deb4bf2570 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 13 Sep 2022 16:57:17 +0200 Subject: [PATCH 14/48] Better comments --- bin/wasm-node/javascript/src/index-browser.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index e90e00da05..bc371622ff 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -185,13 +185,15 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; + // The payload of `/certhash` is the hash of the self-generated certificate that the + // server presents. // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better const certSha256Hash = new Uint8Array( base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(webRTCParsed[4]!).slice(2) ); - // Transform ufrag (multibase-encoded multihash) to fingerprint (upper-hex; - // each byte separated by ":"). + // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":") + // and into ufrag (lower-hex; no separator). const ufrag = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toLowerCase()).join(''); const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); From 81aa1962e4f5872e3ec22cfa4e87df97125e3be2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Wed, 14 Sep 2022 16:30:24 +0200 Subject: [PATCH 15/48] Update the ufrag and pwd --- bin/wasm-node/javascript/src/index-browser.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index bc371622ff..eadf0c5d95 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -184,17 +184,16 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; + const certMultibase = webRTCParsed[4]!; // The payload of `/certhash` is the hash of the self-generated certificate that the // server presents. // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better const certSha256Hash = new Uint8Array( - base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(webRTCParsed[4]!).slice(2) + base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase).slice(2) ); - // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":") - // and into ufrag (lower-hex; no separator). - const ufrag = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toLowerCase()).join(''); + // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); // Note that the trailing line feed is important, as otherwise Chrome @@ -235,8 +234,8 @@ function trustedBase64Decode(base64: string): Uint8Array { // ICE username and password, which are used for establishing and // maintaining the ICE connection. (RFC8839) // MUST match ones used by the answerer (server). - "a=ice-ufrag:" + ufrag + "\n" + - "a=ice-pwd:" + ufrag + "\n" + + "a=ice-ufrag:" + certMultibase + "\n" + + "a=ice-pwd:" + certMultibase + "\n" + // Fingerprint of the certificate that the server will use during the TLS // handshake. (RFC8122) // MUST be derived from the certificate used by the answerer (server). From 8f118c6ea92dbf950e8cab178092067ff9fb4927 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 16:22:13 +0200 Subject: [PATCH 16/48] Fix compilation --- bin/wasm-node/javascript/src/index-browser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index eadf0c5d95..673dbc06c7 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -297,7 +297,7 @@ function trustedBase64Decode(base64: string): Uint8Array { return } - config.onOpen({ type: 'multi-stream', peerId: remotePeerId.toBytes() }); + config.onOpen({ type: 'multi-stream' }); }; dataChannel.onerror = (error) => { From a752b958ccfaad725a8137ce2d4b60985136b5f2 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 16:54:35 +0200 Subject: [PATCH 17/48] Bridge index-browser's WebRTC with smoldot --- bin/wasm-node/javascript/package.json | 7 +- bin/wasm-node/javascript/src/index-browser.ts | 127 ++++++------------ src/network/service.rs | 7 - 3 files changed, 41 insertions(+), 100 deletions(-) diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index bcbb120b09..5fd8d19f7e 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -36,12 +36,7 @@ "dependencies": { "pako": "^2.0.4", "ws": "^8.8.1", - "multiformats": "^9.8.1", - "@chainsafe/libp2p-noise": "^8.0.1", - "@libp2p/peer-id": "^1.1.15", - "@libp2p/crypto": "^1.0.4", - "it-stream-types": "^1.0.4", - "@libp2p/interface-peer-id": "^1.0.4" + "multiformats": "^9.8.1" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 673dbc06c7..74f160c83d 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -22,11 +22,6 @@ import { Connection, ConnectionError, ConnectionConfig } from './instance/instan import { inflate } from 'pako'; import { base64, base64pad, base64url, base64urlpad } from 'multiformats/bases/base64'; -import { Noise } from '@chainsafe/libp2p-noise'; -import { peerIdFromString, peerIdFromKeys } from '@libp2p/peer-id'; -import { generateKeyPair, marshalPrivateKey, marshalPublicKey } from '@libp2p/crypto/keys'; -import type { Duplex } from 'it-stream-types'; -import type { PeerId } from '@libp2p/interface-peer-id'; export { AddChainError, @@ -158,14 +153,14 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.onconnectionstatechange = (_event) => { console.log(`conn state: ${pc.connectionState}`); - if (pc.connectionState == "closed") { - config.onConnectionClose(""); + if (pc.connectionState == "closed" || pc.connectionState == "disconnected" || pc.connectionState == "failed") { + config.onConnectionClose("WebRTC state transitioned to " + pc.connectionState); } }; // Create an initial data channel with a predefined `id = 1`, which is used // to verify remote peer's identity. - const dataChannel = pc.createDataChannel("data", { id: 1, negotiated: true }); + //const dataChannel = pc.createDataChannel("data", { id: 1, negotiated: true }); pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. @@ -259,56 +254,41 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log("REMOTE ANSWER: " + pc.remoteDescription!.sdp); }; - dataChannel.onopen = async () => { - console.log(`'${dataChannel.label}' opened`); - - let messages: Array = []; - dataChannel.onmessage = (m) => { - messages.push(m.data); - }; - - const privateKey = await generateKeyPair('Ed25519'); - const localPeerId: PeerId = await peerIdFromKeys(marshalPublicKey(privateKey.public), marshalPrivateKey(privateKey)); - const remotePeerId = peerIdFromString(webRTCParsed[7] || ''); - - console.log(`noise handshake with addr=${config.address}`); - const noise = new Noise(privateKey.bytes); - const conn: Duplex = { - sink: async source => { - for await (const v of source) { - dataChannel.send(v); - } - }, - source: (async function * () { - let m = messages.shift() - while (m != null) { - yield m; - m = messages.shift(); - } - }()) - }; - const secureConn = await noise.secureOutbound(localPeerId, conn, remotePeerId); - - dataChannel.close(); - - console.log(`verifying peer's identity addr=${config.address}`); - if (!secureConn.remotePeer.equals(remotePeerId)) { - console.error(`invalid peer ID (expected ${secureConn.remotePeer}, got ${remotePeerId})`); - return - } + const dataChannels = new Map(); + const addChannel = (dataChannel: RTCDataChannel, direction: 'inbound' | 'outbound') => { + const dataChannelId = dataChannel.id!; - config.onOpen({ type: 'multi-stream' }); - }; + dataChannel.onopen = () => { + console.log(`'${dataChannel.label}' opened`); + config.onStreamOpened(dataChannelId, direction); + }; - dataChannel.onerror = (error) => { - console.log(`'${dataChannel.label}' errored: ${error}`); - }; + dataChannel.onerror = (error) => { + console.log(`'${dataChannel.label}' errored: ${error}`); + config.onStreamClose(dataChannelId); + }; + + dataChannel.onclose = () => { + console.log(`'${dataChannel.label}' closed`); + config.onStreamClose(dataChannelId); + }; + + dataChannel.onmessage = (m) => { + console.log(`new message on '${dataChannel.label}': '${m.data}'`); + config.onMessage(m.data, dataChannelId); + } + + dataChannels.set(dataChannelId, dataChannel); + } - dataChannel.onclose = () => { - console.log(`'${dataChannel.label}' closed`); + pc.ondatachannel = ({ channel }) => { + addChannel(channel, 'inbound') }; - let dataChannels = new Map(); + // TODO: smoldot panics if we call onOpen before returning + setTimeout(() => { + config.onOpen({ type: 'multi-stream' }); + }, 0); return { close: (streamId: number): void => { @@ -317,47 +297,20 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.onnegotiationneeded = null; pc.close(); } else { - let dc = dataChannels.get(streamId); - if (dc != null) { - dc.close(); - } else { - console.log(`Data channel ${streamId} not found`); - } + const channel = dataChannels.get(streamId)!; + channel.close(); + dataChannels.delete(streamId); } }, - send: (data: Uint8Array, streamId: number): void => { - let dc = dataChannels.get(streamId); - if (dc != null) { - dc.send(data); - } else { - console.log(`Data channel ${streamId} not found`); - } + const channel = dataChannels.get(streamId)!; + console.log("sent", data); + channel.send(data); }, openOutSubstream: () => { - var dataChannel = pc.createDataChannel("data"); - - dataChannel.onopen = () => { - console.log(`'${dataChannel.label}' opened`); - }; - - dataChannel.onerror = (error) => { - console.log(`'${dataChannel.label}' errored: ${error}`); - }; - - dataChannel.onclose = () => { - console.log(`'${dataChannel.label}' closed`); - }; - - dataChannel.onmessage = (m) => { - console.log(`new message on '${dataChannel.label}': '${m.data}'`); - } - - if (dataChannel.id != null) { - dataChannels.set(dataChannel.id, dataChannel); - } + addChannel(pc.createDataChannel("data"), 'outbound') } }; } else { diff --git a/src/network/service.rs b/src/network/service.rs index e7168a67bc..99cc442334 100644 --- a/src/network/service.rs +++ b/src/network/service.rs @@ -1075,13 +1075,6 @@ where } } - // Because multi-stream connections are considered as having immediately finished their - // handshake, we mark the address as connected. - if let Some(KBucketsPeer { addresses, .. }) = self.kbuckets_peers.get_mut(expected_peer_id) - { - addresses.set_connected(multiaddr); - } - self.pending_ids.remove(id.0); (connection_id, connection_task) From 06bf315eb4425f77f859a0d0e4dd56f3562e8915 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 17:17:06 +0200 Subject: [PATCH 18/48] Forgot a #[no_mangle] --- bin/wasm-node/rust/src/bindings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/wasm-node/rust/src/bindings.rs b/bin/wasm-node/rust/src/bindings.rs index 88e3036a60..b125e9a878 100644 --- a/bin/wasm-node/rust/src/bindings.rs +++ b/bin/wasm-node/rust/src/bindings.rs @@ -499,6 +499,7 @@ pub extern "C" fn stream_message(connection_id: u32, stream_id: u32, ptr: u32, l /// For the `outbound` parameter, pass `0` if the substream has been opened by the remote, and any /// value other than `0` if the substream has been opened in response to a call to /// [`connection_stream_open`]. +#[no_mangle] pub extern "C" fn connection_stream_opened(connection_id: u32, stream_id: u32, outbound: u32) { crate::platform::connection_stream_opened(connection_id, stream_id, outbound) } From 7f705ee3de09bcd7b1443358960e2cd772c4f477 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 17:32:36 +0200 Subject: [PATCH 19/48] Call reset() if the connection is closed --- bin/light-base/src/network_service/tasks.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/bin/light-base/src/network_service/tasks.rs b/bin/light-base/src/network_service/tasks.rs index 6cafc4e2d4..2677384bc0 100644 --- a/bin/light-base/src/network_service/tasks.rs +++ b/bin/light-base/src/network_service/tasks.rs @@ -358,6 +358,8 @@ async fn multi_stream_connection_task( let mut pending_opening_out_substreams = 0; // Newly-open substream that has just been yielded by the connection. let mut newly_open_substream = None; + // `true` if the remote has force-closed our connection. + let mut has_reset = false; // List of all currently open substreams. The index (as a `usize`) corresponds to the id // of this substream within the `connection_task` state machine. let mut open_substreams = slab::Slab::::with_capacity(16); @@ -562,8 +564,15 @@ async fn multi_stream_connection_task( debug_assert!(newly_open_substream.is_none()); futures::select! { _ = message_from_coordinator => {} - substream = TPlat::next_substream(&mut connection).fuse() => { - newly_open_substream = substream; + substream = if has_reset { either::Right(future::pending()) } else { either::Left(TPlat::next_substream(&mut connection)) }.fuse() => { + match substream { + Some(s) => newly_open_substream = Some(s), + None => { + // `None` is returned if the remote has force-closed the connection. + connection_task.reset(); + has_reset = true; + } + } } _ = poll_after => {} _ = data_ready.fuse() => {} From 9eca8bfe405fa6e9614063b8b36db1c9ec617f32 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 17:38:11 +0200 Subject: [PATCH 20/48] Ooops, inbound <-> outbound --- src/libp2p/collection/multi_stream.rs | 12 ++++++------ src/libp2p/connection/established/multi_stream.rs | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libp2p/collection/multi_stream.rs b/src/libp2p/collection/multi_stream.rs index 81fcf5ce53..cb3664f135 100644 --- a/src/libp2p/collection/multi_stream.rs +++ b/src/libp2p/collection/multi_stream.rs @@ -551,29 +551,29 @@ where /// Notifies the state machine that a new substream has been opened. /// - /// `inbound` indicates whether the substream has been opened by the remote (`true`) or - /// locally (`false`). + /// `outbound` indicates whether the substream has been opened by the remote (`false`) or + /// locally (`true`). /// - /// If `inbound` is `false`, then the value returned by + /// If `outbound` is `true`, then the value returned by /// [`MultiStreamConnectionTask::desired_outbound_substreams`] will decrease by one. /// /// # Panic /// /// Panics if there already exists a substream with an identical identifier. /// - pub fn add_substream(&mut self, id: TSubId, inbound: bool) { + pub fn add_substream(&mut self, id: TSubId, outbound: bool) { match &mut self.connection { MultiStreamConnectionTaskInner::Handshake { opened_substream: ref mut opened_substream @ None, .. - } if !inbound => { + } if outbound => { *opened_substream = Some(id); } MultiStreamConnectionTaskInner::Handshake { .. } => { // TODO: protocol has been violated, reset the connection? } MultiStreamConnectionTaskInner::Established { established, .. } => { - established.add_substream(id, inbound) + established.add_substream(id, outbound) } MultiStreamConnectionTaskInner::ShutdownAcked { .. } | MultiStreamConnectionTaskInner::ShutdownWaitingAck { .. } => { diff --git a/src/libp2p/connection/established/multi_stream.rs b/src/libp2p/connection/established/multi_stream.rs index 70811092d6..c5487d0030 100644 --- a/src/libp2p/connection/established/multi_stream.rs +++ b/src/libp2p/connection/established/multi_stream.rs @@ -178,18 +178,18 @@ where /// Notifies the state machine that a new substream has been opened. /// - /// `inbound` indicates whether the substream has been opened by the remote (`true`) or - /// locally (`false`). + /// `outbound` indicates whether the substream has been opened by the remote (`false`) or + /// locally (`true`). /// - /// If `inbound` is `false`, then the value returned by + /// If `outbound` is `true`, then the value returned by /// [`MultiStream::desired_outbound_substreams`] will decrease by one. /// /// # Panic /// /// Panics if there already exists a substream with an identical identifier. /// - pub fn add_substream(&mut self, id: TSubId, inbound: bool) { - let (substream, out_substream_id) = if inbound { + pub fn add_substream(&mut self, id: TSubId, outbound: bool) { + let (substream, out_substream_id) = if !outbound { let out_substream_id = self.next_out_substream_id; self.next_out_substream_id += 1; From b215d6c6fb4289eca445aec409d559df6c428809 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 17:46:25 +0200 Subject: [PATCH 21/48] Restore the id: 1, negotiated: true --- bin/wasm-node/javascript/src/index-browser.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 74f160c83d..c17cfad320 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -158,10 +158,6 @@ function trustedBase64Decode(base64: string): Uint8Array { } }; - // Create an initial data channel with a predefined `id = 1`, which is used - // to verify remote peer's identity. - //const dataChannel = pc.createDataChannel("data", { id: 1, negotiated: true }); - pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. let sdpOffer = (await pc.createOffer()).sdp!; @@ -310,7 +306,8 @@ function trustedBase64Decode(base64: string): Uint8Array { }, openOutSubstream: () => { - addChannel(pc.createDataChannel("data"), 'outbound') + // TODO: the `id: 1` is a complete hack + addChannel(pc.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') } }; } else { From 2286fbe73d959e1c69a6770064dd009c25ba2d69 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 17:48:56 +0200 Subject: [PATCH 22/48] The data is in fact an ArrayBuffer --- bin/wasm-node/javascript/src/index-browser.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c17cfad320..20797f9767 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -271,7 +271,8 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannel.onmessage = (m) => { console.log(`new message on '${dataChannel.label}': '${m.data}'`); - config.onMessage(m.data, dataChannelId); + // The `data` field is an `ArrayBuffer`. + config.onMessage(new Uint8Array(m.data), dataChannelId); } dataChannels.set(dataChannelId, dataChannel); From cee8d4a5b117c870b3e979abbe939697829f013e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:12:48 +0200 Subject: [PATCH 23/48] Fix the definition of ready_substreams --- bin/light-base/src/network_service/tasks.rs | 8 ++---- src/libp2p/collection/multi_stream.rs | 27 +++++++++------------ src/libp2p/connection/noise.rs | 6 ----- 3 files changed, 14 insertions(+), 27 deletions(-) diff --git a/bin/light-base/src/network_service/tasks.rs b/bin/light-base/src/network_service/tasks.rs index 2677384bc0..f5485a29bc 100644 --- a/bin/light-base/src/network_service/tasks.rs +++ b/bin/light-base/src/network_service/tasks.rs @@ -421,12 +421,8 @@ async fn multi_stream_connection_task( } // Perform a read-write on all substreams that are ready. - loop { - let substream_id = match connection_task.ready_substreams().next() { - Some(s) => *s, - None => break, - }; - + // TODO: what is a ready substream is a bit of a clusterfuck, figure out + for substream_id in connection_task.ready_substreams().copied().collect::>() { let substream = &mut open_substreams[substream_id]; let mut read_write = ReadWrite { diff --git a/src/libp2p/collection/multi_stream.rs b/src/libp2p/collection/multi_stream.rs index cb3664f135..8b8e275812 100644 --- a/src/libp2p/collection/multi_stream.rs +++ b/src/libp2p/collection/multi_stream.rs @@ -595,26 +595,23 @@ where /// > **Note**: An example situation is: a notification is queued, which leads to a message /// > being sent to a connection task, which, once injected, leads to a notifications /// > substream being "ready" because it needs to send more data. + // TODO: this function really should be more precise as to what a ready substream means pub fn ready_substreams(&self) -> impl Iterator { match &self.connection { MultiStreamConnectionTaskInner::Handshake { opened_substream: Some(opened_substream), - handshake, .. - } => { - let iter = if handshake.as_ref().unwrap().ready_to_write() { - Some(opened_substream) - } else { - None - } - .into_iter(); - either::Right(either::Left(iter)) - } - MultiStreamConnectionTaskInner::Established { established, .. } => { - // Note that the handshake substream is never ready as it never has anything - // to write after the end of the handshake. - either::Left(established.ready_substreams()) - } + } => either::Right(either::Left(iter::once(opened_substream))), + MultiStreamConnectionTaskInner::Established { + established, + handshake_substream, + .. + } => either::Left( + handshake_substream + .as_ref() + .into_iter() + .chain(established.ready_substreams()), + ), MultiStreamConnectionTaskInner::Handshake { opened_substream: None, .. diff --git a/src/libp2p/connection/noise.rs b/src/libp2p/connection/noise.rs index 8bff6ac224..85528afa10 100644 --- a/src/libp2p/connection/noise.rs +++ b/src/libp2p/connection/noise.rs @@ -626,12 +626,6 @@ impl HandshakeInProgress { } } - /// Returns `true` if the Noise handshake is waiting to write out data. Returns `false` if - /// instead it is blocked on incoming data. - pub fn ready_to_write(&self) -> bool { - !self.tx_buffer_encrypted.is_empty() - } - /// Feeds data coming from a socket and outputs data to write to the socket. /// /// On success, returns the new state of the negotiation. From 71d584f16ab695d2bb4b67919efbb09ad50de07c Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:12:56 +0200 Subject: [PATCH 24/48] Remove callbacks before closing a substream --- bin/wasm-node/javascript/src/index-browser.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 20797f9767..07753c6304 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -295,6 +295,10 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.close(); } else { const channel = dataChannels.get(streamId)!; + channel.onopen = null; + channel.onerror = null; + channel.onclose = null; + channel.onmessage = null; channel.close(); dataChannels.delete(streamId); } From 7ff23836984b46c313a7eed98b024499f8322466 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:23:30 +0200 Subject: [PATCH 25/48] Make the substream IDs hack less hacky --- bin/wasm-node/javascript/src/index-browser.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 07753c6304..7e58478f05 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -282,6 +282,9 @@ function trustedBase64Decode(base64: string): Uint8Array { addChannel(channel, 'inbound') }; + // TODO: this system is a complete hack + let outId = 1; + // TODO: smoldot panics if we call onOpen before returning setTimeout(() => { config.onOpen({ type: 'multi-stream' }); @@ -311,8 +314,8 @@ function trustedBase64Decode(base64: string): Uint8Array { }, openOutSubstream: () => { - // TODO: the `id: 1` is a complete hack - addChannel(pc.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') + addChannel(pc.createDataChannel("data", { id: outId, negotiated: true }), 'outbound') + outId += 1; } }; } else { From 29b1c4d004c815a2d3d21d98b4dc08a8a7a7eec4 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:23:45 +0200 Subject: [PATCH 26/48] Fix multi-stream connections now handshaking --- src/libp2p/collection.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libp2p/collection.rs b/src/libp2p/collection.rs index 7224289f34..1243c53603 100644 --- a/src/libp2p/collection.rs +++ b/src/libp2p/collection.rs @@ -404,7 +404,7 @@ where let _previous_value = self.connections.insert( connection_id, Connection { - state: InnerConnectionState::Established, + state: InnerConnectionState::Handshaking, user_data, }, ); From 66c55b22c728d148dd3cbd9e2a4001f08c7e6f11 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:25:28 +0200 Subject: [PATCH 27/48] Print the direction --- bin/wasm-node/javascript/src/index-browser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 7e58478f05..25378b33ee 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -255,7 +255,7 @@ function trustedBase64Decode(base64: string): Uint8Array { const dataChannelId = dataChannel.id!; dataChannel.onopen = () => { - console.log(`'${dataChannel.label}' opened`); + console.log(`'${dataChannel.label}' opened, direction is ${direction}`); config.onStreamOpened(dataChannelId, direction); }; From 050a75658219d49e4a1d32868f96d26a3424af24 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 18:32:54 +0200 Subject: [PATCH 28/48] Fix weird unicode --- bin/wasm-node/javascript/src/index-browser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 25378b33ee..c27681df88 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -153,7 +153,7 @@ function trustedBase64Decode(base64: string): Uint8Array { pc.onconnectionstatechange = (_event) => { console.log(`conn state: ${pc.connectionState}`); - if (pc.connectionState == "closed" || pc.connectionState == "disconnected" || pc.connectionState == "failed") { + if (pc.connectionState == "closed" || pc.connectionState == "disconnected" || pc.connectionState == "failed") { config.onConnectionClose("WebRTC state transitioned to " + pc.connectionState); } }; From baff21bf32b99d7bf9cf7b51878a98b9961d4de8 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 20:06:11 +0200 Subject: [PATCH 29/48] Fix no-std compilation --- bin/light-base/src/network_service/tasks.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/light-base/src/network_service/tasks.rs b/bin/light-base/src/network_service/tasks.rs index f5485a29bc..ca9d2c6d8a 100644 --- a/bin/light-base/src/network_service/tasks.rs +++ b/bin/light-base/src/network_service/tasks.rs @@ -18,7 +18,7 @@ use super::Shared; use crate::platform::{Platform, PlatformConnection, PlatformSubstreamDirection}; -use alloc::{string::ToString as _, sync::Arc, vec}; +use alloc::{string::ToString as _, sync::Arc, vec, vec::Vec}; use core::{iter, pin::Pin}; use futures::{channel::mpsc, prelude::*}; use smoldot::{libp2p::read_write::ReadWrite, network::service}; From 91d6b483b13bf0ac1f1512ad324033bc55d202c9 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Thu, 15 Sep 2022 20:06:20 +0200 Subject: [PATCH 30/48] Don't send id after first substream --- bin/wasm-node/javascript/src/index-browser.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c27681df88..f80e7e1fc2 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -283,7 +283,7 @@ function trustedBase64Decode(base64: string): Uint8Array { }; // TODO: this system is a complete hack - let outId = 1; + let isFirstSubstream = true; // TODO: smoldot panics if we call onOpen before returning setTimeout(() => { @@ -314,8 +314,12 @@ function trustedBase64Decode(base64: string): Uint8Array { }, openOutSubstream: () => { - addChannel(pc.createDataChannel("data", { id: outId, negotiated: true }), 'outbound') - outId += 1; + if (isFirstSubstream) { + isFirstSubstream = false; + addChannel(pc.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') + } else { + addChannel(pc.createDataChannel("data"), 'outbound') + } } }; } else { From 89e049d09d5b4df19365212db7f728b89caeb983 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 10:50:25 +0200 Subject: [PATCH 31/48] Add a `enableExperimentalWebRTC` option flag instead of `forbidWebRTC` --- bin/wasm-node/javascript/src/client.ts | 10 +++++++--- bin/wasm-node/javascript/src/index-browser.ts | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/bin/wasm-node/javascript/src/client.ts b/bin/wasm-node/javascript/src/client.ts index 567512cc99..5b5acb0e15 100644 --- a/bin/wasm-node/javascript/src/client.ts +++ b/bin/wasm-node/javascript/src/client.ts @@ -255,10 +255,14 @@ export interface ClientOptions { forbidWss?: boolean; /** - * If `true`, then the client will never open any WebRTC connection. - * Defaults to `false`. + * Enable experimental support for WebRTC connections. + * + * Support for WebRTC connections is currently in progress and might have significant issues. + * + * This flag currently defaults to `false`. In a later version, it will be removed and WebRTC + * connections will be enabled by default. */ - forbidWebRTC?: boolean; + enableExperimentalWebRTC?: boolean; } /** diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index f80e7e1fc2..bdf8d34a3f 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -60,7 +60,13 @@ export function start(options?: ClientOptions): Client { crypto.getRandomValues(buffer); }, connect: (config) => { - return connect(config, options?.forbidWs || false, options?.forbidNonLocalWs || false, options?.forbidWss || false, options?.forbidWebRTC || false) + return connect( + config, + options?.forbidWs || false, + options?.forbidNonLocalWs || false, + options?.forbidWss || false, + !(options?.enableExperimentalWebRTC || false) + ) } }) } From 91979821d6967ba6e1a045ea2112ce95eb7b962a Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 10:59:30 +0200 Subject: [PATCH 32/48] Tweak the close() and send() functions --- bin/wasm-node/javascript/src/index-browser.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index bdf8d34a3f..b91323f9e2 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -297,11 +297,23 @@ function trustedBase64Decode(base64: string): Uint8Array { }, 0); return { - close: (streamId: number): void => { - if (streamId == null) { + close: (streamId: number | undefined): void => { + if (streamId === undefined) { pc.onconnectionstatechange = null; pc.onnegotiationneeded = null; + pc.ondatachannel = null; + + for (const channel of Array.from(dataChannels.values())) { + channel.onopen = null; + channel.onerror = null; + channel.onclose = null; + channel.onmessage = null; + channel.close(); + } + pc.close(); + dataChannels.clear(); + } else { const channel = dataChannels.get(streamId)!; channel.onopen = null; @@ -314,9 +326,7 @@ function trustedBase64Decode(base64: string): Uint8Array { }, send: (data: Uint8Array, streamId: number): void => { - const channel = dataChannels.get(streamId)!; - console.log("sent", data); - channel.send(data); + dataChannels.get(streamId)!.send(data); }, openOutSubstream: () => { From 2d51af9e85dfbe0cc9ef937fc9715a39e4be8fae Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 12:50:43 +0200 Subject: [PATCH 33/48] Extract multibaseMultihashToSha256 to separate function --- bin/wasm-node/javascript/src/index-browser.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index b91323f9e2..df91a6e0eb 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -185,10 +185,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // The payload of `/certhash` is the hash of the self-generated certificate that the // server presents. - // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better - const certSha256Hash = new Uint8Array( - base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase).slice(2) - ); + const certSha256Hash = multibaseMultihashToSha256(certMultibase); // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); @@ -342,3 +339,13 @@ function trustedBase64Decode(base64: string): Uint8Array { throw new ConnectionError('Unrecognized multiaddr format'); } } + +/// Parses a multihash-multibase-encoded string into a SHA256. +/// +/// Throws an exception if the multihash algorithm isn't SHA256. +const multibaseMultihashToSha256 = (certMultibase: string): Uint8Array => { + // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better + return new Uint8Array( + base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase).slice(2) + ); +} From 14a7055bb1956982c1bebf78490800ecfbdd45fb Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 12:51:56 +0200 Subject: [PATCH 34/48] Move the multiaddr parsing at the right place --- bin/wasm-node/javascript/src/index-browser.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index df91a6e0eb..613969800e 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -154,6 +154,16 @@ function trustedBase64Decode(base64: string): Uint8Array { throw new ConnectionError('Connection type not allowed'); } + const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; + const targetIp = webRTCParsed[2]; + const certMultibase = webRTCParsed[4]!; + + // The payload of `/certhash` is the hash of the self-generated certificate that the + // server presents. + // This function throws an exception if the certhash isn't correct. For this reason, this call + // is performed as part of the parsing of the multiaddr. + const certSha256Hash = multibaseMultihashToSha256(certMultibase); + // Create a new peer connection. pc = new RTCPeerConnection(); @@ -179,14 +189,6 @@ function trustedBase64Decode(base64: string): Uint8Array { console.log("LOCAL OFFER: " + pc.localDescription!.sdp); - const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; - const targetIp = webRTCParsed[2]; - const certMultibase = webRTCParsed[4]!; - - // The payload of `/certhash` is the hash of the self-generated certificate that the - // server presents. - const certSha256Hash = multibaseMultihashToSha256(certMultibase); - // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); From 4f059f1d847c6beb1a48d824200542498dfec1a8 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 12:52:37 +0200 Subject: [PATCH 35/48] Minor JS tweak --- bin/wasm-node/javascript/src/index-browser.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 613969800e..64775189b1 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -147,8 +147,6 @@ function trustedBase64Decode(base64: string): Uint8Array { openOutSubstream: () => { throw new Error('Wrong connection type') } }; } else if (webRTCParsed != null) { - let pc: RTCPeerConnection; - const targetPort = webRTCParsed[3]; if (forbidWebRTC || targetPort == '0') { throw new ConnectionError('Connection type not allowed'); @@ -165,7 +163,7 @@ function trustedBase64Decode(base64: string): Uint8Array { const certSha256Hash = multibaseMultihashToSha256(certMultibase); // Create a new peer connection. - pc = new RTCPeerConnection(); + const pc = new RTCPeerConnection(); pc.onconnectionstatechange = (_event) => { console.log(`conn state: ${pc.connectionState}`); From 288f14df3a5f0c2b042ec9f3210ceda8e41f36eb Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 12:53:23 +0200 Subject: [PATCH 36/48] Don't log the candidates --- bin/wasm-node/javascript/src/index-browser.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 64775189b1..97948fca96 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -185,8 +185,6 @@ function trustedBase64Decode(base64: string): Uint8Array { } await pc.setLocalDescription({ type: 'offer', sdp: sdpOffer }); - console.log("LOCAL OFFER: " + pc.localDescription!.sdp); - // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); @@ -249,8 +247,6 @@ function trustedBase64Decode(base64: string): Uint8Array { "a=candidate:1 1 UDP 1 " + targetIp + " " + targetPort + " typ host" + "\n"; await pc.setRemoteDescription({ type: "answer", sdp: remoteSdp }); - - console.log("REMOTE ANSWER: " + pc.remoteDescription!.sdp); }; const dataChannels = new Map(); From 7f63a758f75840a4b1aa695899dab93e27ca6fa6 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 14:42:07 +0200 Subject: [PATCH 37/48] Update for the main branch --- bin/wasm-node/javascript/src/index-browser.ts | 246 ++++++++++-------- .../src/instance/bindings-smoldot-light.ts | 4 +- bin/wasm-node/rust/src/platform.rs | 2 +- 3 files changed, 140 insertions(+), 112 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index d40665439d..c60873f8b0 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -154,102 +154,20 @@ function trustedBase64Decode(base64: string): Uint8Array { const ipVersion = webRTCParsed[1] == 'ip4'? '4' : '6'; const targetIp = webRTCParsed[2]; - const certMultibase = webRTCParsed[4]!; + const remoteCertMultibase = webRTCParsed[4]!; // The payload of `/certhash` is the hash of the self-generated certificate that the // server presents. // This function throws an exception if the certhash isn't correct. For this reason, this call // is performed as part of the parsing of the multiaddr. - const certSha256Hash = multibaseMultihashToSha256(certMultibase); - - // Create a new peer connection. - const pc = new RTCPeerConnection(); - - pc.onconnectionstatechange = (_event) => { - console.log(`conn state: ${pc.connectionState}`); - if (pc.connectionState == "closed" || pc.connectionState == "disconnected" || pc.connectionState == "failed") { - config.onConnectionClose("WebRTC state transitioned to " + pc.connectionState); - } - }; - - pc.onnegotiationneeded = async (_event) => { - // Create a new offer and set it as local description. - let sdpOffer = (await pc.createOffer()).sdp!; - // Ensure ufrag and pwd are the same (expected by the server). - const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); - if (pwd != null) { - sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); - } else { - console.error("Failed to set ufrag to pwd."); - return; - } - await pc.setLocalDescription({ type: 'offer', sdp: sdpOffer }); - - // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). - const fingerprint = Array.from(certSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); - - // Note that the trailing line feed is important, as otherwise Chrome - // fails to parse the payload. - const remoteSdp = - // Version of the SDP protocol. Always 0. (RFC8866) - "v=0" + "\n" + - // Identifies the creator of the SDP document. We are allowed to use dummy values - // (`-` and `0.0.0.0`) to remain anonymous, which we do. Note that "IN" means - // "Internet". (RFC8866) - "o=- 0 0 IN IP" + ipVersion + " " + targetIp + "\n" + - // Name for the session. We are allowed to pass a dummy `-`. (RFC8866) - "s=-" + "\n" + - // Start and end of the validity of the session. `0 0` means that the session never - // expires. (RFC8866) - "t=0 0" + "\n" + - // A lite implementation is only appropriate for devices that will - // *always* be connected to the public Internet and have a public - // IP address at which it can receive packets from any - // correspondent. ICE will not function when a lite implementation - // is placed behind a NAT (RFC8445). - "a=ice-lite" + "\n" + - // A `m=` line describes a request to establish a certain protocol. - // The protocol in this line (i.e. `TCP/DTLS/SCTP` or `UDP/DTLS/SCTP`) must always be - // the same as the one in the offer. We know that this is true because we tweak the - // offer to match the protocol. - // The `` component must always be `pc-datachannel` for WebRTC. - // The rest of the SDP payload adds attributes to this specific media stream. - // RFCs: 8839, 8866, 8841 - "m=application " + targetPort + " " + "UDP/DTLS/SCTP webrtc-datachannel" + "\n" + - // Indicates the IP address of the remote. - // Note that "IN" means "Internet". - "c=IN IP" + ipVersion + " " + targetIp + "\n" + - // Media ID - uniquely identifies this media stream (RFC9143). - "a=mid:0" + "\n" + - // Indicates that we are complying with RFC8839 (as oppposed to the legacy RFC5245). - "a=ice-options:ice2" + "\n" + - // ICE username and password, which are used for establishing and - // maintaining the ICE connection. (RFC8839) - // MUST match ones used by the answerer (server). - "a=ice-ufrag:" + certMultibase + "\n" + - "a=ice-pwd:" + certMultibase + "\n" + - // Fingerprint of the certificate that the server will use during the TLS - // handshake. (RFC8122) - // MUST be derived from the certificate used by the answerer (server). - "a=fingerprint:sha-256 " + fingerprint + "\n" + - // Indicates that the remote DTLS server will only listen for incoming - // connections. (RFC5763) - // The answerer (server) MUST not be located behind a NAT (RFC6135). - "a=setup:passive" + "\n" + - // The SCTP port (RFC8841) - // Note it's different from the "m=" line port value, which - // indicates the port of the underlying transport-layer protocol - // (UDP or TCP) - "a=sctp-port:5000" + "\n" + - // The maximum SCTP user message size (in bytes) (RFC8841) - "a=max-message-size:100000" + "\n" + - // A transport address for a candidate that can be used for connectivity checks (RFC8839). - "a=candidate:1 1 UDP 1 " + targetIp + " " + targetPort + " typ host" + "\n"; - - await pc.setRemoteDescription({ type: "answer", sdp: remoteSdp }); - }; + const remoteCertMultihash = multibaseDecode(remoteCertMultibase); + const remoteCertSha256Hash = multihashToSha256(remoteCertMultihash); + let pc: RTCPeerConnection | null = null; const dataChannels = new Map(); + // TODO: this system is a complete hack + let isFirstSubstream = true; + const addChannel = (dataChannel: RTCDataChannel, direction: 'inbound' | 'outbound') => { const dataChannelId = dataChannel.id!; @@ -277,24 +195,129 @@ function trustedBase64Decode(base64: string): Uint8Array { dataChannels.set(dataChannelId, dataChannel); } - pc.ondatachannel = ({ channel }) => { - addChannel(channel, 'inbound') - }; + // It is possible for the browser to use multiple different certificates. + // In order for our local certificate to be deterministic, we need to generate it manually and + // set it explicitly as part of the configuration. + RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256" } as EcKeyGenParams).then((localCertificate) => { + let localTlsCertificateMultihash: Uint8Array | null = null; + for (const { algorithm, value } of localCertificate.getFingerprints()) { + if (algorithm === 'sha-256') { + localTlsCertificateMultihash = new Uint8Array(34); + localTlsCertificateMultihash.set([0x12, 32], 0); + localTlsCertificateMultihash.set(value!.split(':').map((s) => parseInt(s, 16)), 2); + break; + } + } + if (localTlsCertificateMultihash === null) { + config.onConnectionClose('Failed to obtain the browser certificate fingerprint'); + return; + } - // TODO: this system is a complete hack - let isFirstSubstream = true; + // Create a new peer connection. + pc = new RTCPeerConnection({ certificates: [localCertificate] }); + + pc.onconnectionstatechange = (_event) => { + console.log(`conn state: ${pc!.connectionState}`); + if (pc!.connectionState == "closed" || pc!.connectionState == "disconnected" || pc!.connectionState == "failed") { + config.onConnectionClose("WebRTC state transitioned to " + pc!.connectionState); + } + }; - // TODO: smoldot panics if we call onOpen before returning - setTimeout(() => { - config.onOpen({ type: 'multi-stream' }); - }, 0); + pc.onnegotiationneeded = async (_event) => { + // Create a new offer and set it as local description. + let sdpOffer = (await pc!.createOffer()).sdp!; + // Ensure ufrag and pwd are the same (expected by the server). + const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); + if (pwd != null) { + sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); + } else { + console.error("Failed to set ufrag to pwd."); + return; + } + await pc!.setLocalDescription({ type: 'offer', sdp: sdpOffer }); + + // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). + const fingerprint = Array.from(remoteCertSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); + + // Note that the trailing line feed is important, as otherwise Chrome + // fails to parse the payload. + const remoteSdp = + // Version of the SDP protocol. Always 0. (RFC8866) + "v=0" + "\n" + + // Identifies the creator of the SDP document. We are allowed to use dummy values + // (`-` and `0.0.0.0`) to remain anonymous, which we do. Note that "IN" means + // "Internet". (RFC8866) + "o=- 0 0 IN IP" + ipVersion + " " + targetIp + "\n" + + // Name for the session. We are allowed to pass a dummy `-`. (RFC8866) + "s=-" + "\n" + + // Start and end of the validity of the session. `0 0` means that the session never + // expires. (RFC8866) + "t=0 0" + "\n" + + // A lite implementation is only appropriate for devices that will + // *always* be connected to the public Internet and have a public + // IP address at which it can receive packets from any + // correspondent. ICE will not function when a lite implementation + // is placed behind a NAT (RFC8445). + "a=ice-lite" + "\n" + + // A `m=` line describes a request to establish a certain protocol. + // The protocol in this line (i.e. `TCP/DTLS/SCTP` or `UDP/DTLS/SCTP`) must always be + // the same as the one in the offer. We know that this is true because we tweak the + // offer to match the protocol. + // The `` component must always be `pc-datachannel` for WebRTC. + // The rest of the SDP payload adds attributes to this specific media stream. + // RFCs: 8839, 8866, 8841 + "m=application " + targetPort + " " + "UDP/DTLS/SCTP webrtc-datachannel" + "\n" + + // Indicates the IP address of the remote. + // Note that "IN" means "Internet". + "c=IN IP" + ipVersion + " " + targetIp + "\n" + + // Media ID - uniquely identifies this media stream (RFC9143). + "a=mid:0" + "\n" + + // Indicates that we are complying with RFC8839 (as oppposed to the legacy RFC5245). + "a=ice-options:ice2" + "\n" + + // ICE username and password, which are used for establishing and + // maintaining the ICE connection. (RFC8839) + // MUST match ones used by the answerer (server). + "a=ice-ufrag:" + remoteCertMultibase + "\n" + + "a=ice-pwd:" + remoteCertMultibase + "\n" + + // Fingerprint of the certificate that the server will use during the TLS + // handshake. (RFC8122) + // MUST be derived from the certificate used by the answerer (server). + "a=fingerprint:sha-256 " + fingerprint + "\n" + + // Indicates that the remote DTLS server will only listen for incoming + // connections. (RFC5763) + // The answerer (server) MUST not be located behind a NAT (RFC6135). + "a=setup:passive" + "\n" + + // The SCTP port (RFC8841) + // Note it's different from the "m=" line port value, which + // indicates the port of the underlying transport-layer protocol + // (UDP or TCP) + "a=sctp-port:5000" + "\n" + + // The maximum SCTP user message size (in bytes) (RFC8841) + "a=max-message-size:100000" + "\n" + + // A transport address for a candidate that can be used for connectivity checks (RFC8839). + "a=candidate:1 1 UDP 1 " + targetIp + " " + targetPort + " typ host" + "\n"; + + await pc!.setRemoteDescription({ type: "answer", sdp: remoteSdp }); + }; + + pc.ondatachannel = ({ channel }) => { + addChannel(channel, 'inbound') + }; + + config.onOpen({ + type: 'multi-stream', + handshake: 'webrtc', + localTlsCertificateMultihash, + remoteTlsCertificateMultihash: remoteCertMultihash + }); + }); return { close: (streamId: number | undefined): void => { if (streamId === undefined) { - pc.onconnectionstatechange = null; - pc.onnegotiationneeded = null; - pc.ondatachannel = null; + pc!.onconnectionstatechange = null; + pc!.onnegotiationneeded = null; + pc!.ondatachannel = null; for (const channel of Array.from(dataChannels.values())) { channel.onopen = null; @@ -304,7 +327,7 @@ function trustedBase64Decode(base64: string): Uint8Array { channel.close(); } - pc.close(); + pc!.close(); dataChannels.clear(); } else { @@ -325,9 +348,9 @@ function trustedBase64Decode(base64: string): Uint8Array { openOutSubstream: () => { if (isFirstSubstream) { isFirstSubstream = false; - addChannel(pc.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') + addChannel(pc!.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') } else { - addChannel(pc.createDataChannel("data"), 'outbound') + addChannel(pc!.createDataChannel("data"), 'outbound') } } }; @@ -336,12 +359,17 @@ function trustedBase64Decode(base64: string): Uint8Array { } } -/// Parses a multihash-multibase-encoded string into a SHA256. +/// Parses a multibase-encoded string. +const multibaseDecode = (certMultibase: string): Uint8Array => { + return new Uint8Array( + base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase) + ); +} + +/// Parses a multihash-multibase-encoded string into a SHA256 hash. /// /// Throws an exception if the multihash algorithm isn't SHA256. -const multibaseMultihashToSha256 = (certMultibase: string): Uint8Array => { +const multihashToSha256 = (certMultihash: Uint8Array): Uint8Array => { // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better - return new Uint8Array( - base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase).slice(2) - ); + return new Uint8Array(certMultihash.slice(2)); } diff --git a/bin/wasm-node/javascript/src/instance/bindings-smoldot-light.ts b/bin/wasm-node/javascript/src/instance/bindings-smoldot-light.ts index efd832729a..3519258f93 100644 --- a/bin/wasm-node/javascript/src/instance/bindings-smoldot-light.ts +++ b/bin/wasm-node/javascript/src/instance/bindings-smoldot-light.ts @@ -334,12 +334,12 @@ export default function (config: Config): { imports: WebAssembly.ModuleImports, break } case 'multi-stream': { - const bufferLen = 2 + info.localTlsCertificateMultihash.length + info.remoteTlsCertificateMultihash.length; + const bufferLen = 1 + info.localTlsCertificateMultihash.length + info.remoteTlsCertificateMultihash.length; const ptr = instance.exports.alloc(bufferLen) >>> 0; const mem = new Uint8Array(instance.exports.memory.buffer); buffer.writeUInt8(mem, ptr, 0); mem.set(info.localTlsCertificateMultihash, ptr + 1) - mem.set(info.remoteTlsCertificateMultihash, ptr + info.localTlsCertificateMultihash.length) + mem.set(info.remoteTlsCertificateMultihash, ptr + 1 + info.localTlsCertificateMultihash.length) instance.exports.connection_open_multi_stream(connectionId, ptr, bufferLen); break } diff --git a/bin/wasm-node/rust/src/platform.rs b/bin/wasm-node/rust/src/platform.rs index 3898083c38..628192de3b 100644 --- a/bin/wasm-node/rust/src/platform.rs +++ b/bin/wasm-node/rust/src/platform.rs @@ -571,7 +571,7 @@ pub(crate) fn connection_open_multi_stream( }, )), )(&handshake_ty[..]) - .unwrap(); + .expect("invalid handshake type provided to connection_open_multi_stream"); let mut lock = STATE.try_lock().unwrap(); let connection = lock.connections.get_mut(&connection_id).unwrap(); From 373865f23fd2163a8528c24f122460fb10f4129e Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 16 Sep 2022 14:46:40 +0200 Subject: [PATCH 38/48] CHANGELOG --- bin/wasm-node/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/wasm-node/CHANGELOG.md b/bin/wasm-node/CHANGELOG.md index 9f77d62ffa..9667b90d29 100644 --- a/bin/wasm-node/CHANGELOG.md +++ b/bin/wasm-node/CHANGELOG.md @@ -12,6 +12,7 @@ ### Added +- Add experimental support for WebRTC according to the in-progress specification for libp2p-webrtc. For now this feature must explicitly be enabled by passing `enableExperimentalWebRTC: true` as part of the ̀`ClientConfig`. The multiaddress format for WebRTC is `/ip4/.../udp/.../webrtc/certhash/...` (or `/ip6/...`), where the payload behind `/certhash` is a multibase-encoded multihash-encoded SHA256 of the DTLS certificate used by the remote. ([#2579](https://github.com/paritytech/smoldot/pull/2579)) - Add support for the `chainHead_unstable_finalizedDatabase` JSON-RPC method. This JSON-RPC method aims to be a replacement for the `databaseContent` method of the `Chain` and is expected to remain a permanently unstable smoldot-specific function. ([#2749](https://github.com/paritytech/smoldot/pull/2749)) ## 0.6.33 - 2022-09-13 From 13e21cd932716d66892742f409b285a2421fe8b0 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 08:00:21 +0200 Subject: [PATCH 39/48] Improve multihashToSha256 --- bin/wasm-node/javascript/src/index-browser.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index c60873f8b0..3adcf407e9 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -370,6 +370,12 @@ const multibaseDecode = (certMultibase: string): Uint8Array => { /// /// Throws an exception if the multihash algorithm isn't SHA256. const multihashToSha256 = (certMultihash: Uint8Array): Uint8Array => { - // TODO: this `slice(2)` after decoding the multibase is a hack to remove the multihash prefix, do this better + if (certMultihash.length != 34) { + throw new Error('Invalid certificate multihash'); + } + if (certMultihash[0] != 0x12 || certMultihash[1] != 32) { + throw new Error('Certificate multihash is not SHA-256'); + } + return new Uint8Array(certMultihash.slice(2)); } From ffc5f951bc2994285a78284ea88a6d6c9d799672 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 08:01:26 +0200 Subject: [PATCH 40/48] Fix the exception being thrown --- bin/wasm-node/javascript/src/index-browser.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 3adcf407e9..b76f067477 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -370,10 +370,7 @@ const multibaseDecode = (certMultibase: string): Uint8Array => { /// /// Throws an exception if the multihash algorithm isn't SHA256. const multihashToSha256 = (certMultihash: Uint8Array): Uint8Array => { - if (certMultihash.length != 34) { - throw new Error('Invalid certificate multihash'); - } - if (certMultihash[0] != 0x12 || certMultihash[1] != 32) { + if (certMultihash.length != 34 || certMultihash[0] != 0x12 || certMultihash[1] != 32) { throw new Error('Certificate multihash is not SHA-256'); } From 17853e2b9edb953b28389a51906d55ce4a8e2375 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 08:30:54 +0200 Subject: [PATCH 41/48] Many small improvements to JS code --- bin/wasm-node/javascript/src/index-browser.ts | 78 ++++++++++++++++--- 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index b76f067477..10d63bb660 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -148,7 +148,7 @@ function trustedBase64Decode(base64: string): Uint8Array { }; } else if (webRTCParsed != null) { const targetPort = webRTCParsed[3]; - if (forbidWebRTC || targetPort == '0') { + if (forbidWebRTC || targetPort === '0') { throw new ConnectionError('Connection type not allowed'); } @@ -167,7 +167,12 @@ function trustedBase64Decode(base64: string): Uint8Array { const dataChannels = new Map(); // TODO: this system is a complete hack let isFirstSubstream = true; + // The opening of the connection is asynchronous. If smoldot calls `close` in the meanwhile, + // this variable is set to `true`, and we interrupt the opening. + let cancelOpening = false; + // Function that configures a newly-opened channel and adds it to the map. Used for both + // inbound and outbound substreams. const addChannel = (dataChannel: RTCDataChannel, direction: 'inbound' | 'outbound') => { const dataChannelId = dataChannel.id!; @@ -198,7 +203,13 @@ function trustedBase64Decode(base64: string): Uint8Array { // It is possible for the browser to use multiple different certificates. // In order for our local certificate to be deterministic, we need to generate it manually and // set it explicitly as part of the configuration. + // According to , + // browsers are guaranteed to support `{ name: "ECDSA", namedCurve: "P-256" }`. RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256" } as EcKeyGenParams).then((localCertificate) => { + if (cancelOpening) + return; + + // We need to build the multihash corresponding to the local certificate. let localTlsCertificateMultihash: Uint8Array | null = null; for (const { algorithm, value } of localCertificate.getFingerprints()) { if (algorithm === 'sha-256') { @@ -209,24 +220,50 @@ function trustedBase64Decode(base64: string): Uint8Array { } } if (localTlsCertificateMultihash === null) { + // Because we've already returned from the `connect` function at this point, we pretend + // that the connection has failed to open. config.onConnectionClose('Failed to obtain the browser certificate fingerprint'); return; } - // Create a new peer connection. + // Create a new WebRTC connection. pc = new RTCPeerConnection({ certificates: [localCertificate] }); + // `onconnectionstatechange` is used to detect when the connection has closed or has failed + // to open. + // Note that smoldot will think that the connection is open even when it is still opening. + // Therefore we don't care about events concerning the fact that the connection is now fully + // open. pc.onconnectionstatechange = (_event) => { console.log(`conn state: ${pc!.connectionState}`); if (pc!.connectionState == "closed" || pc!.connectionState == "disconnected" || pc!.connectionState == "failed") { - config.onConnectionClose("WebRTC state transitioned to " + pc!.connectionState); + config.onConnectionClose("WebRTC state transitioned to " + pc!.connectionState); + + pc!.onconnectionstatechange = null; + pc!.onnegotiationneeded = null; + pc!.ondatachannel = null; + + for (const channel of Array.from(dataChannels.values())) { + channel.onopen = null; + channel.onerror = null; + channel.onclose = null; + channel.onmessage = null; + } + + pc!.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. + + for (const channel of Array.from(dataChannels.values())) { + channel.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. + } + dataChannels.clear(); } }; pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. let sdpOffer = (await pc!.createOffer()).sdp!; - // Ensure ufrag and pwd are the same (expected by the server). + // The server excepts the ufrag and pwd to be the same. Modify the local description + // to ensure that. const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); if (pwd != null) { sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); @@ -236,7 +273,7 @@ function trustedBase64Decode(base64: string): Uint8Array { } await pc!.setLocalDescription({ type: 'offer', sdp: sdpOffer }); - // Transform certifcate hash into fingerprint (upper-hex; each byte separated by ":"). + // Transform certificate hash into fingerprint (upper-hex; each byte separated by ":"). const fingerprint = Array.from(remoteCertSha256Hash).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':'); // Note that the trailing line feed is important, as otherwise Chrome @@ -304,6 +341,13 @@ function trustedBase64Decode(base64: string): Uint8Array { addChannel(channel, 'inbound') }; + // Creating a `RTCPeerConnection` doesn't actually do anything before a channel is created. + // The connection is therefore immediately reported as opened to smoldot so that it starts + // opening substreams. + // One concern might be that smoldot will think that the remote is reachable at this address + // (because we report the connection as being open) even when it might not be the case. + // However, WebRTC has a handshake to perform, and smoldot will only consider a connection + // as "actually open" once the handshake has finished. config.onOpen({ type: 'multi-stream', handshake: 'webrtc', @@ -314,20 +358,32 @@ function trustedBase64Decode(base64: string): Uint8Array { return { close: (streamId: number | undefined): void => { + // If `streamId` is undefined, then the whole connection must be destroyed. if (streamId === undefined) { - pc!.onconnectionstatechange = null; - pc!.onnegotiationneeded = null; - pc!.ondatachannel = null; + // The `RTCPeerConnection` is created at the same time as we report the connection as + // being open. It is however possible for smoldot to cancel the opening, in which case + // `pc` will still be undefined. + if (!pc) { + cancelOpening = true; + return; + } + + pc.onconnectionstatechange = null; + pc.onnegotiationneeded = null; + pc.ondatachannel = null; for (const channel of Array.from(dataChannels.values())) { channel.onopen = null; channel.onerror = null; channel.onclose = null; channel.onmessage = null; - channel.close(); } - pc!.close(); + pc.close(); + + for (const channel of Array.from(dataChannels.values())) { + channel.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. + } dataChannels.clear(); } else { @@ -346,6 +402,8 @@ function trustedBase64Decode(base64: string): Uint8Array { }, openOutSubstream: () => { + // `openOutSubstream` can only be called after we have called `config.onOpen`, therefore + // `pc` is guaranteed to be non-null. if (isFirstSubstream) { isFirstSubstream = false; addChannel(pc!.createDataChannel("data", { id: 1, negotiated: true }), 'outbound') From 83d8a4ed379e757147ccb3f1a3654043a278862c Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 09:15:09 +0200 Subject: [PATCH 42/48] Rustfmt --- bin/light-base/src/network_service/tasks.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/light-base/src/network_service/tasks.rs b/bin/light-base/src/network_service/tasks.rs index 1819d5418a..756af6c90c 100644 --- a/bin/light-base/src/network_service/tasks.rs +++ b/bin/light-base/src/network_service/tasks.rs @@ -436,7 +436,11 @@ async fn multi_stream_connection_task( // Perform a read-write on all substreams that are ready. // TODO: what is a ready substream is a bit of a clusterfuck, figure out - for substream_id in connection_task.ready_substreams().copied().collect::>() { + for substream_id in connection_task + .ready_substreams() + .copied() + .collect::>() + { let substream = &mut open_substreams[substream_id]; let mut read_write = ReadWrite { From 356408ec6b47fde30e177ce8c5b590d42a39a286 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 09:59:24 +0200 Subject: [PATCH 43/48] Use a custom base64 implementation --- bin/wasm-node/javascript/package-lock.json | 1128 +---------------- bin/wasm-node/javascript/package.json | 3 +- bin/wasm-node/javascript/src/base64.ts | 115 ++ bin/wasm-node/javascript/src/index-browser.ts | 31 +- 4 files changed, 129 insertions(+), 1148 deletions(-) create mode 100644 bin/wasm-node/javascript/src/base64.ts diff --git a/bin/wasm-node/javascript/package-lock.json b/bin/wasm-node/javascript/package-lock.json index 916d2e148c..4849b9ce1c 100644 --- a/bin/wasm-node/javascript/package-lock.json +++ b/bin/wasm-node/javascript/package-lock.json @@ -9,12 +9,6 @@ "version": "0.6.33", "license": "GPL-3.0-or-later WITH Classpath-exception-2.0", "dependencies": { - "@chainsafe/libp2p-noise": "^8.0.1", - "@libp2p/crypto": "^1.0.4", - "@libp2p/interface-peer-id": "^1.0.4", - "@libp2p/peer-id": "^1.1.15", - "it-stream-types": "^1.0.4", - "multiformats": "^9.8.1", "pako": "^2.0.4", "ws": "^8.8.1" }, @@ -28,35 +22,6 @@ "typescript": "^4.5.4" } }, - "node_modules/@chainsafe/libp2p-noise": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.1.tgz", - "integrity": "sha512-mr1/CMTBIfraqTY4OWBdmJ2v+0+D89vbIp1nJTHz64oDPRgU0Ah8wb7K5hgs0erU8aYMkgMtbhXeouhJK3A7wA==", - "dependencies": { - "@libp2p/crypto": "^1.0.0", - "@libp2p/interface-connection-encrypter": "^2.0.1", - "@libp2p/interface-keys": "^1.0.2", - "@libp2p/interface-peer-id": "^1.0.2", - "@libp2p/logger": "^2.0.0", - "@libp2p/peer-id": "^1.1.8", - "@stablelib/chacha20poly1305": "^1.0.1", - "@stablelib/hkdf": "^1.0.1", - "@stablelib/sha256": "^1.0.1", - "@stablelib/x25519": "^1.0.1", - "it-length-prefixed": "^8.0.2", - "it-pair": "^2.0.2", - "it-pb-stream": "^2.0.2", - "it-pipe": "^2.0.3", - "it-stream-types": "^1.0.4", - "protons-runtime": "^3.1.0", - "uint8arraylist": "^2.3.2", - "uint8arrays": "^3.1.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/@definitelytyped/header-parser": { "version": "0.0.85", "resolved": "https://registry.npmjs.org/@definitelytyped/header-parser/-/header-parser-0.0.85.tgz", @@ -110,112 +75,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/@libp2p/crypto": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-1.0.4.tgz", - "integrity": "sha512-3hHZvqi+vI8YoTHE+0u8nA5SYGPLZRLMvbgXQoAn0IyPjez66Taaxym/3p3Duf9QkFlvJu95nzpNzv0OdHs9Yw==", - "dependencies": { - "@libp2p/interface-keys": "^1.0.2", - "@noble/ed25519": "^1.6.0", - "@noble/secp256k1": "^1.5.4", - "err-code": "^3.0.1", - "multiformats": "^9.4.5", - "node-forge": "^1.1.0", - "protons-runtime": "^3.1.0", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@libp2p/interface-connection-encrypter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@libp2p/interface-connection-encrypter/-/interface-connection-encrypter-2.0.1.tgz", - "integrity": "sha512-GtqsNJuL1q7LWX3z41t9eFFFrlLSmMH92E0rupoXeFx1dJ8Gs/Zy8b6lZro96Ld6rjU1CeZa87SmYeqQQeHRmw==", - "dependencies": { - "@libp2p/interface-peer-id": "^1.0.0", - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.1.1" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@libp2p/interface-keys": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface-keys/-/interface-keys-1.0.3.tgz", - "integrity": "sha512-K8/HlRl/swbVTWuGHNHF28EytszYfUhKgUHfv8CdbMk9ZA/bgO4uU+d9rcrg/Dhw3511U3aRz2bwl2psn6rJfg==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@libp2p/interface-peer-id": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/interface-peer-id/-/interface-peer-id-1.0.4.tgz", - "integrity": "sha512-VRnE0MqmS1kN43hyKCEdkhz0gciuDML7hpL3p8zDm0LnveNMLJsR+/VSUaugCi/muOzLaLk26WffKWbMYfnGfA==", - "dependencies": { - "multiformats": "^9.6.3" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@libp2p/logger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-2.0.1.tgz", - "integrity": "sha512-Mtj7ImjRYbaANuT53QRqc7ooBYpWieLo7KbqYYGas5O2AWQeOu/zyGBMM35WbWIo7sMuhCas9XBPJdFOR7A05w==", - "dependencies": { - "@libp2p/interface-peer-id": "^1.0.2", - "debug": "^4.3.3", - "interface-datastore": "^7.0.0", - "multiformats": "^9.6.3" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@libp2p/peer-id": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-1.1.15.tgz", - "integrity": "sha512-Y33JLEfsLmLUjuC2nhQ2lBXP6PIsR892gSsNy4Vd7oILkuRhjPouIojP9BbME0m9bhVbAws+Zh9NBKtp7UH7wA==", - "dependencies": { - "@libp2p/interface-peer-id": "^1.0.0", - "err-code": "^3.0.1", - "multiformats": "^9.6.3", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/@noble/ed25519": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.1.tgz", - "integrity": "sha512-Rk4SkJFaXZiznFyC/t77Q0NKS4FL7TLJJsVG2V2oiEq3kJVeTdxysEe/yRWSpnWMe808XRDJ+VFh5pt/FN5plw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, - "node_modules/@noble/secp256k1": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.0.tgz", - "integrity": "sha512-kbacwGSsH/CTout0ZnZWxnW1B+jH/7r/WAAKLBtrRJ/+CUH7lgmQzl3GTrQua3SGKWNSDsS6lmjnDpIJ5Dxyaw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -251,190 +110,11 @@ "node": ">= 8" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@stablelib/aead": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", - "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" - }, - "node_modules/@stablelib/binary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", - "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", - "dependencies": { - "@stablelib/int": "^1.0.1" - } - }, - "node_modules/@stablelib/bytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", - "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" - }, - "node_modules/@stablelib/chacha": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", - "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/chacha20poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", - "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", - "dependencies": { - "@stablelib/aead": "^1.0.1", - "@stablelib/binary": "^1.0.1", - "@stablelib/chacha": "^1.0.1", - "@stablelib/constant-time": "^1.0.1", - "@stablelib/poly1305": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", - "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" - }, - "node_modules/@stablelib/hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", - "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" - }, - "node_modules/@stablelib/hkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", - "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", - "dependencies": { - "@stablelib/hash": "^1.0.1", - "@stablelib/hmac": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/hmac": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", - "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", - "dependencies": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/int": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", - "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" - }, - "node_modules/@stablelib/keyagreement": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", - "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", - "dependencies": { - "@stablelib/bytes": "^1.0.1" - } - }, - "node_modules/@stablelib/poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", - "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", - "dependencies": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/random": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", - "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/sha256": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", - "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", - "dependencies": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "node_modules/@stablelib/wipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", - "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" - }, - "node_modules/@stablelib/x25519": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", - "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", - "dependencies": { - "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.2", - "@stablelib/wipe": "^1.0.1" - } - }, "node_modules/@types/node": { "version": "18.7.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", + "dev": true }, "node_modules/@types/pako": { "version": "2.0.0", @@ -1138,18 +818,6 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, - "node_modules/byte-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", - "integrity": "sha512-GKYa+lvxnzhgHWj9X+LCsQ4s2/C5uvib573eAOiQKywXMkzFFErY2+yQdzmdE5iWVpmqecsRx3bOtOY4/1eINw==", - "dependencies": { - "uint8arraylist": "^2.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/callsites": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", @@ -1649,6 +1317,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -1865,11 +1534,6 @@ "once": "^1.4.0" } }, - "node_modules/err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1937,11 +1601,6 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, - "node_modules/fast-fifo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", - "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" - }, "node_modules/fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -2353,29 +2012,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/interface-datastore": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-7.0.0.tgz", - "integrity": "sha512-q9OveOhexQ3Fx8h4YbuR4mZtUHwvlOynKnIwTm6x8oBTWfIyAKtlYtrOYdlHfqQztbYpdzRFcapopNJBMx36NQ==", - "dependencies": { - "interface-store": "^3.0.0", - "nanoid": "^3.0.2", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/interface-store": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-3.0.0.tgz", - "integrity": "sha512-IBJn3hE6hYutwdDcStR76mcwfV98vZc49LkEN9ANHHpsxcm6YbGMJxowO2G3FITU4U5ZH4KJPlHOT6Oe2vzTWA==", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/irregular-plurals": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", @@ -2518,141 +2154,6 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "node_modules/it-handshake": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-4.1.2.tgz", - "integrity": "sha512-Q/EvrB4KWIX5+/wO7edBK3l79Vh28+iWPGZvZSSqwAtOJnHZIvywC+JUbiXPRJVXfICBJRqFETtIJcvrqWL2Zw==", - "dependencies": { - "it-pushable": "^3.1.0", - "it-reader": "^6.0.1", - "it-stream-types": "^1.0.4", - "p-defer": "^4.0.0", - "uint8arraylist": "^2.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-handshake/node_modules/p-defer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", - "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/it-length-prefixed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-8.0.2.tgz", - "integrity": "sha512-qYCGZ6lTaI6lcuTXUrJmVpE6clq63ULrkq1FGTxHrzexjB2cCrS/CZ5HCRDZ5IRPw33tSDUDK91S7X5S64dPyQ==", - "dependencies": { - "err-code": "^3.0.1", - "it-stream-types": "^1.0.4", - "uint8-varint": "^1.0.1", - "uint8arraylist": "^2.0.0", - "uint8arrays": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-merge": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-1.0.4.tgz", - "integrity": "sha512-DcL6GksTD2HQ7+5/q3JznXaLNfwjyG3/bObaF98da+oHfUiPmdo64oJlT9J8R8G5sJRU7thwaY5zxoAKCn7FJw==", - "dependencies": { - "it-pushable": "^1.4.0" - } - }, - "node_modules/it-merge/node_modules/it-pushable": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-1.4.2.tgz", - "integrity": "sha512-vVPu0CGRsTI8eCfhMknA7KIBqqGFolbRx+1mbQ6XuZ7YCz995Qj7L4XUviwClFunisDq96FdxzF5FnAbw15afg==", - "dependencies": { - "fast-fifo": "^1.0.0" - } - }, - "node_modules/it-pair": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.3.tgz", - "integrity": "sha512-heCgsbYscFCQY5YvltlGT9tjgLGYo7NxPEoJyl55X4BD2KOXpTyuwOhPLWhi9Io0y6+4ZUXCkyaQXIB6Y8xhRw==", - "dependencies": { - "it-stream-types": "^1.0.3", - "p-defer": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-pair/node_modules/p-defer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", - "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/it-pb-stream": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/it-pb-stream/-/it-pb-stream-2.0.2.tgz", - "integrity": "sha512-FR1FM9W71wMTZlAij1Pq4PKNcfVb0TGhUTpNQ3tv0LMV/pJ5cDh4g3jW7jhwB+kHtr7PywD1CybBHaT8iAVpKg==", - "dependencies": { - "it-handshake": "^4.1.2", - "it-length-prefixed": "^8.0.2", - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-pipe": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-2.0.4.tgz", - "integrity": "sha512-lK0BV0egwfc64DFJva+0Jh1z8UxwmYBpAHDwq21s0OenRCaEDIntx/iOyWH/jg5efBU6Xa8igzmOqm2CPPNDgg==", - "dependencies": { - "it-merge": "^1.0.4", - "it-pushable": "^3.1.0", - "it-stream-types": "^1.0.3" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-pushable": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.1.0.tgz", - "integrity": "sha512-sEAdT86u6aIWvLkH4hlOmgvHpRyUOUG22HD365H+Dh67zYpaPdILmT4Om7Wjdb+m/SjEB81z3nYCoIrgVYpOFA==" - }, - "node_modules/it-reader": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.1.tgz", - "integrity": "sha512-C+YRk3OTufbKSJMNEonfEw+9F38llmwwZvqhkjb0xIgob7l4L3p01Yt43+bHRI8SSppAOgk5AKLqas7ea0UTAw==", - "dependencies": { - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/it-stream-types": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-1.0.4.tgz", - "integrity": "sha512-0F3CqTIcIHwtnmIgqd03a7sw8BegAmE32N2w7anIGdALea4oAN4ltqPgDMZ7zn4XPLZifXEZlBXSzgg64L1Ebw==" - }, "node_modules/js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -2774,24 +2275,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "node_modules/long": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", - "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" - }, - "node_modules/longbits": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/longbits/-/longbits-1.1.0.tgz", - "integrity": "sha512-22U2exkkYy7sr7nuQJYx2NEZ2kEMsC69+BxM5h8auLvkVIJa+LwAB5mFIExnuW2dFuYXFOWsFMKXjaWiq/htYQ==", - "dependencies": { - "byte-access": "^1.0.1", - "uint8arraylist": "^2.0.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2959,31 +2442,8 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/multiformats": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.8.1.tgz", - "integrity": "sha512-Cu7NfUYtCV+WN7w59WsRRF138S+um4tTo11ScYsWbNgWyCEGOu8wID1e5eMJs91gFZ0I7afodkkdxCF8NGkqZQ==" - }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "engines": { - "node": ">= 6.13.0" - } + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node_modules/node-gyp-build": { "version": "4.2.3", @@ -3417,45 +2877,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "node_modules/protobufjs": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.1.tgz", - "integrity": "sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/protons-runtime": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz", - "integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==", - "dependencies": { - "protobufjs": "^7.0.0", - "uint8arraylist": "^2.3.2" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - }, - "peerDependencies": { - "uint8arraylist": "^2.3.2" - } - }, "node_modules/psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -4153,41 +3574,6 @@ "node": ">=4.2.0" } }, - "node_modules/uint8-varint": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-1.0.3.tgz", - "integrity": "sha512-ESs/P/AYPy2wWZCT2V6Tg7RPqA6jzlhJbdsNPFvbDeIrDxj12dwTcm0rD9yFlnmgEf6vRBCZrP3d0SiRTcPwSQ==", - "dependencies": { - "byte-access": "^1.0.0", - "longbits": "^1.1.0", - "uint8arraylist": "^2.0.0", - "uint8arrays": "^3.1.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/uint8arraylist": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.3.2.tgz", - "integrity": "sha512-4ybc/jixmtGhUrebJ0bzB95TjEbskWxBKBRrAozw7P6WcAcZdPMYSLdDuNoEEGo/Cwe+0TNic9CXzWUWzy1quw==", - "dependencies": { - "uint8arrays": "^3.1.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/uint8arrays": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", - "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", - "dependencies": { - "multiformats": "^9.4.2" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -4492,31 +3878,6 @@ } }, "dependencies": { - "@chainsafe/libp2p-noise": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@chainsafe/libp2p-noise/-/libp2p-noise-8.0.1.tgz", - "integrity": "sha512-mr1/CMTBIfraqTY4OWBdmJ2v+0+D89vbIp1nJTHz64oDPRgU0Ah8wb7K5hgs0erU8aYMkgMtbhXeouhJK3A7wA==", - "requires": { - "@libp2p/crypto": "^1.0.0", - "@libp2p/interface-connection-encrypter": "^2.0.1", - "@libp2p/interface-keys": "^1.0.2", - "@libp2p/interface-peer-id": "^1.0.2", - "@libp2p/logger": "^2.0.0", - "@libp2p/peer-id": "^1.1.8", - "@stablelib/chacha20poly1305": "^1.0.1", - "@stablelib/hkdf": "^1.0.1", - "@stablelib/sha256": "^1.0.1", - "@stablelib/x25519": "^1.0.1", - "it-length-prefixed": "^8.0.2", - "it-pair": "^2.0.2", - "it-pb-stream": "^2.0.2", - "it-pipe": "^2.0.3", - "it-stream-types": "^1.0.4", - "protons-runtime": "^3.1.0", - "uint8arraylist": "^2.3.2", - "uint8arrays": "^3.1.0" - } - }, "@definitelytyped/header-parser": { "version": "0.0.85", "resolved": "https://registry.npmjs.org/@definitelytyped/header-parser/-/header-parser-0.0.85.tgz", @@ -4569,76 +3930,6 @@ } } }, - "@libp2p/crypto": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-1.0.4.tgz", - "integrity": "sha512-3hHZvqi+vI8YoTHE+0u8nA5SYGPLZRLMvbgXQoAn0IyPjez66Taaxym/3p3Duf9QkFlvJu95nzpNzv0OdHs9Yw==", - "requires": { - "@libp2p/interface-keys": "^1.0.2", - "@noble/ed25519": "^1.6.0", - "@noble/secp256k1": "^1.5.4", - "err-code": "^3.0.1", - "multiformats": "^9.4.5", - "node-forge": "^1.1.0", - "protons-runtime": "^3.1.0", - "uint8arrays": "^3.0.0" - } - }, - "@libp2p/interface-connection-encrypter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@libp2p/interface-connection-encrypter/-/interface-connection-encrypter-2.0.1.tgz", - "integrity": "sha512-GtqsNJuL1q7LWX3z41t9eFFFrlLSmMH92E0rupoXeFx1dJ8Gs/Zy8b6lZro96Ld6rjU1CeZa87SmYeqQQeHRmw==", - "requires": { - "@libp2p/interface-peer-id": "^1.0.0", - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.1.1" - } - }, - "@libp2p/interface-keys": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface-keys/-/interface-keys-1.0.3.tgz", - "integrity": "sha512-K8/HlRl/swbVTWuGHNHF28EytszYfUhKgUHfv8CdbMk9ZA/bgO4uU+d9rcrg/Dhw3511U3aRz2bwl2psn6rJfg==" - }, - "@libp2p/interface-peer-id": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@libp2p/interface-peer-id/-/interface-peer-id-1.0.4.tgz", - "integrity": "sha512-VRnE0MqmS1kN43hyKCEdkhz0gciuDML7hpL3p8zDm0LnveNMLJsR+/VSUaugCi/muOzLaLk26WffKWbMYfnGfA==", - "requires": { - "multiformats": "^9.6.3" - } - }, - "@libp2p/logger": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-2.0.1.tgz", - "integrity": "sha512-Mtj7ImjRYbaANuT53QRqc7ooBYpWieLo7KbqYYGas5O2AWQeOu/zyGBMM35WbWIo7sMuhCas9XBPJdFOR7A05w==", - "requires": { - "@libp2p/interface-peer-id": "^1.0.2", - "debug": "^4.3.3", - "interface-datastore": "^7.0.0", - "multiformats": "^9.6.3" - } - }, - "@libp2p/peer-id": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-1.1.15.tgz", - "integrity": "sha512-Y33JLEfsLmLUjuC2nhQ2lBXP6PIsR892gSsNy4Vd7oILkuRhjPouIojP9BbME0m9bhVbAws+Zh9NBKtp7UH7wA==", - "requires": { - "@libp2p/interface-peer-id": "^1.0.0", - "err-code": "^3.0.1", - "multiformats": "^9.6.3", - "uint8arrays": "^3.0.0" - } - }, - "@noble/ed25519": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.1.tgz", - "integrity": "sha512-Rk4SkJFaXZiznFyC/t77Q0NKS4FL7TLJJsVG2V2oiEq3kJVeTdxysEe/yRWSpnWMe808XRDJ+VFh5pt/FN5plw==" - }, - "@noble/secp256k1": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.0.tgz", - "integrity": "sha512-kbacwGSsH/CTout0ZnZWxnW1B+jH/7r/WAAKLBtrRJ/+CUH7lgmQzl3GTrQua3SGKWNSDsS6lmjnDpIJ5Dxyaw==" - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4665,190 +3956,11 @@ "fastq": "^1.6.0" } }, - "@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "requires": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "@stablelib/aead": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/aead/-/aead-1.0.1.tgz", - "integrity": "sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==" - }, - "@stablelib/binary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", - "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", - "requires": { - "@stablelib/int": "^1.0.1" - } - }, - "@stablelib/bytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", - "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" - }, - "@stablelib/chacha": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha/-/chacha-1.0.1.tgz", - "integrity": "sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/chacha20poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/chacha20poly1305/-/chacha20poly1305-1.0.1.tgz", - "integrity": "sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==", - "requires": { - "@stablelib/aead": "^1.0.1", - "@stablelib/binary": "^1.0.1", - "@stablelib/chacha": "^1.0.1", - "@stablelib/constant-time": "^1.0.1", - "@stablelib/poly1305": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", - "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" - }, - "@stablelib/hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", - "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" - }, - "@stablelib/hkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", - "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", - "requires": { - "@stablelib/hash": "^1.0.1", - "@stablelib/hmac": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/hmac": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", - "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", - "requires": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/int": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", - "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" - }, - "@stablelib/keyagreement": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", - "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", - "requires": { - "@stablelib/bytes": "^1.0.1" - } - }, - "@stablelib/poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", - "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", - "requires": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/random": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", - "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/sha256": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", - "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/wipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", - "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" - }, - "@stablelib/x25519": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", - "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", - "requires": { - "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.2", - "@stablelib/wipe": "^1.0.1" - } - }, "@types/node": { "version": "18.7.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.18.tgz", - "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==" + "integrity": "sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg==", + "dev": true }, "@types/pako": { "version": "2.0.0", @@ -5404,14 +4516,6 @@ "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", "dev": true }, - "byte-access": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/byte-access/-/byte-access-1.0.1.tgz", - "integrity": "sha512-GKYa+lvxnzhgHWj9X+LCsQ4s2/C5uvib573eAOiQKywXMkzFFErY2+yQdzmdE5iWVpmqecsRx3bOtOY4/1eINw==", - "requires": { - "uint8arraylist": "^2.0.0" - } - }, "callsites": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.0.0.tgz", @@ -5799,6 +4903,7 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -5957,11 +5062,6 @@ "once": "^1.4.0" } }, - "err-code": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", - "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==" - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -6010,11 +5110,6 @@ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", "dev": true }, - "fast-fifo": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.1.0.tgz", - "integrity": "sha512-Kl29QoNbNvn4nhDsLYjyIAaIqaJB6rBx5p3sL9VjaefJ+eMFBWVZiaoguaoZfzEKr5RhAti0UgM8703akGPJ6g==" - }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -6341,21 +5436,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "interface-datastore": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-7.0.0.tgz", - "integrity": "sha512-q9OveOhexQ3Fx8h4YbuR4mZtUHwvlOynKnIwTm6x8oBTWfIyAKtlYtrOYdlHfqQztbYpdzRFcapopNJBMx36NQ==", - "requires": { - "interface-store": "^3.0.0", - "nanoid": "^3.0.2", - "uint8arrays": "^3.0.0" - } - }, - "interface-store": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-3.0.0.tgz", - "integrity": "sha512-IBJn3hE6hYutwdDcStR76mcwfV98vZc49LkEN9ANHHpsxcm6YbGMJxowO2G3FITU4U5ZH4KJPlHOT6Oe2vzTWA==" - }, "irregular-plurals": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.3.0.tgz", @@ -6465,111 +5545,6 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, - "it-handshake": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/it-handshake/-/it-handshake-4.1.2.tgz", - "integrity": "sha512-Q/EvrB4KWIX5+/wO7edBK3l79Vh28+iWPGZvZSSqwAtOJnHZIvywC+JUbiXPRJVXfICBJRqFETtIJcvrqWL2Zw==", - "requires": { - "it-pushable": "^3.1.0", - "it-reader": "^6.0.1", - "it-stream-types": "^1.0.4", - "p-defer": "^4.0.0", - "uint8arraylist": "^2.0.0" - }, - "dependencies": { - "p-defer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", - "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==" - } - } - }, - "it-length-prefixed": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-8.0.2.tgz", - "integrity": "sha512-qYCGZ6lTaI6lcuTXUrJmVpE6clq63ULrkq1FGTxHrzexjB2cCrS/CZ5HCRDZ5IRPw33tSDUDK91S7X5S64dPyQ==", - "requires": { - "err-code": "^3.0.1", - "it-stream-types": "^1.0.4", - "uint8-varint": "^1.0.1", - "uint8arraylist": "^2.0.0", - "uint8arrays": "^3.0.0" - } - }, - "it-merge": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-1.0.4.tgz", - "integrity": "sha512-DcL6GksTD2HQ7+5/q3JznXaLNfwjyG3/bObaF98da+oHfUiPmdo64oJlT9J8R8G5sJRU7thwaY5zxoAKCn7FJw==", - "requires": { - "it-pushable": "^1.4.0" - }, - "dependencies": { - "it-pushable": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-1.4.2.tgz", - "integrity": "sha512-vVPu0CGRsTI8eCfhMknA7KIBqqGFolbRx+1mbQ6XuZ7YCz995Qj7L4XUviwClFunisDq96FdxzF5FnAbw15afg==", - "requires": { - "fast-fifo": "^1.0.0" - } - } - } - }, - "it-pair": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.3.tgz", - "integrity": "sha512-heCgsbYscFCQY5YvltlGT9tjgLGYo7NxPEoJyl55X4BD2KOXpTyuwOhPLWhi9Io0y6+4ZUXCkyaQXIB6Y8xhRw==", - "requires": { - "it-stream-types": "^1.0.3", - "p-defer": "^4.0.0" - }, - "dependencies": { - "p-defer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz", - "integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ==" - } - } - }, - "it-pb-stream": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/it-pb-stream/-/it-pb-stream-2.0.2.tgz", - "integrity": "sha512-FR1FM9W71wMTZlAij1Pq4PKNcfVb0TGhUTpNQ3tv0LMV/pJ5cDh4g3jW7jhwB+kHtr7PywD1CybBHaT8iAVpKg==", - "requires": { - "it-handshake": "^4.1.2", - "it-length-prefixed": "^8.0.2", - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.0.0" - } - }, - "it-pipe": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-2.0.4.tgz", - "integrity": "sha512-lK0BV0egwfc64DFJva+0Jh1z8UxwmYBpAHDwq21s0OenRCaEDIntx/iOyWH/jg5efBU6Xa8igzmOqm2CPPNDgg==", - "requires": { - "it-merge": "^1.0.4", - "it-pushable": "^3.1.0", - "it-stream-types": "^1.0.3" - } - }, - "it-pushable": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.1.0.tgz", - "integrity": "sha512-sEAdT86u6aIWvLkH4hlOmgvHpRyUOUG22HD365H+Dh67zYpaPdILmT4Om7Wjdb+m/SjEB81z3nYCoIrgVYpOFA==" - }, - "it-reader": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.1.tgz", - "integrity": "sha512-C+YRk3OTufbKSJMNEonfEw+9F38llmwwZvqhkjb0xIgob7l4L3p01Yt43+bHRI8SSppAOgk5AKLqas7ea0UTAw==", - "requires": { - "it-stream-types": "^1.0.4", - "uint8arraylist": "^2.0.0" - } - }, - "it-stream-types": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-1.0.4.tgz", - "integrity": "sha512-0F3CqTIcIHwtnmIgqd03a7sw8BegAmE32N2w7anIGdALea4oAN4ltqPgDMZ7zn4XPLZifXEZlBXSzgg64L1Ebw==" - }, "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", @@ -6673,20 +5648,6 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "long": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.0.tgz", - "integrity": "sha512-9RTUNjK60eJbx3uz+TEGF7fUr29ZDxR5QzXcyDpeSfeH28S9ycINflOgOlppit5U+4kNTe83KQnMEerw7GmE8w==" - }, - "longbits": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/longbits/-/longbits-1.1.0.tgz", - "integrity": "sha512-22U2exkkYy7sr7nuQJYx2NEZ2kEMsC69+BxM5h8auLvkVIJa+LwAB5mFIExnuW2dFuYXFOWsFMKXjaWiq/htYQ==", - "requires": { - "byte-access": "^1.0.1", - "uint8arraylist": "^2.0.0" - } - }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -6805,22 +5766,8 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "multiformats": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.8.1.tgz", - "integrity": "sha512-Cu7NfUYtCV+WN7w59WsRRF138S+um4tTo11ScYsWbNgWyCEGOu8wID1e5eMJs91gFZ0I7afodkkdxCF8NGkqZQ==" - }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "node-gyp-build": { "version": "4.2.3", @@ -7135,34 +6082,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "protobufjs": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.1.tgz", - "integrity": "sha512-d0nMQqS/aT3lfV8bKi9Gbg73vPd2LcDdTDOu6RE/M+h9DY8g1EmDzk3ADPccthEWfTBjkR2oxNdx9Gs8YubT+g==", - "requires": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - } - }, - "protons-runtime": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-3.1.0.tgz", - "integrity": "sha512-S1iSPQC0McdHKJRi0XcATBkWgwWPx46UDfrnshYDXBvGHSYqkFtn4MQ8Gatf67w7FzFtHivA+Hb0ZPq56upG8w==", - "requires": { - "protobufjs": "^7.0.0", - "uint8arraylist": "^2.3.2" - } - }, "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", @@ -7695,33 +6614,6 @@ "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true }, - "uint8-varint": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-1.0.3.tgz", - "integrity": "sha512-ESs/P/AYPy2wWZCT2V6Tg7RPqA6jzlhJbdsNPFvbDeIrDxj12dwTcm0rD9yFlnmgEf6vRBCZrP3d0SiRTcPwSQ==", - "requires": { - "byte-access": "^1.0.0", - "longbits": "^1.1.0", - "uint8arraylist": "^2.0.0", - "uint8arrays": "^3.1.0" - } - }, - "uint8arraylist": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.3.2.tgz", - "integrity": "sha512-4ybc/jixmtGhUrebJ0bzB95TjEbskWxBKBRrAozw7P6WcAcZdPMYSLdDuNoEEGo/Cwe+0TNic9CXzWUWzy1quw==", - "requires": { - "uint8arrays": "^3.1.0" - } - }, - "uint8arrays": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.0.tgz", - "integrity": "sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==", - "requires": { - "multiformats": "^9.4.2" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/bin/wasm-node/javascript/package.json b/bin/wasm-node/javascript/package.json index 5fd8d19f7e..71c59ef966 100644 --- a/bin/wasm-node/javascript/package.json +++ b/bin/wasm-node/javascript/package.json @@ -35,8 +35,7 @@ }, "dependencies": { "pako": "^2.0.4", - "ws": "^8.8.1", - "multiformats": "^9.8.1" + "ws": "^8.8.1" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/bin/wasm-node/javascript/src/base64.ts b/bin/wasm-node/javascript/src/base64.ts new file mode 100644 index 0000000000..d43a238dca --- /dev/null +++ b/bin/wasm-node/javascript/src/base64.ts @@ -0,0 +1,115 @@ +// Smoldot +// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +let rfc4648Alphabet: Map = new Map(); +const rfc4648AlphabetAsStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +for (let i = 0; i < rfc4648AlphabetAsStr.length; ++i) { + rfc4648Alphabet.set(rfc4648AlphabetAsStr[i]!, i) +} + +let urlSafeAlphabet: Map = new Map(); +const urlSafeAlphabetAsStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; +for (let i = 0; i < urlSafeAlphabetAsStr.length; ++i) { + urlSafeAlphabet.set(urlSafeAlphabetAsStr[i]!, i) +} + +/** + * Decodes a multibase-encoded string. + * + * Throws an exception if the encoding isn't base64 or one of its variants. + */ +export function multibaseBase64Decode(input: string): Uint8Array { + if (input.length === 0) + throw new Error("Invalid multibase"); + + switch (input[0]) { + case 'm': + case 'M': + return classicDecode(input.slice(1)) + case 'u': + case 'U': + return classicDecode(input.slice(1)) + default: + throw new Error('Unknown multibase prefix: ' + input[0]); + } +} + +/** + * Decodes a base64-encoded string into bytes using the original alphabet from RFC4648. + * + * See . + */ +export function classicDecode(input: string): Uint8Array { + return base64Decode(input, rfc4648Alphabet); +} + +/** + * Decodes a base64-encoded string into bytes using the URL-safe alphabet. + * + * See . + */ +export function urlSafeDecode(input: string): Uint8Array { + return base64Decode(input, urlSafeAlphabet); +} + +/** + * Decodes a base64-encoded string into bytes using the given alphabet. + */ +export function base64Decode(input: string, alphabet: Map): Uint8Array { + // Remove the padding bytes at the end of the string. We don't check whether the padding is + // accurate. + while (input.length !== 0 && input[input.length - 1] === '=') + input = input.slice(0, -1) + + // Contains the output data. + const out = new Uint8Array(Math.floor(input.length * 6 / 8)); + // Position within `out` of the next byte to write. + let outPos = 0; + + // The bits decoded from the input are added to the right of this value. + let currentByte = 0; + // The left-most `validBitsInCurrentByte` bits of `currentByte` must be written out. + let validBitsInCurrentByte = 0; + + for (let i = 0; i < input.length; ++i) { + const inputChr = input[i]!; + + const bitsToAppend = alphabet.get(inputChr); + if (bitsToAppend === undefined) + throw new Error('Invalid base64 character: ' + inputChr); + console.assert(bitsToAppend < (1 << 6)); + + currentByte = (currentByte << 6) | bitsToAppend; + validBitsInCurrentByte += 6; + + if (validBitsInCurrentByte >= 8) { + let outByte = currentByte >> (validBitsInCurrentByte - 8); + out[outPos] = outByte; + outPos += 1; + validBitsInCurrentByte -= 8; + } + console.assert(validBitsInCurrentByte < 8); + currentByte &= 0xff; + } + + if ((currentByte & ((1 << validBitsInCurrentByte) - 1)) !== 0) + throw new Error("Unexpected EOF"); + if (validBitsInCurrentByte >= 6) + throw new Error("Unexpected EOF"); + + return out; +} diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 10d63bb660..3f334db56e 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -19,10 +19,9 @@ import { Client, ClientOptions, start as innerStart } from './client.js' import { Connection, ConnectionError, ConnectionConfig } from './instance/instance.js'; +import { classicDecode, multibaseBase64Decode } from './base64.js' import { inflate } from 'pako'; -import { base64, base64pad, base64url, base64urlpad } from 'multiformats/bases/base64'; - export { AddChainError, AddChainOptions, @@ -48,7 +47,7 @@ export function start(options?: ClientOptions): Client { return innerStart(options, { trustedBase64DecodeAndZlibInflate: (input) => { - return Promise.resolve(inflate(trustedBase64Decode(input))) + return Promise.resolve(inflate(classicDecode(input))) }, performanceNow: () => { return performance.now() @@ -71,23 +70,6 @@ export function start(options?: ClientOptions): Client { }) } -/** - * Decodes a base64 string. - * - * The input is assumed to be correct. - */ -function trustedBase64Decode(base64: string): Uint8Array { - // This code is a bit sketchy due to the fact that we decode into a string, but it seems to - // work. - const binaryString = atob(base64); - const size = binaryString.length; - const bytes = new Uint8Array(size); - for (let i = 0; i < size; i++) { - bytes[i] = binaryString.charCodeAt(i); - } - return bytes; -} - /** * Tries to open a new connection using the given configuration. * @@ -160,7 +142,7 @@ function trustedBase64Decode(base64: string): Uint8Array { // server presents. // This function throws an exception if the certhash isn't correct. For this reason, this call // is performed as part of the parsing of the multiaddr. - const remoteCertMultihash = multibaseDecode(remoteCertMultibase); + const remoteCertMultihash = multibaseBase64Decode(remoteCertMultibase); const remoteCertSha256Hash = multihashToSha256(remoteCertMultihash); let pc: RTCPeerConnection | null = null; @@ -417,13 +399,6 @@ function trustedBase64Decode(base64: string): Uint8Array { } } -/// Parses a multibase-encoded string. -const multibaseDecode = (certMultibase: string): Uint8Array => { - return new Uint8Array( - base64.decoder.or(base64pad.decoder).or(base64url.decoder).or(base64urlpad.decoder).decode(certMultibase) - ); -} - /// Parses a multihash-multibase-encoded string into a SHA256 hash. /// /// Throws an exception if the multihash algorithm isn't SHA256. From daab79e941d1872e3a55c12aa814d3f3473554fe Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 10:01:49 +0200 Subject: [PATCH 44/48] Revert moduleResolution change --- bin/wasm-node/javascript/tsconfig.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/wasm-node/javascript/tsconfig.json b/bin/wasm-node/javascript/tsconfig.json index 654c8d4d62..7a3e945da5 100644 --- a/bin/wasm-node/javascript/tsconfig.json +++ b/bin/wasm-node/javascript/tsconfig.json @@ -8,8 +8,7 @@ "noPropertyAccessFromIndexSignature": true, "noUncheckedIndexedAccess": true, "noUnusedLocals": true, - "noUnusedParameters": true, - "moduleResolution": "node" + "noUnusedParameters": true }, "include": [ "src/**/*" From 98823ecec636b2df328a568e885052f96ecd7554 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 10:07:51 +0200 Subject: [PATCH 45/48] Tweaks --- bin/wasm-node/javascript/src/index-browser.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 3f334db56e..ee18c16226 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -159,22 +159,18 @@ export function start(options?: ClientOptions): Client { const dataChannelId = dataChannel.id!; dataChannel.onopen = () => { - console.log(`'${dataChannel.label}' opened, direction is ${direction}`); config.onStreamOpened(dataChannelId, direction); }; - dataChannel.onerror = (error) => { - console.log(`'${dataChannel.label}' errored: ${error}`); + dataChannel.onerror = (_error) => { config.onStreamClose(dataChannelId); }; dataChannel.onclose = () => { - console.log(`'${dataChannel.label}' closed`); config.onStreamClose(dataChannelId); }; dataChannel.onmessage = (m) => { - console.log(`new message on '${dataChannel.label}': '${m.data}'`); // The `data` field is an `ArrayBuffer`. config.onMessage(new Uint8Array(m.data), dataChannelId); } @@ -217,7 +213,6 @@ export function start(options?: ClientOptions): Client { // Therefore we don't care about events concerning the fact that the connection is now fully // open. pc.onconnectionstatechange = (_event) => { - console.log(`conn state: ${pc!.connectionState}`); if (pc!.connectionState == "closed" || pc!.connectionState == "disconnected" || pc!.connectionState == "failed") { config.onConnectionClose("WebRTC state transitioned to " + pc!.connectionState); @@ -246,12 +241,12 @@ export function start(options?: ClientOptions): Client { let sdpOffer = (await pc!.createOffer()).sdp!; // The server excepts the ufrag and pwd to be the same. Modify the local description // to ensure that. + // TODO: why does the server want that? const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); if (pwd != null) { sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); } else { - console.error("Failed to set ufrag to pwd."); - return; + console.error("Failed to set ufrag to pwd. WebRTC connections will likely fail. Please report this issues."); } await pc!.setLocalDescription({ type: 'offer', sdp: sdpOffer }); From 43652296e4db8293b6442f8494c9075bf3b4de57 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 10:45:04 +0200 Subject: [PATCH 46/48] Ooops, wrong variant was used --- bin/wasm-node/javascript/src/base64.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/base64.ts b/bin/wasm-node/javascript/src/base64.ts index d43a238dca..57df72ab00 100644 --- a/bin/wasm-node/javascript/src/base64.ts +++ b/bin/wasm-node/javascript/src/base64.ts @@ -42,7 +42,7 @@ export function multibaseBase64Decode(input: string): Uint8Array { return classicDecode(input.slice(1)) case 'u': case 'U': - return classicDecode(input.slice(1)) + return urlSafeDecode(input.slice(1)) default: throw new Error('Unknown multibase prefix: ' + input[0]); } From 64f82ba67672fcdb8a478402672015d0e7cd1746 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 11:20:13 +0200 Subject: [PATCH 47/48] Add certificate hash field --- bin/wasm-node/javascript/src/index-browser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index ee18c16226..076afb20c7 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -183,7 +183,7 @@ export function start(options?: ClientOptions): Client { // set it explicitly as part of the configuration. // According to , // browsers are guaranteed to support `{ name: "ECDSA", namedCurve: "P-256" }`. - RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256" } as EcKeyGenParams).then((localCertificate) => { + RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" } as EcKeyGenParams).then((localCertificate) => { if (cancelOpening) return; From 683a81a247df33f7655716054db98948da768d92 Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Tue, 20 Sep 2022 11:22:47 +0200 Subject: [PATCH 48/48] Address review --- bin/wasm-node/javascript/src/index-browser.ts | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/bin/wasm-node/javascript/src/index-browser.ts b/bin/wasm-node/javascript/src/index-browser.ts index 076afb20c7..ec03dcd124 100644 --- a/bin/wasm-node/javascript/src/index-browser.ts +++ b/bin/wasm-node/javascript/src/index-browser.ts @@ -227,11 +227,7 @@ export function start(options?: ClientOptions): Client { channel.onmessage = null; } - pc!.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. - - for (const channel of Array.from(dataChannels.values())) { - channel.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. - } + pc!.close(); // Not necessarily necessary, but it doesn't hurt to do so. dataChannels.clear(); } }; @@ -239,9 +235,8 @@ export function start(options?: ClientOptions): Client { pc.onnegotiationneeded = async (_event) => { // Create a new offer and set it as local description. let sdpOffer = (await pc!.createOffer()).sdp!; - // The server excepts the ufrag and pwd to be the same. Modify the local description - // to ensure that. - // TODO: why does the server want that? + // According to the libp2p WebRTC spec, the ufrag and pwd are the same + // randomly-generated string. We modify the local description to ensure that. const pwd = sdpOffer.match(/^a=ice-pwd:(.+)$/m); if (pwd != null) { sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + pwd[1]); @@ -357,10 +352,6 @@ export function start(options?: ClientOptions): Client { } pc.close(); - - for (const channel of Array.from(dataChannels.values())) { - channel.close(); // Unclear whether this is necessary, but it doesn't hurt to do so. - } dataChannels.clear(); } else {