namespace DodoSSH.Contracts; /// /// A request for permission to relay to a host. /// /// /// There is deliberately no address field. The server resolves the target from /// , which must belong to a vault the caller holds Connect on and must have /// relay enabled. Accepting a client-supplied address would turn the relay into an /// authenticated open TCP proxy into the operator's network; see ADR 0004. /// /// The host to reach. /// /// A configured port forward to use instead of the host's own SSH port. Resolved server-side the /// same way. /// public sealed record RelayTicketRequest( Guid HostId, Guid? PortForwardId); /// /// A short-lived, single-use ticket authorising exactly one relay connection. /// /// /// The ticket grants no API access at all, which is why the WebSocket endpoint can accept it /// alone. It is also the extraction seam: a standalone relay process needs only the data /// protection key ring and the replay-guard table, no authorization code. /// /// /// Opaque token. Sent as the ticket.<token> element of the /// Sec-WebSocket-Protocol header, because constrained WebSocket clients cannot set /// arbitrary headers. /// /// Absolute URL of the relay endpoint. /// Required WebSocket subprotocol. /// Correlates the ticket with the resulting session record. /// Expiry, at most 30 seconds out. public sealed record RelayTicketResponse( string Ticket, Uri WebSocketUrl, string SubProtocol, Guid SessionId, DateTimeOffset ExpiresAt); /// Why a relay session ended. public enum RelaySessionCloseReason { /// Not a legal value. Unspecified = 0, /// The client closed the connection. ClientClosed = 1, /// The target closed the connection. TargetClosed = 2, /// No traffic within the idle timeout. IdleTimeout = 3, /// The maximum session duration was reached. DurationLimit = 4, /// The server is shutting down and drained the session. ServerShutdown = 5, /// The connection to the target failed. TargetUnreachable = 6, /// An error ended the session. Error = 7, } /// /// An audit record of one relay session. /// /// /// Byte counts and duration are recorded; content never is. The relay forwards SSH ciphertext, /// so session recording is impossible in this mode by construction — the compliance strength /// and the limitation are the same fact. /// /// The session. /// Host that was reached. /// Resolved target hostname. /// Resolved target port. /// When the session opened. /// When it closed, or null while still open. /// Bytes forwarded from client to target. /// Bytes forwarded from target to client. /// Why it ended. public sealed record RelaySessionSummary( Guid SessionId, Guid HostId, string TargetHost, int TargetPort, DateTimeOffset StartedAt, DateTimeOffset? EndedAt, long BytesClientToTarget, long BytesTargetToClient, RelaySessionCloseReason CloseReason);