wire-mesh-core 1.58.7 → 2.0.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/README.md +1 -0
- package/dist/adapters/frame-codec.d.cts +1 -1
- package/dist/adapters/frame-codec.d.mts +1 -1
- package/dist/adapters/node-identity.d.cts +2 -2
- package/dist/adapters/node-identity.d.mts +2 -2
- package/dist/adapters/tcp-transport.d.cts +1 -1
- package/dist/adapters/tcp-transport.d.mts +1 -1
- package/dist/adapters/threshold-identity.d.cts +2 -2
- package/dist/adapters/threshold-identity.d.mts +2 -2
- package/dist/adapters/threshold-wasm.d.cts +1 -1
- package/dist/adapters/threshold-wasm.d.mts +1 -1
- package/dist/adapters/tls-transport.d.cts +1 -1
- package/dist/adapters/tls-transport.d.mts +1 -1
- package/dist/domain/bulk.d.cts +2 -2
- package/dist/domain/bulk.d.mts +2 -2
- package/dist/domain/capability-grant.d.cts +3 -3
- package/dist/domain/capability-grant.d.mts +3 -3
- package/dist/domain/capability-request.d.cts +2 -2
- package/dist/domain/capability-request.d.mts +2 -2
- package/dist/domain/data-sync.d.cts +2 -2
- package/dist/domain/data-sync.d.mts +2 -2
- package/dist/domain/device-id.d.cts +1 -1
- package/dist/domain/device-id.d.mts +1 -1
- package/dist/domain/direct-manage-request.d.cts +2 -2
- package/dist/domain/direct-manage-request.d.mts +2 -2
- package/dist/domain/gossip-expansion.d.cts +1 -1
- package/dist/domain/gossip-expansion.d.mts +1 -1
- package/dist/domain/gossip-extensions.cjs +1 -1
- package/dist/domain/gossip-extensions.mjs +1 -1
- package/dist/domain/grant-candidates.d.cts +1 -1
- package/dist/domain/grant-candidates.d.mts +1 -1
- package/dist/domain/handshake.d.cts +1 -1
- package/dist/domain/handshake.d.mts +1 -1
- package/dist/domain/mesh-session.cjs +13 -10
- package/dist/domain/mesh-session.d.cts +3 -3
- package/dist/domain/mesh-session.d.mts +3 -3
- package/dist/domain/mesh-session.mjs +13 -10
- package/dist/domain/notice-board.d.cts +3 -3
- package/dist/domain/notice-board.d.mts +3 -3
- package/dist/domain/path-trace.d.cts +1 -1
- package/dist/domain/path-trace.d.mts +1 -1
- package/dist/domain/peer-advert.cjs +61 -0
- package/dist/domain/peer-advert.d.cts +45 -0
- package/dist/domain/peer-advert.d.mts +45 -0
- package/dist/domain/peer-advert.mjs +55 -0
- package/dist/domain/relay-hub.cjs +93 -5
- package/dist/domain/relay-hub.d.cts +32 -3
- package/dist/domain/relay-hub.d.mts +32 -3
- package/dist/domain/relay-hub.mjs +93 -5
- package/dist/domain/relay-use-gate.d.cts +2 -2
- package/dist/domain/relay-use-gate.d.mts +2 -2
- package/dist/domain/revocation-view.d.cts +2 -2
- package/dist/domain/revocation-view.d.mts +2 -2
- package/dist/domain/room-rekey.d.cts +3 -3
- package/dist/domain/room-rekey.d.mts +3 -3
- package/dist/domain/room-token-verification.d.cts +1 -1
- package/dist/domain/room-token-verification.d.mts +1 -1
- package/dist/domain/room.d.cts +4 -4
- package/dist/domain/room.d.mts +4 -4
- package/dist/domain/shard-manifest.d.cts +1 -1
- package/dist/domain/shard-manifest.d.mts +1 -1
- package/dist/domain/tokens.d.cts +1 -1
- package/dist/domain/tokens.d.mts +1 -1
- package/dist/domain/topology-snapshot.d.cts +1 -1
- package/dist/domain/topology-snapshot.d.mts +1 -1
- package/dist/domain/topology.cjs +1 -1
- package/dist/domain/topology.d.cts +1 -1
- package/dist/domain/topology.d.mts +1 -1
- package/dist/domain/topology.mjs +1 -1
- package/dist/domain/webrtc-signaling.d.cts +2 -2
- package/dist/domain/webrtc-signaling.d.mts +2 -2
- package/dist/generated/protocol.cjs +3 -1
- package/dist/generated/protocol.d.cts +1 -1
- package/dist/generated/protocol.d.mts +1 -1
- package/dist/generated/protocol.mjs +3 -1
- package/dist/{gossip-extensions-Cdy5mQhY.mjs → gossip-extensions-BNiI44sU.mjs} +5 -2
- package/dist/{gossip-extensions-Dr_T7hk_.cjs → gossip-extensions-DRVTHKnR.cjs} +5 -2
- package/dist/{identity-BRlM-Krs.d.cts → identity-DImeXZcq.d.cts} +1 -1
- package/dist/{identity-DiuayfEd.d.mts → identity-Dc4xmwp3.d.mts} +1 -1
- package/dist/ports/identity.d.cts +1 -1
- package/dist/ports/identity.d.mts +1 -1
- package/dist/ports/transport.d.cts +1 -1
- package/dist/ports/transport.d.mts +1 -1
- package/dist/{protocol-BnbpCk0Z.d.cts → protocol-Bi2fzBCc.d.cts} +20 -0
- package/dist/{protocol-BnbpCk0Z.d.mts → protocol-Bi2fzBCc.d.mts} +20 -0
- package/dist/{room-token-verification-NjaqYY4k.d.mts → room-token-verification-CDXkm_Tg.d.cts} +2 -2
- package/dist/{room-token-verification-D9ogJTO3.d.cts → room-token-verification-CnHNaA8J.d.mts} +2 -2
- package/dist/{tokens-DtjdYS_a.d.mts → tokens-0r9ipK1r.d.mts} +2 -2
- package/dist/{tokens-BL2BzOmN.d.cts → tokens-BDVxEvl2.d.cts} +2 -2
- package/dist/{transport-BH8kGWXt.d.mts → transport-Cq_odHy3.d.cts} +1 -1
- package/dist/{transport-Ca_ZyyZe.d.cts → transport-GcJ4LYVE.d.mts} +1 -1
- package/package.json +5 -1
- package/wasm-dist/wire_mesh_threshold_wasm_bg.wasm +0 -0
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ The TypeScript implementation of wire-mesh's protocol, built ports/adapters: dom
|
|
|
13
13
|
|
|
14
14
|
- **Handshake negotiation** (`src/domain/handshake.ts`) -- protocol-version and capability-domain negotiation between two peers, the mechanism agent-comms issue #31 is fixed by.
|
|
15
15
|
- **Capability-token verification** (`src/domain/tokens.ts`) -- the full chain tokens.cddl documents: COSE_Sign1 signature verification, the self-certifying issuer-key check (`sha256(issuer-key.public-key) == issuer`), expiry/not-before, issuer-matched revocation (only a token's own issuer's signed revocation-entry counts, checked across every ancestor in the delegation chain, not just the leaf), and recursive delegation-chain narrowing across all three axes of authority: a delegated token's issuer must be its parent's bearer (the chain is unbroken), its expiry must not exceed its parent's, and its scope must narrow its parent's (identical kind, equal-or-descendant path when the parent carries one) with an identical capability verb (the verb grammar has no sub-verb relation, so a different verb is different authority, not narrower). Also exports `verifyRevocationEntry` for ingesting gossiped revocation-announce frames: each entry is itself a signed, self-certifying COSE_Sign1 over revocation-claims, verified before it may enter the revocation view.
|
|
16
|
+
- **Peer-advert verification** (`src/domain/peer-advert.ts`): the two checks transport.cddl states for a gossiped advert, applied by the relay hub before it registers or forwards one and by every session before one reaches its directory: the embedded identity-key self-certifies (`sha256(identity-key.public-key) == device`), and the signature verifies under that same key over the domain-separated canonical encoding of the advert with its signature removed, which covers the open extension tail as well. Deliberately not tokens.cddl's COSE Sig_structure: an advert's open tail lets an attacker craft one whose encoding also satisfies token-claims, so the prefixed construction keeps the two byte strings disjoint. Reaches a verdict for every input rather than throwing, since an advert's algorithm and key bytes are attacker-chosen.
|
|
16
17
|
|
|
17
18
|
## Deliberately deferred
|
|
18
19
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-
|
|
1
|
+
import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
//#region src/adapters/frame-codec.d.ts
|
|
3
3
|
export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
|
|
4
4
|
/** Wraps frame as a relay-data-frame's own opaque payload, stamping to-device when the caller knows which established pairing to address it to (wire-mesh#30) -- the outbound counterpart to tryDecodeFrame's own doc comment below, which describes the inbound side of the same relay-data envelope. Omitting toDevice leaves the frame unaddressed, which the receiving hub then routes via its own most-recently-established-pairing fallback. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-
|
|
1
|
+
import { D as DeviceId, N as Frame, ht as RelayDataFrame } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
//#region src/adapters/frame-codec.d.ts
|
|
3
3
|
export declare function messageFromFrame(frame: Frame): Uint8Array<ArrayBuffer>;
|
|
4
4
|
/** Wraps frame as a relay-data-frame's own opaque payload, stamping to-device when the caller knows which established pairing to address it to (wire-mesh#30) -- the outbound counterpart to tryDecodeFrame's own doc comment below, which describes the inbound side of the same relay-data envelope. Omitting toDevice leaves the frame unaddressed, which the receiving hub then routes via its own most-recently-established-pairing fallback. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as IdentityKey, D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { B as IdentityKey, D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
3
3
|
import { webcrypto } from "node:crypto";
|
|
4
4
|
//#region src/adapters/node-identity.d.ts
|
|
5
5
|
export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { B as IdentityKey, D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { B as IdentityKey, D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
3
3
|
import { webcrypto } from "node:crypto";
|
|
4
4
|
//#region src/adapters/node-identity.d.ts
|
|
5
5
|
export declare function deriveDeviceId(publicKey: Uint8Array): Promise<DeviceId>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Transport } from "../transport-
|
|
1
|
+
import { r as Transport } from "../transport-Cq_odHy3.cjs";
|
|
2
2
|
//#region src/adapters/tcp-transport.d.ts
|
|
3
3
|
/** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
|
|
4
4
|
export declare function createTcpTransport(): Transport;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Transport } from "../transport-
|
|
1
|
+
import { r as Transport } from "../transport-GcJ4LYVE.mjs";
|
|
2
2
|
//#region src/adapters/tcp-transport.d.ts
|
|
3
3
|
/** A Node net.Socket-based Transport: length-prefixed, CBOR-encoded frames over plain TCP -- matching Cascade's own transport shape, since interop with Cascade nodes is wire-mesh's stated goal. Framing (not TLS) is this adapter's own concern; a TLS-terminated variant is a separate adapter behind the same Transport contract. */
|
|
4
4
|
export declare function createTcpTransport(): Transport;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
3
3
|
import { DeviceKeyed } from "./threshold-wasm.cjs";
|
|
4
4
|
import { ThresholdSubject } from "../domain/threshold-subject.cjs";
|
|
5
5
|
//#region src/adapters/threshold-identity.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
3
3
|
import { DeviceKeyed } from "./threshold-wasm.mjs";
|
|
4
4
|
import { ThresholdSubject } from "../domain/threshold-subject.mjs";
|
|
5
5
|
//#region src/adapters/threshold-identity.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
//#region src/adapters/threshold-wasm.d.ts
|
|
3
3
|
/** One `(deviceId, bytes)` pair -- the wasm boundary's own encoding of a map keyed by participant, since wasm-bindgen has no built-in `Map<Uint8Array, Uint8Array>` marshalling. */
|
|
4
4
|
export interface DeviceKeyed<T extends Uint8Array = Uint8Array<ArrayBuffer>> {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
//#region src/adapters/threshold-wasm.d.ts
|
|
3
3
|
/** One `(deviceId, bytes)` pair -- the wasm boundary's own encoding of a map keyed by participant, since wasm-bindgen has no built-in `Map<Uint8Array, Uint8Array>` marshalling. */
|
|
4
4
|
export interface DeviceKeyed<T extends Uint8Array = Uint8Array<ArrayBuffer>> {
|
package/dist/domain/bulk.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.cjs";
|
|
3
|
-
import { t as Connection } from "../transport-
|
|
3
|
+
import { t as Connection } from "../transport-Cq_odHy3.cjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
|
|
5
5
|
//#region src/domain/bulk.d.ts
|
|
6
6
|
/** The two capabilities matching the direction each manage-command actually flows (spec/bulk.cddl): the sender proves write authority to open a transfer, the receiver proves read authority to ask for one to continue. */
|
package/dist/domain/bulk.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, N as Frame, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.mjs";
|
|
3
|
-
import { t as Connection } from "../transport-
|
|
3
|
+
import { t as Connection } from "../transport-GcJ4LYVE.mjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
|
|
5
5
|
//#region src/domain/bulk.d.ts
|
|
6
6
|
/** The two capabilities matching the direction each manage-command actually flows (spec/bulk.cddl): the sender proves write authority to open a transfer, the receiver proves read authority to ask for one to continue. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
4
4
|
import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
|
|
5
|
-
import { a as RevocationCheck } from "../tokens-
|
|
5
|
+
import { a as RevocationCheck } from "../tokens-BDVxEvl2.cjs";
|
|
6
6
|
//#region src/domain/capability-grant.d.ts
|
|
7
7
|
/**
|
|
8
8
|
* Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
4
4
|
import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
|
|
5
|
-
import { a as RevocationCheck } from "../tokens-
|
|
5
|
+
import { a as RevocationCheck } from "../tokens-0r9ipK1r.mjs";
|
|
6
6
|
//#region src/domain/capability-grant.d.ts
|
|
7
7
|
/**
|
|
8
8
|
* Builds a capability-grant command per management.cddl. The outer `manage-command.verb` is the capability string itself, the identical convention capability-request.ts's own buildCapabilityRequestCommand already establishes -- a receiver's per-capability handler is how it knows which grant this push is even for. `params.verb` is the fixed "capability.grant" marker. No scope or invitee field: manage-request-frame's own top-level scope already carries the former, and the request's own destination already carries the latter -- naming either a second time inside params could only ever disagree with the fact it duplicates.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.cjs";
|
|
5
5
|
//#region src/domain/capability-request.d.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, u as CapabilityGrantOk } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
4
4
|
import { IncomingManageRequest, MeshSession } from "./mesh-session.mjs";
|
|
5
5
|
//#region src/domain/capability-request.d.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.cjs";
|
|
3
|
-
import { t as IdentityPort } from "../identity-
|
|
3
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
4
4
|
//#region src/domain/data-sync.d.ts
|
|
5
5
|
export interface DataSyncOptions {
|
|
6
6
|
identity: IdentityPort;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, T as DataHaveFrame, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.mjs";
|
|
3
|
-
import { t as IdentityPort } from "../identity-
|
|
3
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
4
4
|
//#region src/domain/data-sync.d.ts
|
|
5
5
|
export interface DataSyncOptions {
|
|
6
6
|
identity: IdentityPort;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
//#region src/domain/device-id.d.ts
|
|
3
3
|
/** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
|
|
4
4
|
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId } from "../protocol-
|
|
1
|
+
import { D as DeviceId } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
//#region src/domain/device-id.d.ts
|
|
3
3
|
/** Lowercase, byte-exact hex for an arbitrary-length byte string -- the same encoding convention deviceIdToHex uses for the fixed-length device-id case, extracted so any other byte string needing a stable, displayable, map-keyable text form (e.g. a token-id, which tokens.cddl defines as an arbitrary-length bstr rather than a 32-byte device-id) can use the identical convention without going through a device-id-shaped function. */
|
|
4
4
|
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
2
|
-
import { r as Transport, t as Connection } from "../transport-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { r as Transport, t as Connection } from "../transport-Cq_odHy3.cjs";
|
|
3
3
|
import { IncomingManageRequest, ManageOutcome } from "./mesh-session.cjs";
|
|
4
4
|
//#region src/domain/direct-manage-request.d.ts
|
|
5
5
|
/** Reads exactly one frame off a freshly-accepted, bare connection and, if it's a manage-request, returns an IncomingManageRequest ready to hand to the same application-level dispatch logic session.incomingManageRequests already feeds elsewhere -- no handshake or gossip is ever read or sent on this connection (wire-mesh#38: the manage-request/manage-response exchange has no dependency on handshake state at the dispatch layer, confirmed against mesh-session.ts's own applyManageRequest/applyFrame). respond() sends the manage-response directly and closes the connection, since a one-off request/response is this connection's entire purpose -- unlike a real MeshSession, there is nothing further to do with it afterwards. Resolves null, without closing the connection (that's the caller's call), for any other first frame or if the connection ends before one arrives: interpreting either case is a Transport.listen() caller's own business, e.g. peeking the first frame to route between this path and acceptMeshSession's own handshake path. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
2
|
-
import { r as Transport, t as Connection } from "../transport-
|
|
1
|
+
import { D as DeviceId, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { r as Transport, t as Connection } from "../transport-GcJ4LYVE.mjs";
|
|
3
3
|
import { IncomingManageRequest, ManageOutcome } from "./mesh-session.mjs";
|
|
4
4
|
//#region src/domain/direct-manage-request.d.ts
|
|
5
5
|
/** Reads exactly one frame off a freshly-accepted, bare connection and, if it's a manage-request, returns an IncomingManageRequest ready to hand to the same application-level dispatch logic session.incomingManageRequests already feeds elsewhere -- no handshake or gossip is ever read or sent on this connection (wire-mesh#38: the manage-request/manage-response exchange has no dependency on handshake state at the dispatch layer, confirmed against mesh-session.ts's own applyManageRequest/applyFrame). respond() sends the manage-response directly and closes the connection, since a one-off request/response is this connection's entire purpose -- unlike a real MeshSession, there is nothing further to do with it afterwards. Resolves null, without closing the connection (that's the caller's call), for any other first frame or if the connection ends before one arrives: interpreting either case is a Transport.listen() caller's own business, e.g. peeking the first frame to route between this path and acceptMeshSession's own handshake path. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, et as PeerAdvert } from "../protocol-
|
|
1
|
+
import { D as DeviceId, et as PeerAdvert } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { MeshSession } from "./mesh-session.cjs";
|
|
3
3
|
//#region src/domain/gossip-expansion.d.ts
|
|
4
4
|
/** One not-yet-considered device this session's gossip directory has surfaced, carrying only what a dial/trust decision needs: the device-id to decide identity, and the "host:port" addresses its own peer-advert claims are directly reachable at, in the order it advertised them. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, et as PeerAdvert } from "../protocol-
|
|
1
|
+
import { D as DeviceId, et as PeerAdvert } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { MeshSession } from "./mesh-session.mjs";
|
|
3
3
|
//#region src/domain/gossip-expansion.d.ts
|
|
4
4
|
/** One not-yet-considered device this session's gossip directory has surfaced, carrying only what a dial/trust decision needs: the device-id to decide identity, and the "host:port" addresses its own peer-advert claims are directly reachable at, in the order it advertised them. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_gossip_extensions = require("../gossip-extensions-
|
|
2
|
+
const require_gossip_extensions = require("../gossip-extensions-DRVTHKnR.cjs");
|
|
3
3
|
exports.TOPOLOGY_PEERS_GOSSIP_KEY = require_gossip_extensions.TOPOLOGY_PEERS_GOSSIP_KEY;
|
|
4
4
|
exports.validateGossipExtensions = require_gossip_extensions.validateGossipExtensions;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as validateGossipExtensions, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-
|
|
1
|
+
import { n as validateGossipExtensions, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-BNiI44sU.mjs";
|
|
2
2
|
export { TOPOLOGY_PEERS_GOSSIP_KEY, validateGossipExtensions };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, f as CapabilityScope } from "../protocol-
|
|
1
|
+
import { D as DeviceId, f as CapabilityScope } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { DirectoryEntry, MeshSession } from "./mesh-session.cjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/domain/grant-candidates.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, f as CapabilityScope } from "../protocol-
|
|
1
|
+
import { D as DeviceId, f as CapabilityScope } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { DirectoryEntry, MeshSession } from "./mesh-session.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/domain/grant-candidates.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-
|
|
1
|
+
import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
//#region src/domain/handshake.d.ts
|
|
3
3
|
/** The highest protocol version this build of core understands. */
|
|
4
4
|
export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-
|
|
1
|
+
import { A as DomainId, R as HandshakeFrame, lt as ProtocolVersion } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
//#region src/domain/handshake.d.ts
|
|
3
3
|
/** The highest protocol version this build of core understands. */
|
|
4
4
|
export declare const SUPPORTED_PROTOCOL_VERSION: ProtocolVersion;
|
|
@@ -4,7 +4,8 @@ const require_domain_handshake = require("./handshake.cjs");
|
|
|
4
4
|
const require_domain_async_queue = require("./async-queue.cjs");
|
|
5
5
|
const require_domain_ping_round_trips = require("./ping-round-trips.cjs");
|
|
6
6
|
const require_domain_topology_snapshot = require("./topology-snapshot.cjs");
|
|
7
|
-
const require_gossip_extensions = require("../gossip-extensions-
|
|
7
|
+
const require_gossip_extensions = require("../gossip-extensions-DRVTHKnR.cjs");
|
|
8
|
+
const require_domain_peer_advert = require("./peer-advert.cjs");
|
|
8
9
|
const require_adapters_frame_codec = require("../adapters/frame-codec.cjs");
|
|
9
10
|
//#region src/domain/relay-pairing.ts
|
|
10
11
|
function createRelayPairings() {
|
|
@@ -135,7 +136,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
135
136
|
}
|
|
136
137
|
incomingQueue.push(incoming);
|
|
137
138
|
}
|
|
138
|
-
function applyFrame(frame) {
|
|
139
|
+
async function applyFrame(frame) {
|
|
139
140
|
if (frame.type === "relay-data") {
|
|
140
141
|
const inner = require_adapters_frame_codec.tryDecodeFrame(frame.payload);
|
|
141
142
|
if (inner !== null && (inner.type === "manage-request" || inner.type === "manage-response")) {
|
|
@@ -159,6 +160,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
159
160
|
});
|
|
160
161
|
if (frame.type === "handshake") applyRemoteHandshake(frame);
|
|
161
162
|
else if (frame.type === "gossip") for (const advert of frame.peers) {
|
|
163
|
+
if (!await require_domain_peer_advert.verifyPeerAdvert(identity, advert)) continue;
|
|
162
164
|
directory.set(require_domain_device_id.deviceIdToHex(advert.device), {
|
|
163
165
|
device: advert.device,
|
|
164
166
|
advert
|
|
@@ -241,26 +243,27 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
241
243
|
async function consume(link, address, localDomains) {
|
|
242
244
|
for await (const frame of link.receive()) {
|
|
243
245
|
if (feedCancelled) return;
|
|
244
|
-
applyFrame(frame);
|
|
246
|
+
await applyFrame(frame);
|
|
245
247
|
await onFrame?.(link, frame);
|
|
246
248
|
emit();
|
|
247
249
|
}
|
|
248
250
|
onSessionEnd?.(link);
|
|
249
251
|
if (state.status === "connected") handleDisconnect("node closed the connection", address, localDomains);
|
|
250
252
|
}
|
|
251
|
-
/** Builds this side's own self-advert
|
|
252
|
-
function buildSelfAdvert(extensions) {
|
|
253
|
+
/** Builds this side's own self-advert and signs it with this node's own key (wire-mesh#225), which is what makes it usable by a receiver that learned of it through a hub or a gateway rather than directly from here. this node's own directly-reachable addresses (wire-mesh#38) are advertised, or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime, and every such key is covered by the signature. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
|
|
254
|
+
async function buildSelfAdvert(extensions) {
|
|
253
255
|
if (extensions !== void 0) require_gossip_extensions.validateGossipExtensions(extensions);
|
|
254
256
|
return {
|
|
255
257
|
type: "gossip",
|
|
256
|
-
peers: [{
|
|
258
|
+
peers: [await require_domain_peer_advert.signPeerAdvert(identity, {
|
|
257
259
|
...extensions,
|
|
258
260
|
[require_gossip_extensions.CORE_VERSION_GOSSIP_KEY]: require_gossip_extensions.OWN_VERSION,
|
|
259
261
|
[require_gossip_extensions.TOPOLOGY_PEERS_GOSSIP_KEY]: topology.compute(),
|
|
260
262
|
device: identity.deviceId,
|
|
261
263
|
addresses: [...addresses],
|
|
262
|
-
"snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND)
|
|
263
|
-
|
|
264
|
+
"snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND),
|
|
265
|
+
"identity-key": identity.identityKey
|
|
266
|
+
})]
|
|
264
267
|
};
|
|
265
268
|
}
|
|
266
269
|
/** Everything a connection needs once it exists, regardless of whether it was dialled (createMeshSession's own doConnect, below) or handed over already established (acceptMeshSession): send this side's handshake and self-advert, arm the handshake timeout, and start consuming frames. The two entry points differ only in how link itself came to exist and what address means for it -- a real dial target for one, a caller-chosen label for the other, since the Connection/Transport ports expose no remote-address concept of their own for an accepted connection. */
|
|
@@ -279,7 +282,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
279
282
|
});
|
|
280
283
|
await connection.send(localHandshakeSent);
|
|
281
284
|
emit();
|
|
282
|
-
const selfAdvert = buildSelfAdvert();
|
|
285
|
+
const selfAdvert = await buildSelfAdvert();
|
|
283
286
|
frameLog.push({
|
|
284
287
|
direction: "sent",
|
|
285
288
|
frame: selfAdvert
|
|
@@ -397,7 +400,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
397
400
|
},
|
|
398
401
|
async sendGossipUpdate(extensions) {
|
|
399
402
|
requireConnectedLink();
|
|
400
|
-
const frame = buildSelfAdvert(extensions);
|
|
403
|
+
const frame = await buildSelfAdvert(extensions);
|
|
401
404
|
frameLog.push({
|
|
402
405
|
direction: "sent",
|
|
403
406
|
frame
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.cjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
4
|
-
import { r as Transport, t as Connection } from "../transport-
|
|
4
|
+
import { r as Transport, t as Connection } from "../transport-Cq_odHy3.cjs";
|
|
5
5
|
//#region src/domain/mesh-session.d.ts
|
|
6
6
|
/** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
|
|
7
7
|
export declare const HANDSHAKE_TIMEOUT_MS = 3000;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-
|
|
2
|
-
import { t as IdentityPort } from "../identity-
|
|
1
|
+
import { D as DeviceId, E as DataRequestFrame, N as Frame, T as DataHaveFrame, U as ManageError, V as ManageCommand, W as ManageOk, bt as RevocationEntry, en as TopologyPeers, et as PeerAdvert, f as CapabilityScope, lt as ProtocolVersion, p as CapabilityToken, w as DataEntriesFrame } from "../protocol-Bi2fzBCc.mjs";
|
|
2
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
3
3
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
4
|
-
import { r as Transport, t as Connection } from "../transport-
|
|
4
|
+
import { r as Transport, t as Connection } from "../transport-GcJ4LYVE.mjs";
|
|
5
5
|
//#region src/domain/mesh-session.d.ts
|
|
6
6
|
/** How long to wait for the node's handshake before calling it unanswered. A relay-only node never sends one; that is a state to display, not an error. */
|
|
7
7
|
export declare const HANDSHAKE_TIMEOUT_MS = 3000;
|
|
@@ -3,7 +3,8 @@ import { negotiate } from "./handshake.mjs";
|
|
|
3
3
|
import { createAsyncQueue } from "./async-queue.mjs";
|
|
4
4
|
import { createPingRoundTrips } from "./ping-round-trips.mjs";
|
|
5
5
|
import { createTopologySnapshotTracker } from "./topology-snapshot.mjs";
|
|
6
|
-
import { a as isVersionGetCommand, i as OWN_VERSION, n as validateGossipExtensions, o as versionGetOutcome, r as CORE_VERSION_GOSSIP_KEY, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-
|
|
6
|
+
import { a as isVersionGetCommand, i as OWN_VERSION, n as validateGossipExtensions, o as versionGetOutcome, r as CORE_VERSION_GOSSIP_KEY, t as TOPOLOGY_PEERS_GOSSIP_KEY } from "../gossip-extensions-BNiI44sU.mjs";
|
|
7
|
+
import { signPeerAdvert, verifyPeerAdvert } from "./peer-advert.mjs";
|
|
7
8
|
import { tryDecodeFrame, wrapRelayData } from "../adapters/frame-codec.mjs";
|
|
8
9
|
//#region src/domain/relay-pairing.ts
|
|
9
10
|
function createRelayPairings() {
|
|
@@ -134,7 +135,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
134
135
|
}
|
|
135
136
|
incomingQueue.push(incoming);
|
|
136
137
|
}
|
|
137
|
-
function applyFrame(frame) {
|
|
138
|
+
async function applyFrame(frame) {
|
|
138
139
|
if (frame.type === "relay-data") {
|
|
139
140
|
const inner = tryDecodeFrame(frame.payload);
|
|
140
141
|
if (inner !== null && (inner.type === "manage-request" || inner.type === "manage-response")) {
|
|
@@ -158,6 +159,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
158
159
|
});
|
|
159
160
|
if (frame.type === "handshake") applyRemoteHandshake(frame);
|
|
160
161
|
else if (frame.type === "gossip") for (const advert of frame.peers) {
|
|
162
|
+
if (!await verifyPeerAdvert(identity, advert)) continue;
|
|
161
163
|
directory.set(deviceIdToHex(advert.device), {
|
|
162
164
|
device: advert.device,
|
|
163
165
|
advert
|
|
@@ -240,26 +242,27 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
240
242
|
async function consume(link, address, localDomains) {
|
|
241
243
|
for await (const frame of link.receive()) {
|
|
242
244
|
if (feedCancelled) return;
|
|
243
|
-
applyFrame(frame);
|
|
245
|
+
await applyFrame(frame);
|
|
244
246
|
await onFrame?.(link, frame);
|
|
245
247
|
emit();
|
|
246
248
|
}
|
|
247
249
|
onSessionEnd?.(link);
|
|
248
250
|
if (state.status === "connected") handleDisconnect("node closed the connection", address, localDomains);
|
|
249
251
|
}
|
|
250
|
-
/** Builds this side's own self-advert
|
|
251
|
-
function buildSelfAdvert(extensions) {
|
|
252
|
+
/** Builds this side's own self-advert and signs it with this node's own key (wire-mesh#225), which is what makes it usable by a receiver that learned of it through a hub or a gateway rather than directly from here. this node's own directly-reachable addresses (wire-mesh#38) are advertised, or none for a caller with nothing to offer (a browser client, which cannot accept inbound connections) -- either is an honest advert, not a stopgap. extensions merge onto peer-advert's own open `* tstr => any` tail -- the mechanism sendGossipUpdate uses to keep a gossiped fact (presence status, an accept/refuse policy, or any future domain's own) live over the connection's lifetime, and every such key is covered by the signature. Extensions, CORE_VERSION_GOSSIP_KEY, and topology/peers are all spread before the mandatory fields (never after) so a caller-supplied key of the same name can never shadow them on the wire -- validateGossipExtensions already rejects every such collision loudly, but the field order is kept safe in its own right rather than relying solely on the guard staying in sync. topology/peers (wire-mesh#180) is recomputed fresh on every call, the same "always current, never cached" treatment snapshot-seconds already gets, since a session's own connection identity and relay pairings can change between one self-advert and the next. */
|
|
253
|
+
async function buildSelfAdvert(extensions) {
|
|
252
254
|
if (extensions !== void 0) validateGossipExtensions(extensions);
|
|
253
255
|
return {
|
|
254
256
|
type: "gossip",
|
|
255
|
-
peers: [{
|
|
257
|
+
peers: [await signPeerAdvert(identity, {
|
|
256
258
|
...extensions,
|
|
257
259
|
[CORE_VERSION_GOSSIP_KEY]: OWN_VERSION,
|
|
258
260
|
[TOPOLOGY_PEERS_GOSSIP_KEY]: topology.compute(),
|
|
259
261
|
device: identity.deviceId,
|
|
260
262
|
addresses: [...addresses],
|
|
261
|
-
"snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND)
|
|
262
|
-
|
|
263
|
+
"snapshot-seconds": Math.floor(clock.now() / MS_PER_SECOND),
|
|
264
|
+
"identity-key": identity.identityKey
|
|
265
|
+
})]
|
|
263
266
|
};
|
|
264
267
|
}
|
|
265
268
|
/** Everything a connection needs once it exists, regardless of whether it was dialled (createMeshSession's own doConnect, below) or handed over already established (acceptMeshSession): send this side's handshake and self-advert, arm the handshake timeout, and start consuming frames. The two entry points differ only in how link itself came to exist and what address means for it -- a real dial target for one, a caller-chosen label for the other, since the Connection/Transport ports expose no remote-address concept of their own for an accepted connection. */
|
|
@@ -278,7 +281,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
278
281
|
});
|
|
279
282
|
await connection.send(localHandshakeSent);
|
|
280
283
|
emit();
|
|
281
|
-
const selfAdvert = buildSelfAdvert();
|
|
284
|
+
const selfAdvert = await buildSelfAdvert();
|
|
282
285
|
frameLog.push({
|
|
283
286
|
direction: "sent",
|
|
284
287
|
frame: selfAdvert
|
|
@@ -396,7 +399,7 @@ function createSessionCore(identity, clock, reconnect, dial, onPeerAdvert, addre
|
|
|
396
399
|
},
|
|
397
400
|
async sendGossipUpdate(extensions) {
|
|
398
401
|
requireConnectedLink();
|
|
399
|
-
const frame = buildSelfAdvert(extensions);
|
|
402
|
+
const frame = await buildSelfAdvert(extensions);
|
|
400
403
|
frameLog.push({
|
|
401
404
|
direction: "sent",
|
|
402
405
|
frame
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.cjs";
|
|
3
|
-
import { t as IdentityPort } from "../identity-
|
|
3
|
+
import { t as IdentityPort } from "../identity-DImeXZcq.cjs";
|
|
4
4
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
5
|
-
import { a as RevocationCheck } from "../tokens-
|
|
5
|
+
import { a as RevocationCheck } from "../tokens-BDVxEvl2.cjs";
|
|
6
6
|
import { RoomNoticeVerdictReason } from "./room.cjs";
|
|
7
7
|
//#region src/domain/notice-board.d.ts
|
|
8
8
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, Ot as RoomNotice, T as DataHaveFrame, kt as RoomNoticeClaims, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { KeyValueStorage } from "../ports/storage.mjs";
|
|
3
|
-
import { t as IdentityPort } from "../identity-
|
|
3
|
+
import { t as IdentityPort } from "../identity-Dc4xmwp3.mjs";
|
|
4
4
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
5
|
-
import { a as RevocationCheck } from "../tokens-
|
|
5
|
+
import { a as RevocationCheck } from "../tokens-0r9ipK1r.mjs";
|
|
6
6
|
import { RoomNoticeVerdictReason } from "./room.mjs";
|
|
7
7
|
//#region src/domain/notice-board.d.ts
|
|
8
8
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.cjs";
|
|
2
2
|
import { t as Clock } from "../clock-DiSx-WKM.cjs";
|
|
3
3
|
import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.cjs";
|
|
4
4
|
//#region src/domain/path-trace.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-
|
|
1
|
+
import { D as DeviceId, H as ManageCommandParams, Q as PathTrace, V as ManageCommand, f as CapabilityScope, p as CapabilityToken } from "../protocol-Bi2fzBCc.mjs";
|
|
2
2
|
import { t as Clock } from "../clock-DiSx-WKM.mjs";
|
|
3
3
|
import { IncomingManageRequest, ManageOutcome, MeshSession } from "./mesh-session.mjs";
|
|
4
4
|
//#region src/domain/path-trace.d.ts
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_token_scope = require("../token-scope-CxHXTT3u.cjs");
|
|
3
|
+
let cbor2 = require("cbor2");
|
|
4
|
+
//#region src/domain/peer-advert.ts
|
|
5
|
+
/** peer-advert's own signature field, the one entry the signature does not cover, named once here so the signing input and the reserved-extension-key guard cannot drift apart. */
|
|
6
|
+
const PEER_ADVERT_SIGNATURE_KEY = "signature";
|
|
7
|
+
/** peer-advert's own self-certifying key field. Covered by the signature like every other entry, so an advert cannot be re-keyed after signing. */
|
|
8
|
+
const PEER_ADVERT_IDENTITY_KEY_KEY = "identity-key";
|
|
9
|
+
/**
|
|
10
|
+
* The domain-separation prefix every peer-advert signature is computed over, per spec/transport.cddl: the ASCII string "wire-mesh/peer-advert/v1" followed by one zero byte.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately not tokens.cddl's COSE Sig_structure, which every other signature in this codebase reuses via sig1ToBeSigned. An advert's extension tail is an open `* tstr => any` map, so an attacker can craft an advert whose canonical encoding also satisfies token-claims; a Sig_structure over that encoding would then be replayable as a capability token's own signed payload. This prefix makes the two byte strings disjoint by construction, since a Sig_structure always begins with the CBOR head of a 4-element array (0x84) rather than the ASCII "w" this one starts with.
|
|
13
|
+
*/
|
|
14
|
+
const PEER_ADVERT_SIGNING_CONTEXT = new TextEncoder().encode("wire-mesh/peer-advert/v1\0");
|
|
15
|
+
/**
|
|
16
|
+
* The exact bytes a peer-advert's signature is computed over: PEER_ADVERT_SIGNING_CONTEXT followed by the canonical CDE encoding of the advert with its `signature` entry removed and nothing else changed.
|
|
17
|
+
*
|
|
18
|
+
* Takes the advert rather than a pre-stripped copy so a verifier derives the input from precisely the bytes it received, leaving no room for the signed and checked views of an advert to disagree.
|
|
19
|
+
*/
|
|
20
|
+
function peerAdvertSigningInput(advert) {
|
|
21
|
+
const content = {};
|
|
22
|
+
for (const [key, value] of Object.entries(advert)) {
|
|
23
|
+
if (key === "signature") continue;
|
|
24
|
+
content[key] = value;
|
|
25
|
+
}
|
|
26
|
+
const encoded = (0, cbor2.encode)(content, cbor2.cdeEncodeOptions);
|
|
27
|
+
const input = new Uint8Array(PEER_ADVERT_SIGNING_CONTEXT.length + encoded.length);
|
|
28
|
+
input.set(PEER_ADVERT_SIGNING_CONTEXT, 0);
|
|
29
|
+
input.set(encoded, PEER_ADVERT_SIGNING_CONTEXT.length);
|
|
30
|
+
return input;
|
|
31
|
+
}
|
|
32
|
+
/** Signs an advert's content into the complete peer-advert that goes on the wire. The caller supplies `device` and `identity-key` itself rather than having them read off the signer, since the signer port carries only `sign`: a node building its own self-advert already holds both, and nothing else may legitimately sign an advert at all. */
|
|
33
|
+
async function signPeerAdvert(identity, advert) {
|
|
34
|
+
const signature = await identity.sign(peerAdvertSigningInput(advert));
|
|
35
|
+
return {
|
|
36
|
+
...advert,
|
|
37
|
+
[PEER_ADVERT_SIGNATURE_KEY]: signature
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Both validity checks spec/transport.cddl states for a gossiped advert, in the order a verifier must apply them: the embedded identity-key self-certifies (sha256 of its public-key equals the advert's own `device`), and the signature verifies under that same key over peerAdvertSigningInput's bytes.
|
|
42
|
+
*
|
|
43
|
+
* Returns a verdict for every input, including a hostile one, and never throws. An advert's `alg` and `public-key` are attacker-chosen (identity-key constrains them to an int and a bstr, nothing more), so importing the key can legitimately fail for an algorithm no verifier implements or for key bytes of the wrong length. An unverifiable advert is a refused advert, exactly as if its signature had simply been wrong, which is why the import failure is turned into `false` here rather than propagated to a caller iterating a frame's other adverts.
|
|
44
|
+
*/
|
|
45
|
+
async function verifyPeerAdvert(identity, advert) {
|
|
46
|
+
const key = advert[PEER_ADVERT_IDENTITY_KEY_KEY];
|
|
47
|
+
try {
|
|
48
|
+
const derived = await identity.deriveDeviceId(key["public-key"]);
|
|
49
|
+
if (!require_token_scope.bytesEqual(derived, advert.device)) return false;
|
|
50
|
+
return await identity.verify(key, peerAdvertSigningInput(advert), advert[PEER_ADVERT_SIGNATURE_KEY]);
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
exports.PEER_ADVERT_IDENTITY_KEY_KEY = PEER_ADVERT_IDENTITY_KEY_KEY;
|
|
57
|
+
exports.PEER_ADVERT_SIGNATURE_KEY = PEER_ADVERT_SIGNATURE_KEY;
|
|
58
|
+
exports.PEER_ADVERT_SIGNING_CONTEXT = PEER_ADVERT_SIGNING_CONTEXT;
|
|
59
|
+
exports.peerAdvertSigningInput = peerAdvertSigningInput;
|
|
60
|
+
exports.signPeerAdvert = signPeerAdvert;
|
|
61
|
+
exports.verifyPeerAdvert = verifyPeerAdvert;
|