stun_types/attribute/
nonce.rs1use std::convert::TryFrom;
10
11use crate::message::{StunParseError, StunWriteError};
12
13use super::{
14 Attribute, AttributeExt, AttributeStaticType, AttributeType, AttributeWrite, AttributeWriteExt,
15 RawAttribute,
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct Nonce {
21 nonce: String,
22}
23
24impl AttributeStaticType for Nonce {
25 const TYPE: AttributeType = AttributeType(0x0015);
26}
27impl Attribute for Nonce {
28 fn get_type(&self) -> AttributeType {
29 Self::TYPE
30 }
31
32 fn length(&self) -> u16 {
33 self.nonce.len() as u16
34 }
35}
36impl AttributeWrite for Nonce {
37 fn to_raw(&self) -> RawAttribute {
38 RawAttribute::new(Nonce::TYPE, self.nonce.as_bytes())
39 }
40 fn write_into_unchecked(&self, dest: &mut [u8]) {
41 let len = self.padded_len();
42 self.write_header_unchecked(dest);
43 let offset = 4 + self.nonce.len();
44 dest[4..offset].copy_from_slice(self.nonce.as_bytes());
45 if len > offset {
46 dest[offset..len].fill(0);
47 }
48 }
49}
50impl<'a> TryFrom<&RawAttribute<'a>> for Nonce {
51 type Error = StunParseError;
52
53 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
54 raw.check_type_and_len(Self::TYPE, ..=763)?;
55 Ok(Self {
56 nonce: std::str::from_utf8(&raw.value)
57 .map_err(|_| StunParseError::InvalidAttributeData)?
58 .to_owned(),
59 })
60 }
61}
62
63impl Nonce {
64 pub fn new(nonce: &str) -> Result<Self, StunWriteError> {
74 if nonce.len() > 763 {
75 return Err(StunWriteError::TooLarge {
76 expected: 763,
77 actual: nonce.len(),
78 });
79 }
80 Ok(Self {
81 nonce: nonce.to_string(),
82 })
83 }
84
85 pub fn nonce(&self) -> &str {
95 &self.nonce
96 }
97}
98
99impl std::fmt::Display for Nonce {
100 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101 write!(f, "{}: {}", Self::TYPE, self.nonce)
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108 use byteorder::{BigEndian, ByteOrder};
109 use tracing::trace;
110
111 #[test]
112 fn nonce() {
113 let _log = crate::tests::test_init_log();
114 let attr = Nonce::new("nonce").unwrap();
115 trace!("{attr}");
116 assert_eq!(attr.nonce(), "nonce");
117 assert_eq!(attr.length() as usize, "nonce".len());
118 let raw = RawAttribute::from(&attr);
119 trace!("{raw}");
120 assert_eq!(raw.get_type(), Nonce::TYPE);
121 let mapped2 = Nonce::try_from(&raw).unwrap();
122 assert_eq!(mapped2.nonce(), "nonce");
123 let mut data: Vec<_> = raw.into();
125 BigEndian::write_u16(&mut data[0..2], 0);
126 assert!(matches!(
127 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
128 Err(StunParseError::WrongAttributeImplementation)
129 ));
130 }
131
132 #[test]
133 fn nonce_not_utf8() {
134 let _log = crate::tests::test_init_log();
135 let attr = Nonce::new("nonce").unwrap();
136 let raw = RawAttribute::from(&attr);
137 let mut data = raw.to_bytes();
138 data[6] = 0x88;
139 assert!(matches!(
140 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
141 Err(StunParseError::InvalidAttributeData)
142 ));
143 }
144
145 #[test]
146 fn nonce_new_too_large() {
147 let _log = crate::tests::test_init_log();
148 let mut large = String::new();
149 for _i in 0..95 {
150 large.push_str("abcdefgh");
151 }
152 large.push_str("abcd");
153 assert!(matches!(
154 Nonce::new(&large),
155 Err(StunWriteError::TooLarge {
156 expected: 763,
157 actual: 764
158 })
159 ));
160 }
161}