1use crate::attributes::{stunt_attribute, DecodeAttributeValue, EncodeAttributeValue};
2use crate::context::{AttributeDecoderContext, AttributeEncoderContext};
3use crate::error::{StunError, StunErrorType};
4use crate::strings::QuotedString;
5use crate::{strings, Decode, Encode};
6use precis_core::profile::PrecisFastInvocation;
7use precis_profiles::OpaqueString;
8use std::convert::TryFrom;
9
10const REALM: u16 = 0x0014;
11
12const MAX_ENCODED_SIZE: usize = 509;
13const MAX_DECODED_SIZE: usize = 763;
14
15#[derive(Debug, PartialEq, Clone, Hash, Eq, PartialOrd, Ord)]
44pub struct Realm(QuotedString);
45
46impl Realm {
47 pub fn new<S>(value: S) -> Result<Self, StunError>
51 where
52 S: AsRef<str>,
53 {
54 let realm = strings::opaque_string_prepapre(value.as_ref())?;
55 let realm = QuotedString::try_from(realm.as_ref())?;
56 let realm_len = realm.as_str().len();
57 (realm_len <= MAX_ENCODED_SIZE)
58 .then_some(Realm(realm))
59 .ok_or_else(|| {
60 StunError::new(
61 StunErrorType::ValueTooLong,
62 format!(
63 "Value length {} > max. encoded size {}",
64 realm_len, MAX_ENCODED_SIZE
65 ),
66 )
67 })
68 }
69
70 pub fn as_str(&self) -> &str {
72 self.0.as_str()
73 }
74}
75
76impl PartialEq<&str> for Realm {
77 fn eq(&self, other: &&str) -> bool {
78 OpaqueString::compare(self, *other).unwrap_or(false)
79 }
80}
81
82impl PartialEq<Realm> for &str {
83 fn eq(&self, other: &Realm) -> bool {
84 OpaqueString::compare(*self, other).unwrap_or(false)
85 }
86}
87
88impl PartialEq<str> for Realm {
89 fn eq(&self, other: &str) -> bool {
90 OpaqueString::compare(self, other).unwrap_or(false)
91 }
92}
93
94impl PartialEq<String> for Realm {
95 fn eq(&self, other: &String) -> bool {
96 OpaqueString::compare(self, other).unwrap_or(false)
97 }
98}
99
100impl PartialEq<Realm> for String {
101 fn eq(&self, other: &Realm) -> bool {
102 OpaqueString::compare(self.as_str(), other).unwrap_or(false)
103 }
104}
105
106impl AsRef<str> for Realm {
107 fn as_ref(&self) -> &str {
108 self.0.as_ref()
109 }
110}
111
112impl AsRef<String> for Realm {
113 fn as_ref(&self) -> &String {
114 self.0.as_ref()
115 }
116}
117
118impl TryFrom<&str> for Realm {
119 type Error = StunError;
120
121 fn try_from(value: &str) -> Result<Self, Self::Error> {
122 Realm::new(value)
123 }
124}
125
126impl TryFrom<&String> for Realm {
127 type Error = StunError;
128
129 fn try_from(value: &String) -> Result<Self, Self::Error> {
130 Realm::new(value)
131 }
132}
133
134impl TryFrom<String> for Realm {
135 type Error = StunError;
136
137 fn try_from(value: String) -> Result<Self, Self::Error> {
138 Realm::new(value)
139 }
140}
141
142impl DecodeAttributeValue for Realm {
143 fn decode(ctx: AttributeDecoderContext) -> Result<(Self, usize), StunError> {
144 let raw_value = ctx.raw_value();
145
146 if raw_value.len() > MAX_DECODED_SIZE {
147 return Err(StunError::new(
148 StunErrorType::ValueTooLong,
149 format!(
150 "Value length {} > max. decoded size {}",
151 raw_value.len(),
152 MAX_DECODED_SIZE
153 ),
154 ));
155 }
156
157 let (quoted, size) = QuotedString::decode(raw_value)?;
158
159 Ok((Self(quoted), size))
160 }
161}
162
163impl EncodeAttributeValue for Realm {
164 fn encode(&self, mut ctx: AttributeEncoderContext) -> Result<usize, StunError> {
165 if self.as_str().len() > MAX_ENCODED_SIZE {
166 return Err(StunError::new(
167 StunErrorType::ValueTooLong,
168 format!(
169 "Value length {} > max. encoded size {}",
170 self.as_str().len(),
171 MAX_ENCODED_SIZE
172 ),
173 ));
174 }
175
176 self.0.encode(ctx.raw_value_mut())
177 }
178}
179
180impl crate::attributes::AsVerifiable for Realm {}
181
182stunt_attribute!(Realm, REALM);
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::error::StunErrorType;
188 use crate::StunAttribute;
189
190 #[test]
191 fn constructor_realm() {
192 let value = String::from("realm");
193 let realm_1 = Realm::new(&value).expect("Can not create REALM attribute");
194 let realm_2 = Realm::new(&value).expect("Can not create REALM attribute");
195 assert_eq!(realm_1, "realm");
196 assert_eq!("realm", realm_1);
197 assert_eq!(value, realm_1);
198 assert_eq!(realm_1, value);
199 assert_eq!(realm_1, realm_2);
200
201 let val: &String = realm_1.as_ref();
202 assert!(value.eq(val));
203
204 let value: &str = realm_1.as_ref();
205 assert!(value.eq(val));
206
207 let result = Realm::try_from("");
209 assert_eq!(
210 result.expect_err("Error expected"),
211 StunErrorType::InvalidParam
212 );
213
214 let result = Realm::try_from("bad\u{0009}realm");
216 assert_eq!(
217 result.expect_err("Error expected"),
218 StunErrorType::InvalidParam
219 );
220
221 let value = "x".repeat(MAX_ENCODED_SIZE);
222 let _result = Realm::try_from(value).expect("Can not create a Realm attribute");
223
224 let value = "x".repeat(MAX_ENCODED_SIZE + 1);
225 let result = Realm::try_from(&value);
226 assert_eq!(
227 result.expect_err("Error expected"),
228 StunErrorType::ValueTooLong
229 );
230 }
231
232 #[test]
233 fn decode_realm_value() {
234 let dummy_msg = [];
235 let buffer = [
237 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, ];
241 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
242
243 let (realm, size) = Realm::decode(ctx).expect("Can not decode REALM");
244 assert_eq!(size, 11);
245 assert_eq!(realm.as_str(), "example.org");
246
247 let value = "x".repeat(MAX_DECODED_SIZE);
248 let ctx = AttributeDecoderContext::new(None, &dummy_msg, value.as_bytes());
249 let (_realm, size) = Realm::decode(ctx).expect("Can not decode NONCE");
250 assert_eq!(size, MAX_DECODED_SIZE);
251 }
252
253 #[test]
254 fn decode_realm_value_error() {
255 let dummy_msg = [];
256 let buffer = [
258 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, ];
262 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
263
264 assert_eq!(
266 Realm::decode(ctx).expect_err("Error expected"),
267 StunErrorType::InvalidParam
268 );
269
270 let buffer = [
272 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x22, ];
278 let ctx = AttributeDecoderContext::new(None, &dummy_msg, &buffer);
279
280 assert_eq!(
282 Realm::decode(ctx).expect_err("Error expected"),
283 StunErrorType::InvalidParam
284 );
285
286 let value = "x".repeat(MAX_DECODED_SIZE + 1);
287 let ctx = AttributeDecoderContext::new(None, &dummy_msg, value.as_bytes());
288 assert_eq!(
289 Realm::decode(ctx).expect_err("Error expected"),
290 StunErrorType::ValueTooLong
291 );
292 }
293
294 #[test]
295 fn encode_realm_value() {
296 let dummy_msg: [u8; 0] = [0x0; 0];
297 let realm = Realm::try_from(" example.org ").expect("Expected QuotedString");
298
299 let mut buffer: [u8; 11] = [0x0; 11];
300 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
301 let result = realm.encode(ctx);
302 assert_eq!(result, Ok(11));
303
304 let mut buffer: [u8; MAX_ENCODED_SIZE] = [0x0; MAX_ENCODED_SIZE];
305 let realm = Realm::try_from("x".repeat(MAX_ENCODED_SIZE))
306 .expect("Can not create a Realm attribute");
307 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
308 let result = realm.encode(ctx);
309 assert_eq!(result, Ok(MAX_ENCODED_SIZE));
310 }
311
312 #[test]
313 fn encode_realm_value_error() {
314 let dummy_msg: [u8; 0] = [0x0; 0];
315 let realm = Realm::try_from(" example.org ").expect("Expected QuotedString");
316
317 let mut buffer: [u8; 10] = [0x0; 10];
318 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
319 let result = realm.encode(ctx);
320 assert_eq!(
321 result.expect_err("Error expected"),
322 StunErrorType::SmallBuffer
323 );
324
325 let mut buffer: [u8; MAX_ENCODED_SIZE + 1] = [0x0; MAX_ENCODED_SIZE + 1];
326 let str = "x".repeat(MAX_ENCODED_SIZE + 1);
327 let value = QuotedString::try_from(str.as_str()).expect("Expected QuotedString");
328 let realm = Realm(value);
329 let ctx = AttributeEncoderContext::new(None, &dummy_msg, &mut buffer);
330 let result = realm.encode(ctx);
331 assert_eq!(
332 result.expect_err("Error expected"),
333 StunErrorType::ValueTooLong
334 );
335 }
336
337 #[test]
338 fn realm_stunt_attribute() {
339 let attr = StunAttribute::Realm(Realm::try_from("test").expect("Expected QuotedString"));
340 assert!(attr.is_realm());
341 assert!(attr.as_realm().is_ok());
342 assert!(attr.as_unknown().is_err());
343
344 assert!(attr.attribute_type().is_comprehension_required());
345 assert!(!attr.attribute_type().is_comprehension_optional());
346
347 let dbg_fmt = format!("{:?}", attr);
348 assert_eq!("Realm(Realm(QuotedString(\"test\")))", dbg_fmt);
349 }
350}