Skip to content

Commit 723b70c

Browse files
author
oleksandr.volha
committed
fixes
1 parent 0b0a8d9 commit 723b70c

File tree

5 files changed

+110
-113
lines changed

5 files changed

+110
-113
lines changed

uncoder-core/app/translator/platforms/base/aql/functions/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from app.translator.core.models.functions.sort import SortLimitFunction
2828
from app.translator.platforms.base.aql.const import TABLE_PATTERN
2929
from app.translator.platforms.base.aql.functions.const import func_aliases_ctx_var, AGGREGATION_FUNCTIONS_MAP
30-
from app.translator.platforms.base.aql.functions.custom_types.functions import AQLFunctionType
30+
from app.translator.platforms.base.aql.functions.const import AQLFunctionType
3131
from app.translator.platforms.base.aql.functions.manager import AQLFunctionsManager
3232

3333

uncoder-core/app/translator/platforms/base/aql/functions/const.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
from contextvars import ContextVar
22

33
from app.translator.core.custom_types.functions import FunctionType
4-
from app.translator.platforms.base.aql.functions import AQLFunctionType
54
from app.translator.tools.custom_enum import CustomEnum
65

76

7+
class AQLFunctionType(CustomEnum):
8+
lower: str = "LOWER"
9+
upper: str = "UPPER"
10+
min: str = "MIN"
11+
max: str = "MAX"
12+
sum: str = "SUM"
13+
avg: str = "AVG"
14+
count: str = "COUNT"
15+
distinct_count: str = "DISTINCTCOUNT"
16+
last: str = "LAST"
17+
fields: str = "fields"
18+
aggregation_data_parser: str = "aggregation_data_parser"
19+
20+
821
class AQLSortOrderType(CustomEnum):
922
asc: str = "ASC"
1023
desc: str = "DESC"

uncoder-core/app/translator/platforms/base/aql/functions/custom_types/__init__.py

Whitespace-only changes.

uncoder-core/app/translator/platforms/base/aql/functions/custom_types/functions.py

Lines changed: 0 additions & 15 deletions
This file was deleted.
Lines changed: 95 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1,96 +1,95 @@
1-
"""
2-
Uncoder IO Commercial Edition License
3-
-----------------------------------------------------------------
4-
Copyright (c) 2024 SOC Prime, Inc.
5-
6-
This file is part of the Uncoder IO Commercial Edition ("CE") and is
7-
licensed under the Uncoder IO Non-Commercial License (the "License");
8-
you may not use this file except in compliance with the License.
9-
You may obtain a copy of the License at
10-
11-
https://github.com/UncoderIO/UncoderIO/blob/main/LICENSE
12-
13-
Unless required by applicable law or agreed to in writing, software
14-
distributed under the License is distributed on an "AS IS" BASIS,
15-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16-
-----------------------------------------------------------------
17-
"""
18-
import re
19-
from typing import ClassVar, Optional, Union
20-
21-
from app.translator.core.custom_types.tokens import OperatorType
22-
from app.translator.core.custom_types.values import ValueType
23-
from app.translator.core.models.field import FieldValue, Keyword
24-
from app.translator.core.models.identifier import Identifier
25-
from app.translator.core.str_value_manager import StrValue
26-
from app.translator.core.tokenizer import QueryTokenizer
27-
from app.translator.platforms.base.aql.const import NUM_VALUE_PATTERN, SINGLE_QUOTES_VALUE_PATTERN, UTF8_PAYLOAD_PATTERN
28-
from app.translator.platforms.base.aql.str_value_manager import aql_str_value_manager
29-
from app.translator.tools.utils import get_match_group
30-
31-
32-
class AQLTokenizer(QueryTokenizer):
33-
single_value_operators_map: ClassVar[dict[str, str]] = {
34-
"=": OperatorType.EQ,
35-
"<=": OperatorType.LTE,
36-
"<": OperatorType.LT,
37-
">=": OperatorType.GTE,
38-
">": OperatorType.GT,
39-
"!=": OperatorType.NOT_EQ,
40-
"like": OperatorType.EQ,
41-
"ilike": OperatorType.EQ,
42-
"matches": OperatorType.REGEX,
43-
"imatches": OperatorType.REGEX,
44-
}
45-
multi_value_operators_map: ClassVar[dict[str, str]] = {"in": OperatorType.EQ}
46-
47-
field_pattern = r'(?P<field_name>"[a-zA-Z\._\-\s]+"|[a-zA-Z\._\-]+)'
48-
bool_value_pattern = rf"(?P<{ValueType.bool_value}>true|false)\s*"
49-
_value_pattern = rf"{NUM_VALUE_PATTERN}|{bool_value_pattern}|{SINGLE_QUOTES_VALUE_PATTERN}"
50-
multi_value_pattern = rf"""\((?P<{ValueType.multi_value}>[:a-zA-Z\"\*0-9=+%#\-_\/\\'\,.&^@!\(\s]*)\)"""
51-
keyword_pattern = rf"{UTF8_PAYLOAD_PATTERN}\s+(?:like|LIKE|ilike|ILIKE)\s+{SINGLE_QUOTES_VALUE_PATTERN}"
52-
53-
wildcard_symbol = "%"
54-
str_value_manager = aql_str_value_manager
55-
56-
@staticmethod
57-
def should_process_value_wildcards(operator: Optional[str]) -> bool:
58-
return operator and operator.lower() in ("like", "ilike")
59-
60-
def get_operator_and_value(
61-
self, match: re.Match, mapped_operator: str = OperatorType.EQ, operator: Optional[str] = None
62-
) -> tuple[str, StrValue]:
63-
if (num_value := get_match_group(match, group_name=ValueType.number_value)) is not None:
64-
return mapped_operator, StrValue(num_value, split_value=[num_value])
65-
66-
if (bool_value := get_match_group(match, group_name=ValueType.bool_value)) is not None:
67-
return mapped_operator, StrValue(bool_value, split_value=[bool_value])
68-
69-
if (s_q_value := get_match_group(match, group_name=ValueType.single_quotes_value)) is not None:
70-
if mapped_operator == OperatorType.REGEX:
71-
return mapped_operator, self.str_value_manager.from_re_str_to_container(s_q_value)
72-
73-
if self.should_process_value_wildcards(operator):
74-
return mapped_operator, self.str_value_manager.from_str_to_container(s_q_value)
75-
76-
return mapped_operator, self.str_value_manager.from_str_to_container(s_q_value)
77-
78-
return super().get_operator_and_value(match, mapped_operator, operator)
79-
80-
def escape_field_name(self, field_name: str) -> str:
81-
return field_name.replace('"', r"\"").replace(" ", r"\ ")
82-
83-
@staticmethod
84-
def create_field_value(field_name: str, operator: Identifier, value: Union[str, list]) -> FieldValue:
85-
field_name = field_name.strip('"')
86-
return FieldValue(source_name=field_name, operator=operator, value=value)
87-
88-
def search_keyword(self, query: str) -> tuple[Keyword, str]:
89-
keyword_search = re.search(self.keyword_pattern, query)
90-
_, value = self.get_operator_and_value(keyword_search)
91-
keyword = Keyword(value=value.strip(self.wildcard_symbol))
92-
pos = keyword_search.end()
93-
return keyword, query[pos:]
94-
95-
96-
aql_tokenizer = AQLTokenizer()
1+
from typing import Optional
2+
3+
from app.translator.core.mapping import DEFAULT_MAPPING_NAME, BasePlatformMappings, LogSourceSignature, SourceMapping
4+
5+
6+
class AQLLogSourceSignature(LogSourceSignature):
7+
def __init__(
8+
self,
9+
device_types: Optional[list[int]],
10+
categories: Optional[list[int]],
11+
qids: Optional[list[int]],
12+
qid_event_categories: Optional[list[int]],
13+
default_source: dict,
14+
):
15+
self.device_types = set(device_types or [])
16+
self.categories = set(categories or [])
17+
self.qids = set(qids or [])
18+
self.qid_event_categories = set(qid_event_categories or [])
19+
self._default_source = default_source or {}
20+
21+
def is_suitable(
22+
self,
23+
devicetype: Optional[list[int]],
24+
category: Optional[list[int]],
25+
qid: Optional[list[int]],
26+
qideventcategory: Optional[list[int]],
27+
) -> bool:
28+
device_type_match = set(devicetype).issubset(self.device_types) if devicetype else None
29+
category_match = set(category).issubset(self.categories) if category else None
30+
qid_match = set(qid).issubset(self.qids) if qid else None
31+
qid_event_category_match = (
32+
set(qideventcategory).issubset(self.qid_event_categories) if qideventcategory else None
33+
)
34+
return all(
35+
condition
36+
for condition in (device_type_match, category_match, qid_match, qid_event_category_match)
37+
if condition is not None
38+
)
39+
40+
def __str__(self) -> str:
41+
return self._default_source.get("table", "events")
42+
43+
@property
44+
def extra_condition(self) -> str:
45+
default_source = self._default_source
46+
return " AND ".join((f"{key}={value}" for key, value in default_source.items() if key != "table" and value))
47+
48+
49+
class AQLMappings(BasePlatformMappings):
50+
skip_load_default_mappings: bool = False
51+
extend_default_mapping_with_all_fields: bool = True
52+
53+
def prepare_log_source_signature(self, mapping: dict) -> AQLLogSourceSignature:
54+
log_source = mapping.get("log_source", {})
55+
default_log_source = mapping["default_log_source"]
56+
return AQLLogSourceSignature(
57+
device_types=log_source.get("devicetype"),
58+
categories=log_source.get("category"),
59+
qids=log_source.get("qid"),
60+
qid_event_categories=log_source.get("qideventcategory"),
61+
default_source=default_log_source,
62+
)
63+
64+
def get_suitable_source_mappings(
65+
self,
66+
field_names: list[str],
67+
devicetype: Optional[list[int]] = None,
68+
category: Optional[list[int]] = None,
69+
qid: Optional[list[int]] = None,
70+
qideventcategory: Optional[list[int]] = None,
71+
) -> list[SourceMapping]:
72+
suitable_source_mappings = []
73+
for source_mapping in self._source_mappings.values():
74+
if source_mapping.source_id == DEFAULT_MAPPING_NAME:
75+
continue
76+
77+
log_source_signature: AQLLogSourceSignature = source_mapping.log_source_signature
78+
if log_source_signature.is_suitable(devicetype, category, qid, qideventcategory): # noqa: SIM102
79+
if source_mapping.fields_mapping.is_suitable(field_names):
80+
suitable_source_mappings.append(source_mapping)
81+
82+
if not suitable_source_mappings:
83+
for source_mapping in self._source_mappings.values():
84+
if source_mapping.source_id == DEFAULT_MAPPING_NAME:
85+
continue
86+
if source_mapping.fields_mapping.is_suitable(field_names):
87+
suitable_source_mappings.append(source_mapping)
88+
89+
if not suitable_source_mappings:
90+
suitable_source_mappings = [self._source_mappings[DEFAULT_MAPPING_NAME]]
91+
92+
return suitable_source_mappings
93+
94+
95+
aql_mappings = AQLMappings(platform_dir="qradar")

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy