ssh_transfer/
known_host.rs1use 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}