ssh_transfer/
known_host.rs

1use crate::error::{Error, Result};
2use regex::Regex;
3use ssh2::KnownHostKeyFormat;
4use std::convert::TryFrom;
5
6#[derive(Clone, Debug)]
7pub struct KnownHost {
8  pub hostname: String,
9  pub key_format: KnownHostKeyFormat,
10  pub fingerprint: Vec<u8>,
11  pub comment: Option<String>,
12}
13
14impl TryFrom<&str> for KnownHost {
15  type Error = crate::error::Error;
16  fn try_from(value: &str) -> Result<Self> {
17    let re = Regex::new(r"(?P<host>\S*) (?P<type>\S*) (?P<hash>\S*) ?(?P<comment>.*)?")?;
18    let captures = re
19      .captures(value)
20      .ok_or_else(|| Error::KnownHostParsingError("invalid known host format.".to_string()))?;
21
22    let hostname = captures
23      .name("host")
24      .ok_or_else(|| Error::KnownHostParsingError("cannot get hostname.".to_string()))?
25      .as_str()
26      .to_string();
27    let key_format = captures
28      .name("type")
29      .ok_or_else(|| Error::KnownHostParsingError("cannot get key format.".to_string()))?
30      .as_str();
31    let fingerprint = captures
32      .name("hash")
33      .ok_or_else(|| Error::KnownHostParsingError("cannot get fingerprint.".to_string()))?
34      .as_str();
35    let fingerprint = base64::decode(fingerprint)?;
36    let comment = captures
37      .name("comment")
38      .map(|c| c.as_str().to_string())
39      .filter(|c| !c.is_empty());
40
41    let key_format = match key_format {
42      "rsa1" => KnownHostKeyFormat::Rsa1,
43      "ssh-rsa" => KnownHostKeyFormat::SshRsa,
44      "ssh-dss" => KnownHostKeyFormat::SshDss,
45      "ecdsa-sha2-nistp256" => KnownHostKeyFormat::Ecdsa256,
46      "ecdsa-sha2-nistp384" => KnownHostKeyFormat::Ecdsa384,
47      "ecdsa-sha2-nistp521" => KnownHostKeyFormat::Ecdsa521,
48      "ssh-ed25519" => KnownHostKeyFormat::Ed25519,
49      _ => KnownHostKeyFormat::Unknown,
50    };
51
52    Ok(KnownHost {
53      hostname,
54      key_format,
55      fingerprint,
56      comment,
57    })
58  }
59}
60
61#[test]
62pub fn test_known_host() {
63  let known_host = KnownHost::try_from("localhost ssh-ed25519 SGVsbG8gV29ybGQh").unwrap();
64  assert_eq!("localhost", &known_host.hostname);
65  assert_eq!(
66    format!("{:?}", KnownHostKeyFormat::Ed25519),
67    format!("{:?}", known_host.key_format)
68  );
69  assert_eq!("Hello World!".as_bytes().to_vec(), known_host.fingerprint);
70  assert_eq!(None, known_host.comment);
71}