iterm2_client/
validate.rs1use crate::error::{Error, Result};
2
3const MAX_ID_LEN: usize = 256;
4const MAX_VEC_LEN: usize = 10_000;
5const MAX_TEXT_LEN: usize = 10 * 1024 * 1024; pub fn identifier(id: &str, kind: &str) -> Result<()> {
10 if id.len() > MAX_ID_LEN {
11 return Err(Error::Api(format!(
12 "{kind} ID too long ({} bytes, max {MAX_ID_LEN})",
13 id.len()
14 )));
15 }
16 if id.contains('\0') {
17 return Err(Error::Api(format!(
18 "{kind} ID contains null byte"
19 )));
20 }
21 Ok(())
22}
23
24pub fn vec_len<T>(v: &[T], param: &str) -> Result<()> {
26 if v.len() > MAX_VEC_LEN {
27 return Err(Error::Api(format!(
28 "{param} too many elements ({}, max {MAX_VEC_LEN})",
29 v.len()
30 )));
31 }
32 Ok(())
33}
34
35pub fn text_len(text: &str) -> Result<()> {
37 if text.len() > MAX_TEXT_LEN {
38 return Err(Error::Api(format!(
39 "Text too long ({} bytes, max {MAX_TEXT_LEN})",
40 text.len()
41 )));
42 }
43 Ok(())
44}
45
46pub fn json_value(value: &str) -> Result<()> {
48 serde_json::from_str::<serde_json::Value>(value).map_err(|e| {
49 Error::Api(format!("Invalid JSON value: {e}"))
50 })?;
51 Ok(())
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn valid_identifier() {
60 identifier("session-abc-123", "session").unwrap();
61 identifier("active", "session").unwrap();
62 identifier("all", "session").unwrap();
63 }
64
65 #[test]
66 fn identifier_with_null_byte() {
67 let err = identifier("session\0id", "session").unwrap_err();
68 assert!(err.to_string().contains("null byte"));
69 }
70
71 #[test]
72 fn identifier_too_long() {
73 let long_id = "x".repeat(MAX_ID_LEN + 1);
74 let err = identifier(&long_id, "session").unwrap_err();
75 assert!(err.to_string().contains("too long"));
76 }
77
78 #[test]
79 fn vec_within_bounds() {
80 vec_len(&vec![1, 2, 3], "ids").unwrap();
81 }
82
83 #[test]
84 fn vec_exceeds_bounds() {
85 let big: Vec<i32> = vec![0; MAX_VEC_LEN + 1];
86 let err = vec_len(&big, "ids").unwrap_err();
87 assert!(err.to_string().contains("too many"));
88 }
89
90 #[test]
91 fn text_within_bounds() {
92 text_len("hello world").unwrap();
93 }
94
95 #[test]
96 fn text_exceeds_bounds() {
97 let big = "x".repeat(MAX_TEXT_LEN + 1);
98 let err = text_len(&big).unwrap_err();
99 assert!(err.to_string().contains("too long"));
100 }
101
102 #[test]
103 fn valid_json_values() {
104 json_value(r#""hello""#).unwrap();
105 json_value("42").unwrap();
106 json_value("true").unwrap();
107 json_value("null").unwrap();
108 json_value(r#"{"key": "value"}"#).unwrap();
109 json_value(r#"[1, 2, 3]"#).unwrap();
110 }
111
112 #[test]
113 fn invalid_json_value() {
114 let err = json_value("not valid json").unwrap_err();
115 assert!(err.to_string().contains("Invalid JSON"));
116 }
117
118 #[test]
119 fn empty_string_is_invalid_json() {
120 let err = json_value("").unwrap_err();
121 assert!(err.to_string().contains("Invalid JSON"));
122 }
123}