Skip to content

Commit 6973aa3

Browse files
authored
Merge pull request #114 from UncoderIO/gis-7328
Created base platform: aql. And fixes for qradar
2 parents d3dba4e + 87274f8 commit 6973aa3

File tree

49 files changed

+308
-411
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+308
-411
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,7 @@ class InvalidYamlStructure(InvalidRuleStructure):
7777

7878
class InvalidJSONStructure(InvalidRuleStructure):
7979
rule_type: str = "JSON"
80+
81+
82+
class InvalidXMLStructure(InvalidRuleStructure):
83+
rule_type: str = "XML"

uncoder-core/app/translator/core/mixins/rule.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import json
2+
from typing import Union
23

4+
import xmltodict
35
import yaml
46

5-
from app.translator.core.exceptions.core import InvalidJSONStructure, InvalidYamlStructure
7+
from app.translator.core.exceptions.core import InvalidJSONStructure, InvalidXMLStructure, InvalidYamlStructure
68
from app.translator.core.mitre import MitreConfig
79

810

@@ -36,5 +38,13 @@ def parse_mitre_attack(self, tags: list[str]) -> dict[str, list]:
3638
result["techniques"].append(technique)
3739
elif tactic := self.mitre_config.get_tactic(tag):
3840
result["tactics"].append(tactic)
39-
4041
return result
42+
43+
44+
class XMLRuleMixin:
45+
@staticmethod
46+
def load_rule(text: Union[str, bytes]) -> dict:
47+
try:
48+
return xmltodict.parse(text)
49+
except Exception as err:
50+
raise InvalidXMLStructure(error=str(err)) from err

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,13 @@ class RawQueryContainer:
5656
meta_info: MetaInfoContainer = field(default_factory=MetaInfoContainer)
5757

5858

59+
@dataclass
60+
class RawQueryDictContainer:
61+
query: dict
62+
language: str
63+
meta_info: dict
64+
65+
5966
@dataclass
6067
class TokenizedQueryContainer:
6168
tokens: list[TOKEN_TYPE]

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,13 @@
3232

3333
class QueryParser(ABC):
3434
wrapped_with_comment_pattern: str = None
35+
details: PlatformDetails = None
3536

3637
def remove_comments(self, text: str) -> str:
37-
return re.sub(self.wrapped_with_comment_pattern, "\n", text, flags=re.MULTILINE).strip()
38+
if self.wrapped_with_comment_pattern:
39+
return re.sub(self.wrapped_with_comment_pattern, "\n", text, flags=re.MULTILINE).strip()
40+
41+
return text
3842

3943
def parse_raw_query(self, text: str, language: str) -> RawQueryContainer:
4044
return RawQueryContainer(query=text, language=language)
@@ -47,7 +51,6 @@ def parse(self, raw_query_container: RawQueryContainer) -> TokenizedQueryContain
4751
class PlatformQueryParser(QueryParser, ABC):
4852
mappings: BasePlatformMappings = None
4953
tokenizer: QueryTokenizer = None
50-
details: PlatformDetails = None
5154
platform_functions: PlatformFunctions = None
5255

5356
def get_fields_tokens(self, tokens: list[Union[FieldValue, Keyword, Identifier]]) -> list[Field]:

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020

2121
from app.translator.core.models.iocs import IocsChunkValue
22+
from app.translator.core.models.platform_details import PlatformDetails
2223

2324

2425
class RenderCTI:
@@ -31,6 +32,7 @@ class RenderCTI:
3132
final_result_for_many: str = "union * | where ({result})\n"
3233
final_result_for_one: str = "union * | where {result}\n"
3334
default_mapping = None
35+
details: PlatformDetails = None
3436

3537
def create_field_value(self, field: str, value: str, generic_field: str) -> str: # noqa: ARG002
3638
return self.field_value_template.format(key=field, value=value)

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class QueryTokenizer(BaseTokenizer):
5252
single_value_operators_map: ClassVar[dict[str, str]] = {}
5353
# used to generate re pattern. so the keys order is important
5454
multi_value_operators_map: ClassVar[dict[str, str]] = {}
55+
# used to generate re pattern. so the keys order is important
56+
fields_operator_map: ClassVar[dict[str, str]] = {}
5557
operators_map: ClassVar[dict[str, str]] = {} # used to generate re pattern. so the keys order is important
5658

5759
logical_operator_pattern = r"^(?P<logical_operator>and|or|not|AND|OR|NOT)\s+"
@@ -73,7 +75,11 @@ class QueryTokenizer(BaseTokenizer):
7375
def __init_subclass__(cls, **kwargs):
7476
cls._validate_re_patterns()
7577
cls.value_pattern = cls.base_value_pattern.replace("___value_pattern___", cls._value_pattern)
76-
cls.operators_map = {**cls.single_value_operators_map, **cls.multi_value_operators_map}
78+
cls.operators_map = {
79+
**cls.single_value_operators_map,
80+
**cls.multi_value_operators_map,
81+
**cls.fields_operator_map,
82+
}
7783
cls.operator_pattern = rf"""(?:___field___\s*(?P<operator>(?:{'|'.join(cls.operators_map)})))\s*"""
7884

7985
@classmethod

uncoder-core/app/translator/managers.py

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
from abc import ABC
22
from functools import cached_property
3+
from typing import ClassVar, Union
34

45
from app.models.translation import TranslatorPlatform
5-
from app.translator.core.exceptions.core import UnsupportedRootAParser
6+
from app.translator.core.exceptions.core import UnsupportedPlatform, UnsupportedRootAParser
7+
from app.translator.core.parser import QueryParser
8+
from app.translator.core.render import QueryRender
9+
from app.translator.core.render_cti import RenderCTI
610

711

8-
class Manager(ABC):
9-
platforms = {}
10-
11-
def register(self, cls):
12-
self.platforms[cls.details.platform_id] = cls()
13-
return cls
14-
15-
def get(self, platform_id: str): # noqa: ANN201
16-
if platform := self.platforms.get(platform_id):
17-
return platform
18-
raise UnsupportedRootAParser(parser=platform_id)
12+
class PlatformManager(ABC):
13+
platforms: ClassVar[dict[str, Union[QueryParser, QueryRender, RenderCTI]]] = {}
1914

2015
def all_platforms(self) -> list:
2116
return list(self.platforms.keys())
@@ -40,54 +35,61 @@ def get_platforms_details(self) -> list[TranslatorPlatform]:
4035
return sorted(platforms, key=lambda platform: platform.group_name)
4136

4237

43-
class ParserManager(Manager):
44-
platforms = {}
45-
supported_by_roota_platforms = {}
46-
main_platforms = {}
38+
class ParserManager(PlatformManager):
39+
supported_by_roota_platforms: ClassVar[dict[str, QueryParser]] = {}
40+
main_platforms: ClassVar[dict[str, QueryParser]] = {}
4741

48-
def get_supported_by_roota(self, platform_id: str): # noqa: ANN201
42+
def get(self, platform_id: str) -> QueryParser:
43+
if platform := self.platforms.get(platform_id):
44+
return platform
45+
raise UnsupportedPlatform(platform=platform_id, is_parser=True)
46+
47+
def register(self, cls: type[QueryParser]) -> type[QueryParser]:
48+
self.platforms[cls.details.platform_id] = cls()
49+
return cls
50+
51+
def get_supported_by_roota(self, platform_id: str) -> QueryParser:
4952
if platform := self.supported_by_roota_platforms.get(platform_id):
5053
return platform
5154
raise UnsupportedRootAParser(parser=platform_id)
5255

53-
def register_supported_by_roota(self, cls):
56+
def register_supported_by_roota(self, cls: type[QueryParser]) -> type[QueryParser]:
5457
parser = cls()
5558
self.supported_by_roota_platforms[cls.details.platform_id] = parser
5659
self.platforms[cls.details.platform_id] = parser
5760
return cls
5861

59-
def register_main(self, cls):
62+
def register_main(self, cls: type[QueryParser]) -> type[QueryParser]:
6063
parser = cls()
6164
self.main_platforms[cls.details.platform_id] = parser
6265
self.platforms[cls.details.platform_id] = parser
6366
return cls
6467

65-
@cached_property
66-
def get_platforms_details(self) -> list[TranslatorPlatform]:
67-
platforms = [
68-
TranslatorPlatform(
69-
id=platform.details.platform_id,
70-
name=platform.details.name,
71-
code=platform.details.platform_id,
72-
group_name=platform.details.group_name,
73-
group_id=platform.details.group_id,
74-
platform_name=platform.details.platform_name,
75-
platform_id=platform.details.platform_id,
76-
alt_platform_name=platform.details.alt_platform_name,
77-
alt_platform=platform.details.alt_platform,
78-
first_choice=platform.details.first_choice,
79-
)
80-
for platform in self.platforms.values()
81-
]
82-
return sorted(platforms, key=lambda platform: platform.group_name)
8368

69+
class RenderManager(PlatformManager):
70+
platforms: ClassVar[dict[str, QueryRender]] = {}
71+
72+
def get(self, platform_id: str) -> QueryRender:
73+
if platform := self.platforms.get(platform_id):
74+
return platform
75+
raise UnsupportedPlatform(platform=platform_id)
76+
77+
def register(self, cls: type[QueryRender]) -> type[QueryRender]:
78+
self.platforms[cls.details.platform_id] = cls()
79+
return cls
8480

85-
class RenderManager(Manager):
86-
platforms = {}
8781

82+
class RenderCTIManager(PlatformManager):
83+
platforms: ClassVar[dict[str, RenderCTI]] = {}
8884

89-
class RenderCTIManager(Manager):
90-
platforms = {}
85+
def get(self, platform_id: str) -> RenderCTI:
86+
if platform := self.platforms.get(platform_id):
87+
return platform
88+
raise UnsupportedPlatform(platform=platform_id)
89+
90+
def register(self, cls: type[RenderCTI]) -> type[RenderCTI]:
91+
self.platforms[cls.details.platform_id] = cls()
92+
return cls
9193

9294

9395
parser_manager = ParserManager()
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from app.translator.platforms.arcsight.renders.arcsight_cti import ArcsightKeyword
1+
from app.translator.platforms.arcsight.renders.arcsight_cti import ArcsightKeyword # noqa: F401
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ARCSIGHT_QUERY_DETAILS = {
2+
"platform_id": "arcsight",
3+
"name": "ArcSight Query",
4+
"group_name": "ArcSight",
5+
"group_id": "arcsight",
6+
"platform_name": "Query",
7+
"alt_platform_name": "CEF",
8+
}

uncoder-core/app/translator/platforms/arcsight/mappings/__init__.py

Whitespace-only changes.

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