|
| 1 | +use std::collections::HashMap; |
1 | 2 | use std::fmt::{Debug, Display}; |
| 3 | +use std::sync::Arc; |
2 | 4 |
|
3 | 5 | use crate::transport::error::Error; |
4 | 6 | use crate::transport::Device; |
| 7 | +use crate::webauthn::TransportError; |
5 | 8 | use crate::UxUpdate; |
6 | 9 |
|
7 | 10 | use async_trait::async_trait; |
| 11 | +use futures::lock::Mutex; |
8 | 12 | use tokio::sync::mpsc; |
| 13 | +use tracing::{debug, trace}; |
9 | 14 |
|
10 | 15 | use super::channel::CableChannel; |
| 16 | +use super::tunnel::CableLinkingInfo; |
11 | 17 | use super::Cable; |
12 | 18 |
|
13 | 19 | #[async_trait] |
14 | | -pub trait CableKnownDeviceInfoStore: Debug + Send { |
15 | | - /// Called whenever a known device should be added. |
16 | | - async fn put_known_device(&mut self, device: &CableKnownDeviceInfo); |
| 20 | +pub trait CableKnownDeviceInfoStore: Debug + Send + Sync { |
| 21 | + /// Called whenever a known device should be added or updated. |
| 22 | + async fn put_known_device(&self, device_id: &CableKnownDeviceId, device: &CableKnownDeviceInfo); |
17 | 23 | /// Called whenever a known device becomes permanently unavailable. |
18 | | - async fn delete_known_device(&mut self, device_id: String); |
| 24 | + async fn delete_known_device(&self, device_id: &CableKnownDeviceId); |
19 | 25 | } |
20 | 26 |
|
21 | | -/// A no-op known-device store for ephemeral-only implementations. |
| 27 | +/// An in-memory store for testing purposes. |
22 | 28 | #[derive(Debug, Default, Clone)] |
23 | 29 | pub struct EphemeralDeviceInfoStore { |
24 | | - pub last_device_info: Option<CableKnownDeviceInfo>, |
| 30 | + pub known_devices: Arc<Mutex<HashMap<CableKnownDeviceId, CableKnownDeviceInfo>>>, |
| 31 | +} |
| 32 | + |
| 33 | +impl EphemeralDeviceInfoStore { |
| 34 | + pub fn new() -> Self { |
| 35 | + Self { |
| 36 | + known_devices: Arc::new(Mutex::new(HashMap::new())), |
| 37 | + } |
| 38 | + } |
25 | 39 | } |
26 | 40 |
|
27 | 41 | unsafe impl Send for EphemeralDeviceInfoStore {} |
28 | 42 |
|
29 | 43 | #[async_trait] |
30 | 44 | impl CableKnownDeviceInfoStore for EphemeralDeviceInfoStore { |
31 | | - async fn put_known_device(&mut self, device: &CableKnownDeviceInfo) { |
32 | | - self.last_device_info = Some(device.clone()) |
| 45 | + async fn put_known_device( |
| 46 | + &self, |
| 47 | + device_id: &CableKnownDeviceId, |
| 48 | + device: &CableKnownDeviceInfo, |
| 49 | + ) { |
| 50 | + debug!(?device_id, "Inserting or updating known device"); |
| 51 | + trace!(?device); |
| 52 | + let mut known_devices = self.known_devices.lock().await; |
| 53 | + known_devices.insert(device_id.clone(), device.clone()); |
33 | 54 | } |
34 | 55 |
|
35 | | - async fn delete_known_device(&mut self, device_id: String) { |
36 | | - if let Some(last_device_info) = &self.last_device_info { |
37 | | - if last_device_info.device_id == device_id { |
38 | | - self.last_device_info = None |
39 | | - } |
40 | | - } |
| 56 | + async fn delete_known_device(&self, device_id: &CableKnownDeviceId) { |
| 57 | + debug!(?device_id, "Deleting known device"); |
| 58 | + let mut known_devices = self.known_devices.lock().await; |
| 59 | + known_devices.remove(device_id); |
41 | 60 | } |
42 | 61 | } |
43 | 62 |
|
| 63 | +pub type CableKnownDeviceId = String; |
| 64 | + |
44 | 65 | #[derive(Debug, Clone)] |
45 | 66 | pub struct CableKnownDeviceInfo { |
46 | | - pub device_id: String, |
47 | 67 | pub contact_id: Vec<u8>, |
48 | 68 | pub link_id: [u8; 8], |
49 | 69 | pub link_secret: [u8; 32], |
50 | 70 | pub public_key: [u8; 65], |
51 | 71 | pub name: String, |
| 72 | + pub tunnel_domain: String, |
| 73 | +} |
| 74 | + |
| 75 | +impl From<&CableLinkingInfo> for CableKnownDeviceId { |
| 76 | + fn from(linking_info: &CableLinkingInfo) -> Self { |
| 77 | + hex::encode(&linking_info.authenticator_public_key) |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +impl CableKnownDeviceInfo { |
| 82 | + pub(crate) fn new(tunnel_domain: &str, linking_info: &CableLinkingInfo) -> Result<Self, Error> { |
| 83 | + let info = Self { |
| 84 | + contact_id: linking_info.contact_id.to_vec(), |
| 85 | + link_id: linking_info |
| 86 | + .link_id |
| 87 | + .clone() |
| 88 | + .try_into() |
| 89 | + .map_err(|_| Error::Transport(TransportError::InvalidFraming))?, |
| 90 | + link_secret: linking_info |
| 91 | + .link_secret |
| 92 | + .clone() |
| 93 | + .try_into() |
| 94 | + .map_err(|_| Error::Transport(TransportError::InvalidFraming))?, |
| 95 | + public_key: linking_info |
| 96 | + .authenticator_public_key |
| 97 | + .clone() |
| 98 | + .try_into() |
| 99 | + .map_err(|_| Error::Transport(TransportError::InvalidFraming))?, |
| 100 | + name: linking_info.authenticator_name.clone(), |
| 101 | + tunnel_domain: tunnel_domain.to_string(), |
| 102 | + }; |
| 103 | + Ok(info) |
| 104 | + } |
52 | 105 | } |
53 | 106 |
|
54 | 107 | #[derive(Debug)] |
55 | | -pub struct CableKnownDevice<'d> { |
| 108 | +pub struct CableKnownDevice { |
56 | 109 | pub device_info: CableKnownDeviceInfo, |
57 | | - _store: &'d mut Box<dyn CableKnownDeviceInfoStore>, |
| 110 | + _store: Arc<dyn CableKnownDeviceInfoStore>, |
58 | 111 | } |
59 | 112 |
|
60 | | -impl<'d> Display for CableKnownDevice<'d> { |
| 113 | +impl Display for CableKnownDevice { |
61 | 114 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
62 | 115 | write!( |
63 | 116 | f, |
64 | 117 | "{} ({})", |
65 | | - self.device_info.name, self.device_info.device_id |
| 118 | + &self.device_info.name, |
| 119 | + hex::encode(&self.device_info.public_key) |
66 | 120 | ) |
67 | 121 | } |
68 | 122 | } |
69 | 123 |
|
70 | | -unsafe impl<'d> Send for CableKnownDevice<'d> {} |
71 | | -unsafe impl<'d> Sync for CableKnownDevice<'d> {} |
| 124 | +unsafe impl Send for CableKnownDevice {} |
| 125 | +unsafe impl Sync for CableKnownDevice {} |
72 | 126 |
|
73 | 127 | #[async_trait] |
74 | | -impl<'d> Device<'d, Cable, CableChannel<'d>> for CableKnownDevice<'d> { |
| 128 | +impl<'d> Device<'d, Cable, CableChannel<'d>> for CableKnownDevice { |
75 | 129 | async fn channel(&'d mut self) -> Result<(CableChannel, mpsc::Receiver<UxUpdate>), Error> { |
76 | 130 | todo!() |
77 | 131 | } |
|
0 commit comments