stun_types/attribute/
nonce.rs1use alloc::borrow::ToOwned;
12use alloc::string::{String, ToString};
13use core::convert::TryFrom;
14
15use crate::message::{StunParseError, StunWriteError};
16
17use super::{
18 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
19 AttributeWriteExt, RawAttribute,
20};
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct Nonce {
25 nonce: String,
26}
27
28impl AttributeStaticType for Nonce {
29 const TYPE: AttributeType = AttributeType(0x0015);
30}
31
32impl Attribute for Nonce {
33 fn get_type(&self) -> AttributeType {
34 Self::TYPE
35 }
36
37 fn length(&self) -> u16 {
38 self.nonce.len() as u16
39 }
40}
41
42impl AttributeWrite for Nonce {
43 fn to_raw(&self) -> RawAttribute<'_> {
44 RawAttribute::new(Nonce::TYPE, self.nonce.as_bytes())
45 }
46
47 fn write_into_unchecked(&self, dest: &mut [u8]) {
48 let len = self.padded_len();
49 self.write_header_unchecked(dest);
50 let offset = 4 + self.nonce.len();
51 dest[4..offset].copy_from_slice(self.nonce.as_bytes());
52 if len > offset {
53 dest[offset..len].fill(0);
54 }
55 }
56}
57
58impl AttributeFromRaw<'_> for Nonce {
59 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
60 where
61 Self: Sized,
62 {
63 Self::try_from(raw)
64 }
65}
66
67impl TryFrom<&RawAttribute<'_>> for Nonce {
68 type Error = StunParseError;
69
70 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
71 raw.check_type_and_len(Self::TYPE, ..=763)?;
72 Ok(Self {
73 nonce: core::str::from_utf8(&raw.value)
74 .map_err(|_| StunParseError::InvalidAttributeData)?
75 .to_owned(),
76 })
77 }
78}
79
80impl Nonce {
81 pub fn new(nonce: &str) -> Result<Self, StunWriteError> {
91 if nonce.len() > 763 {
92 return Err(StunWriteError::TooLarge {
93 expected: 763,
94 actual: nonce.len(),
95 });
96 }
97 Ok(Self {
98 nonce: nonce.to_string(),
99 })
100 }
101
102 pub fn nonce(&self) -> &str {
112 &self.nonce
113 }
114}
115
116impl core::fmt::Display for Nonce {
117 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 write!(f, "{}: {}", Self::TYPE, self.nonce)
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use alloc::vec;
126 use alloc::vec::Vec;
127 use byteorder::{BigEndian, ByteOrder};
128 use tracing::trace;
129
130 #[test]
131 fn nonce() {
132 let _log = crate::tests::test_init_log();
133 let attr = Nonce::new("nonce").unwrap();
134 trace!("{attr}");
135 assert_eq!(attr.nonce(), "nonce");
136 assert_eq!(attr.length() as usize, "nonce".len());
137 }
138
139 #[test]
140 fn nonce_raw() {
141 let _log = crate::tests::test_init_log();
142 let attr = Nonce::new("nonce").unwrap();
143 let raw = RawAttribute::from(&attr);
144 trace!("{raw}");
145 assert_eq!(raw.get_type(), Nonce::TYPE);
146 let mapped2 = Nonce::try_from(&raw).unwrap();
147 assert_eq!(mapped2.nonce(), "nonce");
148 }
149
150 #[test]
151 fn nonce_raw_wrong_type() {
152 let _log = crate::tests::test_init_log();
153 let attr = Nonce::new("nonce").unwrap();
154 let raw = RawAttribute::from(&attr);
155
156 let mut data: Vec<_> = raw.into();
158 BigEndian::write_u16(&mut data[0..2], 0);
159 assert!(matches!(
160 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
161 Err(StunParseError::WrongAttributeImplementation)
162 ));
163 }
164
165 #[test]
166 fn nonce_write_into() {
167 let _log = crate::tests::test_init_log();
168 let attr = Nonce::new("nonce").unwrap();
169 let raw = RawAttribute::from(&attr);
170
171 let mut dest = vec![0; raw.padded_len()];
172 attr.write_into(&mut dest).unwrap();
173 let raw = RawAttribute::from_bytes(&dest).unwrap();
174 let nonce = Nonce::try_from(&raw).unwrap();
175 assert_eq!(nonce.nonce(), "nonce");
176 }
177
178 #[test]
179 #[should_panic(expected = "out of range")]
180 fn nonce_write_into_unchecked() {
181 let _log = crate::tests::test_init_log();
182 let attr = Nonce::new("nonce").unwrap();
183 let raw = RawAttribute::from(&attr);
184
185 let mut dest = vec![0; raw.padded_len() - 1];
186 attr.write_into_unchecked(&mut dest);
187 }
188
189 #[test]
190 fn nonce_not_utf8() {
191 let _log = crate::tests::test_init_log();
192 let attr = Nonce::new("nonce").unwrap();
193 let raw = RawAttribute::from(&attr);
194 let mut data = raw.to_bytes();
195 data[6] = 0x88;
196 assert!(matches!(
197 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
198 Err(StunParseError::InvalidAttributeData)
199 ));
200 }
201
202 #[test]
203 fn nonce_new_too_large() {
204 let _log = crate::tests::test_init_log();
205 let mut large = String::new();
206 for _i in 0..95 {
207 large.push_str("abcdefgh");
208 }
209 large.push_str("abcd");
210 assert!(matches!(
211 Nonce::new(&large),
212 Err(StunWriteError::TooLarge {
213 expected: 763,
214 actual: 764
215 })
216 ));
217 }
218}