zoe_client/client/
secret.rs

1use crate::ClientError;
2use crate::error::Result;
3use serde::{Deserialize, Deserializer, Serialize, Serializer};
4use std::net::SocketAddr;
5use std::sync::Arc;
6use zoe_app_primitives::RelayAddress;
7use zoe_wire_protocol::{KeyPair, VerifyingKey};
8
9#[cfg(feature = "frb-api")]
10use flutter_rust_bridge::frb;
11
12#[cfg_attr(feature = "frb-api", frb(opaque))]
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct ClientSecret {
15    #[serde(
16        serialize_with = "serialize_key_pair",
17        deserialize_with = "deserialize_key_pair"
18    )]
19    pub(crate) inner_keypair: Arc<KeyPair>, // inner protocol
20    pub(crate) servers: Vec<RelayAddress>,
21    pub(crate) encryption_key: [u8; 32],
22}
23
24impl PartialEq for ClientSecret {
25    fn eq(&self, other: &Self) -> bool {
26        // Compare servers and encryption key, but not keypair (since KeyPair doesn't implement Eq)
27        self.servers == other.servers && self.encryption_key == other.encryption_key
28    }
29}
30
31impl Eq for ClientSecret {}
32
33impl ClientSecret {
34    /// Get the list of configured servers
35    pub fn servers(&self) -> &[RelayAddress] {
36        &self.servers
37    }
38}
39
40#[cfg_attr(feature = "frb-api", frb(ignore))]
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct LegacyClientSecret {
43    #[serde(
44        serialize_with = "serialize_key_pair",
45        deserialize_with = "deserialize_key_pair"
46    )]
47    inner_keypair: Arc<KeyPair>, // inner protocol
48    server_public_key: VerifyingKey, // TLS server key
49    server_addr: SocketAddr,
50    encryption_key: [u8; 32],
51}
52
53impl PartialEq for LegacyClientSecret {
54    fn eq(&self, other: &Self) -> bool {
55        // Compare all fields except keypair (since KeyPair doesn't implement Eq)
56        self.server_public_key == other.server_public_key
57            && self.server_addr == other.server_addr
58            && self.encryption_key == other.encryption_key
59    }
60}
61
62impl Eq for LegacyClientSecret {}
63
64fn serialize_key_pair<S>(
65    key_pair: &Arc<KeyPair>,
66    serializer: S,
67) -> std::result::Result<S::Ok, S::Error>
68where
69    S: Serializer,
70{
71    serializer.serialize_str(&key_pair.to_pem().map_err(serde::ser::Error::custom)?)
72}
73fn deserialize_key_pair<'de, D>(deserializer: D) -> std::result::Result<Arc<KeyPair>, D::Error>
74where
75    D: Deserializer<'de>,
76{
77    let s = String::deserialize(deserializer)?;
78    Ok(Arc::new(
79        KeyPair::from_pem(&s).map_err(serde::de::Error::custom)?,
80    ))
81}
82
83impl ClientSecret {
84    pub fn from_hex(hex: &str) -> Result<Self> {
85        let bytes = hex::decode(hex).map_err(|e| {
86            ClientError::BuildError(format!("Failed to decode hex for client secret: {e}"))
87        })?;
88        let secret = match postcard::from_bytes(&bytes) {
89            Ok(secret) => secret,
90            Err(e) => {
91                tracing::warn!(
92                    "Failed to deserialize client secret: {}. Trying with legacy format.",
93                    e
94                );
95                let legacy_secret: LegacyClientSecret =
96                    postcard::from_bytes(&bytes).map_err(|e| {
97                        ClientError::BuildError(format!(
98                            "Failed to deserialize legacy client secret: {e}"
99                        ))
100                    })?;
101                ClientSecret {
102                    inner_keypair: legacy_secret.inner_keypair,
103                    servers: vec![
104                        RelayAddress::new(legacy_secret.server_public_key)
105                            .with_address(legacy_secret.server_addr.into()),
106                    ],
107                    encryption_key: legacy_secret.encryption_key,
108                }
109            }
110        };
111        Ok(secret)
112    }
113
114    pub fn to_hex(&self) -> Result<String> {
115        let bytes = postcard::to_stdvec(&self).map_err(|e| {
116            ClientError::BuildError(format!("Failed to serialize client secret: {e}"))
117        })?;
118        Ok(hex::encode(bytes))
119    }
120}