tx5_core/
wire.rs

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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//! Tx5-signal wire-level protocol encoding utilities.

use crate::*;

/// 24 byte nonce for crypto_box cipher.
#[derive(Clone, Debug, Copy)]
pub struct Nonce(pub [u8; 24]);

impl serde::Serialize for Nonce {
    fn serialize<S>(
        &self,
        serializer: S,
    ) -> std::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let s = base64::encode_config(self.0, base64::URL_SAFE_NO_PAD);
        serializer.serialize_str(&s)
    }
}

impl<'de> serde::Deserialize<'de> for Nonce {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        let v = base64::decode_config(s, base64::URL_SAFE_NO_PAD)
            .map_err(serde::de::Error::custom)?;
        if v.len() != 24 {
            return Err(serde::de::Error::custom(Error::id("InvalidLen")));
        }
        let mut out = [0; 24];
        out.copy_from_slice(&v);
        Ok(Self(out))
    }
}

impl From<[u8; 24]> for Nonce {
    fn from(f: [u8; 24]) -> Self {
        Self(f)
    }
}

/// Cipher data for crypto_box.
#[derive(Clone, Debug)]
pub struct Cipher(pub Box<[u8]>);

impl serde::Serialize for Cipher {
    fn serialize<S>(
        &self,
        serializer: S,
    ) -> std::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let s = base64::encode_config(&self.0, base64::URL_SAFE_NO_PAD);
        serializer.serialize_str(&s)
    }
}

impl<'de> serde::Deserialize<'de> for Cipher {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        Ok(Self(
            base64::decode_config(s, base64::URL_SAFE_NO_PAD)
                .map_err(serde::de::Error::custom)?
                .into_boxed_slice(),
        ))
    }
}

impl From<Box<[u8]>> for Cipher {
    fn from(f: Box<[u8]>) -> Self {
        Self(f)
    }
}

/// Tx5 signal server wire protocol for client to server communication.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum Wire {
    /// When a client connects to a server, the server sends an initial
    /// authentication / hello request.
    #[serde(rename_all = "camelCase")]
    AuthReqV1 {
        /// The x25519 public key of this server.
        srv_pub: Id,

        /// The crypto box nonce for the encoded con_key.
        nonce: Nonce,

        /// An encoded con_key that must be returned in the AuthResV1 response.
        cipher: Cipher,

        /// iceServers configuration associated with this webrtc signal server.
        ice: serde_json::Value,
    },

    /// On receiving an AuthReqV1, a client should respond with this AuthResV1.
    #[serde(rename_all = "camelCase")]
    AuthResV1 {
        /// The decoded con_key proving we have a private key associated with
        /// our public key.
        con_key: Id,

        /// If we would like the server to consider us addressable, send true
        /// here. A server may have a limited number of addressable slots.
        req_addr: bool,
    },

    /// A client sends an encrypted message to another client.
    #[serde(rename_all = "camelCase")]
    FwdV1 {
        /// The remote id to send this message to,
        /// or that this message came from.
        rem_pub: Id,

        /// The crypto box nonce for the encoded FwdInnerV1 message.
        nonce: Nonce,

        /// The cipher bytes for the encoded FwdInnerV1 message.
        cipher: Cipher,
    },

    /// As a standin for bootstrapping, clients may trigger "demo" broadcasts
    /// announcing themselves to everyone else connected on the signal server.
    /// If "demo" mode is not enabled, sending a demo command may cause a ban.
    #[serde(rename_all = "camelCase")]
    DemoV1 {
        /// The client pub key to announce.
        rem_pub: Id,
    },
}

impl Wire {
    /// Decode from wire format (json).
    pub fn decode(wire: &[u8]) -> Result<Self> {
        serde_json::from_slice(wire).map_err(Error::err)
    }

    /// Encode into wire format (json).
    pub fn encode(&self) -> Result<Vec<u8>> {
        serde_json::to_string(&self)
            .map_err(Error::err)
            .map(|s| s.into_bytes())
    }
}

/// The internal message that is encrypted and forwarded between clients.
#[derive(Debug, serde::Deserialize, serde::Serialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum FwdInnerV1 {
    /// WebRTC offer.
    #[serde(rename_all = "camelCase")]
    Offer {
        /// Sequence.
        seq: f64,

        /// WebRTC offer.
        offer: serde_json::Value,
    },

    /// WebRTC answer.
    #[serde(rename_all = "camelCase")]
    Answer {
        /// Sequence.
        seq: f64,

        /// WebRTC answer.
        answer: serde_json::Value,
    },

    /// WebRTC ICE candidate.
    #[serde(rename_all = "camelCase")]
    Ice {
        /// Sequence.
        seq: f64,

        /// WebRTC ICE candidate.
        ice: serde_json::Value,
    },
}

impl FwdInnerV1 {
    /// Decode from wire format (json).
    pub fn decode(wire: &[u8]) -> Result<Self> {
        serde_json::from_slice(wire).map_err(Error::err)
    }

    /// Encode into wire format (json).
    pub fn encode(&self) -> Result<Vec<u8>> {
        serde_json::to_string(&self)
            .map_err(Error::err)
            .map(|s| s.into_bytes())
    }

    /// Set the seq.
    pub fn set_seq(&mut self, new_seq: f64) {
        match self {
            FwdInnerV1::Offer { seq, .. } => *seq = new_seq,
            FwdInnerV1::Answer { seq, .. } => *seq = new_seq,
            FwdInnerV1::Ice { seq, .. } => *seq = new_seq,
        }
    }

    /// Get the seq.
    pub fn get_seq(&self) -> f64 {
        match self {
            FwdInnerV1::Offer { seq, .. } => *seq,
            FwdInnerV1::Answer { seq, .. } => *seq,
            FwdInnerV1::Ice { seq, .. } => *seq,
        }
    }
}