stun_types/attribute/
nonce.rs1use std::convert::TryFrom;
10
11use crate::message::{StunParseError, StunWriteError};
12
13use super::{
14 Attribute, AttributeExt, AttributeFromRaw, AttributeStaticType, AttributeType, AttributeWrite,
15 AttributeWriteExt, 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}
27
28impl Attribute for Nonce {
29 fn get_type(&self) -> AttributeType {
30 Self::TYPE
31 }
32
33 fn length(&self) -> u16 {
34 self.nonce.len() as u16
35 }
36}
37
38impl AttributeWrite for Nonce {
39 fn to_raw(&self) -> RawAttribute<'_> {
40 RawAttribute::new(Nonce::TYPE, self.nonce.as_bytes())
41 }
42
43 fn write_into_unchecked(&self, dest: &mut [u8]) {
44 let len = self.padded_len();
45 self.write_header_unchecked(dest);
46 let offset = 4 + self.nonce.len();
47 dest[4..offset].copy_from_slice(self.nonce.as_bytes());
48 if len > offset {
49 dest[offset..len].fill(0);
50 }
51 }
52}
53
54impl AttributeFromRaw<'_> for Nonce {
55 fn from_raw_ref(raw: &RawAttribute) -> Result<Self, StunParseError>
56 where
57 Self: Sized,
58 {
59 Self::try_from(raw)
60 }
61}
62
63impl TryFrom<&RawAttribute<'_>> for Nonce {
64 type Error = StunParseError;
65
66 fn try_from(raw: &RawAttribute) -> Result<Self, Self::Error> {
67 raw.check_type_and_len(Self::TYPE, ..=763)?;
68 Ok(Self {
69 nonce: std::str::from_utf8(&raw.value)
70 .map_err(|_| StunParseError::InvalidAttributeData)?
71 .to_owned(),
72 })
73 }
74}
75
76impl Nonce {
77 pub fn new(nonce: &str) -> Result<Self, StunWriteError> {
87 if nonce.len() > 763 {
88 return Err(StunWriteError::TooLarge {
89 expected: 763,
90 actual: nonce.len(),
91 });
92 }
93 Ok(Self {
94 nonce: nonce.to_string(),
95 })
96 }
97
98 pub fn nonce(&self) -> &str {
108 &self.nonce
109 }
110}
111
112impl std::fmt::Display for Nonce {
113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
114 write!(f, "{}: {}", Self::TYPE, self.nonce)
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use byteorder::{BigEndian, ByteOrder};
122 use tracing::trace;
123
124 #[test]
125 fn nonce() {
126 let _log = crate::tests::test_init_log();
127 let attr = Nonce::new("nonce").unwrap();
128 trace!("{attr}");
129 assert_eq!(attr.nonce(), "nonce");
130 assert_eq!(attr.length() as usize, "nonce".len());
131 let raw = RawAttribute::from(&attr);
132 trace!("{raw}");
133 assert_eq!(raw.get_type(), Nonce::TYPE);
134 let mapped2 = Nonce::try_from(&raw).unwrap();
135 assert_eq!(mapped2.nonce(), "nonce");
136 let mut data: Vec<_> = raw.into();
138 BigEndian::write_u16(&mut data[0..2], 0);
139 assert!(matches!(
140 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
141 Err(StunParseError::WrongAttributeImplementation)
142 ));
143 }
144
145 #[test]
146 fn nonce_not_utf8() {
147 let _log = crate::tests::test_init_log();
148 let attr = Nonce::new("nonce").unwrap();
149 let raw = RawAttribute::from(&attr);
150 let mut data = raw.to_bytes();
151 data[6] = 0x88;
152 assert!(matches!(
153 Nonce::try_from(&RawAttribute::from_bytes(data.as_ref()).unwrap()),
154 Err(StunParseError::InvalidAttributeData)
155 ));
156 }
157
158 #[test]
159 fn nonce_new_too_large() {
160 let _log = crate::tests::test_init_log();
161 let mut large = String::new();
162 for _i in 0..95 {
163 large.push_str("abcdefgh");
164 }
165 large.push_str("abcd");
166 assert!(matches!(
167 Nonce::new(&large),
168 Err(StunWriteError::TooLarge {
169 expected: 763,
170 actual: 764
171 })
172 ));
173 }
174}