wire-mesh-core 3.2.0 → 3.3.1
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/adapters/byte-stream-connection.cjs +1 -2
- package/dist/adapters/byte-stream-connection.mjs +1 -2
- package/dist/domain/mesh-session.cjs +4 -0
- package/dist/domain/mesh-session.mjs +4 -0
- package/dist/domain/pinned-address.cjs +9 -8
- package/dist/domain/pinned-address.d.cts +8 -8
- package/dist/domain/pinned-address.d.mts +8 -8
- package/dist/domain/pinned-address.mjs +9 -8
- package/package.json +1 -1
|
@@ -67,8 +67,7 @@ function connectionFromByteStream(stream, options = { opened: false }) {
|
|
|
67
67
|
},
|
|
68
68
|
receive: () => frames,
|
|
69
69
|
close: async () => {
|
|
70
|
-
await writer.close();
|
|
71
|
-
await reader.cancel();
|
|
70
|
+
await Promise.allSettled([writer.close(), reader.cancel()]);
|
|
72
71
|
}
|
|
73
72
|
};
|
|
74
73
|
}
|
|
@@ -66,8 +66,7 @@ function connectionFromByteStream(stream, options = { opened: false }) {
|
|
|
66
66
|
},
|
|
67
67
|
receive: () => frames,
|
|
68
68
|
close: async () => {
|
|
69
|
-
await writer.close();
|
|
70
|
-
await reader.cancel();
|
|
69
|
+
await Promise.allSettled([writer.close(), reader.cancel()]);
|
|
71
70
|
}
|
|
72
71
|
};
|
|
73
72
|
}
|
|
@@ -19,6 +19,9 @@ function createRelayPairings() {
|
|
|
19
19
|
remove: (device) => {
|
|
20
20
|
established.delete(require_domain_device_id.deviceIdToHex(device));
|
|
21
21
|
},
|
|
22
|
+
clear: () => {
|
|
23
|
+
established.clear();
|
|
24
|
+
},
|
|
22
25
|
list: () => [...established.values()]
|
|
23
26
|
};
|
|
24
27
|
}
|
|
@@ -560,6 +563,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
560
563
|
async function wireUpConnection(link, address, localDomains) {
|
|
561
564
|
connection = link;
|
|
562
565
|
relayChannels.reset("the connection changed before the channel was ready");
|
|
566
|
+
relayPairings.clear();
|
|
563
567
|
localHandshakeSent = localHandshake(localDomains);
|
|
564
568
|
handshake = { status: "pending" };
|
|
565
569
|
state = {
|
|
@@ -18,6 +18,9 @@ function createRelayPairings() {
|
|
|
18
18
|
remove: (device) => {
|
|
19
19
|
established.delete(deviceIdToHex(device));
|
|
20
20
|
},
|
|
21
|
+
clear: () => {
|
|
22
|
+
established.clear();
|
|
23
|
+
},
|
|
21
24
|
list: () => [...established.values()]
|
|
22
25
|
};
|
|
23
26
|
}
|
|
@@ -559,6 +562,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
559
562
|
async function wireUpConnection(link, address, localDomains) {
|
|
560
563
|
connection = link;
|
|
561
564
|
relayChannels.reset("the connection changed before the channel was ready");
|
|
565
|
+
relayPairings.clear();
|
|
562
566
|
localHandshakeSent = localHandshake(localDomains);
|
|
563
567
|
handshake = { status: "pending" };
|
|
564
568
|
state = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#region src/domain/pinned-address.ts
|
|
3
3
|
const PIN_FRAGMENT = "#sha256=";
|
|
4
|
+
const HASH_SEPARATOR = ",";
|
|
4
5
|
const SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;
|
|
5
6
|
function hexToBytes(hex) {
|
|
6
7
|
const bytes = new Uint8Array(hex.length / 2);
|
|
@@ -8,29 +9,29 @@ function hexToBytes(hex) {
|
|
|
8
9
|
return bytes;
|
|
9
10
|
}
|
|
10
11
|
/**
|
|
11
|
-
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex
|
|
12
|
+
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex>[,<hex>...]`, the address and the hashes of the certificates it serves now and will serve next. A client that pins the hashes needs nothing else from the network to trust the node, so they travel with the address in one string, which `wire-candidate.address` already permits.
|
|
12
13
|
*/
|
|
13
14
|
function formatPinnedAddress(hostPort, sha256Hex) {
|
|
14
|
-
return `https://${hostPort}${PIN_FRAGMENT}${sha256Hex}`;
|
|
15
|
+
return `https://${hostPort}${PIN_FRAGMENT}${sha256Hex.join(HASH_SEPARATOR)}`;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
|
-
* Whether an address carries
|
|
18
|
+
* Whether an address carries certificate pins, and so is dialled over WebTransport rather than WebSocket.
|
|
18
19
|
*/
|
|
19
20
|
function isPinnedAddress(address) {
|
|
20
21
|
return address.startsWith("https://") && address.includes(PIN_FRAGMENT);
|
|
21
22
|
}
|
|
22
23
|
/**
|
|
23
|
-
* Splits an address of the form `https://host:port#sha256=<hex
|
|
24
|
-
* @throws Error when the address is not `https://` or
|
|
24
|
+
* Splits an address of the form `https://host:port#sha256=<hex>[,<hex>...]`.
|
|
25
|
+
* @throws Error when the address is not `https://` or does not carry one or more 64-digit lowercase hex hashes.
|
|
25
26
|
*/
|
|
26
27
|
function parsePinnedAddress(address) {
|
|
27
28
|
const url = new URL(address);
|
|
28
|
-
const
|
|
29
|
-
if (url.protocol !== "https:" || !SHA256_HEX_PATTERN.test(
|
|
29
|
+
const hashes = url.hash.startsWith(PIN_FRAGMENT) ? url.hash.slice(8).split(HASH_SEPARATOR) : [];
|
|
30
|
+
if (url.protocol !== "https:" || hashes.length === 0 || !hashes.every((hash) => SHA256_HEX_PATTERN.test(hash))) throw new Error(`expected "https://host:port${PIN_FRAGMENT}<64 hex digits>[${HASH_SEPARATOR}<64 hex digits>...]", got "${address}"`);
|
|
30
31
|
url.hash = "";
|
|
31
32
|
return {
|
|
32
33
|
url: url.toString(),
|
|
33
|
-
sha256: hexToBytes
|
|
34
|
+
sha256: hashes.map(hexToBytes)
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
//#endregion
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
//#region src/domain/pinned-address.d.ts
|
|
2
|
-
/** A WebTransport address and the SHA-256
|
|
2
|
+
/** A WebTransport address and the SHA-256 hashes of the certificates it may serve. */
|
|
3
3
|
export interface PinnedAddress {
|
|
4
4
|
/** `https://host:port/`, the URL to open. */
|
|
5
5
|
readonly url: string;
|
|
6
|
-
/**
|
|
7
|
-
readonly sha256: Uint8Array<ArrayBuffer
|
|
6
|
+
/** Each acceptable certificate's SHA-256 hash, as bytes. A browser accepts the server's certificate when it matches any of them, so a node can list the certificates it will serve next and an address stays usable across its renewals. */
|
|
7
|
+
readonly sha256: readonly Uint8Array<ArrayBuffer>[];
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex
|
|
10
|
+
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex>[,<hex>...]`, the address and the hashes of the certificates it serves now and will serve next. A client that pins the hashes needs nothing else from the network to trust the node, so they travel with the address in one string, which `wire-candidate.address` already permits.
|
|
11
11
|
*/
|
|
12
|
-
export declare function formatPinnedAddress(hostPort: string, sha256Hex: string): string;
|
|
12
|
+
export declare function formatPinnedAddress(hostPort: string, sha256Hex: readonly string[]): string;
|
|
13
13
|
/**
|
|
14
|
-
* Whether an address carries
|
|
14
|
+
* Whether an address carries certificate pins, and so is dialled over WebTransport rather than WebSocket.
|
|
15
15
|
*/
|
|
16
16
|
export declare function isPinnedAddress(address: string): boolean;
|
|
17
17
|
/**
|
|
18
|
-
* Splits an address of the form `https://host:port#sha256=<hex
|
|
19
|
-
* @throws Error when the address is not `https://` or
|
|
18
|
+
* Splits an address of the form `https://host:port#sha256=<hex>[,<hex>...]`.
|
|
19
|
+
* @throws Error when the address is not `https://` or does not carry one or more 64-digit lowercase hex hashes.
|
|
20
20
|
*/
|
|
21
21
|
export declare function parsePinnedAddress(address: string): PinnedAddress;
|
|
22
22
|
//#endregion
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
//#region src/domain/pinned-address.d.ts
|
|
2
|
-
/** A WebTransport address and the SHA-256
|
|
2
|
+
/** A WebTransport address and the SHA-256 hashes of the certificates it may serve. */
|
|
3
3
|
export interface PinnedAddress {
|
|
4
4
|
/** `https://host:port/`, the URL to open. */
|
|
5
5
|
readonly url: string;
|
|
6
|
-
/**
|
|
7
|
-
readonly sha256: Uint8Array<ArrayBuffer
|
|
6
|
+
/** Each acceptable certificate's SHA-256 hash, as bytes. A browser accepts the server's certificate when it matches any of them, so a node can list the certificates it will serve next and an address stays usable across its renewals. */
|
|
7
|
+
readonly sha256: readonly Uint8Array<ArrayBuffer>[];
|
|
8
8
|
}
|
|
9
9
|
/**
|
|
10
|
-
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex
|
|
10
|
+
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex>[,<hex>...]`, the address and the hashes of the certificates it serves now and will serve next. A client that pins the hashes needs nothing else from the network to trust the node, so they travel with the address in one string, which `wire-candidate.address` already permits.
|
|
11
11
|
*/
|
|
12
|
-
export declare function formatPinnedAddress(hostPort: string, sha256Hex: string): string;
|
|
12
|
+
export declare function formatPinnedAddress(hostPort: string, sha256Hex: readonly string[]): string;
|
|
13
13
|
/**
|
|
14
|
-
* Whether an address carries
|
|
14
|
+
* Whether an address carries certificate pins, and so is dialled over WebTransport rather than WebSocket.
|
|
15
15
|
*/
|
|
16
16
|
export declare function isPinnedAddress(address: string): boolean;
|
|
17
17
|
/**
|
|
18
|
-
* Splits an address of the form `https://host:port#sha256=<hex
|
|
19
|
-
* @throws Error when the address is not `https://` or
|
|
18
|
+
* Splits an address of the form `https://host:port#sha256=<hex>[,<hex>...]`.
|
|
19
|
+
* @throws Error when the address is not `https://` or does not carry one or more 64-digit lowercase hex hashes.
|
|
20
20
|
*/
|
|
21
21
|
export declare function parsePinnedAddress(address: string): PinnedAddress;
|
|
22
22
|
//#endregion
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//#region src/domain/pinned-address.ts
|
|
2
2
|
const PIN_FRAGMENT = "#sha256=";
|
|
3
|
+
const HASH_SEPARATOR = ",";
|
|
3
4
|
const SHA256_HEX_PATTERN = /^[0-9a-f]{64}$/;
|
|
4
5
|
function hexToBytes(hex) {
|
|
5
6
|
const bytes = new Uint8Array(hex.length / 2);
|
|
@@ -7,29 +8,29 @@ function hexToBytes(hex) {
|
|
|
7
8
|
return bytes;
|
|
8
9
|
}
|
|
9
10
|
/**
|
|
10
|
-
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex
|
|
11
|
+
* The address a node advertises for WebTransport: `https://host:port#sha256=<hex>[,<hex>...]`, the address and the hashes of the certificates it serves now and will serve next. A client that pins the hashes needs nothing else from the network to trust the node, so they travel with the address in one string, which `wire-candidate.address` already permits.
|
|
11
12
|
*/
|
|
12
13
|
function formatPinnedAddress(hostPort, sha256Hex) {
|
|
13
|
-
return `https://${hostPort}${PIN_FRAGMENT}${sha256Hex}`;
|
|
14
|
+
return `https://${hostPort}${PIN_FRAGMENT}${sha256Hex.join(HASH_SEPARATOR)}`;
|
|
14
15
|
}
|
|
15
16
|
/**
|
|
16
|
-
* Whether an address carries
|
|
17
|
+
* Whether an address carries certificate pins, and so is dialled over WebTransport rather than WebSocket.
|
|
17
18
|
*/
|
|
18
19
|
function isPinnedAddress(address) {
|
|
19
20
|
return address.startsWith("https://") && address.includes(PIN_FRAGMENT);
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
|
-
* Splits an address of the form `https://host:port#sha256=<hex
|
|
23
|
-
* @throws Error when the address is not `https://` or
|
|
23
|
+
* Splits an address of the form `https://host:port#sha256=<hex>[,<hex>...]`.
|
|
24
|
+
* @throws Error when the address is not `https://` or does not carry one or more 64-digit lowercase hex hashes.
|
|
24
25
|
*/
|
|
25
26
|
function parsePinnedAddress(address) {
|
|
26
27
|
const url = new URL(address);
|
|
27
|
-
const
|
|
28
|
-
if (url.protocol !== "https:" || !SHA256_HEX_PATTERN.test(
|
|
28
|
+
const hashes = url.hash.startsWith(PIN_FRAGMENT) ? url.hash.slice(8).split(HASH_SEPARATOR) : [];
|
|
29
|
+
if (url.protocol !== "https:" || hashes.length === 0 || !hashes.every((hash) => SHA256_HEX_PATTERN.test(hash))) throw new Error(`expected "https://host:port${PIN_FRAGMENT}<64 hex digits>[${HASH_SEPARATOR}<64 hex digits>...]", got "${address}"`);
|
|
29
30
|
url.hash = "";
|
|
30
31
|
return {
|
|
31
32
|
url: url.toString(),
|
|
32
|
-
sha256: hexToBytes
|
|
33
|
+
sha256: hashes.map(hexToBytes)
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
//#endregion
|