tellaro_query_language/mutators/
encoding.rs1use super::{Mutator, MutatorParams};
6use crate::error::{Result, TqlError};
7use base64::{engine::general_purpose, Engine as _};
8use serde_json::Value as JsonValue;
9
10pub struct Base64EncodeMutator {
12 _params: MutatorParams,
13}
14
15impl Base64EncodeMutator {
16 pub fn new(params: MutatorParams) -> Self {
17 Self { _params: params }
18 }
19}
20
21impl Mutator for Base64EncodeMutator {
22 fn apply(
23 &self,
24 _field_name: &str,
25 _record: &JsonValue,
26 value: &JsonValue,
27 ) -> Result<JsonValue> {
28 match value {
29 JsonValue::String(s) => {
30 let encoded = general_purpose::STANDARD.encode(s.as_bytes());
31 Ok(JsonValue::String(encoded))
32 }
33 JsonValue::Array(arr) => {
34 let transformed: Vec<JsonValue> = arr
35 .iter()
36 .map(|item| {
37 if let JsonValue::String(s) = item {
38 JsonValue::String(general_purpose::STANDARD.encode(s.as_bytes()))
39 } else {
40 item.clone()
41 }
42 })
43 .collect();
44 Ok(JsonValue::Array(transformed))
45 }
46 _ => Ok(value.clone()),
47 }
48 }
49
50 fn name(&self) -> &str {
51 "b64encode"
52 }
53}
54
55pub struct Base64DecodeMutator {
57 _params: MutatorParams,
58}
59
60impl Base64DecodeMutator {
61 pub fn new(params: MutatorParams) -> Self {
62 Self { _params: params }
63 }
64}
65
66impl Mutator for Base64DecodeMutator {
67 fn apply(
68 &self,
69 _field_name: &str,
70 _record: &JsonValue,
71 value: &JsonValue,
72 ) -> Result<JsonValue> {
73 match value {
74 JsonValue::String(s) => {
75 let decoded_bytes = general_purpose::STANDARD
76 .decode(s.as_bytes())
77 .map_err(|e| TqlError::MutatorError(format!("Base64 decode error: {}", e)))?;
78
79 let decoded_str = String::from_utf8(decoded_bytes)
80 .map_err(|e| TqlError::MutatorError(format!("UTF-8 decode error: {}", e)))?;
81
82 Ok(JsonValue::String(decoded_str))
83 }
84 JsonValue::Array(arr) => {
85 let transformed: Result<Vec<JsonValue>> = arr
86 .iter()
87 .map(|item| {
88 if let JsonValue::String(s) = item {
89 let decoded_bytes = general_purpose::STANDARD
90 .decode(s.as_bytes())
91 .map_err(|e| {
92 TqlError::MutatorError(format!("Base64 decode error: {}", e))
93 })?;
94
95 let decoded_str = String::from_utf8(decoded_bytes).map_err(|e| {
96 TqlError::MutatorError(format!("UTF-8 decode error: {}", e))
97 })?;
98
99 Ok(JsonValue::String(decoded_str))
100 } else {
101 Ok(item.clone())
102 }
103 })
104 .collect();
105 Ok(JsonValue::Array(transformed?))
106 }
107 _ => Ok(value.clone()),
108 }
109 }
110
111 fn name(&self) -> &str {
112 "b64decode"
113 }
114}
115
116pub struct URLDecodeMutator {
118 _params: MutatorParams,
119}
120
121impl URLDecodeMutator {
122 pub fn new(params: MutatorParams) -> Self {
123 Self { _params: params }
124 }
125}
126
127impl Mutator for URLDecodeMutator {
128 fn apply(
129 &self,
130 _field_name: &str,
131 _record: &JsonValue,
132 value: &JsonValue,
133 ) -> Result<JsonValue> {
134 match value {
135 JsonValue::String(s) => {
136 let decoded = percent_encoding::percent_decode_str(s)
138 .decode_utf8()
139 .map_err(|e| TqlError::MutatorError(format!("URL decode error: {}", e)))?
140 .to_string();
141 Ok(JsonValue::String(decoded))
142 }
143 JsonValue::Array(arr) => {
144 let transformed: Result<Vec<JsonValue>> = arr
145 .iter()
146 .map(|item| {
147 if let JsonValue::String(s) = item {
148 let decoded = percent_encoding::percent_decode_str(s)
149 .decode_utf8()
150 .map_err(|e| {
151 TqlError::MutatorError(format!("URL decode error: {}", e))
152 })?
153 .to_string();
154 Ok(JsonValue::String(decoded))
155 } else {
156 Ok(item.clone())
157 }
158 })
159 .collect();
160 Ok(JsonValue::Array(transformed?))
161 }
162 _ => Ok(value.clone()),
163 }
164 }
165
166 fn name(&self) -> &str {
167 "urldecode"
168 }
169}
170
171pub struct HexEncodeMutator {
173 _params: MutatorParams,
174}
175
176impl HexEncodeMutator {
177 pub fn new(params: MutatorParams) -> Self {
178 Self { _params: params }
179 }
180}
181
182impl Mutator for HexEncodeMutator {
183 fn apply(
184 &self,
185 _field_name: &str,
186 _record: &JsonValue,
187 value: &JsonValue,
188 ) -> Result<JsonValue> {
189 match value {
190 JsonValue::String(s) => {
191 let encoded = hex::encode(s.as_bytes());
192 Ok(JsonValue::String(encoded))
193 }
194 JsonValue::Array(arr) => {
195 let transformed: Vec<JsonValue> = arr
196 .iter()
197 .map(|item| {
198 if let JsonValue::String(s) = item {
199 JsonValue::String(hex::encode(s.as_bytes()))
200 } else {
201 item.clone()
202 }
203 })
204 .collect();
205 Ok(JsonValue::Array(transformed))
206 }
207 _ => Ok(value.clone()),
208 }
209 }
210
211 fn name(&self) -> &str {
212 "hexencode"
213 }
214}
215
216pub struct HexDecodeMutator {
218 _params: MutatorParams,
219}
220
221impl HexDecodeMutator {
222 pub fn new(params: MutatorParams) -> Self {
223 Self { _params: params }
224 }
225}
226
227impl Mutator for HexDecodeMutator {
228 fn apply(
229 &self,
230 _field_name: &str,
231 _record: &JsonValue,
232 value: &JsonValue,
233 ) -> Result<JsonValue> {
234 match value {
235 JsonValue::String(s) => {
236 let decoded_bytes = hex::decode(s)
237 .map_err(|e| TqlError::MutatorError(format!("Hex decode error: {}", e)))?;
238
239 let decoded_str = String::from_utf8(decoded_bytes)
240 .map_err(|e| TqlError::MutatorError(format!("UTF-8 decode error: {}", e)))?;
241
242 Ok(JsonValue::String(decoded_str))
243 }
244 JsonValue::Array(arr) => {
245 let transformed: Result<Vec<JsonValue>> = arr
246 .iter()
247 .map(|item| {
248 if let JsonValue::String(s) = item {
249 let decoded_bytes = hex::decode(s).map_err(|e| {
250 TqlError::MutatorError(format!("Hex decode error: {}", e))
251 })?;
252
253 let decoded_str = String::from_utf8(decoded_bytes).map_err(|e| {
254 TqlError::MutatorError(format!("UTF-8 decode error: {}", e))
255 })?;
256
257 Ok(JsonValue::String(decoded_str))
258 } else {
259 Ok(item.clone())
260 }
261 })
262 .collect();
263 Ok(JsonValue::Array(transformed?))
264 }
265 _ => Ok(value.clone()),
266 }
267 }
268
269 fn name(&self) -> &str {
270 "hexdecode"
271 }
272}
273
274pub struct MD5Mutator {
276 _params: MutatorParams,
277}
278
279impl MD5Mutator {
280 pub fn new(params: MutatorParams) -> Self {
281 Self { _params: params }
282 }
283}
284
285impl Mutator for MD5Mutator {
286 fn apply(
287 &self,
288 _field_name: &str,
289 _record: &JsonValue,
290 value: &JsonValue,
291 ) -> Result<JsonValue> {
292 match value {
293 JsonValue::String(s) => {
294 let digest = md5::compute(s.as_bytes());
295 Ok(JsonValue::String(format!("{:x}", digest)))
296 }
297 JsonValue::Array(arr) => {
298 let transformed: Vec<JsonValue> = arr
299 .iter()
300 .map(|item| {
301 if let JsonValue::String(s) = item {
302 let digest = md5::compute(s.as_bytes());
303 JsonValue::String(format!("{:x}", digest))
304 } else {
305 item.clone()
306 }
307 })
308 .collect();
309 Ok(JsonValue::Array(transformed))
310 }
311 _ => Ok(value.clone()),
312 }
313 }
314
315 fn name(&self) -> &str {
316 "md5"
317 }
318}
319
320pub struct SHA256Mutator {
322 _params: MutatorParams,
323}
324
325impl SHA256Mutator {
326 pub fn new(params: MutatorParams) -> Self {
327 Self { _params: params }
328 }
329}
330
331impl Mutator for SHA256Mutator {
332 fn apply(
333 &self,
334 _field_name: &str,
335 _record: &JsonValue,
336 value: &JsonValue,
337 ) -> Result<JsonValue> {
338 use sha2::{Digest, Sha256};
339
340 match value {
341 JsonValue::String(s) => {
342 let mut hasher = Sha256::new();
343 hasher.update(s.as_bytes());
344 let result = hasher.finalize();
345 Ok(JsonValue::String(format!("{:x}", result)))
346 }
347 JsonValue::Array(arr) => {
348 let transformed: Vec<JsonValue> = arr
349 .iter()
350 .map(|item| {
351 if let JsonValue::String(s) = item {
352 let mut hasher = Sha256::new();
353 hasher.update(s.as_bytes());
354 let result = hasher.finalize();
355 JsonValue::String(format!("{:x}", result))
356 } else {
357 item.clone()
358 }
359 })
360 .collect();
361 Ok(JsonValue::Array(transformed))
362 }
363 _ => Ok(value.clone()),
364 }
365 }
366
367 fn name(&self) -> &str {
368 "sha256"
369 }
370}
371
372#[cfg(test)]
373mod tests {
374 use super::*;
375 use serde_json::json;
376 use std::collections::HashMap;
377
378 #[test]
379 fn test_base64_encode_mutator() {
380 let mutator = Base64EncodeMutator::new(HashMap::new());
381 let record = json!({});
382
383 let value = json!("hello world");
385 let result = mutator.apply("field", &record, &value).unwrap();
386 assert_eq!(result, json!("aGVsbG8gd29ybGQ="));
387
388 let value = json!(["hello", "world"]);
390 let result = mutator.apply("field", &record, &value).unwrap();
391 assert_eq!(result, json!(["aGVsbG8=", "d29ybGQ="]));
392 }
393
394 #[test]
395 fn test_base64_decode_mutator() {
396 let mutator = Base64DecodeMutator::new(HashMap::new());
397 let record = json!({});
398
399 let value = json!("aGVsbG8gd29ybGQ=");
401 let result = mutator.apply("field", &record, &value).unwrap();
402 assert_eq!(result, json!("hello world"));
403
404 let value = json!(["aGVsbG8=", "d29ybGQ="]);
406 let result = mutator.apply("field", &record, &value).unwrap();
407 assert_eq!(result, json!(["hello", "world"]));
408 }
409
410 #[test]
411 fn test_base64_encode_decode_round_trip() {
412 let encode_mutator = Base64EncodeMutator::new(HashMap::new());
413 let decode_mutator = Base64DecodeMutator::new(HashMap::new());
414 let record = json!({});
415
416 let original = json!("test string 123");
417 let encoded = encode_mutator.apply("field", &record, &original).unwrap();
418 let decoded = decode_mutator.apply("field", &record, &encoded).unwrap();
419 assert_eq!(decoded, original);
420 }
421
422 #[test]
423 fn test_base64_decode_invalid() {
424 let mutator = Base64DecodeMutator::new(HashMap::new());
425 let record = json!({});
426
427 let value = json!("invalid!!!base64");
428 let result = mutator.apply("field", &record, &value);
429 assert!(result.is_err());
430 assert!(result
431 .unwrap_err()
432 .to_string()
433 .contains("Base64 decode error"));
434 }
435
436 #[test]
437 fn test_url_decode_mutator() {
438 let mutator = URLDecodeMutator::new(HashMap::new());
439 let record = json!({});
440
441 let value = json!("hello%20world");
443 let result = mutator.apply("field", &record, &value).unwrap();
444 assert_eq!(result, json!("hello world"));
445
446 let value = json!("test%2Fpath%3Fquery%3Dvalue");
448 let result = mutator.apply("field", &record, &value).unwrap();
449 assert_eq!(result, json!("test/path?query=value"));
450
451 let value = json!(["hello%20world", "test%2Fpath"]);
453 let result = mutator.apply("field", &record, &value).unwrap();
454 assert_eq!(result, json!(["hello world", "test/path"]));
455 }
456
457 #[test]
458 fn test_encoding_mutators_with_non_strings() {
459 let b64_encode = Base64EncodeMutator::new(HashMap::new());
460 let url_decode = URLDecodeMutator::new(HashMap::new());
461 let record = json!({});
462
463 let value = json!(42);
465 assert_eq!(
466 b64_encode.apply("field", &record, &value).unwrap(),
467 json!(42)
468 );
469 assert_eq!(
470 url_decode.apply("field", &record, &value).unwrap(),
471 json!(42)
472 );
473
474 let value = json!(true);
476 assert_eq!(
477 b64_encode.apply("field", &record, &value).unwrap(),
478 json!(true)
479 );
480 assert_eq!(
481 url_decode.apply("field", &record, &value).unwrap(),
482 json!(true)
483 );
484 }
485
486 #[test]
487 fn test_hex_encode_mutator() {
488 let mutator = HexEncodeMutator::new(HashMap::new());
489 let record = json!({});
490
491 let value = json!("hello");
492 let result = mutator.apply("field", &record, &value).unwrap();
493 assert_eq!(result, json!("68656c6c6f"));
494 }
495
496 #[test]
497 fn test_hex_decode_mutator() {
498 let mutator = HexDecodeMutator::new(HashMap::new());
499 let record = json!({});
500
501 let value = json!("68656c6c6f");
502 let result = mutator.apply("field", &record, &value).unwrap();
503 assert_eq!(result, json!("hello"));
504 }
505
506 #[test]
507 fn test_md5_mutator() {
508 let mutator = MD5Mutator::new(HashMap::new());
509 let record = json!({});
510
511 let value = json!("hello");
512 let result = mutator.apply("field", &record, &value).unwrap();
513 assert_eq!(result, json!("5d41402abc4b2a76b9719d911017c592"));
514 }
515
516 #[test]
517 fn test_sha256_mutator() {
518 let mutator = SHA256Mutator::new(HashMap::new());
519 let record = json!({});
520
521 let value = json!("hello");
522 let result = mutator.apply("field", &record, &value).unwrap();
523 assert_eq!(
524 result,
525 json!("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824")
526 );
527 }
528}