1use bytes::Bytes;
6
7use crate::{
8 Version,
9 coding::{self, Decode, DecodeError, Encode, EncodeError, Sizer},
10 ietf, lite,
11};
12
13pub(crate) const MAX_SETUP_SIZE: usize = 64 * 1024;
15
16const CLIENT_SETUP: u8 = 0x20;
17const SERVER_SETUP: u8 = 0x21;
18
19pub(crate) const SETUP_V17: u64 = 0x2F00;
21
22#[derive(Clone, PartialEq, Eq)]
26pub struct Token {
27 pub kind: u64,
29 pub value: Vec<u8>,
31}
32
33impl std::fmt::Debug for Token {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "Token(kind={}, <{} bytes>)", self.kind, self.value.len())
36 }
37}
38
39impl Token {
40 pub const OUT_OF_BAND: u64 = 0x0;
42 pub const CAT: u64 = 0x1;
44}
45
46#[derive(Clone)]
48pub(crate) struct Setup {
49 pub parameters: Bytes,
50}
51
52impl std::fmt::Debug for Setup {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.debug_struct("Setup")
56 .field("parameters_len", &self.parameters.len())
57 .finish()
58 }
59}
60
61impl Setup {
62 fn check_version(v: Version) {
63 match v {
64 Version::Ietf(ietf::Version::Draft14 | ietf::Version::Draft15 | ietf::Version::Draft16)
65 | Version::Lite(_) => unreachable!("Setup is draft-17+ only"),
66 _ => {}
67 }
68 }
69}
70
71impl Encode<Version> for Setup {
72 fn control(&self, _: Version) -> Option<crate::stats::Control> {
73 Some(crate::stats::Control::Session)
74 }
75
76 fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
77 Self::check_version(v);
78 SETUP_V17.encode(w, v)?;
79 u16::try_from(self.parameters.len())
80 .map_err(|_| EncodeError::TooLarge)?
81 .encode(w, v)?;
82 if w.remaining_mut() < self.parameters.len() {
83 return Err(EncodeError::Short);
84 }
85 w.put_slice(&self.parameters);
86 Ok(())
87 }
88}
89
90impl Decode<Version> for Setup {
91 fn control(&self, _: Version) -> Option<crate::stats::Control> {
92 Some(crate::stats::Control::Session)
93 }
94
95 fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
96 Self::check_version(v);
97 let kind = u64::decode(r, v)?;
98 if kind != SETUP_V17 {
99 return Err(DecodeError::InvalidValue);
100 }
101 let size = u16::decode(r, v)? as usize;
103 if r.remaining() < size {
104 return Err(DecodeError::Short);
105 }
106 let msg = r.copy_to_bytes(size);
107 Ok(Self { parameters: msg })
108 }
109}
110
111#[derive(Clone, Copy, Debug, PartialEq, Eq)]
112enum SetupVersion {
113 Draft14,
114 Draft15Plus,
115 Modern,
117 LiteLegacy,
118 Unsupported,
119}
120
121impl SetupVersion {
122 fn from_version(v: Version) -> Self {
123 match v {
124 Version::Ietf(ietf::Version::Draft14) => Self::Draft14,
125 Version::Ietf(ietf::Version::Draft15) | Version::Ietf(ietf::Version::Draft16) => Self::Draft15Plus,
126 Version::Ietf(ietf::Version::Draft17)
127 | Version::Ietf(ietf::Version::Draft18)
128 | Version::Ietf(ietf::Version::Draft19)
129 | Version::Ietf(ietf::Version::Draft20)
130 | Version::Ietf(ietf::Version::Draft21)
131 | Version::Ietf(ietf::Version::Draft22) => Self::Modern,
132 Version::Lite(lite::Version::Lite01) | Version::Lite(lite::Version::Lite02) => Self::LiteLegacy,
133 Version::Lite(_) => Self::Unsupported,
134 }
135 }
136}
137
138#[derive(Clone)]
140pub(crate) struct Client {
141 pub versions: coding::Versions,
143
144 pub parameters: Bytes,
146}
147
148impl std::fmt::Debug for Client {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 f.debug_struct("Client")
151 .field("versions", &self.versions)
152 .field("parameters_len", &self.parameters.len())
153 .finish()
154 }
155}
156
157impl Client {
158 fn encode_inner<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
159 match SetupVersion::from_version(v) {
160 SetupVersion::Draft15Plus => {
161 }
163 SetupVersion::Draft14 | SetupVersion::LiteLegacy => self.versions.encode(w, v)?,
164 SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
165 };
166 if w.remaining_mut() < self.parameters.len() {
167 return Err(EncodeError::Short);
168 }
169 w.put_slice(&self.parameters);
170 Ok(())
171 }
172}
173
174impl Decode<Version> for Client {
175 fn control(&self, _: Version) -> Option<crate::stats::Control> {
176 Some(crate::stats::Control::Session)
177 }
178
179 fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
181 let kind = u8::decode(r, v)?;
182 if kind != CLIENT_SETUP {
183 return Err(DecodeError::InvalidValue);
184 }
185
186 let size = match SetupVersion::from_version(v) {
187 SetupVersion::Draft14 | SetupVersion::Draft15Plus => u16::decode(r, v)? as usize,
188 SetupVersion::LiteLegacy => usize::decode(r, v)?,
189 SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
190 };
191
192 if size > MAX_SETUP_SIZE {
193 return Err(DecodeError::MessageTooLarge {
194 size,
195 max: MAX_SETUP_SIZE,
196 });
197 }
198
199 if r.remaining() < size {
200 return Err(DecodeError::Short);
201 }
202
203 let mut msg = r.copy_to_bytes(size);
204
205 let versions = match SetupVersion::from_version(v) {
206 SetupVersion::Draft15Plus => {
207 coding::Versions::from([v.into()])
209 }
210 SetupVersion::Draft14 | SetupVersion::LiteLegacy => {
211 coding::Versions::decode(&mut msg, v).map_err(DecodeError::complete)?
212 }
213 SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
214 };
215
216 Ok(Self {
217 versions,
218 parameters: msg,
219 })
220 }
221}
222
223impl Encode<Version> for Client {
224 fn control(&self, _: Version) -> Option<crate::stats::Control> {
225 Some(crate::stats::Control::Session)
226 }
227
228 fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
230 CLIENT_SETUP.encode(w, v)?;
231
232 let mut sizer = Sizer::default();
233 self.encode_inner(&mut sizer, v)?;
234 let size = sizer.size;
235 if size > MAX_SETUP_SIZE {
236 return Err(EncodeError::TooLarge);
237 }
238
239 match SetupVersion::from_version(v) {
240 SetupVersion::Draft14 | SetupVersion::Draft15Plus => {
241 u16::try_from(size).map_err(|_| EncodeError::TooLarge)?.encode(w, v)?;
242 }
243 SetupVersion::LiteLegacy => (size as u64).encode(w, v)?,
244 SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
245 }
246 self.encode_inner(w, v)
247 }
248}
249
250#[derive(Clone)]
252pub(crate) struct Server {
253 pub version: coding::Version,
255
256 pub parameters: Bytes,
258}
259
260impl std::fmt::Debug for Server {
261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
262 f.debug_struct("Server")
263 .field("version", &self.version)
264 .field("parameters_len", &self.parameters.len())
265 .finish()
266 }
267}
268
269impl Server {
270 fn encode_inner<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
271 match SetupVersion::from_version(v) {
272 SetupVersion::Draft15Plus => {
273 }
275 SetupVersion::Draft14 | SetupVersion::LiteLegacy => self.version.encode(w, v)?,
276 SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
277 };
278 if w.remaining_mut() < self.parameters.len() {
279 return Err(EncodeError::Short);
280 }
281 w.put_slice(&self.parameters);
282 Ok(())
283 }
284}
285
286impl Encode<Version> for Server {
287 fn control(&self, _: Version) -> Option<crate::stats::Control> {
288 Some(crate::stats::Control::Session)
289 }
290
291 fn encode<W: bytes::BufMut>(&self, w: &mut W, v: Version) -> Result<(), EncodeError> {
293 SERVER_SETUP.encode(w, v)?;
294
295 let mut sizer = Sizer::default();
296 self.encode_inner(&mut sizer, v)?;
297 let size = sizer.size;
298 if size > MAX_SETUP_SIZE {
299 return Err(EncodeError::TooLarge);
300 }
301
302 match SetupVersion::from_version(v) {
303 SetupVersion::Draft14 | SetupVersion::Draft15Plus => {
304 u16::try_from(size).map_err(|_| EncodeError::TooLarge)?.encode(w, v)?;
305 }
306 SetupVersion::LiteLegacy => (size as u64).encode(w, v)?,
307 SetupVersion::Modern | SetupVersion::Unsupported => return Err(EncodeError::Version),
308 }
309
310 self.encode_inner(w, v)
311 }
312}
313
314impl Decode<Version> for Server {
315 fn control(&self, _: Version) -> Option<crate::stats::Control> {
316 Some(crate::stats::Control::Session)
317 }
318
319 fn decode<R: bytes::Buf>(r: &mut R, v: Version) -> Result<Self, DecodeError> {
321 let kind = u8::decode(r, v)?;
322 if kind != SERVER_SETUP {
323 return Err(DecodeError::InvalidValue);
324 }
325
326 let size = match SetupVersion::from_version(v) {
327 SetupVersion::Draft14 | SetupVersion::Draft15Plus => u16::decode(r, v)? as usize,
328 SetupVersion::LiteLegacy => usize::decode(r, v)?,
329 SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
330 };
331
332 if size > MAX_SETUP_SIZE {
333 return Err(DecodeError::MessageTooLarge {
334 size,
335 max: MAX_SETUP_SIZE,
336 });
337 }
338
339 if r.remaining() < size {
340 return Err(DecodeError::Short);
341 }
342
343 let mut msg = r.copy_to_bytes(size);
344 let version = match SetupVersion::from_version(v) {
345 SetupVersion::Draft15Plus => v.into(),
346 SetupVersion::Draft14 | SetupVersion::LiteLegacy => {
347 coding::Version::decode(&mut msg, v).map_err(DecodeError::complete)?
348 }
349 SetupVersion::Modern | SetupVersion::Unsupported => return Err(DecodeError::Version),
350 };
351
352 Ok(Self {
353 version,
354 parameters: msg,
355 })
356 }
357}
358
359#[cfg(test)]
360mod tests {
361 use super::*;
362
363 #[test]
364 #[tracing_test::traced_test]
365 fn credentials_stay_out_of_traces() {
366 let secret = "credential-that-must-not-be-logged";
367 let token = Token {
368 kind: Token::OUT_OF_BAND,
369 value: secret.as_bytes().to_vec(),
370 };
371 let setup = lite::Setup {
372 path: Some(format!("/room?jwt={secret}")),
373 ..Default::default()
374 };
375 let wire = setup.encode_bytes(lite::Version::Lite06).unwrap();
376 let decoded = lite::Setup::decode(&mut wire.as_ref(), lite::Version::Lite06).unwrap();
377 assert_eq!(decoded, setup);
378
379 let version = ietf::Version::Draft22;
380 let mut params = ietf::Parameters::default();
381 ietf::token::into_setup(&mut params, &token, version).unwrap();
382 params.set_bytes(ietf::ParameterBytes::Path, format!("/room?jwt={secret}").into_bytes());
383 let setup = Setup {
384 parameters: params.encode_bytes(version).unwrap(),
385 };
386 let wire = setup.encode_bytes(Version::Ietf(version)).unwrap();
387 let decoded = Setup::decode(&mut wire.as_ref(), Version::Ietf(version)).unwrap();
388 let params = ietf::Parameters::decode(&mut decoded.parameters.as_ref(), version).unwrap();
389 assert_eq!(ietf::token::from_setup(¶ms, version).unwrap(), Some(token.clone()));
390 let client = Client {
391 versions: coding::Versions::from([Version::Ietf(version).into()]),
392 parameters: setup.parameters.clone(),
393 };
394 let server = Server {
395 version: Version::Ietf(version).into(),
396 parameters: setup.parameters.clone(),
397 };
398 let mut lite_params = lite::Parameters::default();
399 lite_params.set_bytes(999, secret.as_bytes().to_vec());
400 tracing::trace!(
401 ?token,
402 ?setup,
403 ?decoded,
404 ?params,
405 ?client,
406 ?server,
407 ?lite_params,
408 "SETUP diagnostics"
409 );
410
411 let uri = format!("https://relay.example/room?jwt={secret}");
412 let goaway = lite::Goaway {
413 uri: uri.as_str().into(),
414 };
415 let wire = goaway.encode_bytes(lite::Version::Lite06).unwrap();
416 assert_eq!(
417 lite::Goaway::decode(&mut wire.as_ref(), lite::Version::Lite06)
418 .unwrap()
419 .uri,
420 uri
421 );
422 let goaway = ietf::GoAway {
423 new_session_uri: uri.as_str().into(),
424 timeout: 0,
425 };
426 let wire = goaway.encode_bytes(version).unwrap();
427 assert_eq!(
428 ietf::GoAway::decode(&mut wire.as_ref(), version)
429 .unwrap()
430 .new_session_uri,
431 uri
432 );
433 tracing::trace!(goaway = ?crate::goaway::Goaway::redirect(uri), "GOAWAY diagnostics");
434
435 let mut body = Vec::new();
437 (secret.len() + 1).encode(&mut body, lite::Version::Lite06).unwrap();
438 body.extend_from_slice(secret.as_bytes());
439 let mut malformed = Vec::new();
440 body.len().encode(&mut malformed, lite::Version::Lite06).unwrap();
441 malformed.extend_from_slice(&body);
442 assert!(lite::Goaway::decode(&mut malformed.as_slice(), lite::Version::Lite06).is_err());
443 let mut body = Vec::new();
444 format!("https://relay.example/?jwt={secret}")
446 .encode(&mut body, version)
447 .unwrap();
448 let mut malformed = Vec::new();
449 (body.len() as u16).encode(&mut malformed, version).unwrap();
450 malformed.extend_from_slice(&body);
451 assert!(ietf::GoAway::decode(&mut malformed.as_slice(), version).is_err());
452
453 assert!(logs_contain("encoding"));
454 assert!(logs_contain("decoded"));
455 assert!(logs_contain("SETUP diagnostics"));
456 assert!(logs_contain("GOAWAY diagnostics"));
457 assert!(!logs_contain(secret));
458 let decimal = format!("{:?}", secret.as_bytes());
459 assert!(!logs_contain(&decimal[1..decimal.len() - 1]));
460 }
461
462 #[test]
464 fn encode_enforces_the_setup_limit() {
465 let v = Version::Lite(lite::Version::Lite01);
466 let parameters = Bytes::from(vec![0; MAX_SETUP_SIZE]);
467
468 let client = Client {
469 versions: coding::Versions::from([v.into()]),
470 parameters: parameters.clone(),
471 };
472 let mut buf = Vec::new();
473 assert!(matches!(client.encode(&mut buf, v), Err(EncodeError::TooLarge)));
474
475 let server = Server {
476 version: v.into(),
477 parameters,
478 };
479 let mut buf = Vec::new();
480 assert!(matches!(server.encode(&mut buf, v), Err(EncodeError::TooLarge)));
481 }
482}