authorized_keys_merger/
lib.rs

1use std::cmp::Ordering;
2use std::fs;
3
4pub struct Config {
5    pub authorized_keys_fpath: String,
6    pub public_key_fpath: String,
7}
8
9impl Config {
10    pub fn new(args: &[String]) -> Result<Config, &'static str> {
11        match args.len().cmp(&3) {
12            Ordering::Less => Err("not enough arguments"),
13            Ordering::Greater => Err("too many arguments"),
14            Ordering::Equal => Ok(Config {
15                authorized_keys_fpath: args[1].clone(),
16                public_key_fpath: args[2].clone(),
17            }),
18        }
19    }
20}
21
22pub fn run(config: &Config) -> Result<(), Box<dyn std::error::Error>> {
23    let authorized_keys_content = fs::read_to_string(&config.authorized_keys_fpath)?;
24    let authorized_keys = authorized_keys_content.lines().collect::<Vec<_>>();
25
26    let public_keys_content = fs::read_to_string(&config.public_key_fpath)?;
27    let public_keys = public_keys_content.lines().collect::<Vec<_>>();
28
29    for &pub_key in authorized_keys.iter() {
30        println!("{}", pub_key);
31    }
32    for pub_key in extract_keys(&authorized_keys, &public_keys) {
33        println!("{}", pub_key);
34    }
35
36    Ok(())
37}
38
39pub fn extract_keys<'a>(public_keys: &Vec<&'a str>, authorized_keys: &Vec<&str>) -> Vec<String> {
40    let mut keys_to_be_append = Vec::new();
41    for &line in public_keys {
42        let pub_key = line.split(" ").collect::<Vec<_>>()[..2].join(" ");
43        let result = search(pub_key.as_str(), &authorized_keys);
44        if result.len() == 0 {
45            // append to authorized_keys file
46            keys_to_be_append.push(pub_key);
47        }
48    }
49    keys_to_be_append
50}
51
52pub fn search<'a>(query: &str, lines: &Vec<&'a str>) -> Vec<&'a str> {
53    let mut results = Vec::new();
54
55    for &line in lines {
56        if line.contains(query) {
57            results.push(line);
58        }
59    }
60
61    results
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_extract_keys() {
70        let public_keys = vec![
71            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfzP+l0IwuGDQT4gQHZZtlLHM7XC07sfZ8B2E5weH1ctepgx23WRWULvr2Dzy5cUUYMdxiuUBeq6E5YJ/6vt+uqvFWjFC8n5SwrwdMsXQiZP8t/cqdIETC9yLrhzYYMyUiVZDrRi0HLv6Ssda/sF+mu7YpT971it155vRKmOvYOX1QlgA7v1cSRklel8pJ7gX2oT9NHwVTj38VYNvrEQDrEF3/wYmUndKgMI2BLI+PUjkk8UL/k6CJJT8NFSa0brU8aQsPQBX07C/8U5CgWX20iWEqNoG065BrSMcyulQ2zndmv/PaWDD973rPH0uU+zXioaHXlpUhKCd4ucdhKOLi+2ZOcFVsBt+1fSAyFR8pjF4fGW3XYwxDehkbx5kAoez1ErJhA3bitlIisfc4d8+pTIYnoG134mKqj04OugLWF5a7kU/D8OXFQkJzPW3bLLr6y2hQlssucb5knCtfPw7hc22T4UoEd6/Pgz/veGNgRsBHxGelmNCVbWd014IZgY0="#,
72            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHc/gCxwO3wAhRYG1YtUfghy+xOCpwxOBNRpERTdcI5Uk/L2wD09mAYt7w6PU9vrdHYP7bIdTy447WxcanVVs+fycUPI2WTaut0DrNwH/d+ahezSj16h1x4AGsoamKxZ7VrtcPeKUu32NiLGIg6/F1/l1F6ISzYSqIPa4xre68SgcSP8o9wDS9Ixh0ZfFnXZGJ4VwG7IyWPj3s1guqUQn2iC7VsuEpA/9ZXR4YkMIm/ZzNxpb4VkXZuyWOGspFZgMoDxGO4wNwT8IuOEb77uSHKNv71nLTw7vuGxvQH1xHsBA/oAd86WYNtyB0BteB4EOlpDy4d4XEp+uSpx5RPV+cnXBImPlBjq5maRuW/3uNs5mlA/GyHuHlGm83HhD7CFhvz9EFyQBojuFGui9B/kGmPgWWA198wt1MRylIM6gSFGDfar+2ZfIa1miyMpziEkN/nD/3XYl0HPz2ppdLpPuZBBKbTSQnrRSkDjV51A7IXMYEY2pn0mbUivSS/6TzBoM="#,
73        ];
74        let authorized_keys = vec![
75            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfzP+l0IwuGDQT4gQHZZtlLHM7XC07sfZ8B2E5weH1ctepgx23WRWULvr2Dzy5cUUYMdxiuUBeq6E5YJ/6vt+uqvFWjFC8n5SwrwdMsXQiZP8t/cqdIETC9yLrhzYYMyUiVZDrRi0HLv6Ssda/sF+mu7YpT971it155vRKmOvYOX1QlgA7v1cSRklel8pJ7gX2oT9NHwVTj38VYNvrEQDrEF3/wYmUndKgMI2BLI+PUjkk8UL/k6CJJT8NFSa0brU8aQsPQBX07C/8U5CgWX20iWEqNoG065BrSMcyulQ2zndmv/PaWDD973rPH0uU+zXioaHXlpUhKCd4ucdhKOLi+2ZOcFVsBt+1fSAyFR8pjF4fGW3XYwxDehkbx5kAoez1ErJhA3bitlIisfc4d8+pTIYnoG134mKqj04OugLWF5a7kU/D8OXFQkJzPW3bLLr6y2hQlssucb5knCtfPw7hc22T4UoEd6/Pgz/veGNgRsBHxGelmNCVbWd014IZgY0= polle@pollenjp-pc"#,
76            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCg+ybUzuO5x6dMjjQe42s7XviyiQGUmB6Tc9Hlkopl0bSjTr4unHLBNlLdSAb85i+9WYvDm+q7bqhGber6c60CtIFGCUrfH6yxXO4weQNTZ5M1CgzhDq9VLwq6cDoRsmJnSmeX4s3tt9ezCTtpITsRwljcpFJQLgfJ3QXkFFAxC/8ClblY7RSmqxCwii+sUDWLDeZG8VcTZAnCGlD7FAO+lLJUhjO15J+vf6dSq82DAU0BTVnOeMkPLxToIxwJMF6tFBPhrneThwaI/i9ibF4FTsCMMq6DW6iZTpGuaSaY98vx3Y1F6JvjAE+7wcTiPyyP3GKxLyqiSwRU5M6+kAyDAZAT4YUks2A7WADk2IVjc0UOrUaJJimXZinhUWWLTA3190VETNtB4Azf4SykB6NL56wdoqUVRg2nf+cb2vEfYuRACJ0bCi3acPGMmE2gZIGwyAoQHL20nasiaxO1buMiSYDXxroM/Y2RC8swuM1L4yqSxCE2csZ/Lue50G/cSM0= polle@pollenjp-pc"#,
77        ];
78        assert_eq!(
79            vec![
80                r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHc/gCxwO3wAhRYG1YtUfghy+xOCpwxOBNRpERTdcI5Uk/L2wD09mAYt7w6PU9vrdHYP7bIdTy447WxcanVVs+fycUPI2WTaut0DrNwH/d+ahezSj16h1x4AGsoamKxZ7VrtcPeKUu32NiLGIg6/F1/l1F6ISzYSqIPa4xre68SgcSP8o9wDS9Ixh0ZfFnXZGJ4VwG7IyWPj3s1guqUQn2iC7VsuEpA/9ZXR4YkMIm/ZzNxpb4VkXZuyWOGspFZgMoDxGO4wNwT8IuOEb77uSHKNv71nLTw7vuGxvQH1xHsBA/oAd86WYNtyB0BteB4EOlpDy4d4XEp+uSpx5RPV+cnXBImPlBjq5maRuW/3uNs5mlA/GyHuHlGm83HhD7CFhvz9EFyQBojuFGui9B/kGmPgWWA198wt1MRylIM6gSFGDfar+2ZfIa1miyMpziEkN/nD/3XYl0HPz2ppdLpPuZBBKbTSQnrRSkDjV51A7IXMYEY2pn0mbUivSS/6TzBoM="#,
81            ],
82            extract_keys(&public_keys, &authorized_keys)
83        )
84    }
85
86    #[test]
87    fn test_extract_keys2() {
88        let public_keys = vec![
89            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfzP+l0IwuGDQT4gQHZZtlLHM7XC07sfZ8B2E5weH1ctepgx23WRWULvr2Dzy5cUUYMdxiuUBeq6E5YJ/6vt+uqvFWjFC8n5SwrwdMsXQiZP8t/cqdIETC9yLrhzYYMyUiVZDrRi0HLv6Ssda/sF+mu7YpT971it155vRKmOvYOX1QlgA7v1cSRklel8pJ7gX2oT9NHwVTj38VYNvrEQDrEF3/wYmUndKgMI2BLI+PUjkk8UL/k6CJJT8NFSa0brU8aQsPQBX07C/8U5CgWX20iWEqNoG065BrSMcyulQ2zndmv/PaWDD973rPH0uU+zXioaHXlpUhKCd4ucdhKOLi+2ZOcFVsBt+1fSAyFR8pjF4fGW3XYwxDehkbx5kAoez1ErJhA3bitlIisfc4d8+pTIYnoG134mKqj04OugLWF5a7kU/D8OXFQkJzPW3bLLr6y2hQlssucb5knCtfPw7hc22T4UoEd6/Pgz/veGNgRsBHxGelmNCVbWd014IZgY0="#,
90            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHc/gCxwO3wAhRYG1YtUfghy+xOCpwxOBNRpERTdcI5Uk/L2wD09mAYt7w6PU9vrdHYP7bIdTy447WxcanVVs+fycUPI2WTaut0DrNwH/d+ahezSj16h1x4AGsoamKxZ7VrtcPeKUu32NiLGIg6/F1/l1F6ISzYSqIPa4xre68SgcSP8o9wDS9Ixh0ZfFnXZGJ4VwG7IyWPj3s1guqUQn2iC7VsuEpA/9ZXR4YkMIm/ZzNxpb4VkXZuyWOGspFZgMoDxGO4wNwT8IuOEb77uSHKNv71nLTw7vuGxvQH1xHsBA/oAd86WYNtyB0BteB4EOlpDy4d4XEp+uSpx5RPV+cnXBImPlBjq5maRuW/3uNs5mlA/GyHuHlGm83HhD7CFhvz9EFyQBojuFGui9B/kGmPgWWA198wt1MRylIM6gSFGDfar+2ZfIa1miyMpziEkN/nD/3XYl0HPz2ppdLpPuZBBKbTSQnrRSkDjV51A7IXMYEY2pn0mbUivSS/6TzBoM= polle@pollenjp-pc"#,
91        ];
92        let authorized_keys = vec![
93            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDfzP+l0IwuGDQT4gQHZZtlLHM7XC07sfZ8B2E5weH1ctepgx23WRWULvr2Dzy5cUUYMdxiuUBeq6E5YJ/6vt+uqvFWjFC8n5SwrwdMsXQiZP8t/cqdIETC9yLrhzYYMyUiVZDrRi0HLv6Ssda/sF+mu7YpT971it155vRKmOvYOX1QlgA7v1cSRklel8pJ7gX2oT9NHwVTj38VYNvrEQDrEF3/wYmUndKgMI2BLI+PUjkk8UL/k6CJJT8NFSa0brU8aQsPQBX07C/8U5CgWX20iWEqNoG065BrSMcyulQ2zndmv/PaWDD973rPH0uU+zXioaHXlpUhKCd4ucdhKOLi+2ZOcFVsBt+1fSAyFR8pjF4fGW3XYwxDehkbx5kAoez1ErJhA3bitlIisfc4d8+pTIYnoG134mKqj04OugLWF5a7kU/D8OXFQkJzPW3bLLr6y2hQlssucb5knCtfPw7hc22T4UoEd6/Pgz/veGNgRsBHxGelmNCVbWd014IZgY0="#,
94            r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCg+ybUzuO5x6dMjjQe42s7XviyiQGUmB6Tc9Hlkopl0bSjTr4unHLBNlLdSAb85i+9WYvDm+q7bqhGber6c60CtIFGCUrfH6yxXO4weQNTZ5M1CgzhDq9VLwq6cDoRsmJnSmeX4s3tt9ezCTtpITsRwljcpFJQLgfJ3QXkFFAxC/8ClblY7RSmqxCwii+sUDWLDeZG8VcTZAnCGlD7FAO+lLJUhjO15J+vf6dSq82DAU0BTVnOeMkPLxToIxwJMF6tFBPhrneThwaI/i9ibF4FTsCMMq6DW6iZTpGuaSaY98vx3Y1F6JvjAE+7wcTiPyyP3GKxLyqiSwRU5M6+kAyDAZAT4YUks2A7WADk2IVjc0UOrUaJJimXZinhUWWLTA3190VETNtB4Azf4SykB6NL56wdoqUVRg2nf+cb2vEfYuRACJ0bCi3acPGMmE2gZIGwyAoQHL20nasiaxO1buMiSYDXxroM/Y2RC8swuM1L4yqSxCE2csZ/Lue50G/cSM0="#,
95        ];
96        assert_eq!(
97            vec![
98                r#"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDHc/gCxwO3wAhRYG1YtUfghy+xOCpwxOBNRpERTdcI5Uk/L2wD09mAYt7w6PU9vrdHYP7bIdTy447WxcanVVs+fycUPI2WTaut0DrNwH/d+ahezSj16h1x4AGsoamKxZ7VrtcPeKUu32NiLGIg6/F1/l1F6ISzYSqIPa4xre68SgcSP8o9wDS9Ixh0ZfFnXZGJ4VwG7IyWPj3s1guqUQn2iC7VsuEpA/9ZXR4YkMIm/ZzNxpb4VkXZuyWOGspFZgMoDxGO4wNwT8IuOEb77uSHKNv71nLTw7vuGxvQH1xHsBA/oAd86WYNtyB0BteB4EOlpDy4d4XEp+uSpx5RPV+cnXBImPlBjq5maRuW/3uNs5mlA/GyHuHlGm83HhD7CFhvz9EFyQBojuFGui9B/kGmPgWWA198wt1MRylIM6gSFGDfar+2ZfIa1miyMpziEkN/nD/3XYl0HPz2ppdLpPuZBBKbTSQnrRSkDjV51A7IXMYEY2pn0mbUivSS/6TzBoM="#,
99            ],
100            extract_keys(&public_keys, &authorized_keys)
101        )
102    }
103
104    #[test]
105    fn test_key_search() {
106        let pub_key =
107            r#"ssh-rsa AAAABasdofadskfalskjdflashdlajdljaALDSKFLKSJDFLSJFLHSDLFSLKHDFLSDJFLSJFD="#;
108        let authorized_keys_content = r#"\
109ssh-rsa AAAABasdofadskfalskjdflashdlajdljaALDSKFLKSJDFLSJFLHSDLFSLKHDFLSDJFLSJFD= pollenjp@fizz
110ssh-rsa AAAABasdofadskfalskjdASLKDFJNLABHHAKDJFKSAHDFLSAJdlfsakjfldsKHDFLSDJFLSF= pollenjp@buzz
111"#;
112
113        let authorized_keys = authorized_keys_content.lines().collect::<Vec<_>>();
114
115        assert_eq!(
116            vec![
117                r#"ssh-rsa AAAABasdofadskfalskjdflashdlajdljaALDSKFLKSJDFLSJFLHSDLFSLKHDFLSDJFLSJFD= pollenjp@fizz"#
118            ],
119            search(pub_key, &authorized_keys)
120        );
121    }
122}