use std::path::PathBuf;
use super::SshError;
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct HostKeyPolicy {
pub files: Vec<PathBuf>,
pub unknown: UnknownHost,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum UnknownHost {
Reject,
AcceptNew,
}
impl HostKeyPolicy {
pub fn new(unknown: UnknownHost) -> Self {
Self {
files: Vec::new(),
unknown,
}
}
#[must_use]
pub fn with_files(mut self, files: Vec<PathBuf>) -> Self {
self.files = files;
self
}
pub(super) fn options(&self) -> Result<Vec<String>, SshError> {
let mut options = vec![
format!(
"StrictHostKeyChecking={}",
match self.unknown {
UnknownHost::Reject => "yes",
UnknownHost::AcceptNew => "accept-new",
}
),
"UpdateHostKeys=no".to_owned(),
];
if !self.files.is_empty() {
let mut files = Vec::new();
for file in &self.files {
let file = file
.to_str()
.filter(|file| {
!file.is_empty()
&& !file.contains(['"', '\0', '\n', '\r'])
&& std::path::Path::new(file).is_absolute()
})
.ok_or(SshError::Configuration("known_hosts path"))?;
files.push(format!("\"{}\"", file.replace('%', "%%")));
}
options.push(format!("UserKnownHostsFile={}", files.join(" ")));
options.push("GlobalKnownHostsFile=none".to_owned());
}
Ok(options)
}
}