reticulum-js
    Preparing search index...

    Class Link

    An ephemeral encrypted channel between two destinations.

    A Link is established through a LINKREQUEST/LRPROOF handshake which derives shared session keys; once ACTIVE, application packets are Token-encrypted over the link. Provides inbound sequencing, keepalive/watchdog handling, link identification, and resource advertisement transport.

    Construct via Link.initiate or Link.accept; do not call the constructor directly.

    Hierarchy

    • EventTarget
      • Link
    Index
    • Low-level constructor. Prefer the Link.initiate / Link.accept factories.

      Parameters

      • opts: {
            destination: Destination;
            ephemeralEd25519Priv?: CryptoKey;
            ephemeralX25519Priv: CryptoKey;
            ephemeralX25519Pub?: Uint8Array<ArrayBufferLike>;
            initiator: boolean;
            linkId: Uint8Array<ArrayBufferLike>;
            mode?: number;
            mtu?: number;
            peerEd25519Pub?: Uint8Array<ArrayBufferLike>;
            peerX25519Pub?: Uint8Array<ArrayBufferLike>;
            transport: TransportCore;
        }
        • destination: Destination
        • OptionalephemeralEd25519Priv?: CryptoKey

          Initiator's fresh ephemeral Ed25519 private key (link-proof signing).

        • ephemeralX25519Priv: CryptoKey

          This side's ephemeral X25519 private key.

        • OptionalephemeralX25519Pub?: Uint8Array<ArrayBufferLike>

          This side's ephemeral X25519 public key (raw 32 bytes).

        • initiator: boolean
        • linkId: Uint8Array<ArrayBufferLike>
        • Optionalmode?: number
        • Optionalmtu?: number
        • OptionalpeerEd25519Pub?: Uint8Array<ArrayBufferLike>

          Peer's ephemeral Ed25519 public key (raw 32 bytes). Responder-only: the initiator's link-proof signing pub, captured from the LINKREQUEST body so the responder can verify initiator-signed link proofs (§6.5).

        • OptionalpeerX25519Pub?: Uint8Array<ArrayBufferLike>

          Peer's ephemeral X25519 public key (raw 32 bytes).

        • transport: TransportCore

      Returns Link

    _peerEd25519Key: CryptoKey | null

    Cached verify-only CryptoKey imported from peerEd25519Pub (responder).

    _pendingLinkProofs: Map<any, any>

    Outbound CTX_NONE DATA packet hashes (hex → bytes) awaiting a link PROOF (§6.5).

    _rxQueue: Promise<void> = ...
    _status: number
    _watchdogTimer: Timeout | null = null
    bz2: Bzip2 | undefined = undefined

    Injected bz2 module (PROTOCOL-SPEC.md §10.2 step 2). The library never imports a compression dependency; the application assigns this if it wants Resource compression. When unset, compressed advertisements cannot be decompressed locally and sender-side compression is skipped.

    derivedKey: Uint8Array<ArrayBufferLike> | null = null
    destination: Destination
    ephemeralEd25519Priv: CryptoKey | null
    ephemeralX25519Priv: CryptoKey
    ephemeralX25519Pub: Uint8Array<ArrayBufferLike> | undefined
    incomingResources: Map<string, Resource> = ...

    Incoming Resources (this side is the receiver) keyed by hex(resource.hash). Populated from RESOURCE_ADV; parts are routed by map_hash matching.

    initiator: boolean
    keepaliveInterval: number = Link.KEEPALIVE_MAX
    lastInboundTime: number
    linkId: Uint8Array<ArrayBufferLike>
    maxResourceSize: number | undefined = undefined

    Cap on advertised Resource size accepted inbound (§10.4 bomb defense). Applications may lower this; null keeps the Resource default.

    mode: number = Link.MODE_AES256_CBC
    mtu: number = Link.DEFAULT_MTU
    outgoingResources: Map<string, Resource> = ...

    Outgoing Resources (this side is the sender) keyed by hex(resource.hash) — PROTOCOL-SPEC.md §10. Driven by Resource.advertise and fulfilled by inbound RESOURCE_REQ / RESOURCE_PRF / RESOURCE_RCL.

    peerEd25519Pub: Uint8Array<ArrayBufferLike> | null
    peerX25519Pub: Uint8Array<ArrayBufferLike> | null
    pendingRequests: Map<
        string,
        { reject: Function; resolve: Function; timer: Timeout },
    > = ...

    Initiator-side pending REQUESTs keyed by hex(request_id) (PROTOCOL-SPEC.md §11.5). Each entry resolves/rejects its returned Promise when the matching RESPONSE arrives or the timeout fires.

    pendingResources: Map<any, any> = ...

    Pending outgoing resource payloads keyed by hex hash (RESOURCE_ADV/REQ).

    remoteIdentity: Identity | undefined
    requestTimeMs: number = 0

    Wall-clock time (ms) at which the LINKREQUEST was sent (initiator) or received (responder). Used to measure RTT.

    rtt: number = 0
    staleTime: number = ...
    teardownReason: number = 0
    token: Token | null = null
    transport: TransportCore
    DEFAULT_MTU: number = 500

    Default Reticulum MTU when MTU discovery is disabled or unavailable.

    ECPUBSIZE: number = 64

    Combined size of the two initiator ephemeral public keys (X25519 + Ed25519).

    KEEPALIVE_MAX: number = 360
    KEEPALIVE_MAX_RTT: number = 1.75
    KEEPALIVE_MIN: number = 5
    LINK_MTU_SIZE: number = 3

    Size of the optional MTU/mode signalling trailer on LINKREQUEST/LRPROOF.

    MODE_AES256_CBC: number = 0x01

    Default link mode (the only enabled mode in upstream RNS).

    RESPONSE_GRACE_FACTOR: number = 1.125

    Fixed multiplier on the response grace term (PROTOCOL-SPEC.md §11.5).

    RESPONSE_MAX_GRACE_TIME: number = 4.0

    Response-side grace term for the default REQUEST timeout (PROTOCOL-SPEC.md §11.5). Mirrors RNS.Resource.RESPONSE_MAX_GRACE_TIME — the same caveat applies.

    STALE_FACTOR: number = 2
    TRAFFIC_TIMEOUT_FACTOR: number = 6

    Multiplier on measured RTT used when computing the default REQUEST response timeout (PROTOCOL-SPEC.md §11.5). Mirrors RNS.Link.TRAFFIC_TIMEOUT_FACTOR — verify against upstream if precise timeout parity matters.

    • get mdu(): number

      Maximum plaintext bytes that fit in a single link DATA packet after Token encryption and the HEADER_1 framing are applied (PROTOCOL-SPEC.md §11.1, §5.2).

      The on-wire form of a link DATA packet is:

      flags(1) hops(1) dest_hash(16) context(1)   iv(16) aes_ct hmac(32)
      \---------------------- 19 ----------------/ \------ 48 ------/

      PKCS#7 padding always adds 1–16 bytes (a full block when the plaintext is itself a block multiple), so the largest plaintext P whose ciphertext fits the remaining budget is the largest block-multiple ciphertext ≤ (mtu − 67) minus one byte. At the default mtu = 500 this yields the spec-pinned MDU = 431 (wire packet 499 B, verified against RNS).

      Returns number

    • get status(): number

      The current link status.

      Returns number

    • set status(newStatus: number): void

      Transitions the link to a new status, emitting statuschange.

      Parameters

      • newStatus: number

      Returns void

    • Internal

      Registers an incoming Resource (receiver side) keyed by hex(resource.hash).

      Parameters

      Returns void

    • Internal

      Registers an outgoing Resource (sender side) keyed by hex(resource.hash).

      Parameters

      Returns void

    • The addEventListener() method of the EventTarget interface sets up a function that will be called whenever the specified event is delivered to the target.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | AddEventListenerOptions

      Returns void

    • The dispatchEvent() method of the EventTarget sends an Event to the object, (synchronously) invoking the affected event listeners in the appropriate order. The normal event processing rules (including the capturing and optional bubbling phase) also apply to events dispatched manually with dispatchEvent().

      MDN Reference

      Parameters

      • event: Event

      Returns boolean

    • Initiator: prove which long-term identity owns this link to the responder.

      Must be called AFTER the link is ACTIVE and BEFORE sending any application DATA. This is load-bearing for Python-LXMF interop: Python's LXMRouter does not install its link-data listener until it has processed LINKIDENTIFY, so a DATA/RESOURCE sent before LINKIDENTIFY is silently dropped on the Python side. Wire body (link-encrypted):

      public_key(64) || signature(64)

      where signature = identity.sign(link_id || public_key) (RNS/Link.py:459-475).

      Parameters

      • identity: Identity

        The initiator's long-term identity.

      Returns Promise<void>

    • The removeEventListener() method of the EventTarget interface removes an event listener previously registered with EventTarget.addEventListener() from the target. The event listener to be removed is identified using a combination of the event type, the event listener function itself, and various optional options that may affect the matching process; see Matching event listeners for removal.

      MDN Reference

      Parameters

      • type: string
      • callback: EventListenerOrEventListenerObject | null
      • Optionaloptions: boolean | EventListenerOptions

      Returns void

    • Initiator: send a REQUEST over the link and await the RESPONSE (PROTOCOL-SPEC.md §11.1, §11.5).

      Packs the msgpack envelope [timestamp, path_hash, data] (single pack — data is encoded directly, NOT pre-msgpacked), dispatches by size, and returns a Promise that resolves with the response value when the server's matching RESPONSE arrives.

      For a single-packet REQUEST the request_id the server echoes back is SHA-256(packet.get_hashable_part())[:16] — the truncated hash of the encrypted wire packet, computed identically on both sides. It is NOT random and NOT a hash of the plaintext envelope.

      Parameters

      • path: string

        Opaque path token (e.g. "/page/index.mu").

      • Optionaldata: any = null

        Application value for envelope element [2] (null for plain GETs, an object for NomadNet form posts, an array for LXMF /get rounds, a Uint8Array for opaque blobs …). Passed to msgpack directly — do NOT pre-pack it.

      • Optionaloptions: { timeout?: number } = {}
        • Optionaltimeout?: number

          Response timeout in ms (defaults to rtt * TRAFFIC_TIMEOUT_FACTOR + RESPONSE_MAX_GRACE_TIME * 1.125).

      Returns Promise<any>

      The decoded RESPONSE value.

    • Sends a packet on the link. The packet is re-addressed to link_id and Token-encrypted unless it is in the not-encrypted set (§6.7.1). Returns the wire-ready outbound packet.

      Parameters

      Returns Promise<Packet>

    • Cleanly tears down the link by sending a LINKCLOSE whose encrypted body is the link_id, then transitioning to CLOSED locally.

      Returns Promise<void>

    • Resolves once the Link reaches ACTIVE status (immediately if it already is). Callers that obtain a Link reference before the handshake finishes — e.g. right after Destination.createLink() resolves — should await this before sending application data, since the session token is only derived once the handshake completes.

      Mirrors the gating the Python LXMF router applies in process_outbound before sending DIRECT messages.

      Parameters

      • OptionaltimeoutMs: number = 15000

        How long to wait for the handshake.

      Returns Promise<Link>

    • Responder side: accept an incoming LINKREQUEST and complete the handshake up to LRPROOF.

      Derives the link_id, extracts the initiator's ephemeral keys, derives the session keys, builds and sends the LRPROOF signed with the destination's long-term identity key, registers the link with the transport, and transitions to HANDSHAKE. The link becomes ACTIVE once the initiator's LRRTT arrives (RNS/Link.py:186-200, 353-394).

      Parameters

      • destination: Destination

        IN destination whose identity is this node's.

      • transport: TransportCore
      • requestPacket: Packet

        The incoming LINKREQUEST (with raw populated).

      Returns Promise<Link>

    • Initiator side: establish a new link to destination.

      Generates fresh ephemeral X25519 + Ed25519 keypairs, builds and sends the LINKREQUEST (dest_type=SINGLE, addressed to the responder's destination hash), derives the link_id from the serialized packet, registers the link with the transport, and transitions to HANDSHAKE. The link becomes ACTIVE once the responder's LRPROOF is validated (RNS/Link.py:283-328).

      Parameters

      • destination: Destination

        OUT destination whose identity is the responder's.

      • transport: TransportCore

      Returns Promise<Link>

    • Packs the 3-byte MTU/mode signalling trailer.

      Parameters

      • mtu: number
      • mode: number

      Returns Uint8Array<ArrayBufferLike>