mmisp-lib 0.1.11__tar.gz → 0.2.0__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.
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/PKG-INFO +3 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/pyproject.toml +10 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/attributes.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/events.py +8 -7
- mmisp_lib-0.2.0/src/mmisp/api_schemas/logs.py +9 -0
- mmisp_lib-0.2.0/src/mmisp/api_schemas/responses/check_graph_response.py +172 -0
- {mmisp_lib-0.1.11/src/mmisp/api_schemas → mmisp_lib-0.2.0/src/mmisp/api_schemas/responses}/standard_status_response.py +6 -3
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/sharing_groups.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/warninglists.py +1 -1
- mmisp_lib-0.2.0/src/mmisp/api_schemas/workflows.py +30 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/config.py +3 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/database.py +9 -6
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/mixins.py +2 -2
- mmisp_lib-0.2.0/src/mmisp/db/models/admin_setting.py +17 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/attribute.py +4 -4
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/auth_key.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/event.py +2 -2
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/galaxy.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/galaxy_cluster.py +1 -1
- mmisp_lib-0.2.0/src/mmisp/db/models/log.py +33 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/object.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/organisation.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/role.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/sharing_group.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/sighting.py +1 -1
- mmisp_lib-0.2.0/src/mmisp/db/models/workflow.py +38 -0
- mmisp_lib-0.2.0/src/mmisp/db/models/workflow_blueprint.py +28 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/mypy.py +1 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/print_changes.py +1 -2
- mmisp_lib-0.2.0/src/mmisp/lib/actions.py +11 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/lib/attributes.py +1 -1
- mmisp_lib-0.2.0/src/mmisp/lib/logging.py +58 -0
- mmisp_lib-0.2.0/src/mmisp/lib/py.typed +0 -0
- mmisp_lib-0.2.0/src/mmisp/lib/uuid.py +10 -0
- mmisp_lib-0.2.0/src/mmisp/plugins/py.typed +0 -0
- mmisp_lib-0.2.0/src/mmisp/util/__init__.py +0 -0
- mmisp_lib-0.2.0/src/mmisp/util/crypto.py +11 -0
- mmisp_lib-0.2.0/src/mmisp/util/models.py +14 -0
- mmisp_lib-0.2.0/src/mmisp/util/partial.py +76 -0
- mmisp_lib-0.2.0/src/mmisp/util/py.typed +0 -0
- mmisp_lib-0.2.0/src/mmisp/util/uuid.py +10 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/__init__.py +0 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/execution.py +238 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/fastapi.py +162 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/graph.py +803 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/input.py +463 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/legacy.py +596 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/misp_core_format.py +163 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/modules.py +1359 -0
- mmisp_lib-0.2.0/src/mmisp/workflows/py.typed +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp_lib.egg-info/PKG-INFO +3 -1
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp_lib.egg-info/SOURCES.txt +29 -3
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp_lib.egg-info/requires.txt +2 -0
- mmisp_lib-0.1.11/tests/test_dummy.py +0 -2
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/LICENSE +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/README.md +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/setup.cfg +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/__init__.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/auth_keys.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/authentication.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/common.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/feeds.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/galaxies.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/noticelists.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/objects.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/organisations.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/py.typed +0 -0
- {mmisp_lib-0.1.11/src/mmisp/db → mmisp_lib-0.2.0/src/mmisp/api_schemas/responses}/__init__.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/roles.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/sightings.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/tags.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/taxonomies.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/user_settings.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/api_schemas/users.py +0 -0
- {mmisp_lib-0.1.11/src/mmisp/db/models → mmisp_lib-0.2.0/src/mmisp/db}/__init__.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/all_models.py +0 -0
- {mmisp_lib-0.1.11/src/mmisp/lib → mmisp_lib-0.2.0/src/mmisp/db/models}/__init__.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/feed.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/identity_provider.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/noticelist.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/server.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/tag.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/taxonomy.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/user.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/user_setting.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/models/warninglist.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/db/py.typed +0 -0
- /mmisp_lib-0.1.11/src/mmisp/lib/py.typed → /mmisp_lib-0.2.0/src/mmisp/lib/__init__.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp/lib/permissions.py +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp_lib.egg-info/dependency_links.txt +0 -0
- {mmisp_lib-0.1.11 → mmisp_lib-0.2.0}/src/mmisp_lib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: mmisp-lib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
4
4
|
Requires-Python: >=3.11.0
|
5
5
|
Description-Content-Type: text/markdown
|
6
6
|
License-File: LICENSE
|
@@ -19,11 +19,13 @@ Requires-Dist: argon2-cffi==23.1.0
|
|
19
19
|
Requires-Dist: bcrypt==4.1.2
|
20
20
|
Requires-Dist: nanoid==2.0.0
|
21
21
|
Requires-Dist: cryptography==42.0.5
|
22
|
+
Requires-Dist: jinja2~=3.1.4
|
22
23
|
Provides-Extra: dev
|
23
24
|
Requires-Dist: ruff>=0.3.7; extra == "dev"
|
24
25
|
Requires-Dist: mypy==1.8.0; extra == "dev"
|
25
26
|
Requires-Dist: pre-commit==3.6.0; extra == "dev"
|
26
27
|
Requires-Dist: pytest==8.0.0; extra == "dev"
|
28
|
+
Requires-Dist: pytest-test-groups; extra == "dev"
|
27
29
|
Requires-Dist: pytest-asyncio==0.23.5.post1; extra == "dev"
|
28
30
|
Requires-Dist: pytest-cov==4.1.0; extra == "dev"
|
29
31
|
Requires-Dist: respx==0.20.2; extra == "dev"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[project]
|
2
2
|
name = "mmisp-lib"
|
3
|
-
version = "0.
|
3
|
+
version = "0.2.0"
|
4
4
|
description = ""
|
5
5
|
authors = []
|
6
6
|
readme = "README.md"
|
@@ -23,6 +23,7 @@ dependencies = [
|
|
23
23
|
"bcrypt==4.1.2",
|
24
24
|
"nanoid==2.0.0",
|
25
25
|
"cryptography==42.0.5",
|
26
|
+
"jinja2~=3.1.4",
|
26
27
|
]
|
27
28
|
|
28
29
|
|
@@ -32,6 +33,7 @@ dev = [
|
|
32
33
|
"mypy==1.8.0",
|
33
34
|
"pre-commit==3.6.0",
|
34
35
|
"pytest==8.0.0",
|
36
|
+
"pytest-test-groups",
|
35
37
|
"pytest-asyncio==0.23.5.post1",
|
36
38
|
"pytest-cov==4.1.0",
|
37
39
|
"respx==0.20.2",
|
@@ -42,12 +44,15 @@ dev = [
|
|
42
44
|
"mmisp.lib" = ["py.typed"]
|
43
45
|
"mmisp.api_schemas" = ["py.typed"]
|
44
46
|
"mmisp.db" = ["py.typed"]
|
47
|
+
"mmisp.plugins" = ["py.typed"]
|
48
|
+
"mmisp.util" = ["py.typed"]
|
45
49
|
|
46
50
|
[tool.ruff]
|
47
51
|
fix = true
|
48
52
|
line-length = 120
|
49
53
|
required-version = ">=0.3.7"
|
50
54
|
src = ["src"]
|
55
|
+
unsafe-fixes = true
|
51
56
|
|
52
57
|
[tool.ruff.lint]
|
53
58
|
select = ["E", "F", "W", "I", "ICN", "ANN"]
|
@@ -55,3 +60,7 @@ ignore = ["ANN002", "ANN003", "ANN401"]
|
|
55
60
|
|
56
61
|
[tool.coverage.run]
|
57
62
|
concurrency = ["greenlet", "thread"]
|
63
|
+
include = [
|
64
|
+
"/usr/local/lib/python3.11/site-packages/mmisp/*",
|
65
|
+
"/home/mmisp/.local/lib/python3.11/site-packages/mmisp/*"
|
66
|
+
]
|
@@ -384,7 +384,7 @@ class AddAttributeResponse(BaseModel):
|
|
384
384
|
|
385
385
|
|
386
386
|
class AddAttributeBody(BaseModel):
|
387
|
-
type: literal_valid_attribute_types
|
387
|
+
type: literal_valid_attribute_types # type:ignore[valid-type]
|
388
388
|
value: str | None = None
|
389
389
|
value1: str | None = None
|
390
390
|
value2: str | None = None
|
@@ -330,11 +330,19 @@ class PublishEventResponse(BaseModel):
|
|
330
330
|
orm_mode = True
|
331
331
|
|
332
332
|
|
333
|
+
class GetAllEventsEventTagTag(BaseModel):
|
334
|
+
id: str
|
335
|
+
name: str
|
336
|
+
colour: str
|
337
|
+
is_galaxy: bool
|
338
|
+
|
339
|
+
|
333
340
|
class IndexEventsEventTag(BaseModel):
|
334
341
|
id: str
|
335
342
|
event_id: str
|
336
343
|
tag_id: str
|
337
344
|
local: bool
|
345
|
+
Tag: GetAllEventsEventTagTag
|
338
346
|
|
339
347
|
|
340
348
|
class IndexEventsAttributes(BaseModel):
|
@@ -403,13 +411,6 @@ class ObjectEventResponse(BaseModel):
|
|
403
411
|
orgc_id: str | None = None
|
404
412
|
|
405
413
|
|
406
|
-
class GetAllEventsEventTagTag(BaseModel):
|
407
|
-
id: str
|
408
|
-
name: str
|
409
|
-
colour: str
|
410
|
-
is_galaxy: bool
|
411
|
-
|
412
|
-
|
413
414
|
class GetAllEventsEventTag(BaseModel):
|
414
415
|
id: str
|
415
416
|
event_id: str
|
@@ -0,0 +1,172 @@
|
|
1
|
+
from typing import Dict, List
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
5
|
+
|
6
|
+
class IsAcyclicInfo(BaseModel):
|
7
|
+
nodeID1: int
|
8
|
+
nodeID2: int
|
9
|
+
cycle: str = "Cycle"
|
10
|
+
|
11
|
+
|
12
|
+
class IsAcyclic(BaseModel):
|
13
|
+
"""
|
14
|
+
Represents the whether graph is acyclic and details of the first detected cycle.
|
15
|
+
|
16
|
+
- **is_acyclic**: False if the graph contains at least one cycle.
|
17
|
+
- **cycles**: A list of entries, each containing two node IDs and a "Cycle" string.
|
18
|
+
Conbined they result in the cycle.
|
19
|
+
|
20
|
+
Example:
|
21
|
+
```json
|
22
|
+
"is_acyclic": {
|
23
|
+
"is_acyclic": false,
|
24
|
+
"cycles": [
|
25
|
+
[
|
26
|
+
4,
|
27
|
+
3,
|
28
|
+
"Cycle"
|
29
|
+
],
|
30
|
+
[
|
31
|
+
3,
|
32
|
+
4,
|
33
|
+
"Cycle"
|
34
|
+
]
|
35
|
+
]
|
36
|
+
}
|
37
|
+
```
|
38
|
+
"""
|
39
|
+
|
40
|
+
is_acyclic: bool
|
41
|
+
cycles: List[IsAcyclicInfo]
|
42
|
+
|
43
|
+
|
44
|
+
class MultipleOutputConnection(BaseModel):
|
45
|
+
"""
|
46
|
+
Represents the status and details of nodes with illegal multiple output connections in a graph.
|
47
|
+
|
48
|
+
- **has_multiple_output_connection**: True if at least one node has multiple output
|
49
|
+
connections that are not allowed.
|
50
|
+
For example, the 'Concurrent Task' node can have multiple output connections while the value here is `False`.
|
51
|
+
- **edges**: A dictionary where the key is the ID of a node with multiple illegal connections,
|
52
|
+
and the value is a list of node IDs to which these illegal connections are made.
|
53
|
+
|
54
|
+
Example:
|
55
|
+
```json
|
56
|
+
"multiple_output_connection": {
|
57
|
+
"has_multiple_output_connection": true,
|
58
|
+
"edges": {
|
59
|
+
"1": [
|
60
|
+
5,
|
61
|
+
3
|
62
|
+
]
|
63
|
+
}
|
64
|
+
}
|
65
|
+
```
|
66
|
+
"""
|
67
|
+
|
68
|
+
has_multiple_output_connection: bool
|
69
|
+
edges: Dict[int, List[int]]
|
70
|
+
|
71
|
+
|
72
|
+
class PathWarningsInfo(BaseModel):
|
73
|
+
source_id: int # is a string in legacy misp
|
74
|
+
next_node_id: int # is a string in legacy misp
|
75
|
+
warning: str
|
76
|
+
blocking: bool
|
77
|
+
module_name: str
|
78
|
+
module_id: int
|
79
|
+
|
80
|
+
|
81
|
+
class PathWarnings(BaseModel):
|
82
|
+
"""
|
83
|
+
Represents warnings for paths in a graph.
|
84
|
+
|
85
|
+
- **has_path_warnings**: True if the graph contains at least one warning.
|
86
|
+
- **edges**: A list containing all connections which are flagged as warnings.
|
87
|
+
|
88
|
+
Example:
|
89
|
+
```json
|
90
|
+
"path_warnings": {
|
91
|
+
"has_path_warnings": true,
|
92
|
+
"edges": [
|
93
|
+
[
|
94
|
+
5,
|
95
|
+
2,
|
96
|
+
"This path leads to a blocking node from a non-blocking context",
|
97
|
+
true,
|
98
|
+
"stop-execution",
|
99
|
+
2
|
100
|
+
]
|
101
|
+
]
|
102
|
+
}
|
103
|
+
```
|
104
|
+
"""
|
105
|
+
|
106
|
+
has_path_warnings: bool
|
107
|
+
edges: List[PathWarningsInfo]
|
108
|
+
|
109
|
+
|
110
|
+
class MiscellaneousGraphValidationError(BaseModel):
|
111
|
+
"""
|
112
|
+
Validation errors that do no fit in the legacy MISP json response format for Graph Validation will be returned as
|
113
|
+
errors in this format.
|
114
|
+
"""
|
115
|
+
|
116
|
+
error_id: str
|
117
|
+
"""
|
118
|
+
The type of error that this instance represents.
|
119
|
+
"""
|
120
|
+
|
121
|
+
message: str
|
122
|
+
"""
|
123
|
+
The error message of this instance.
|
124
|
+
"""
|
125
|
+
|
126
|
+
|
127
|
+
class CheckGraphResponse(BaseModel):
|
128
|
+
"""
|
129
|
+
Response schema from the API for checking a graph.
|
130
|
+
|
131
|
+
- **is_acyclic**: Indicates whether the graph is acyclic and provides information
|
132
|
+
about the first detected cycle, if any.
|
133
|
+
- **multiple_output_connection**: Indicates whether the graph has illegal multiple output connections,
|
134
|
+
detailing the nodes involved.
|
135
|
+
- **path_warnings**: Records warnings if a path leads to a blocking node from a
|
136
|
+
'Concurrent Task' node, providing relevant details. Not used in Modern MISP, and will be returned empty.
|
137
|
+
- **unsupported_modules"" List of the modules (identified with their graph_id) that are currently unsupported in
|
138
|
+
Modern MISP (not yet implemented) causing the workflow to be invalid.
|
139
|
+
- **misc_errors** Other miscellaneous errors indicating that the workflow graph is broken or etc. (edges registered
|
140
|
+
at ports outside the valid range, inconsistencies between the incoming and outgoing adjacency lists etc.)
|
141
|
+
|
142
|
+
Example JSON structure:
|
143
|
+
```json
|
144
|
+
{
|
145
|
+
"is_acyclic": {
|
146
|
+
"is_acyclic": false,
|
147
|
+
"cycles": [
|
148
|
+
[4, 3, "Cycle"],
|
149
|
+
[3, 4, "Cycle"]
|
150
|
+
]
|
151
|
+
},
|
152
|
+
"multiple_output_connection": {
|
153
|
+
"has_multiple_output_connection": true,
|
154
|
+
"edges": {
|
155
|
+
"1": [5, 3]
|
156
|
+
}
|
157
|
+
},
|
158
|
+
"path_warnings": {
|
159
|
+
"has_path_warnings": true,
|
160
|
+
"edges": [
|
161
|
+
[5, 2, "This path leads to a blocking node from a non-blocking context", true, "stop-execution", 2]
|
162
|
+
]
|
163
|
+
}
|
164
|
+
}
|
165
|
+
```
|
166
|
+
"""
|
167
|
+
|
168
|
+
is_acyclic: IsAcyclic
|
169
|
+
multiple_output_connection: MultipleOutputConnection
|
170
|
+
path_warnings: PathWarnings
|
171
|
+
unsupported_modules: List[int]
|
172
|
+
misc_errors: List[MiscellaneousGraphValidationError]
|
@@ -1,13 +1,16 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
2
|
|
3
3
|
|
4
|
-
class
|
5
|
-
saved: bool
|
6
|
-
success: bool
|
4
|
+
class StandartResponse(BaseModel):
|
7
5
|
name: str
|
8
6
|
message: str
|
9
7
|
url: str
|
10
8
|
|
11
9
|
|
10
|
+
class StandardStatusResponse(StandartResponse):
|
11
|
+
saved: bool
|
12
|
+
success: bool
|
13
|
+
|
14
|
+
|
12
15
|
class StandardStatusIdentifiedResponse(StandardStatusResponse):
|
13
16
|
id: str
|
@@ -3,7 +3,7 @@ from datetime import datetime
|
|
3
3
|
from pydantic import BaseModel, Field
|
4
4
|
|
5
5
|
from mmisp.api_schemas.organisations import Organisation
|
6
|
-
from mmisp.api_schemas.standard_status_response import StandardStatusResponse
|
6
|
+
from mmisp.api_schemas.responses.standard_status_response import StandardStatusResponse
|
7
7
|
|
8
8
|
|
9
9
|
class SharingGroup(BaseModel):
|
@@ -115,7 +115,7 @@ class CreateWarninglistBody(BaseModel):
|
|
115
115
|
enabled: bool
|
116
116
|
default: bool
|
117
117
|
category: WarninglistCategory
|
118
|
-
valid_attributes: list[literal_valid_attribute_types]
|
118
|
+
valid_attributes: list[literal_valid_attribute_types] # type:ignore[valid-type]
|
119
119
|
values: str = Field(min_length=1, max_length=65535)
|
120
120
|
|
121
121
|
class Config:
|
@@ -0,0 +1,30 @@
|
|
1
|
+
from typing import Any, Optional
|
2
|
+
|
3
|
+
from pydantic import BaseModel
|
4
|
+
|
5
|
+
|
6
|
+
class GraphRequest(BaseModel):
|
7
|
+
workflow_graph: dict
|
8
|
+
|
9
|
+
|
10
|
+
class WorkflowEditRequest(BaseModel):
|
11
|
+
# workflow_name: str
|
12
|
+
# workflow_description: str
|
13
|
+
# workflow_graph: dict
|
14
|
+
data: Any
|
15
|
+
|
16
|
+
|
17
|
+
class ModuleIndexRequest(BaseModel):
|
18
|
+
enabled: Optional[bool] = None
|
19
|
+
type: str = "action"
|
20
|
+
actiontype: str = "all"
|
21
|
+
limit: int = 50
|
22
|
+
page: int = 1
|
23
|
+
|
24
|
+
|
25
|
+
class TriggerRequest(BaseModel):
|
26
|
+
scope: Optional[str] = None
|
27
|
+
enabled: Optional[bool] = None
|
28
|
+
blocking: Optional[bool] = None
|
29
|
+
limit: int = 50
|
30
|
+
page: int = 1
|
@@ -13,4 +13,6 @@ class DatabaseConfig:
|
|
13
13
|
load_dotenv(getenv("ENV_FILE", ".env"))
|
14
14
|
|
15
15
|
|
16
|
-
config: DatabaseConfig = DatabaseConfig(
|
16
|
+
config: DatabaseConfig = DatabaseConfig(
|
17
|
+
DATABASE_URL=getenv("DATABASE_URL", "sqlite:///dev/null"), DEBUG=bool(getenv("DEBUG", False))
|
18
|
+
)
|
@@ -16,18 +16,18 @@ Base = declarative_base()
|
|
16
16
|
|
17
17
|
|
18
18
|
class DatabaseSessionManager:
|
19
|
-
def __init__(self: Self) -> None:
|
19
|
+
def __init__(self: Self, db_url: str = config.DATABASE_URL) -> None:
|
20
20
|
self._engine: AsyncEngine | None = None
|
21
21
|
self._sessionmaker: sessionmaker | None = None
|
22
22
|
|
23
|
-
self._url = make_url(
|
23
|
+
self._url = make_url(db_url)
|
24
24
|
|
25
25
|
def init(self: Self) -> None:
|
26
26
|
if config.DEBUG:
|
27
27
|
self._engine = create_async_engine(self._url, echo=True)
|
28
28
|
else:
|
29
29
|
self._engine = create_async_engine(self._url)
|
30
|
-
self._sessionmaker = sessionmaker(
|
30
|
+
self._sessionmaker = sessionmaker( # type:ignore[call-overload]
|
31
31
|
autocommit=False, expire_on_commit=False, bind=self._engine, class_=AsyncSession
|
32
32
|
)
|
33
33
|
|
@@ -68,16 +68,19 @@ class DatabaseSessionManager:
|
|
68
68
|
async def create_all(self: Self, engine: AsyncEngine | None = None) -> None:
|
69
69
|
if engine is None:
|
70
70
|
engine = self._engine
|
71
|
+
assert engine is not None
|
71
72
|
async with engine.begin() as conn:
|
72
|
-
await conn.run_sync(Base.metadata.create_all)
|
73
|
+
await conn.run_sync(Base.metadata.create_all) # type:ignore[attr-defined]
|
73
74
|
|
74
75
|
async def drop_all(self: Self, engine: AsyncEngine | None = None) -> None:
|
75
76
|
if engine is None:
|
76
77
|
engine = self._engine
|
77
|
-
|
78
|
+
assert engine is not None
|
79
|
+
async with engine.begin() as conn:
|
80
|
+
await conn.run_sync(Base.metadata.drop_all) # type:ignore[attr-defined]
|
78
81
|
|
79
82
|
|
80
|
-
async def get_db() -> Session:
|
83
|
+
async def get_db() -> AsyncIterator[Session]:
|
81
84
|
async with sessionmanager.session() as session:
|
82
85
|
yield session
|
83
86
|
|
@@ -7,11 +7,11 @@ from sqlalchemy.ext.hybrid import hybrid_property
|
|
7
7
|
class DictMixin:
|
8
8
|
def asdict(self: Self) -> dict:
|
9
9
|
d = {}
|
10
|
-
for key in self.__mapper__.c.keys():
|
10
|
+
for key in self.__mapper__.c.keys(): # type:ignore[attr-defined]
|
11
11
|
if not key.startswith("_"):
|
12
12
|
d[key] = getattr(self, key)
|
13
13
|
|
14
|
-
for key, prop in inspect(self.__class__).all_orm_descriptors.items():
|
14
|
+
for key, prop in inspect(self.__class__).all_orm_descriptors.items(): # type:ignore[union-attr]
|
15
15
|
if isinstance(prop, hybrid_property):
|
16
16
|
d[key] = getattr(self, key)
|
17
17
|
return d
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from sqlalchemy import Integer, String, Text
|
2
|
+
|
3
|
+
from mmisp.db.mypy import Mapped, mapped_column
|
4
|
+
|
5
|
+
from ..database import Base
|
6
|
+
|
7
|
+
|
8
|
+
class AdminSetting(Base):
|
9
|
+
"""
|
10
|
+
A python class representation of the database model for admin settings in MISP
|
11
|
+
"""
|
12
|
+
|
13
|
+
__tablename__ = "admin_settings"
|
14
|
+
|
15
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, autoincrement=True)
|
16
|
+
setting: Mapped[str] = mapped_column(String(255), nullable=False)
|
17
|
+
value: Mapped[str] = mapped_column(Text, nullable=False)
|
@@ -8,7 +8,7 @@ from sqlalchemy.orm.decl_api import DeclarativeMeta
|
|
8
8
|
from mmisp.db.mixins import DictMixin
|
9
9
|
from mmisp.db.mypy import Mapped, mapped_column
|
10
10
|
from mmisp.lib.attributes import categories, default_category, mapper_safe_clsname_val, to_ids
|
11
|
-
from mmisp.
|
11
|
+
from mmisp.lib.uuid import uuid
|
12
12
|
|
13
13
|
from ..database import Base
|
14
14
|
from .event import Event
|
@@ -39,7 +39,7 @@ class Attribute(Base, DictMixin):
|
|
39
39
|
first_seen: Mapped[int] = mapped_column(BigInteger, index=True)
|
40
40
|
last_seen: Mapped[int] = mapped_column(BigInteger, index=True)
|
41
41
|
|
42
|
-
event = relationship("Event", back_populates="attributes", lazy="joined")
|
42
|
+
event = relationship("Event", back_populates="attributes", lazy="joined") # type:ignore[var-annotated]
|
43
43
|
|
44
44
|
__mapper_args__ = {"polymorphic_on": "type"}
|
45
45
|
|
@@ -62,7 +62,7 @@ class Attribute(Base, DictMixin):
|
|
62
62
|
return self.value1
|
63
63
|
return f"{self.value1}|{self.value2}"
|
64
64
|
|
65
|
-
@value.setter
|
65
|
+
@value.setter # type: ignore[no-redef]
|
66
66
|
def value(self: Self, value: str) -> None:
|
67
67
|
split = value.split("|", 1)
|
68
68
|
self.value1 = split[0]
|
@@ -89,7 +89,7 @@ class AttributeMeta(DeclarativeMeta):
|
|
89
89
|
dct["categories"] = categories[mapper_safe_clsname_val[key]]
|
90
90
|
dct["default_to_ids"] = to_ids[mapper_safe_clsname_val[key]]
|
91
91
|
dct["__mapper_args__"] = {"polymorphic_identity": mapper_safe_clsname_val[key]}
|
92
|
-
return super().__new__(cls, clsname, bases, dct)
|
92
|
+
return super().__new__(cls, clsname, bases, dct) # type:ignore[misc]
|
93
93
|
|
94
94
|
|
95
95
|
for k, _ in mapper_safe_clsname_val.items():
|
@@ -4,7 +4,7 @@ from sqlalchemy import Boolean, DateTime, ForeignKey, Integer, String, Text
|
|
4
4
|
from sqlalchemy.orm import relationship
|
5
5
|
|
6
6
|
from mmisp.db.mypy import Mapped, mapped_column
|
7
|
-
from mmisp.
|
7
|
+
from mmisp.lib.uuid import uuid
|
8
8
|
|
9
9
|
from ..database import Base
|
10
10
|
from .organisation import Organisation
|
@@ -37,7 +37,7 @@ class Event(Base):
|
|
37
37
|
extends_uuid: Mapped[str] = mapped_column(String(40), default="", index=True)
|
38
38
|
protected: Mapped[bool] = mapped_column(Boolean)
|
39
39
|
|
40
|
-
attributes = relationship("Attribute", back_populates="event")
|
40
|
+
attributes = relationship("Attribute", back_populates="event") # type:ignore[assignment,var-annotated]
|
41
41
|
|
42
42
|
|
43
43
|
class EventReport(Base):
|
@@ -0,0 +1,33 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
3
|
+
from sqlalchemy import DateTime, Integer, String, Text
|
4
|
+
|
5
|
+
from mmisp.db.mypy import Mapped, mapped_column
|
6
|
+
|
7
|
+
from ..database import Base
|
8
|
+
|
9
|
+
|
10
|
+
class Log(Base):
|
11
|
+
"""
|
12
|
+
A python class representation of the database model for logs in MISP.
|
13
|
+
|
14
|
+
Further explanation for some of the central attributes of the database model:
|
15
|
+
- Action: Describes the action that was logged, e.g. a login or workflow execution
|
16
|
+
- Change: A string-representation of the changes made to the logged object or of
|
17
|
+
central information about the logged object.
|
18
|
+
"""
|
19
|
+
|
20
|
+
__tablename__ = "logs"
|
21
|
+
|
22
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False)
|
23
|
+
title: Mapped[str] = mapped_column(Text, nullable=True)
|
24
|
+
created: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
|
25
|
+
model: Mapped[str] = mapped_column(String(80), nullable=False)
|
26
|
+
model_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
27
|
+
action: Mapped[str] = mapped_column(String(20), nullable=False)
|
28
|
+
user_id: Mapped[int] = mapped_column(Integer, nullable=False)
|
29
|
+
change: Mapped[str] = mapped_column(Text, nullable=True)
|
30
|
+
email: Mapped[str] = mapped_column(String(255), nullable=False)
|
31
|
+
org: Mapped[str] = mapped_column(String(255), nullable=False)
|
32
|
+
description: Mapped[str] = mapped_column(Text, nullable=True)
|
33
|
+
ip: Mapped[str] = mapped_column(String(45), nullable=True)
|
@@ -3,7 +3,7 @@ from sqlalchemy import Boolean, ForeignKey, Integer, String
|
|
3
3
|
from mmisp.db.database import Base
|
4
4
|
from mmisp.db.mixins import DictMixin
|
5
5
|
from mmisp.db.mypy import Mapped, mapped_column
|
6
|
-
from mmisp.
|
6
|
+
from mmisp.lib.uuid import uuid
|
7
7
|
|
8
8
|
|
9
9
|
class Object(Base, DictMixin):
|
@@ -2,7 +2,7 @@ from sqlalchemy import BigInteger, ForeignKey, Integer, String
|
|
2
2
|
|
3
3
|
from mmisp.db.database import Base
|
4
4
|
from mmisp.db.mypy import Mapped, mapped_column
|
5
|
-
from mmisp.
|
5
|
+
from mmisp.lib.uuid import uuid
|
6
6
|
|
7
7
|
from .attribute import Attribute
|
8
8
|
from .event import Event
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from uuid import uuid4 as _uuid4
|
2
|
+
|
3
|
+
from sqlalchemy import Boolean, Integer, String
|
4
|
+
|
5
|
+
from mmisp.db.mypy import Mapped, mapped_column
|
6
|
+
|
7
|
+
from ...workflows.graph import WorkflowGraph
|
8
|
+
from ...workflows.legacy import JSONGraphType
|
9
|
+
from ..database import Base
|
10
|
+
|
11
|
+
|
12
|
+
def uuid() -> str:
|
13
|
+
return str(_uuid4())
|
14
|
+
|
15
|
+
|
16
|
+
class Workflow(Base):
|
17
|
+
"""
|
18
|
+
A python class representation of the database model for workflows in MISP.
|
19
|
+
|
20
|
+
The most central of the attributes in this model is the data attribute,
|
21
|
+
containing the information about the workflow structure and the modules contained in the workflow,
|
22
|
+
represented/stored as a JSON-String.
|
23
|
+
(The other attributes are what their name sais, e.g. counter represents the numer
|
24
|
+
of times the workflow was executed.)
|
25
|
+
"""
|
26
|
+
|
27
|
+
__tablename__ = "workflows"
|
28
|
+
|
29
|
+
id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False, autoincrement=True)
|
30
|
+
uuid: Mapped[str] = mapped_column(String(40), default=uuid, nullable=False, index=True)
|
31
|
+
name: Mapped[str] = mapped_column(String(191), nullable=False, index=True)
|
32
|
+
description: Mapped[str] = mapped_column(String(191), nullable=False)
|
33
|
+
timestamp: Mapped[int] = mapped_column(Integer, nullable=False, default=0, index=True)
|
34
|
+
enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
35
|
+
counter: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
36
|
+
trigger_id: Mapped[str] = mapped_column(String(191), nullable=False, index=True)
|
37
|
+
debug_enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=0)
|
38
|
+
data: Mapped[WorkflowGraph] = mapped_column(JSONGraphType, nullable=False, default=0)
|