use std::io;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum SshAuth {
Agent,
Key {
path: PathBuf,
passphrase: Option<String>,
},
#[cfg(feature = "ssh-password")]
Password(String),
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub enum HostKeyPolicy {
StrictKnownHosts,
TofuStore { path: PathBuf },
#[cfg(any(test, feature = "ssh-insecure"))]
AcceptAny,
}
#[derive(Clone, Debug)]
pub struct HostKeyMismatch {
pub host: String,
pub stored_fingerprint: String,
pub presented_fingerprint: String,
pub algorithm: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Decision {
Reject,
AcceptOnce,
AcceptAndStore,
}
pub type MismatchCallback = Arc<dyn Fn(HostKeyMismatch) -> Decision + Send + Sync + 'static>;
#[derive(Clone)]
pub struct SshConfig {
pub host: String,
pub port: u16,
pub user: String,
pub auth: SshAuth,
pub host_key: HostKeyPolicy,
pub on_mismatch: Option<MismatchCallback>,
pub keepalive: Option<Duration>,
pub connect_timeout: Duration,
pub agent_forward: bool,
pub env: Vec<(String, String)>,
pub term: String,
pub allocate_pty: bool,
}
impl SshConfig {
pub fn for_host(host: impl Into<String>, user: impl Into<String>) -> Self {
Self {
host: host.into(),
port: 22,
user: user.into(),
auth: SshAuth::Agent,
host_key: HostKeyPolicy::StrictKnownHosts,
on_mismatch: None,
keepalive: Some(Duration::from_secs(30)),
connect_timeout: Duration::from_secs(10),
agent_forward: false,
env: Vec::new(),
term: "xterm-256color".into(),
allocate_pty: true,
}
}
pub fn no_pty(mut self) -> Self {
self.allocate_pty = false;
self
}
}
impl Default for SshConfig {
fn default() -> Self {
Self::for_host(String::new(), "root")
}
}
pub struct SshSession {
_config: SshConfig,
}
impl SshSession {
pub fn connect(config: SshConfig) -> io::Result<Self> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"SshSession::connect: M2 — see terminal_crate_plan.md",
))?;
#[allow(unreachable_code)]
Ok(Self { _config: config })
}
}