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