smoldot 3.6.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/internals/bytecode/wasm0.js +1 -1
- package/dist/cjs/internals/bytecode/wasm1.js +1 -1
- package/dist/cjs/internals/bytecode/wasm2.js +1 -1
- package/dist/cjs/internals/bytecode/wasm3.js +1 -1
- package/dist/cjs/internals/dns-over-https.d.ts +31 -0
- package/dist/cjs/internals/dns-over-https.js +255 -0
- package/dist/cjs/internals/local-instance.d.ts +7 -1
- package/dist/cjs/internals/local-instance.js +13 -3
- package/dist/cjs/no-auto-bytecode-browser.js +65 -13
- package/dist/mjs/internals/bytecode/wasm0.js +1 -1
- package/dist/mjs/internals/bytecode/wasm1.js +1 -1
- package/dist/mjs/internals/bytecode/wasm2.js +1 -1
- package/dist/mjs/internals/bytecode/wasm3.js +1 -1
- package/dist/mjs/internals/dns-over-https.d.ts +31 -0
- package/dist/mjs/internals/dns-over-https.js +249 -0
- package/dist/mjs/internals/local-instance.d.ts +7 -1
- package/dist/mjs/internals/local-instance.js +13 -3
- package/dist/mjs/no-auto-bytecode-browser.js +65 -13
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
13
|
import { start as innerStart } from './internals/client.js';
|
|
14
|
+
import { resolveDnsOverHttps } from './internals/dns-over-https.js';
|
|
14
15
|
export { AddChainError, AlreadyDestroyedError, CrashError, JsonRpcDisabledError, QueueFullError } from './public-types.js';
|
|
15
16
|
/**
|
|
16
17
|
* Initializes a new client. This is a pre-requisite to connecting to a blockchain.
|
|
@@ -185,17 +186,46 @@ function connect(config) {
|
|
|
185
186
|
openOutSubstream: () => { throw new Error('Connection is closed'); },
|
|
186
187
|
};
|
|
187
188
|
}
|
|
188
|
-
const { targetPort,
|
|
189
|
+
const { targetPort, remoteTlsCertificateSha256 } = config.address;
|
|
189
190
|
const state = {
|
|
190
191
|
pc: undefined,
|
|
191
192
|
dataChannels: new Map(),
|
|
192
193
|
nextStreamId: 0,
|
|
193
194
|
isFirstOutSubstream: true,
|
|
195
|
+
dnsAbort: null,
|
|
194
196
|
};
|
|
197
|
+
// The SDP answer needs the literal IP address of the remote.
|
|
198
|
+
// Browsers expose no DNS API, so a multiaddress with a domain name is resolved over
|
|
199
|
+
// DNS-over-HTTPS. Resolution is started here and is only awaited in
|
|
200
|
+
// `onnegotiationneeded`, where the IP is actually needed.
|
|
201
|
+
let target;
|
|
202
|
+
if ("targetIp" in config.address) {
|
|
203
|
+
target = Promise.resolve({ targetIp: config.address.targetIp, ipVersion: config.address.ipVersion });
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const { hostname, family } = config.address;
|
|
207
|
+
const controller = new AbortController();
|
|
208
|
+
state.dnsAbort = controller;
|
|
209
|
+
const timeout = setTimeout(() => controller.abort(), 10000);
|
|
210
|
+
const finished = () => {
|
|
211
|
+
clearTimeout(timeout);
|
|
212
|
+
state.dnsAbort = null;
|
|
213
|
+
};
|
|
214
|
+
target = resolveDnsOverHttps(hostname, family, controller.signal).then((ip) => {
|
|
215
|
+
finished();
|
|
216
|
+
return { targetIp: ip, ipVersion: ip.includes(':') ? 6 : 4 };
|
|
217
|
+
}, (error) => {
|
|
218
|
+
finished();
|
|
219
|
+
throw error;
|
|
220
|
+
});
|
|
221
|
+
target.catch(() => { });
|
|
222
|
+
}
|
|
195
223
|
// Kills all the JavaScript objects (the connection and all its substreams), ensuring that no
|
|
196
224
|
// callback will be called again. Doesn't report anything to smoldot, as this should be done
|
|
197
225
|
// by the caller.
|
|
198
226
|
const killAllJs = () => {
|
|
227
|
+
if (state.dnsAbort)
|
|
228
|
+
state.dnsAbort.abort();
|
|
199
229
|
// The `RTCPeerConnection` is created pretty quickly. It is however still possible for
|
|
200
230
|
// smoldot to cancel the opening, in which case `pc` will still be undefined.
|
|
201
231
|
if (!state.pc) {
|
|
@@ -216,6 +246,18 @@ function connect(config) {
|
|
|
216
246
|
state.dataChannels.clear();
|
|
217
247
|
state.pc.close(); // Not necessarily necessary, but it doesn't hurt to do so.
|
|
218
248
|
};
|
|
249
|
+
// Due to <https://bugzilla.mozilla.org/show_bug.cgi?id=1659672>,
|
|
250
|
+
// connections from Firefox to a localhost WebRTC server always fail:
|
|
251
|
+
// Firefox gathers no loopback ICE candidate.
|
|
252
|
+
//
|
|
253
|
+
// Returns `true` if the connection was refused, in which case the caller must stop.
|
|
254
|
+
const refuseIfFirefoxLoopback = (ip) => {
|
|
255
|
+
if ((ip !== '127.0.0.1' && ip !== '::1') || navigator.userAgent.indexOf('Firefox') === -1)
|
|
256
|
+
return false;
|
|
257
|
+
killAllJs();
|
|
258
|
+
config.onConnectionReset("Firefox can't connect to a localhost WebRTC server");
|
|
259
|
+
return true;
|
|
260
|
+
};
|
|
219
261
|
// Function that configures a newly-opened channel and adds it to the map. Used for both
|
|
220
262
|
// inbound and outbound substreams.
|
|
221
263
|
const addChannel = (dataChannel, direction) => {
|
|
@@ -278,19 +320,10 @@ function connect(config) {
|
|
|
278
320
|
RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256", hash: "SHA-256" }).then((localCertificate) => __awaiter(this, void 0, void 0, function* () {
|
|
279
321
|
if (state.pc === null)
|
|
280
322
|
return;
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
// term. In order to provider better user feedback, we straight up refuse connecting
|
|
285
|
-
// and stop the connection.
|
|
286
|
-
// Note that this is just a hint. Failing to detect this will lead to the WebRTC
|
|
287
|
-
// handshake timing out.
|
|
288
|
-
// TODO: eventually remove this if the Firefox bug is fixed
|
|
289
|
-
if ((targetIp == 'localhost' || targetIp == '127.0.0.1' || targetIp == '::1') && navigator.userAgent.indexOf('Firefox') !== -1) {
|
|
290
|
-
killAllJs();
|
|
291
|
-
config.onConnectionReset("Firefox can't connect to a localhost WebRTC server");
|
|
323
|
+
// A literal loopback address can be refused before anything is created. A domain
|
|
324
|
+
// name is checked once resolved, in `onnegotiationneeded`.
|
|
325
|
+
if ("targetIp" in config.address && refuseIfFirefoxLoopback(config.address.targetIp))
|
|
292
326
|
return;
|
|
293
|
-
}
|
|
294
327
|
// Create a new WebRTC connection.
|
|
295
328
|
state.pc = new RTCPeerConnection({ certificates: [localCertificate] });
|
|
296
329
|
// We need to build the multihash corresponding to the local certificate.
|
|
@@ -365,6 +398,25 @@ function connect(config) {
|
|
|
365
398
|
sdpOffer = sdpOffer.replace(/^a=ice-ufrag.*$/m, 'a=ice-ufrag:' + ufragPwd);
|
|
366
399
|
sdpOffer = sdpOffer.replace(/^a=ice-pwd.*$/m, 'a=ice-pwd:' + ufragPwd);
|
|
367
400
|
yield state.pc.setLocalDescription({ type: 'offer', sdp: sdpOffer });
|
|
401
|
+
// The answer needs the literal IP address of the remote, resolution was already stared.
|
|
402
|
+
let targetIp;
|
|
403
|
+
let ipVersion;
|
|
404
|
+
try {
|
|
405
|
+
({ targetIp, ipVersion } = yield target);
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
// `reset()` aborts the resolution, and a failure reported through
|
|
409
|
+
// `onconnectionstatechange` closes the connection.
|
|
410
|
+
if (state.pc.signalingState === "closed")
|
|
411
|
+
return;
|
|
412
|
+
killAllJs();
|
|
413
|
+
config.onConnectionReset("DNS resolution failed: " + (error instanceof Error ? error.message : String(error)));
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (state.pc.signalingState === "closed")
|
|
417
|
+
return;
|
|
418
|
+
if (refuseIfFirefoxLoopback(targetIp))
|
|
419
|
+
return;
|
|
368
420
|
// Transform certificate hash into fingerprint (upper-hex; each byte separated by ":").
|
|
369
421
|
const fingerprint = Array.from(remoteTlsCertificateSha256).map((n) => ("0" + n.toString(16)).slice(-2).toUpperCase()).join(':');
|
|
370
422
|
// Note that the trailing line feed is important, as otherwise Chrome
|