dogesec-commons 1.0.2__py3-none-any.whl
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.
- dogesec_commons/__init__.py +0 -0
- dogesec_commons/asgi.py +16 -0
- dogesec_commons/objects/__init__.py +1 -0
- dogesec_commons/objects/apps.py +10 -0
- dogesec_commons/objects/conf.py +8 -0
- dogesec_commons/objects/db_view_creator.py +164 -0
- dogesec_commons/objects/helpers.py +660 -0
- dogesec_commons/objects/views.py +427 -0
- dogesec_commons/settings.py +161 -0
- dogesec_commons/stixifier/__init__.py +0 -0
- dogesec_commons/stixifier/apps.py +5 -0
- dogesec_commons/stixifier/conf.py +1 -0
- dogesec_commons/stixifier/migrations/0001_initial.py +36 -0
- dogesec_commons/stixifier/migrations/0002_profile_ai_content_check_variable.py +18 -0
- dogesec_commons/stixifier/migrations/0003_rename_ai_content_check_variable_profile_ai_content_check_provider_and_more.py +23 -0
- dogesec_commons/stixifier/migrations/0004_profile_identity_id.py +18 -0
- dogesec_commons/stixifier/migrations/0005_profile_generate_pdf.py +18 -0
- dogesec_commons/stixifier/migrations/__init__.py +0 -0
- dogesec_commons/stixifier/models.py +57 -0
- dogesec_commons/stixifier/serializers.py +192 -0
- dogesec_commons/stixifier/stixifier.py +252 -0
- dogesec_commons/stixifier/summarizer.py +62 -0
- dogesec_commons/stixifier/views.py +193 -0
- dogesec_commons/urls.py +45 -0
- dogesec_commons/utils/__init__.py +3 -0
- dogesec_commons/utils/autoschema.py +88 -0
- dogesec_commons/utils/exceptions.py +28 -0
- dogesec_commons/utils/filters.py +66 -0
- dogesec_commons/utils/ordering.py +47 -0
- dogesec_commons/utils/pagination.py +81 -0
- dogesec_commons/utils/schemas.py +27 -0
- dogesec_commons/utils/serializers.py +47 -0
- dogesec_commons/wsgi.py +16 -0
- dogesec_commons-1.0.2.dist-info/METADATA +57 -0
- dogesec_commons-1.0.2.dist-info/RECORD +37 -0
- dogesec_commons-1.0.2.dist-info/WHEEL +4 -0
- dogesec_commons-1.0.2.dist-info/licenses/LICENSE +202 -0
File without changes
|
dogesec_commons/asgi.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
"""
|
2
|
+
ASGI config for dogesec_commons project.
|
3
|
+
|
4
|
+
It exposes the ASGI callable as a module-level variable named ``application``.
|
5
|
+
|
6
|
+
For more information on this file, see
|
7
|
+
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
|
8
|
+
"""
|
9
|
+
|
10
|
+
import os
|
11
|
+
|
12
|
+
from django.core.asgi import get_asgi_application
|
13
|
+
|
14
|
+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dogesec_commons.settings')
|
15
|
+
|
16
|
+
application = get_asgi_application()
|
@@ -0,0 +1 @@
|
|
1
|
+
from . import apps as app
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from django.apps import AppConfig
|
2
|
+
|
3
|
+
class ArangoObjectsViewApp(AppConfig):
|
4
|
+
name = 'dogesec_commons.objects'
|
5
|
+
label = 'dogesec_arango_objects_views'
|
6
|
+
|
7
|
+
def ready(self) -> None:
|
8
|
+
from .db_view_creator import startup_func
|
9
|
+
startup_func()
|
10
|
+
return super().ready()
|
@@ -0,0 +1,8 @@
|
|
1
|
+
from django.conf import settings
|
2
|
+
|
3
|
+
MAXIMUM_PAGE_SIZE = getattr(settings, 'MAXIMUM_PAGE_SIZE', 200)
|
4
|
+
DEFAULT_PAGE_SIZE = getattr(settings, 'DEFAULT_PAGE_SIZE', 50)
|
5
|
+
|
6
|
+
DB = settings.ARANGODB_DATABASE
|
7
|
+
DB_NAME = f"{DB}_database"
|
8
|
+
ARANGODB_DATABASE_VIEW = getattr(settings, "ARANGODB_DATABASE_VIEW", f"{DB}_view")
|
@@ -0,0 +1,164 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
import arango
|
4
|
+
import arango.exceptions
|
5
|
+
from arango.database import StandardDatabase
|
6
|
+
from arango import ArangoClient
|
7
|
+
|
8
|
+
from dogesec_commons.objects import conf
|
9
|
+
|
10
|
+
logging.basicConfig(
|
11
|
+
level=logging.INFO,
|
12
|
+
format='[ARANGODB VIEW] %(levelname)s %(asctime)s %(message)s',
|
13
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
14
|
+
)
|
15
|
+
|
16
|
+
from django.conf import settings
|
17
|
+
|
18
|
+
|
19
|
+
SORT_FIELDS = [
|
20
|
+
"id",
|
21
|
+
"type",
|
22
|
+
"created",
|
23
|
+
"modified",
|
24
|
+
"name",
|
25
|
+
]
|
26
|
+
|
27
|
+
FILTER_HIDDEN_FIELDS = [
|
28
|
+
"_stix2arango_note",
|
29
|
+
"_id",
|
30
|
+
"_from",
|
31
|
+
"_to",
|
32
|
+
"_is_ref",
|
33
|
+
"_arango_cti_processor_note",
|
34
|
+
"_arango_cve_processor_note",
|
35
|
+
]
|
36
|
+
|
37
|
+
FILTER_FIELDS_VERTEX = [
|
38
|
+
"type",
|
39
|
+
"name",
|
40
|
+
"labels",
|
41
|
+
]
|
42
|
+
FILTER_FIELDS_EDGE = [
|
43
|
+
"source_ref",
|
44
|
+
"target_ref",
|
45
|
+
"relationship_type",
|
46
|
+
]
|
47
|
+
FILTER_SCO_FIELDS = ['value', 'path', 'subject', 'number', 'pid', 'string', 'key', 'iban_number', 'payload_bin', 'hash', 'display_name', 'protocols', 'name', 'body']
|
48
|
+
FILTER_FIELDS = list(set(FILTER_FIELDS_EDGE + FILTER_FIELDS_VERTEX))
|
49
|
+
|
50
|
+
|
51
|
+
def create_database(client: ArangoClient, sys_db: StandardDatabase, db_name):
|
52
|
+
logging.info(f"creating database {db_name}")
|
53
|
+
try:
|
54
|
+
sys_db.create_database(db_name)
|
55
|
+
except arango.exceptions.DatabaseCreateError as e:
|
56
|
+
logging.error(e)
|
57
|
+
return client.db(
|
58
|
+
name=db_name, username=settings.ARANGODB_USERNAME, password=settings.ARANGODB_PASSWORD, verify=True
|
59
|
+
)
|
60
|
+
|
61
|
+
|
62
|
+
def create_view(db: StandardDatabase, view_name, sort_fields=SORT_FIELDS, filter_fields=[SORT_FIELDS, FILTER_FIELDS_VERTEX, FILTER_FIELDS_EDGE, FILTER_HIDDEN_FIELDS, FILTER_SCO_FIELDS]):
|
63
|
+
logging.info(f"creating view {view_name} in {db.name}")
|
64
|
+
primary_sort = []
|
65
|
+
for field in sort_fields:
|
66
|
+
primary_sort.append(dict(field=field, direction="asc"))
|
67
|
+
primary_sort.append(dict(field=field, direction="desc"))
|
68
|
+
|
69
|
+
all_fields = [*filter_fields, sort_fields]
|
70
|
+
|
71
|
+
try:
|
72
|
+
logging.info("try updating view (%s) if exists", view_name)
|
73
|
+
return update_view(db, all_fields, view_name)
|
74
|
+
except BaseException as e:
|
75
|
+
logging.info(f"view update not possible: {e}")
|
76
|
+
|
77
|
+
try:
|
78
|
+
logging.info("create new view: %s", view_name)
|
79
|
+
return db.create_arangosearch_view(
|
80
|
+
view_name, {"primarySort": primary_sort, "storedValues": all_fields}
|
81
|
+
)
|
82
|
+
except arango.exceptions.ViewCreateError as e:
|
83
|
+
logging.error(e)
|
84
|
+
return db.view(view_name)
|
85
|
+
|
86
|
+
|
87
|
+
def get_link_properties(collection_name: str):
|
88
|
+
if collection_name.endswith("_vertex_collection"):
|
89
|
+
return {
|
90
|
+
"fields": {name: {} for name in FILTER_FIELDS_VERTEX},
|
91
|
+
}
|
92
|
+
elif collection_name.endswith("_edge_collection"):
|
93
|
+
return {
|
94
|
+
"fields": {name: {} for name in FILTER_FIELDS_EDGE},
|
95
|
+
}
|
96
|
+
else:
|
97
|
+
return None
|
98
|
+
|
99
|
+
|
100
|
+
def link_one_collection(db: StandardDatabase, view_name, collection_name):
|
101
|
+
logging.info(f"linking collection {collection_name} to {view_name}")
|
102
|
+
view = db.view(view_name)
|
103
|
+
link = {"includeAllFields": True}
|
104
|
+
if link and collection_name:
|
105
|
+
view["links"][collection_name] = link
|
106
|
+
db.update_arangosearch_view(view_name, view)
|
107
|
+
logging.info(f"linked collection {collection_name} to {view_name}")
|
108
|
+
|
109
|
+
|
110
|
+
def update_view(db: StandardDatabase, filter_fields, view_name) -> bool:
|
111
|
+
view = db.view(view_name)
|
112
|
+
view_fields = [sv['fields'] for sv in view['stored_values']]
|
113
|
+
def hash_fields(fields: list[list[str]]) -> set[str]:
|
114
|
+
hashes = set()
|
115
|
+
for ff in fields:
|
116
|
+
hash_val = 0
|
117
|
+
for f in set(ff):
|
118
|
+
hash_val += hash(f)
|
119
|
+
hashes.add(hash_val)
|
120
|
+
return hashes
|
121
|
+
view_hash = hash_fields(view_fields)
|
122
|
+
fields_hash = hash_fields(filter_fields)
|
123
|
+
|
124
|
+
if view_hash == fields_hash:
|
125
|
+
return view
|
126
|
+
|
127
|
+
logging.info("old hash does not match new hash, updating...")
|
128
|
+
|
129
|
+
view['storedValues'] = [{"fields": v} for v in filter_fields]
|
130
|
+
view["stored_values"] = filter_fields
|
131
|
+
|
132
|
+
new_view = db.update_arangosearch_view(view_name, view)
|
133
|
+
|
134
|
+
# should update but for some reason update not working, so recreate instead
|
135
|
+
new_view_hash = hash_fields([sv['fields'] for sv in new_view['stored_values']])
|
136
|
+
if new_view_hash != fields_hash:
|
137
|
+
db.delete_view(view_name, ignore_missing=True)
|
138
|
+
raise Exception("recreate because update is impossible")
|
139
|
+
return new_view
|
140
|
+
|
141
|
+
def link_all_collections(db: StandardDatabase, view: dict):
|
142
|
+
links = view.get("links", {})
|
143
|
+
view_name = view["name"]
|
144
|
+
for collection in db.collections():
|
145
|
+
collection_name = collection["name"]
|
146
|
+
if collection["system"]:
|
147
|
+
continue
|
148
|
+
links[collection_name] = {"includeAllFields": True}
|
149
|
+
if not links[collection_name]:
|
150
|
+
del links[collection]
|
151
|
+
continue
|
152
|
+
logging.info(f"linking collection {collection_name} to {view_name}")
|
153
|
+
db.update_arangosearch_view(view_name, view)
|
154
|
+
logging.info(f"linked {len(links)} collections to view")
|
155
|
+
|
156
|
+
|
157
|
+
def startup_func():
|
158
|
+
logging.info("setting up database")
|
159
|
+
client = ArangoClient(settings.ARANGODB_HOST_URL)
|
160
|
+
sys_db = client.db(username=settings.ARANGODB_USERNAME, password=settings.ARANGODB_PASSWORD)
|
161
|
+
db = create_database(client, sys_db, conf.DB_NAME)
|
162
|
+
view = create_view(db, conf.ARANGODB_DATABASE_VIEW)
|
163
|
+
link_all_collections(db, view)
|
164
|
+
logging.info("app ready")
|