1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Define the [`TrustHandler`] triat which is used to manage trust of devices.
//! Check out its documentation for more details.
use ;
/// A trait that defines how the current device manages trust of other devices.
///
/// When two devices trust each other (usually when they was paired the last time they were
/// connected), they don't need to be paired again, but instead the certificate of the other peer
/// must be compared against the last known certificate of the peer to avoid blindly pairing with
/// an unknown device.
///
/// When implementing this trait, you must prepend the `impl` statement with `#[kdeconnect_proto::async_trait]`.
///
/// ### Example
///
/// This implementation uses two mechanisms:
///
/// - it stores the certificates in a map with the device ID as key to easily retrieves them and
/// check if a device is trusted
/// - it stores the certificates in a dedicated directory with the device ID as file name and reads
/// them at startup to avoid losing the certificates when the program stops
///
/// ```no_run
/// use std::{fs, collections::HashMap, path::{Path, PathBuf}};
/// use kdeconnect_proto::trust::TrustHandler;
///
/// struct TrustHandlerImpl {
/// path: PathBuf,
/// trusted_devices: HashMap<String, Vec<u8>>,
/// }
///
/// impl TrustHandlerImpl {
/// pub fn new<P: AsRef<Path>>(path: P) -> Self {
/// let path = path.as_ref();
///
/// let trusted_devices = if path.exists() {
/// HashMap::from_iter(fs::read_dir(path).unwrap().filter_map(Result::ok).map(|f| {
/// let device_id = f.path().file_stem().unwrap().to_string_lossy().to_string();
/// let cert = fs::read(f.path()).expect("failed to read certificate");
/// (device_id, cert)
/// }))
/// } else {
/// fs::create_dir_all(path).expect("failed to create directory for trusted devices");
/// HashMap::new()
/// };
///
/// Self {
/// path: path.to_path_buf(),
/// trusted_devices,
/// }
/// }
/// }
///
/// #[kdeconnect_proto::async_trait]
/// impl TrustHandler for TrustHandlerImpl {
/// async fn trust_device(&mut self, device_id: String, cert: Vec<u8>) {
/// fs::write(self.path.join(device_id.clone() + ".pem"), &cert).unwrap();
/// self.trusted_devices.insert(device_id, cert);
/// }
///
/// async fn untrust_device(&mut self, device_id: &str) {
/// fs::remove_file(self.path.join(device_id.to_string() + ".pem")).unwrap();
/// self.trusted_devices.remove(device_id);
/// }
///
/// async fn get_certificate(&mut self, device_id: &str) -> Option<&[u8]> {
/// self.trusted_devices.get(device_id).map(|v| &**v)
/// }
/// }
/// ```