@camerontaylor/paseo-relay 0.12.0-fork.1 → 0.13.0-fork.2

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.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Endpoint security for relay-carried daemon sessions.
3
+ *
4
+ * This is the one entrypoint both endpoints use to secure a transport. It owns
5
+ * the handshake, record protection, counters, retries, termination, and the
6
+ * negotiated security mode. Relay adapters own routing and physical I/O;
7
+ * daemon admission owns credentials and authorization.
8
+ *
9
+ * Two modes exist during migration:
10
+ *
11
+ * - "protected": conforming Noise_NK_25519_ChaChaPoly_SHA256 bound to the
12
+ * daemon's static key, with authenticated record framing. Handshake
13
+ * messages travel byte-exact (base64) inside the existing `e2ee_hello` /
14
+ * `e2ee_ready` JSON envelopes under `protected`.
15
+ * - "legacy": the pre-existing ephemeral-static box construction in
16
+ * `encrypted-channel.ts`. It has no replay protection. Chosen only when the
17
+ * peer omits `protected` (an older peer) and policy allows it.
18
+ *
19
+ * A present but invalid `protected` field never falls back to legacy.
20
+ *
21
+ * See docs/relay-endpoint-security.md for the byte-level mapping.
22
+ */
23
+ import { type EncryptedChannelEvents, type Transport } from "./encrypted-channel.js";
24
+ import { type KeyPair } from "./crypto.js";
25
+ export type SecurityMode = "legacy" | "protected";
26
+ export type SecureChannelEvents = EncryptedChannelEvents;
27
+ export interface SecureChannel {
28
+ send(data: string | ArrayBuffer): Promise<void>;
29
+ close(code?: number, reason?: string): void;
30
+ isOpen(): boolean;
31
+ securityMode(): SecurityMode;
32
+ /** Bytes the transport will carry for `data`, including protection overhead. */
33
+ outboundWireByteLength(data: string | ArrayBuffer): number;
34
+ onTransitionToOpen(cb: () => void): void;
35
+ onClose(cb: () => void): void;
36
+ }
37
+ export interface ClientSecureChannelOptions {
38
+ daemonPublicKeyB64: string;
39
+ /** Lowest mode this client accepts. "protected" refuses a daemon that only offers legacy. */
40
+ minimumMode?: SecurityMode;
41
+ events?: SecureChannelEvents;
42
+ }
43
+ export interface DaemonSecureChannelOptions {
44
+ daemonKeyPair: KeyPair;
45
+ /**
46
+ * Lowest mode this daemon admits. "protected" refuses a client that only
47
+ * offers legacy. A function is evaluated when the hello arrives so a policy
48
+ * change applies to every admission from that moment on.
49
+ */
50
+ minimumMode?: SecurityMode | (() => SecurityMode);
51
+ events?: SecureChannelEvents;
52
+ }
53
+ /** Thrown by {@link openDaemonSecureChannel} when the handshake is refused; carries the close to send. */
54
+ export declare class SecureChannelRejectedError extends Error {
55
+ readonly closeCode: number;
56
+ readonly closeReason: string;
57
+ constructor(message: string, closeCode: number, closeReason: string);
58
+ }
59
+ export declare const PROTECTED_MODE_REQUIRED_CLOSE_CODE = 1008;
60
+ export declare const PROTECTED_MODE_REQUIRED_CLOSE_REASON = "protected endpoint security required";
61
+ /** Client-side close when a protected handshake fails. Browser-safe (4000-4999). */
62
+ export declare const PROTECTED_HANDSHAKE_FAILED_CLOSE_CODE = 4002;
63
+ /**
64
+ * Client-side close when an inbound record fails authentication or framing.
65
+ * Browser WebSocket.close accepts only 1000 or 3000-4999, so a client must
66
+ * never try to send a 1011.
67
+ */
68
+ export declare const PROTECTED_RECORD_FAILED_CLOSE_CODE = 4003;
69
+ /**
70
+ * Secures a transport as the initiator. Resolves once the hello has been sent;
71
+ * `events.onopen` fires when the channel is usable. Sends queued before open
72
+ * are flushed in order after the handshake, capped at {@link MAX_PENDING_SENDS}.
73
+ */
74
+ export declare function openClientSecureChannel(transport: Transport, options: ClientSecureChannelOptions): Promise<SecureChannel>;
75
+ /**
76
+ * Secures a transport as the responder. Resolves once the peer's hello has
77
+ * been accepted and the ready sent. Rejects with
78
+ * {@link SecureChannelRejectedError} when policy refuses the peer, and with a
79
+ * plain error for malformed or failed handshakes; the caller closes the socket.
80
+ */
81
+ export declare function openDaemonSecureChannel(transport: Transport, options: DaemonSecureChannelOptions): Promise<SecureChannel>;
82
+ /**
83
+ * Largest plaintext that fits in `wireBytes` as a base64 text frame in either
84
+ * mode. Callers size payloads before the mode is known, so take the tighter bound.
85
+ */
86
+ export declare function maxSecuredPlaintextByteLength(wireBytes: number): number;
87
+ //# sourceMappingURL=secure-channel.d.ts.map