1use crate::{Error, Result};
3use once_cell::sync::OnceCell;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::{
7 collections::BTreeMap,
8 fmt,
9 hash::{Hash, Hasher},
10};
11use time::OffsetDateTime;
12
13pub static DEVICE: OnceCell<DeviceMetaData> = OnceCell::new();
18
19#[derive(Debug, Copy, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
21pub struct DevicePublicKey(
22 #[serde(with = "hex::serde")] [u8; DevicePublicKey::SIZE],
23);
24
25impl DevicePublicKey {
26 pub const SIZE: usize = 32;
28}
29
30impl hex::FromHex for DevicePublicKey {
31 type Error = Error;
32 fn from_hex<T: AsRef<[u8]>>(value: T) -> Result<Self> {
33 let buf = hex::decode(value)?;
34 let buf: [u8; 32] = buf.as_slice().try_into()?;
35 Ok(Self(buf))
36 }
37}
38
39impl From<[u8; 32]> for DevicePublicKey {
40 fn from(value: [u8; 32]) -> Self {
41 Self(value)
42 }
43}
44
45impl From<&[u8; 32]> for DevicePublicKey {
46 fn from(value: &[u8; 32]) -> Self {
47 Self(*value)
48 }
49}
50
51impl TryFrom<&[u8]> for DevicePublicKey {
52 type Error = Error;
53
54 fn try_from(value: &[u8]) -> Result<Self> {
55 let value: [u8; 32] = value.try_into()?;
56 Ok(Self(value))
57 }
58}
59
60impl AsRef<[u8]> for DevicePublicKey {
61 fn as_ref(&self) -> &[u8] {
62 &self.0
63 }
64}
65
66impl fmt::Display for DevicePublicKey {
67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68 write!(f, "{}", hex::encode(self.0))
69 }
70}
71
72#[derive(Default, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
75pub struct DeviceMetaData {
76 #[serde(flatten)]
80 info: BTreeMap<String, Value>,
81}
82
83impl fmt::Display for DeviceMetaData {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 for (o, v) in &self.info {
86 if let Value::Object(map) = v {
87 for (k, v) in map {
88 if let Value::String(s) = v {
89 writeln!(f, "[{}] {}: {}", o, k, s)?;
90 }
91 }
92 }
93 }
94 Ok(())
95 }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, Eq)]
100#[serde(rename_all = "camelCase")]
101pub struct TrustedDevice {
102 public_key: DevicePublicKey,
104 extra_info: DeviceMetaData,
106 created_date: OffsetDateTime,
108}
109
110impl PartialEq for TrustedDevice {
111 fn eq(&self, other: &Self) -> bool {
112 self.public_key == other.public_key
113 }
114}
115
116impl Hash for TrustedDevice {
117 fn hash<H: Hasher>(&self, state: &mut H) {
118 self.public_key.as_ref().hash(state);
119 }
120}
121
122impl TrustedDevice {
123 pub fn new(
125 public_key: DevicePublicKey,
126 extra_info: Option<DeviceMetaData>,
127 created_date: Option<OffsetDateTime>,
128 ) -> Self {
129 let extra_info = if let Some(extra_info) = extra_info {
130 extra_info
131 } else {
132 if let Some(device) = DEVICE.get() {
133 device.clone()
134 } else {
135 Default::default()
136 }
137 };
138
139 Self {
140 public_key,
141 extra_info,
142 created_date: created_date
143 .unwrap_or_else(|| OffsetDateTime::now_utc()),
144 }
145 }
146
147 pub fn public_key(&self) -> &DevicePublicKey {
149 &self.public_key
150 }
151
152 pub fn public_id(&self) -> Result<String> {
154 let mut encoded = String::new();
155 bs58::encode(&self.public_key).into(&mut encoded)?;
156 Ok(encoded)
157 }
158
159 pub fn extra_info(&self) -> &DeviceMetaData {
161 &self.extra_info
162 }
163
164 pub fn created_date(&self) -> &OffsetDateTime {
166 &self.created_date
167 }
168}
169
170impl From<DevicePublicKey> for TrustedDevice {
171 fn from(value: DevicePublicKey) -> Self {
172 Self {
173 extra_info: Default::default(),
174 public_key: value,
175 created_date: OffsetDateTime::now_utc(),
176 }
177 }
178}
179
180impl TryFrom<&TrustedDevice> for (DevicePublicKey, String) {
181 type Error = Error;
182 fn try_from(value: &TrustedDevice) -> Result<Self> {
183 Ok((
184 value.public_key.clone(),
185 serde_json::to_string(&value.extra_info)?,
186 ))
187 }
188}