tellaro-query-language 0.2.15__tar.gz → 0.2.17__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/PKG-INFO +1 -1
  2. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/pyproject.toml +1 -1
  3. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/__init__.py +29 -1
  4. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/encoding.py +197 -0
  5. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/LICENSE +0 -0
  6. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/README.md +0 -0
  7. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/__init__.py +0 -0
  8. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/analyzer.py +0 -0
  9. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/cache/__init__.py +0 -0
  10. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/cache/base.py +0 -0
  11. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/cache/memory.py +0 -0
  12. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/cache/redis.py +0 -0
  13. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/cli.py +0 -0
  14. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core.py +0 -0
  15. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/README.md +0 -0
  16. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/__init__.py +0 -0
  17. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/file_operations.py +0 -0
  18. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/opensearch_operations.py +0 -0
  19. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/stats_operations.py +0 -0
  20. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/core_components/validation_operations.py +0 -0
  21. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator.py +0 -0
  22. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator_components/README.md +0 -0
  23. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator_components/__init__.py +0 -0
  24. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator_components/field_access.py +0 -0
  25. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator_components/special_expressions.py +0 -0
  26. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/evaluator_components/value_comparison.py +0 -0
  27. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/exceptions.py +0 -0
  28. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/field_type_inference.py +0 -0
  29. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/geoip_normalizer.py +0 -0
  30. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutator_analyzer.py +0 -0
  31. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/base.py +0 -0
  32. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/dns.py +0 -0
  33. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/geo.py +0 -0
  34. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/list.py +0 -0
  35. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/network.py +0 -0
  36. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/security.py +0 -0
  37. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/mutators/string.py +0 -0
  38. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch.py +0 -0
  39. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_components/README.md +0 -0
  40. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_components/__init__.py +0 -0
  41. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_components/field_mapping.py +0 -0
  42. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_components/lucene_converter.py +0 -0
  43. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_components/query_converter.py +0 -0
  44. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_mappings.py +0 -0
  45. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/opensearch_stats.py +0 -0
  46. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser.py +0 -0
  47. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/README.md +0 -0
  48. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/__init__.py +0 -0
  49. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/ast_builder.py +0 -0
  50. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/error_analyzer.py +0 -0
  51. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/field_extractor.py +0 -0
  52. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/parser_components/grammar.py +0 -0
  53. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/post_processor.py +0 -0
  54. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/scripts.py +0 -0
  55. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/stats_evaluator.py +0 -0
  56. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/stats_transformer.py +0 -0
  57. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/streaming_file_processor.py +0 -0
  58. {tellaro_query_language-0.2.15 → tellaro_query_language-0.2.17}/src/tql/validators.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tellaro-query-language
3
- Version: 0.2.15
3
+ Version: 0.2.17
4
4
  Summary: A flexible, human-friendly query language for searching and filtering structured data
5
5
  License: Proprietary
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "tellaro-query-language"
3
- version = "0.2.15"
3
+ version = "0.2.17"
4
4
  description = "A flexible, human-friendly query language for searching and filtering structured data"
5
5
  authors = ["Justin Henderson <justin@tellaro.io>"]
6
6
  license = "Proprietary"
@@ -13,7 +13,15 @@ from ..cache import CacheManager, LocalCacheManager, RedisCacheManager
13
13
  # Import all mutator classes
14
14
  from .base import BaseMutator, append_to_result
15
15
  from .dns import NSLookupMutator
16
- from .encoding import Base64DecodeMutator, Base64EncodeMutator, URLDecodeMutator
16
+ from .encoding import (
17
+ Base64DecodeMutator,
18
+ Base64EncodeMutator,
19
+ HexDecodeMutator,
20
+ HexEncodeMutator,
21
+ Md5Mutator,
22
+ Sha256Mutator,
23
+ URLDecodeMutator,
24
+ )
17
25
  from .geo import GeoIPLookupMutator, GeoIPResolver
18
26
  from .list import (
19
27
  AllMutator,
@@ -44,6 +52,10 @@ __all__ = [
44
52
  "Base64EncodeMutator",
45
53
  "Base64DecodeMutator",
46
54
  "URLDecodeMutator",
55
+ "HexEncodeMutator",
56
+ "HexDecodeMutator",
57
+ "Md5Mutator",
58
+ "Sha256Mutator",
47
59
  # Security mutators
48
60
  "RefangMutator",
49
61
  "DefangMutator",
@@ -91,6 +103,10 @@ ALLOWED_MUTATORS: Dict[str, Optional[Dict[str, type]]] = {
91
103
  "b64encode": {"field": str},
92
104
  "b64decode": {"field": str},
93
105
  "urldecode": {"field": str},
106
+ "hexencode": {"field": str},
107
+ "hexdecode": {"field": str},
108
+ "md5": {"field": str},
109
+ "sha256": {"field": str},
94
110
  # List evaluation mutators
95
111
  "any": None,
96
112
  "all": None,
@@ -124,6 +140,10 @@ ENRICHMENT_MUTATORS = {
124
140
  "b64encode",
125
141
  "b64decode",
126
142
  "urldecode",
143
+ "hexencode",
144
+ "hexdecode",
145
+ "md5",
146
+ "sha256",
127
147
  }
128
148
 
129
149
 
@@ -180,6 +200,14 @@ def create_mutator(name: str, params: Optional[List[List[Any]]] = None) -> BaseM
180
200
  return Base64DecodeMutator(params_dict)
181
201
  elif key == "urldecode":
182
202
  return URLDecodeMutator(params_dict)
203
+ elif key == "hexencode":
204
+ return HexEncodeMutator(params_dict)
205
+ elif key == "hexdecode":
206
+ return HexDecodeMutator(params_dict)
207
+ elif key == "md5":
208
+ return Md5Mutator(params_dict)
209
+ elif key == "sha256":
210
+ return Sha256Mutator(params_dict)
183
211
  elif key == "is_private":
184
212
  return IsPrivateMutator(params_dict)
185
213
  elif key == "is_global":
@@ -216,3 +216,200 @@ class URLDecodeMutator(BaseMutator):
216
216
  else:
217
217
  # Return the decoded value directly
218
218
  return decoded_value
219
+
220
+
221
+ class HexEncodeMutator(BaseMutator):
222
+ """
223
+ Mutator that encodes string values to hexadecimal.
224
+
225
+ Converts strings to their hexadecimal representation.
226
+ Supports encoding individual strings or lists of strings.
227
+
228
+ Parameters:
229
+ field: Optional field to store the encoded value
230
+ """
231
+
232
+ def __init__(self, params: Optional[Dict[str, Any]] = None) -> None:
233
+ super().__init__(params)
234
+ self.is_enrichment = True
235
+
236
+ def apply(self, field_name: str, record: Dict[str, Any], value: Any) -> Any:
237
+ """Apply the hex encode transformation."""
238
+ append_field = self.params.get("field")
239
+
240
+ # Handle different input types
241
+ encoded_value: Any
242
+ if value is None:
243
+ encoded_value = None
244
+ elif isinstance(value, str):
245
+ encoded_value = value.encode("utf-8").hex()
246
+ elif isinstance(value, bytes):
247
+ encoded_value = value.hex()
248
+ elif isinstance(value, list):
249
+ encoded_value = []
250
+ for item in value:
251
+ if isinstance(item, str):
252
+ encoded_value.append(item.encode("utf-8").hex())
253
+ elif isinstance(item, bytes):
254
+ encoded_value.append(item.hex())
255
+ elif item is None:
256
+ encoded_value.append(None)
257
+ else:
258
+ encoded_value.append(str(item).encode("utf-8").hex())
259
+ else:
260
+ encoded_value = str(value).encode("utf-8").hex()
261
+
262
+ # If field is specified, add to record and return original value
263
+ if append_field:
264
+ append_to_result(record, append_field, encoded_value)
265
+ return value
266
+ return encoded_value
267
+
268
+
269
+ class HexDecodeMutator(BaseMutator):
270
+ """
271
+ Mutator that decodes hexadecimal string values.
272
+
273
+ Converts hexadecimal strings back to their original string representation.
274
+ Supports decoding individual strings or lists of strings.
275
+
276
+ Parameters:
277
+ field: Optional field to store the decoded value
278
+ """
279
+
280
+ def __init__(self, params: Optional[Dict[str, Any]] = None) -> None:
281
+ super().__init__(params)
282
+ self.is_enrichment = True
283
+
284
+ def apply(self, field_name: str, record: Dict[str, Any], value: Any) -> Any: # noqa: C901
285
+ """Apply the hex decode transformation."""
286
+ append_field = self.params.get("field")
287
+
288
+ def _decode_hex(s: str) -> Optional[str]:
289
+ """Decode a hex string, returning None on failure."""
290
+ try:
291
+ return bytes.fromhex(s).decode("utf-8")
292
+ except (ValueError, UnicodeDecodeError): # noqa: B014
293
+ return None
294
+
295
+ # Handle different input types
296
+ decoded_value: Any
297
+ if value is None:
298
+ decoded_value = None
299
+ elif isinstance(value, str):
300
+ decoded_value = _decode_hex(value)
301
+ elif isinstance(value, list):
302
+ decoded_value = []
303
+ for item in value:
304
+ if isinstance(item, str):
305
+ decoded_value.append(_decode_hex(item))
306
+ else:
307
+ decoded_value.append(item)
308
+ else:
309
+ decoded_value = _decode_hex(str(value))
310
+
311
+ # If field is specified, add to record and return original value
312
+ if append_field:
313
+ append_to_result(record, append_field, decoded_value)
314
+ return value
315
+ return decoded_value
316
+
317
+
318
+ class Md5Mutator(BaseMutator):
319
+ """
320
+ Mutator that calculates MD5 hash of string values.
321
+
322
+ Computes the MD5 hash (as a hexadecimal string) of the input.
323
+ Supports hashing individual strings or lists of strings.
324
+
325
+ Parameters:
326
+ field: Optional field to store the hash value
327
+ """
328
+
329
+ def __init__(self, params: Optional[Dict[str, Any]] = None) -> None:
330
+ super().__init__(params)
331
+ self.is_enrichment = True
332
+
333
+ def apply(self, field_name: str, record: Dict[str, Any], value: Any) -> Any:
334
+ """Apply the MD5 hash transformation."""
335
+ import hashlib
336
+
337
+ append_field = self.params.get("field")
338
+
339
+ # Handle different input types
340
+ hashed_value: Any
341
+ if value is None:
342
+ hashed_value = None
343
+ elif isinstance(value, str):
344
+ hashed_value = hashlib.md5(value.encode("utf-8")).hexdigest()
345
+ elif isinstance(value, bytes):
346
+ hashed_value = hashlib.md5(value).hexdigest()
347
+ elif isinstance(value, list):
348
+ hashed_value = []
349
+ for item in value:
350
+ if isinstance(item, str):
351
+ hashed_value.append(hashlib.md5(item.encode("utf-8")).hexdigest())
352
+ elif isinstance(item, bytes):
353
+ hashed_value.append(hashlib.md5(item).hexdigest())
354
+ elif item is None:
355
+ hashed_value.append(None)
356
+ else:
357
+ hashed_value.append(hashlib.md5(str(item).encode("utf-8")).hexdigest())
358
+ else:
359
+ hashed_value = hashlib.md5(str(value).encode("utf-8")).hexdigest()
360
+
361
+ # If field is specified, add to record and return original value
362
+ if append_field:
363
+ append_to_result(record, append_field, hashed_value)
364
+ return value
365
+ return hashed_value
366
+
367
+
368
+ class Sha256Mutator(BaseMutator):
369
+ """
370
+ Mutator that calculates SHA256 hash of string values.
371
+
372
+ Computes the SHA256 hash (as a hexadecimal string) of the input.
373
+ Supports hashing individual strings or lists of strings.
374
+
375
+ Parameters:
376
+ field: Optional field to store the hash value
377
+ """
378
+
379
+ def __init__(self, params: Optional[Dict[str, Any]] = None) -> None:
380
+ super().__init__(params)
381
+ self.is_enrichment = True
382
+
383
+ def apply(self, field_name: str, record: Dict[str, Any], value: Any) -> Any:
384
+ """Apply the SHA256 hash transformation."""
385
+ import hashlib
386
+
387
+ append_field = self.params.get("field")
388
+
389
+ # Handle different input types
390
+ hashed_value: Any
391
+ if value is None:
392
+ hashed_value = None
393
+ elif isinstance(value, str):
394
+ hashed_value = hashlib.sha256(value.encode("utf-8")).hexdigest()
395
+ elif isinstance(value, bytes):
396
+ hashed_value = hashlib.sha256(value).hexdigest()
397
+ elif isinstance(value, list):
398
+ hashed_value = []
399
+ for item in value:
400
+ if isinstance(item, str):
401
+ hashed_value.append(hashlib.sha256(item.encode("utf-8")).hexdigest())
402
+ elif isinstance(item, bytes):
403
+ hashed_value.append(hashlib.sha256(item).hexdigest())
404
+ elif item is None:
405
+ hashed_value.append(None)
406
+ else:
407
+ hashed_value.append(hashlib.sha256(str(item).encode("utf-8")).hexdigest())
408
+ else:
409
+ hashed_value = hashlib.sha256(str(value).encode("utf-8")).hexdigest()
410
+
411
+ # If field is specified, add to record and return original value
412
+ if append_field:
413
+ append_to_result(record, append_field, hashed_value)
414
+ return value
415
+ return hashed_value