Skip to content

Commit c52a9aa

Browse files
committed
merge prod
1 parent e784000 commit c52a9aa

File tree

29 files changed

+162
-372
lines changed

29 files changed

+162
-372
lines changed

uncoder-core/app/translator/core/mapping.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from abc import ABC, abstractmethod
4-
from typing import TYPE_CHECKING, Optional, TypeVar
4+
from typing import TYPE_CHECKING, Optional, TypeVar, Union
55

66
from app.translator.core.exceptions.core import StrictPlatformException
77
from app.translator.core.models.platform_details import PlatformDetails
@@ -19,9 +19,14 @@ class LogSourceSignature(ABC):
1919
wildcard_symbol = "*"
2020

2121
@abstractmethod
22-
def is_suitable(self, *args, **kwargs) -> bool:
22+
def is_suitable(self, **kwargs) -> bool:
2323
raise NotImplementedError("Abstract method")
2424

25+
@staticmethod
26+
def _check_conditions(conditions: list[Union[bool, None]]) -> bool:
27+
conditions = [condition for condition in conditions if condition is not None]
28+
return bool(conditions) and all(conditions)
29+
2530
@abstractmethod
2631
def __str__(self) -> str:
2732
raise NotImplementedError("Abstract method")
@@ -70,7 +75,7 @@ def update(self, fields_mapping: FieldsMapping) -> None:
7075
self.__render_mapping.update(fields_mapping.__render_mapping)
7176

7277
def is_suitable(self, field_names: list[str]) -> bool:
73-
return set(field_names).issubset(set(self.__parser_mapping.keys()))
78+
return bool(field_names) and set(field_names).issubset(set(self.__parser_mapping.keys()))
7479

7580

7681
_LogSourceSignatureType = TypeVar("_LogSourceSignatureType", bound=LogSourceSignature)
@@ -147,9 +152,23 @@ def prepare_fields_mapping(field_mapping: dict) -> FieldsMapping:
147152
def prepare_log_source_signature(self, mapping: dict) -> LogSourceSignature:
148153
raise NotImplementedError("Abstract method")
149154

150-
@abstractmethod
151-
def get_suitable_source_mappings(self, *args, **kwargs) -> list[SourceMapping]:
152-
raise NotImplementedError("Abstract method")
155+
def get_suitable_source_mappings(
156+
self, field_names: list[str], log_sources: dict[str, list[Union[int, str]]]
157+
) -> list[SourceMapping]:
158+
by_log_sources_and_fields = []
159+
by_fields = []
160+
for source_mapping in self._source_mappings.values():
161+
if source_mapping.source_id == DEFAULT_MAPPING_NAME:
162+
continue
163+
164+
if source_mapping.fields_mapping.is_suitable(field_names):
165+
by_fields.append(source_mapping)
166+
167+
log_source_signature: LogSourceSignature = source_mapping.log_source_signature
168+
if log_source_signature and log_source_signature.is_suitable(**log_sources):
169+
by_log_sources_and_fields.append(source_mapping)
170+
171+
return by_log_sources_and_fields or by_fields or [self._source_mappings[DEFAULT_MAPPING_NAME]]
153172

154173
def get_source_mapping(self, source_id: str) -> Optional[SourceMapping]:
155174
return self._source_mappings.get(source_id)

uncoder-core/app/translator/core/models/query_container.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ def __init__(
7777
def author_str(self) -> str:
7878
return ", ".join(self.author)
7979

80+
@property
81+
def source_mapping_ids(self) -> list[str]:
82+
return sorted(self._source_mapping_ids)
83+
84+
@source_mapping_ids.setter
85+
def source_mapping_ids(self, source_mapping_ids: list[str]) -> None:
86+
self._source_mapping_ids = source_mapping_ids
87+
8088

8189
@dataclass
8290
class RawQueryContainer:

uncoder-core/app/translator/core/models/query_tokens/field.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from abc import ABC, abstractmethod
12
from typing import Optional
23

34
from app.translator.core.mapping import DEFAULT_MAPPING_NAME, SourceMapping
@@ -37,3 +38,10 @@ def set_generic_names_map(self, source_mappings: list[SourceMapping], default_ma
3738
class PredefinedField:
3839
def __init__(self, name: str):
3940
self.name = name
41+
42+
43+
class BaseFieldsGetter(ABC):
44+
@property
45+
@abstractmethod
46+
def fields(self) -> list[Field]:
47+
raise NotImplementedError("Abstract method")

uncoder-core/app/translator/core/models/query_tokens/field_field.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from app.translator.core.models.query_tokens.field import Alias, Field
1+
from app.translator.core.models.query_tokens.field import Alias, BaseFieldsGetter, Field
22
from app.translator.core.models.query_tokens.identifier import Identifier
33

44

5-
class FieldField:
5+
class FieldField(BaseFieldsGetter):
66
def __init__(
77
self,
88
source_name_left: str,
@@ -16,3 +16,13 @@ def __init__(
1616
self.operator = operator
1717
self.field_right = Field(source_name=source_name_right) if not is_alias_right else None
1818
self.alias_right = Alias(name=source_name_right) if is_alias_right else None
19+
20+
@property
21+
def fields(self) -> list[Field]:
22+
fields = []
23+
if self.field_left:
24+
fields.append(self.field_left)
25+
if self.field_right:
26+
fields.append(self.field_right)
27+
28+
return fields

uncoder-core/app/translator/core/models/query_tokens/field_value.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from typing import Union
22

33
from app.translator.core.custom_types.tokens import STR_SEARCH_OPERATORS
4-
from app.translator.core.models.query_tokens.field import Alias, Field, PredefinedField
4+
from app.translator.core.models.query_tokens.field import Alias, BaseFieldsGetter, Field, PredefinedField
55
from app.translator.core.models.query_tokens.identifier import Identifier
66
from app.translator.core.models.query_tokens.value import Value
77
from app.translator.core.str_value_manager import StrValue
88

99

10-
class FieldValue(Value):
10+
class FieldValue(BaseFieldsGetter, Value):
1111
def __init__(
1212
self,
1313
source_name: str,
@@ -33,3 +33,7 @@ def __repr__(self):
3333
return f"{self.predefined_field.name} {self.operator.token_type} {self.values}"
3434

3535
return f"{self.field.source_name} {self.operator.token_type} {self.values}"
36+
37+
@property
38+
def fields(self) -> list[Field]:
39+
return [self.field] if self.field else []

uncoder-core/app/translator/core/models/query_tokens/function_value.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22

33
from app.translator.core.custom_types.tokens import STR_SEARCH_OPERATORS
44
from app.translator.core.models.functions.base import Function
5+
from app.translator.core.models.query_tokens.field import BaseFieldsGetter, Field
56
from app.translator.core.models.query_tokens.identifier import Identifier
67
from app.translator.core.models.query_tokens.value import Value
78
from app.translator.core.str_value_manager import StrValue
89

910

10-
class FunctionValue(Value):
11+
class FunctionValue(BaseFieldsGetter, Value):
1112
def __init__(self, function: Function, operator: Identifier, value: Union[int, str, StrValue, list, tuple]):
1213
super().__init__(value, cast_to_int=operator.token_type not in STR_SEARCH_OPERATORS)
1314
self.function = function
1415
self.operator = operator
16+
17+
@property
18+
def fields(self) -> list[Field]:
19+
return self.function.fields

uncoder-core/app/translator/core/parser.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,30 +62,24 @@ def get_query_tokens(self, query: str) -> list[QUERY_TOKEN_TYPE]:
6262
raise TokenizerGeneralException("Can't translate empty query. Please provide more details")
6363
return self.tokenizer.tokenize(query=query)
6464

65+
@staticmethod
6566
def get_field_tokens(
66-
self, query_tokens: list[QUERY_TOKEN_TYPE], functions: Optional[list[Function]] = None
67+
query_tokens: list[QUERY_TOKEN_TYPE], functions: Optional[list[Function]] = None
6768
) -> list[Field]:
6869
field_tokens = []
6970
for token in query_tokens:
70-
if isinstance(token, FieldValue):
71-
field_tokens.append(token.field)
72-
elif isinstance(token, FieldField):
73-
if token.field_left:
74-
field_tokens.append(token.field_left)
75-
if token.field_right:
76-
field_tokens.append(token.field_right)
77-
elif isinstance(token, FunctionValue):
78-
field_tokens.extend(self.tokenizer.get_field_tokens_from_func_args([token.function]))
71+
if isinstance(token, (FieldField, FieldValue, FunctionValue)):
72+
field_tokens.extend(token.fields)
7973

8074
if functions:
81-
field_tokens.extend(self.tokenizer.get_field_tokens_from_func_args(functions))
75+
field_tokens.extend([field for func in functions for field in func.fields])
8276

8377
return field_tokens
8478

8579
def get_source_mappings(
86-
self, field_tokens: list[Field], log_sources: dict[str, Union[str, list[str]]]
80+
self, field_tokens: list[Field], log_sources: dict[str, list[Union[int, str]]]
8781
) -> list[SourceMapping]:
8882
field_names = [field.source_name for field in field_tokens]
89-
source_mappings = self.mappings.get_suitable_source_mappings(field_names=field_names, **log_sources)
83+
source_mappings = self.mappings.get_suitable_source_mappings(field_names=field_names, log_sources=log_sources)
9084
self.tokenizer.set_field_tokens_generic_names_map(field_tokens, source_mappings, self.mappings.default_mapping)
9185
return source_mappings

uncoder-core/app/translator/core/str_value_manager.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ class ReEndOfStrSymbol(BaseSpecSymbol):
4242
...
4343

4444

45+
class ReWordBoundarySymbol(BaseSpecSymbol):
46+
...
47+
48+
4549
class ReWordSymbol(BaseSpecSymbol):
4650
...
4751

@@ -130,6 +134,7 @@ def has_spec_symbols(self) -> bool:
130134
SingleSymbolWildCard: "?",
131135
UnboundLenWildCard: "*",
132136
ReAnySymbol: ".",
137+
ReWordBoundarySymbol: r"\b",
133138
ReWordSymbol: r"\w",
134139
ReDigitalSymbol: r"\d",
135140
ReWhiteSpaceSymbol: r"\s",

uncoder-core/app/translator/core/tokenizer.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,6 @@
3131
)
3232
from app.translator.core.functions import PlatformFunctions
3333
from app.translator.core.mapping import SourceMapping
34-
from app.translator.core.models.functions.base import Function
35-
from app.translator.core.models.functions.eval import EvalArg
36-
from app.translator.core.models.functions.group_by import GroupByFunction
37-
from app.translator.core.models.functions.join import JoinFunction
38-
from app.translator.core.models.functions.rename import RenameArg
39-
from app.translator.core.models.functions.sort import SortArg
40-
from app.translator.core.models.functions.union import UnionFunction
4134
from app.translator.core.models.query_tokens.field import Field
4235
from app.translator.core.models.query_tokens.field_field import FieldField
4336
from app.translator.core.models.query_tokens.field_value import FieldValue
@@ -356,43 +349,6 @@ def filter_tokens(
356349
) -> list[QUERY_TOKEN_TYPE]:
357350
return [token for token in tokens if isinstance(token, token_type)]
358351

359-
def get_field_tokens_from_func_args( # noqa: PLR0912
360-
self, args: list[Union[Field, FieldValue, Keyword, Identifier, Function, SortArg]]
361-
) -> list[Field]:
362-
result = []
363-
for arg in args:
364-
if isinstance(arg, Field):
365-
result.append(arg)
366-
elif isinstance(arg, FieldField):
367-
if arg.field_left:
368-
result.append(arg.field_left)
369-
if arg.field_right:
370-
result.append(arg.field_right)
371-
elif isinstance(arg, FieldValue):
372-
if arg.field:
373-
result.append(arg.field)
374-
elif isinstance(arg, FunctionValue):
375-
result.extend(self.get_field_tokens_from_func_args(args=[arg.function]))
376-
elif isinstance(arg, GroupByFunction):
377-
result.extend(self.get_field_tokens_from_func_args(args=arg.args))
378-
result.extend(self.get_field_tokens_from_func_args(args=arg.by_clauses))
379-
result.extend(self.get_field_tokens_from_func_args(args=[arg.filter_]))
380-
elif isinstance(arg, JoinFunction):
381-
result.extend(self.get_field_tokens_from_func_args(args=arg.condition))
382-
elif isinstance(arg, UnionFunction):
383-
continue
384-
elif isinstance(arg, Function):
385-
result.extend(self.get_field_tokens_from_func_args(args=arg.args))
386-
elif isinstance(arg, SortArg) and isinstance(arg.field, Field):
387-
result.append(arg.field)
388-
elif isinstance(arg, RenameArg):
389-
result.append(arg.field_)
390-
elif isinstance(arg, EvalArg):
391-
if isinstance(arg.field_, Field):
392-
result.append(arg.field_)
393-
result.extend(self.get_field_tokens_from_func_args(args=arg.expression))
394-
return result
395-
396352
@staticmethod
397353
def set_field_tokens_generic_names_map(
398354
tokens: list[Field], source_mappings: list[SourceMapping], default_mapping: SourceMapping

uncoder-core/app/translator/mappings/platforms/qradar/default.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ field_mapping:
1414
- DstPort
1515
- DestinationPort
1616
- remoteport
17-
dst-hostname: DstHost
18-
src-hostname: SrcHost
1917
src-port:
2018
- SourcePort
2119
- localport
@@ -25,21 +23,23 @@ field_mapping:
2523
- source_ip
2624
- SourceIP
2725
- sourceIP
26+
- SrcHost
2827
dst-ip:
2928
- DestinationIP
3029
- destinationip
3130
- destination_ip
3231
- destinationIP
3332
- destinationaddress
3433
- destination
34+
- DstHost
3535
User:
3636
- userName
3737
- EventUserName
3838
- Alert Threat Cause Actor Name
3939
- Username
4040
- Security ID
4141
CommandLine: Command
42-
Protocol:
42+
Protocol:
4343
- IPProtocol
4444
- protocol
4545
Application:
@@ -97,8 +97,10 @@ field_mapping:
9797
FileName:
9898
- Filename
9999
- File Name
100-
RegistryKey:
100+
- Encoded Filename
101+
RegistryKey:
101102
- Registry Key
102103
- Target Object
103104
RegistryValue: RegistryValue
104105
ProcessPath: Process Path
106+
hasIdentity: hasIdentity

0 commit comments

Comments
 (0)