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::Vec;
124 use byteorder::{BigEndian, ByteOrder};
125 use tracing::trace;
126
127 #[test]
128 fn nonce() {
129 let _log = crate::tests::test_init_log();
130 let attr = Nonce::new("nonce").unwrap();
131 trace!("{attr}");
132 assert_eq!(attr.nonce(), "nonce");
133 assert_eq!(attr.length() as usize, "nonce".len());
134 let raw = RawAttribute::from(&attr);
135 trace!("{raw}");
136 assert_eq!(raw.get_type(), Nonce::TYPE);
137 let mapped2 = Nonce::try_from(&raw).unwrap();
138 assert_eq!(mapped2.nonce(), "nonce");
139 let mut data: Vec<_> = raw.into();
141 BigEndian::write_u16(&mut data[0..2], 0);
142 assert!(matches!(
143 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
144 Err(StunParseError::WrongAttributeImplementation)
145 ));
146 }
147
148 #[test]
149 fn nonce_not_utf8() {
150 let _log = crate::tests::test_init_log();
151 let attr = Nonce::new("nonce").unwrap();
152 let raw = RawAttribute::from(&attr);
153 let mut data = raw.to_bytes();
154 data[6] = 0x88;
155 assert!(matches!(
156 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
157 Err(StunParseError::InvalidAttributeData)
158 ));
159 }
160
161 #[test]
162 fn nonce_new_too_large() {
163 let _log = crate::tests::test_init_log();
164 let mut large = String::new();
165 for _i in 0..95 {
166 large.push_str("abcdefgh");
167 }
168 large.push_str("abcd");
169 assert!(matches!(
170 Nonce::new(&large),
171 Err(StunWriteError::TooLarge {
172 expected: 763,
173 actual: 764
174 })
175 ));
176 }
177}