namespace DodoSSH.Client.Ssh; /// How to authenticate to a host. /// /// Always decrypted from the vault immediately before use and never persisted outside it. Because /// SSH terminates on the client, using a credential requires its plaintext here — which is exactly /// why the Connect permission is a UI hint and not an enforceable boundary. See ADR 0001. /// public abstract record SshCredential; /// Password authentication, and keyboard-interactive where the server prefers it. public sealed record SshPasswordCredential(string Password) : SshCredential; /// Public-key authentication. /// The private key in PEM form, as stored in the vault. /// Passphrase protecting the key, when it has one. public sealed record SshPrivateKeyCredential(byte[] PrivateKeyPem, string? Passphrase) : SshCredential; /// Everything needed to reach one host. /// Hostname or address. /// Port. /// Remote account. /// How to authenticate. /// How long to wait for the transport and handshake. public sealed record SshConnectionRequest( string Host, int Port, string Username, SshCredential Credential, TimeSpan? ConnectTimeout = null); /// An interactive shell over a pseudo-terminal. public interface ISshShellSession : IAsyncDisposable { /// Whether the channel is still usable. bool IsOpen { get; } /// Reads whatever output is available, blocking until at least one byte arrives. /// Bytes read, or 0 once the remote closes the channel. ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken); /// Sends keystrokes to the remote. ValueTask WriteAsync(ReadOnlyMemory data, CancellationToken cancellationToken); /// /// Tells the remote the terminal has been resized. /// /// /// Verified to reach the remote against a real sshd; see PtyAndResizeSpikeTests. Sizes /// that are not are dropped rather than forwarded. /// void Resize(TerminalSize size); } /// An authenticated connection to one host. public interface ISshConnection : IAsyncDisposable { /// Whether the transport is still up. bool IsConnected { get; } /// The host key that was accepted for this connection. HostKeyPresentation HostKey { get; } /// Opens an interactive shell with a pseudo-terminal. Task OpenShellAsync(TerminalSize size, CancellationToken cancellationToken); } /// Opens connections, enforcing host key trust before authenticating. public interface ISshConnectionFactory { /// /// Connects and authenticates. /// /// /// The host has no pinned key. The caller must show the fingerprint, and only on explicit /// confirmation record it via and retry. /// /// /// The presented key differs from the pin. There is no retry path: this is a hard block. /// Task ConnectAsync(SshConnectionRequest request, CancellationToken cancellationToken); }