Fetch User Keys - simple tool for fetching SSH keys from various sources
1// SPDX-FileCopyrightText: 2024 Łukasz Niemier <#@hauleth.dev>
2//
3// SPDX-License-Identifier: EUPL-1.2
4
5use std::collections::HashMap;
6use std::io::{self, prelude::*};
7
8use rayon::prelude::*;
9
10#[derive(PartialEq, Eq, Debug, Copy, Clone)]
11pub enum Format {
12 JSON,
13 TOML,
14 CSV,
15 SSH,
16}
17
18impl Format {
19 pub fn render<W: Write>(self, output: &Output, w: &mut W) -> io::Result<()> {
20 match self {
21 Format::JSON => {
22 serde_json::to_writer_pretty(&mut *w, &output.keys).map_err(io::Error::other)?;
23 writeln!(w)
24 }
25 Format::TOML => write!(w, "{}", toml::to_string_pretty(&output.keys).unwrap()),
26 Format::CSV => as_csv(w, output),
27 Format::SSH => authorized_keys(w, output),
28 }
29 }
30}
31
32impl std::fmt::Display for Format {
33 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
34 match *self {
35 Format::JSON => f.write_str("json"),
36 Format::TOML => f.write_str("toml"),
37 Format::CSV => f.write_str("csv"),
38 Format::SSH => f.write_str("ssh"),
39 }
40 }
41}
42
43impl<'a> From<&'a str> for Format {
44 fn from(s: &'a str) -> Format {
45 match s {
46 "json" => Format::JSON,
47 "toml" => Format::TOML,
48 "csv" => Format::CSV,
49 "ssh" => Format::SSH,
50 _ => unreachable!(),
51 }
52 }
53}
54
55#[derive(Debug, serde::Serialize)]
56pub struct Output {
57 pub keys: HashMap<String, Vec<ssh_key::PublicKey>>,
58}
59
60impl FromParallelIterator<(String, Vec<ssh_key::PublicKey>)> for Output {
61 fn from_par_iter<T>(iter: T) -> Self
62 where
63 T: IntoParallelIterator<Item = (String, Vec<ssh_key::PublicKey>)>,
64 {
65 Output {
66 keys: iter.into_par_iter().collect(),
67 }
68 }
69}
70
71// TODO: proper escaping
72fn as_csv<W: Write>(w: &mut W, output: &Output) -> io::Result<()> {
73 for (name, keys) in &output.keys {
74 for key in keys {
75 writeln!(w, "{name},{}", key.to_string())?;
76 }
77 }
78
79 Ok(())
80}
81
82fn authorized_keys<W: Write>(w: &mut W, output: &Output) -> io::Result<()> {
83 for (name, keys) in &output.keys {
84 for key in keys {
85 let commented = ssh_key::PublicKey::new(key.key_data().clone(), name);
86 writeln!(w, "{}", commented.to_string())?;
87 }
88 }
89
90 Ok(())
91}