1use std::collections::HashSet;
4
5use serde_json::Value;
6
7use crate::functions::Function;
8use crate::interpreter::SearchResult;
9use crate::registry::register_if_enabled;
10use crate::{Context, Runtime, arg, defn};
11
12use crc32fast::Hasher as Crc32Hasher;
13use hmac::{Hmac, Mac};
14use md5::{Digest, Md5};
15use sha1::Sha1;
16use sha2::{Sha256, Sha512};
17
18type HmacMd5 = Hmac<Md5>;
20type HmacSha1 = Hmac<Sha1>;
21type HmacSha256 = Hmac<Sha256>;
22type HmacSha512 = Hmac<Sha512>;
23
24pub fn register_filtered(runtime: &mut Runtime, enabled: &HashSet<&str>) {
26 register_if_enabled(runtime, "md5", enabled, Box::new(Md5Fn::new()));
28 register_if_enabled(runtime, "sha1", enabled, Box::new(Sha1Fn::new()));
29 register_if_enabled(runtime, "sha256", enabled, Box::new(Sha256Fn::new()));
30 register_if_enabled(runtime, "sha512", enabled, Box::new(Sha512Fn::new()));
31
32 register_if_enabled(runtime, "hmac_md5", enabled, Box::new(HmacMd5Fn::new()));
34 register_if_enabled(runtime, "hmac_sha1", enabled, Box::new(HmacSha1Fn::new()));
35 register_if_enabled(
36 runtime,
37 "hmac_sha256",
38 enabled,
39 Box::new(HmacSha256Fn::new()),
40 );
41 register_if_enabled(
42 runtime,
43 "hmac_sha512",
44 enabled,
45 Box::new(HmacSha512Fn::new()),
46 );
47
48 register_if_enabled(runtime, "crc32", enabled, Box::new(Crc32Fn::new()));
50}
51
52defn!(Md5Fn, vec![arg!(string)], None);
57
58impl Function for Md5Fn {
59 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
60 self.signature.validate(args, ctx)?;
61
62 let input = args[0].as_str().ok_or_else(|| {
63 crate::JmespathError::from_ctx(
64 ctx,
65 crate::ErrorReason::Parse("Expected string argument".to_owned()),
66 )
67 })?;
68
69 let mut hasher = Md5::new();
70 hasher.update(input.as_bytes());
71 let result = hasher.finalize();
72 let hex_string = format!("{:x}", result);
73
74 Ok(Value::String(hex_string))
75 }
76}
77
78defn!(Sha1Fn, vec![arg!(string)], None);
83
84impl Function for Sha1Fn {
85 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
86 self.signature.validate(args, ctx)?;
87
88 let input = args[0].as_str().ok_or_else(|| {
89 crate::JmespathError::from_ctx(
90 ctx,
91 crate::ErrorReason::Parse("Expected string argument".to_owned()),
92 )
93 })?;
94
95 let mut hasher = Sha1::new();
96 hasher.update(input.as_bytes());
97 let result = hasher.finalize();
98 let hex_string = format!("{:x}", result);
99
100 Ok(Value::String(hex_string))
101 }
102}
103
104defn!(Sha256Fn, vec![arg!(string)], None);
109
110impl Function for Sha256Fn {
111 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
112 self.signature.validate(args, ctx)?;
113
114 let input = args[0].as_str().ok_or_else(|| {
115 crate::JmespathError::from_ctx(
116 ctx,
117 crate::ErrorReason::Parse("Expected string argument".to_owned()),
118 )
119 })?;
120
121 let mut hasher = Sha256::new();
122 hasher.update(input.as_bytes());
123 let result = hasher.finalize();
124 let hex_string = format!("{:x}", result);
125
126 Ok(Value::String(hex_string))
127 }
128}
129
130defn!(Sha512Fn, vec![arg!(string)], None);
135
136impl Function for Sha512Fn {
137 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
138 self.signature.validate(args, ctx)?;
139
140 let input = args[0].as_str().ok_or_else(|| {
141 crate::JmespathError::from_ctx(
142 ctx,
143 crate::ErrorReason::Parse("Expected string argument".to_owned()),
144 )
145 })?;
146
147 let mut hasher = Sha512::new();
148 hasher.update(input.as_bytes());
149 let result = hasher.finalize();
150 let hex_string = format!("{:x}", result);
151
152 Ok(Value::String(hex_string))
153 }
154}
155
156defn!(HmacMd5Fn, vec![arg!(string), arg!(string)], None);
161
162impl Function for HmacMd5Fn {
163 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
164 self.signature.validate(args, ctx)?;
165
166 let text = args[0].as_str().ok_or_else(|| {
167 crate::JmespathError::from_ctx(
168 ctx,
169 crate::ErrorReason::Parse("Expected string for text argument".to_owned()),
170 )
171 })?;
172
173 let key = args[1].as_str().ok_or_else(|| {
174 crate::JmespathError::from_ctx(
175 ctx,
176 crate::ErrorReason::Parse("Expected string for key argument".to_owned()),
177 )
178 })?;
179
180 let mut mac =
181 HmacMd5::new_from_slice(key.as_bytes()).expect("HMAC can take key of any size");
182 mac.update(text.as_bytes());
183 let result = mac.finalize();
184 let hex_string = format!("{:x}", result.into_bytes());
185
186 Ok(Value::String(hex_string))
187 }
188}
189
190defn!(HmacSha1Fn, vec![arg!(string), arg!(string)], None);
195
196impl Function for HmacSha1Fn {
197 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
198 self.signature.validate(args, ctx)?;
199
200 let text = args[0].as_str().ok_or_else(|| {
201 crate::JmespathError::from_ctx(
202 ctx,
203 crate::ErrorReason::Parse("Expected string for text argument".to_owned()),
204 )
205 })?;
206
207 let key = args[1].as_str().ok_or_else(|| {
208 crate::JmespathError::from_ctx(
209 ctx,
210 crate::ErrorReason::Parse("Expected string for key argument".to_owned()),
211 )
212 })?;
213
214 let mut mac =
215 HmacSha1::new_from_slice(key.as_bytes()).expect("HMAC can take key of any size");
216 mac.update(text.as_bytes());
217 let result = mac.finalize();
218 let hex_string = format!("{:x}", result.into_bytes());
219
220 Ok(Value::String(hex_string))
221 }
222}
223
224defn!(HmacSha256Fn, vec![arg!(string), arg!(string)], None);
229
230impl Function for HmacSha256Fn {
231 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
232 self.signature.validate(args, ctx)?;
233
234 let text = args[0].as_str().ok_or_else(|| {
235 crate::JmespathError::from_ctx(
236 ctx,
237 crate::ErrorReason::Parse("Expected string for text argument".to_owned()),
238 )
239 })?;
240
241 let key = args[1].as_str().ok_or_else(|| {
242 crate::JmespathError::from_ctx(
243 ctx,
244 crate::ErrorReason::Parse("Expected string for key argument".to_owned()),
245 )
246 })?;
247
248 let mut mac =
249 HmacSha256::new_from_slice(key.as_bytes()).expect("HMAC can take key of any size");
250 mac.update(text.as_bytes());
251 let result = mac.finalize();
252 let hex_string = format!("{:x}", result.into_bytes());
253
254 Ok(Value::String(hex_string))
255 }
256}
257
258defn!(HmacSha512Fn, vec![arg!(string), arg!(string)], None);
263
264impl Function for HmacSha512Fn {
265 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
266 self.signature.validate(args, ctx)?;
267
268 let text = args[0].as_str().ok_or_else(|| {
269 crate::JmespathError::from_ctx(
270 ctx,
271 crate::ErrorReason::Parse("Expected string for text argument".to_owned()),
272 )
273 })?;
274
275 let key = args[1].as_str().ok_or_else(|| {
276 crate::JmespathError::from_ctx(
277 ctx,
278 crate::ErrorReason::Parse("Expected string for key argument".to_owned()),
279 )
280 })?;
281
282 let mut mac =
283 HmacSha512::new_from_slice(key.as_bytes()).expect("HMAC can take key of any size");
284 mac.update(text.as_bytes());
285 let result = mac.finalize();
286 let hex_string = format!("{:x}", result.into_bytes());
287
288 Ok(Value::String(hex_string))
289 }
290}
291
292defn!(Crc32Fn, vec![arg!(string)], None);
297
298impl Function for Crc32Fn {
299 fn evaluate(&self, args: &[Value], ctx: &mut Context<'_>) -> SearchResult {
300 self.signature.validate(args, ctx)?;
301
302 let input = args[0].as_str().ok_or_else(|| {
303 crate::JmespathError::from_ctx(
304 ctx,
305 crate::ErrorReason::Parse("Expected string argument".to_owned()),
306 )
307 })?;
308
309 let mut hasher = Crc32Hasher::new();
310 hasher.update(input.as_bytes());
311 let checksum = hasher.finalize();
312
313 Ok(Value::Number(serde_json::Number::from(checksum)))
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use crate::Runtime;
320 use serde_json::json;
321
322 fn setup_runtime() -> Runtime {
323 Runtime::builder()
324 .with_standard()
325 .with_all_extensions()
326 .build()
327 }
328
329 #[test]
334 fn test_md5() {
335 let runtime = setup_runtime();
336 let expr = runtime.compile("md5(@)").unwrap();
337 let data = json!("hello");
338 let result = expr.search(&data).unwrap();
339 assert_eq!(result, json!("5d41402abc4b2a76b9719d911017c592"));
340 }
341
342 #[test]
343 fn test_md5_empty() {
344 let runtime = setup_runtime();
345 let expr = runtime.compile("md5(@)").unwrap();
346 let data = json!("");
347 let result = expr.search(&data).unwrap();
348 assert_eq!(result, json!("d41d8cd98f00b204e9800998ecf8427e"));
349 }
350
351 #[test]
352 fn test_sha1() {
353 let runtime = setup_runtime();
354 let expr = runtime.compile("sha1(@)").unwrap();
355 let data = json!("hello");
356 let result = expr.search(&data).unwrap();
357 assert_eq!(result, json!("aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d"));
358 }
359
360 #[test]
361 fn test_sha256() {
362 let runtime = setup_runtime();
363 let expr = runtime.compile("sha256(@)").unwrap();
364 let data = json!("hello");
365 let result = expr.search(&data).unwrap();
366 assert_eq!(
367 result,
368 json!("2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824")
369 );
370 }
371
372 #[test]
373 fn test_sha512() {
374 let runtime = setup_runtime();
375 let expr = runtime.compile("sha512(@)").unwrap();
376 let data = json!("hello");
377 let result = expr.search(&data).unwrap();
378 assert_eq!(
379 result,
380 json!(
381 "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043"
382 )
383 );
384 }
385
386 #[test]
387 fn test_sha512_empty() {
388 let runtime = setup_runtime();
389 let expr = runtime.compile("sha512(@)").unwrap();
390 let data = json!("");
391 let result = expr.search(&data).unwrap();
392 assert_eq!(
393 result,
394 json!(
395 "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
396 )
397 );
398 }
399
400 #[test]
405 fn test_hmac_md5() {
406 let runtime = setup_runtime();
407 let expr = runtime.compile("hmac_md5(@, `\"secret\"`)").unwrap();
408 let data = json!("hello");
409 let result = expr.search(&data).unwrap();
410 assert_eq!(result, json!("bade63863c61ed0b3165806ecd6acefc"));
411 }
412
413 #[test]
414 fn test_hmac_sha1() {
415 let runtime = setup_runtime();
416 let expr = runtime.compile("hmac_sha1(@, `\"secret\"`)").unwrap();
417 let data = json!("hello");
418 let result = expr.search(&data).unwrap();
419 assert_eq!(result, json!("5112055c05f944f85755efc5cd8970e194e9f45b"));
420 }
421
422 #[test]
423 fn test_hmac_sha256() {
424 let runtime = setup_runtime();
425 let expr = runtime.compile("hmac_sha256(@, `\"secret\"`)").unwrap();
426 let data = json!("hello");
427 let result = expr.search(&data).unwrap();
428 assert_eq!(
429 result,
430 json!("88aab3ede8d3adf94d26ab90d3bafd4a2083070c3bcce9c014ee04a443847c0b")
431 );
432 }
433
434 #[test]
435 fn test_hmac_sha512() {
436 let runtime = setup_runtime();
437 let expr = runtime.compile("hmac_sha512(@, `\"secret\"`)").unwrap();
438 let data = json!("hello");
439 let result = expr.search(&data).unwrap();
440 assert_eq!(
441 result,
442 json!(
443 "db1595ae88a62fd151ec1cba81b98c39df82daae7b4cb9820f446d5bf02f1dcfca6683d88cab3e273f5963ab8ec469a746b5b19086371239f67d1e5f99a79440"
444 )
445 );
446 }
447
448 #[test]
449 fn test_hmac_sha256_empty_message() {
450 let runtime = setup_runtime();
451 let expr = runtime.compile("hmac_sha256(@, `\"key\"`)").unwrap();
452 let data = json!("");
453 let result = expr.search(&data).unwrap();
454 assert_eq!(
455 result,
456 json!("5d5d139563c95b5967b9bd9a8c9b233a9dedb45072794cd232dc1b74832607d0")
457 );
458 }
459
460 #[test]
461 fn test_hmac_sha256_empty_key() {
462 let runtime = setup_runtime();
463 let expr = runtime.compile("hmac_sha256(@, `\"\"`)").unwrap();
464 let data = json!("hello");
465 let result = expr.search(&data).unwrap();
466 assert!(!result.as_str().unwrap().is_empty());
468 }
469
470 #[test]
475 fn test_crc32() {
476 let runtime = setup_runtime();
477 let expr = runtime.compile("crc32(@)").unwrap();
478 let data = json!("hello");
479 let result = expr.search(&data).unwrap();
480 assert_eq!(result, json!(907060870));
481 }
482
483 #[test]
484 fn test_crc32_empty() {
485 let runtime = setup_runtime();
486 let expr = runtime.compile("crc32(@)").unwrap();
487 let data = json!("");
488 let result = expr.search(&data).unwrap();
489 assert_eq!(result, json!(0));
490 }
491}