mmisp-lib 0.3.0__tar.gz → 0.5.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.
Files changed (130) hide show
  1. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/PKG-INFO +2 -2
  2. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/pyproject.toml +3 -2
  3. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/attributes.py +22 -42
  4. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/events.py +7 -5
  5. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/organisations.py +15 -12
  6. mmisp_lib-0.5.0/src/mmisp/api_schemas/servers.py +138 -0
  7. mmisp_lib-0.5.0/src/mmisp/db/additional_properties.py +10 -0
  8. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/all_models.py +2 -0
  9. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/mixins.py +2 -1
  10. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/attribute.py +81 -3
  11. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/event.py +35 -0
  12. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/galaxy.py +7 -0
  13. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/galaxy_cluster.py +32 -0
  14. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/object.py +14 -0
  15. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/organisation.py +28 -0
  16. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/server.py +26 -2
  17. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/tag.py +4 -0
  18. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/user.py +11 -0
  19. mmisp_lib-0.5.0/src/mmisp/db/print_changes.py +47 -0
  20. mmisp_lib-0.5.0/src/mmisp/lib/attribute_search_filter.py +60 -0
  21. mmisp_lib-0.5.0/src/mmisp/lib/attributes.py +2340 -0
  22. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/permissions.py +6 -0
  23. mmisp_lib-0.5.0/src/mmisp/tests/compatibility_helpers.py +65 -0
  24. mmisp_lib-0.5.0/src/mmisp/tests/fixtures.py +787 -0
  25. mmisp_lib-0.5.0/src/mmisp/tests/generators/feed_generator.py +82 -0
  26. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/attribute_generator.py +5 -0
  27. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/auth_key_generator.py +18 -0
  28. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/event_generator.py +16 -0
  29. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/galaxy_generator.py +11 -0
  30. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/identity_provider_generator.py +16 -0
  31. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/noticelist_generator.py +26 -0
  32. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/organisation_generator.py +20 -0
  33. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/role_generator.py +106 -0
  34. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/server_generator.py +27 -0
  35. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/sharing_group_generator.py +16 -0
  36. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/tag_generator.py +15 -0
  37. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/taxonomy_generator.py +40 -0
  38. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/user_generator.py +27 -0
  39. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/user_setting_generator.py +20 -0
  40. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/warninglist_generator.py +31 -0
  41. mmisp_lib-0.5.0/src/mmisp/tests/generators/model_generators/workflow_generator.py +414 -0
  42. mmisp_lib-0.5.0/src/mmisp/tests/generators/object_generator.py +180 -0
  43. mmisp_lib-0.5.0/src/mmisp/tests/generators/sighting_generator.py +47 -0
  44. mmisp_lib-0.5.0/src/mmisp/tests/generators/tag_generator.py +103 -0
  45. mmisp_lib-0.5.0/src/mmisp/tests/generators/taxonomies_generator.py +61 -0
  46. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/execution.py +5 -3
  47. mmisp_lib-0.5.0/src/mmisp/workflows/py.typed +0 -0
  48. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp_lib.egg-info/PKG-INFO +2 -2
  49. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp_lib.egg-info/SOURCES.txt +26 -0
  50. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp_lib.egg-info/requires.txt +1 -1
  51. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/tests/test_commandline_tool.py +1 -1
  52. mmisp_lib-0.3.0/src/mmisp/api_schemas/servers.py +0 -79
  53. mmisp_lib-0.3.0/src/mmisp/db/print_changes.py +0 -58
  54. mmisp_lib-0.3.0/src/mmisp/lib/attributes.py +0 -1387
  55. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/LICENSE +0 -0
  56. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/README.md +0 -0
  57. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/setup.cfg +0 -0
  58. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/__init__.py +0 -0
  59. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/auth_keys.py +0 -0
  60. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/authentication.py +0 -0
  61. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/common.py +0 -0
  62. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/feeds.py +0 -0
  63. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/galaxies.py +0 -0
  64. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/galaxy_clusters.py +0 -0
  65. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/jobs.py +0 -0
  66. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/logs.py +0 -0
  67. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/noticelists.py +0 -0
  68. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/objects.py +0 -0
  69. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/py.typed +0 -0
  70. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/responses/__init__.py +0 -0
  71. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/responses/check_graph_response.py +0 -0
  72. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/responses/standard_status_response.py +0 -0
  73. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/roles.py +0 -0
  74. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/sharing_groups.py +0 -0
  75. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/sightings.py +0 -0
  76. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/statistics.py +0 -0
  77. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/tags.py +0 -0
  78. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/taxonomies.py +0 -0
  79. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/user_settings.py +0 -0
  80. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/users.py +0 -0
  81. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/warninglists.py +0 -0
  82. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/api_schemas/workflows.py +0 -0
  83. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/__init__.py +0 -0
  84. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/main.py +0 -0
  85. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/organisation.py +0 -0
  86. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/py.typed +0 -0
  87. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/setup.py +0 -0
  88. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/commandline_tool/user.py +0 -0
  89. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/__init__.py +0 -0
  90. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/config.py +0 -0
  91. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/database.py +0 -0
  92. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/__init__.py +0 -0
  93. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/admin_setting.py +0 -0
  94. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/auth_key.py +0 -0
  95. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/feed.py +0 -0
  96. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/identity_provider.py +0 -0
  97. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/log.py +0 -0
  98. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/noticelist.py +0 -0
  99. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/role.py +0 -0
  100. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/sharing_group.py +0 -0
  101. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/sighting.py +0 -0
  102. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/taxonomy.py +0 -0
  103. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/user_setting.py +0 -0
  104. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/warninglist.py +0 -0
  105. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/workflow.py +0 -0
  106. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/models/workflow_blueprint.py +0 -0
  107. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/mypy.py +0 -0
  108. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/db/py.typed +0 -0
  109. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/__init__.py +0 -0
  110. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/actions.py +0 -0
  111. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/logging.py +0 -0
  112. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/py.typed +0 -0
  113. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/lib/uuid.py +0 -0
  114. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/plugins/py.typed +0 -0
  115. {mmisp_lib-0.3.0/src/mmisp/util → mmisp_lib-0.5.0/src/mmisp/tests}/__init__.py +0 -0
  116. {mmisp_lib-0.3.0/src/mmisp/workflows → mmisp_lib-0.5.0/src/mmisp/util}/__init__.py +0 -0
  117. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/util/crypto.py +0 -0
  118. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/util/models.py +0 -0
  119. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/util/partial.py +0 -0
  120. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/util/py.typed +0 -0
  121. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/util/uuid.py +0 -0
  122. /mmisp_lib-0.3.0/src/mmisp/workflows/py.typed → /mmisp_lib-0.5.0/src/mmisp/workflows/__init__.py +0 -0
  123. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/fastapi.py +0 -0
  124. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/graph.py +0 -0
  125. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/input.py +0 -0
  126. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/legacy.py +0 -0
  127. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/misp_core_format.py +0 -0
  128. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp/workflows/modules.py +0 -0
  129. {mmisp_lib-0.3.0 → mmisp_lib-0.5.0}/src/mmisp_lib.egg-info/dependency_links.txt +0 -0
  130. {mmisp_lib-0.3.0 → mmisp_lib-0.5.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.0
3
+ Version: 0.5.0
4
4
  Requires-Python: >=3.11.0
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
@@ -27,7 +27,7 @@ Requires-Dist: mypy==1.8.0; extra == "dev"
27
27
  Requires-Dist: pre-commit==3.6.0; extra == "dev"
28
28
  Requires-Dist: pytest==8.0.0; extra == "dev"
29
29
  Requires-Dist: pytest-test-groups; extra == "dev"
30
- Requires-Dist: pytest-asyncio==0.23.5.post1; extra == "dev"
30
+ Requires-Dist: pytest-asyncio==0.21.2; extra == "dev"
31
31
  Requires-Dist: pytest-cov==4.1.0; extra == "dev"
32
32
  Requires-Dist: respx==0.20.2; extra == "dev"
33
33
  Requires-Dist: mysql-connector-python==8.3.0; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mmisp-lib"
3
- version = "0.3.0"
3
+ version = "0.5.0"
4
4
  description = ""
5
5
  authors = []
6
6
  readme = "README.md"
@@ -35,7 +35,7 @@ dev = [
35
35
  "pre-commit==3.6.0",
36
36
  "pytest==8.0.0",
37
37
  "pytest-test-groups",
38
- "pytest-asyncio==0.23.5.post1",
38
+ "pytest-asyncio==0.21.2",
39
39
  "pytest-cov==4.1.0",
40
40
  "respx==0.20.2",
41
41
  "mysql-connector-python==8.3.0",
@@ -63,6 +63,7 @@ ignore = ["ANN002", "ANN003", "ANN401"]
63
63
 
64
64
  [tool.ruff.lint.per-file-ignores]
65
65
  "tests/**" = ["ANN001", "ANN201", "ANN202", "S101"]
66
+ "src/mmisp/tests/**" = ["ANN001", "ANN201", "ANN202", "S101"]
66
67
 
67
68
  [tool.coverage.run]
68
69
  concurrency = ["greenlet", "thread"]
@@ -34,6 +34,7 @@ class SearchAttributesEvent(BaseModel):
34
34
  info: str
35
35
  orgc_id: str
36
36
  uuid: str
37
+ publish_timestamp: int
37
38
 
38
39
 
39
40
  class SearchAttributesAttributesDetails(BaseModel):
@@ -56,7 +57,7 @@ class SearchAttributesAttributesDetails(BaseModel):
56
57
  last_seen: str | None = None
57
58
  Event: SearchAttributesEvent | None = None
58
59
  Object: SearchAttributesObject | None = None
59
- Tag: list[GetAttributeTag] = []
60
+ Tag: list[GetAttributeTag] | None = None
60
61
 
61
62
 
62
63
  class SearchAttributesAttributes(BaseModel):
@@ -86,10 +87,7 @@ class SearchAttributesModelOverrides(BaseModel):
86
87
  base_score_config: SearchAttributesModelOverridesBaseScoreConfig
87
88
 
88
89
 
89
- class SearchAttributesBody(BaseModel):
90
- returnFormat: str = "json"
91
- page: int | None = None
92
- limit: int | None = None
90
+ class RestSearchFilter(BaseModel):
93
91
  value: str | None = None
94
92
  value1: str | None = None
95
93
  value2: str | None = None
@@ -101,15 +99,21 @@ class SearchAttributesBody(BaseModel):
101
99
  to: str | None = None
102
100
  last: int | None = None
103
101
  eventid: str | None = None
102
+ published: bool | None = None
103
+ to_ids: bool | None = None
104
+ deleted: bool | None = None
105
+
106
+
107
+ class SearchAttributesBody(RestSearchFilter):
108
+ returnFormat: str = "json"
109
+ page: int | None = None
110
+ limit: int | None = None
104
111
  with_attachments: Annotated[bool | None, Field(alias="withAttachments")] = None
105
112
  uuid: str | None = None
106
113
  publish_timestamp: str | None = None
107
- published: bool | None = None
108
114
  timestamp: str | None = None
109
115
  attribute_timestamp: str | None = None
110
116
  enforce_warninglist: Annotated[bool | None, Field(alias="enforceWarninglist")]
111
- to_ids: bool | None = None
112
- deleted: bool | None = None
113
117
  event_timestamp: str | None = None
114
118
  threat_level_id: str | None = None
115
119
  eventinfo: str | None = None
@@ -134,9 +138,6 @@ class SearchAttributesBody(BaseModel):
134
138
  include_full_model: Annotated[bool | None, Field(alias="includeFullModel")] = None
135
139
  exclude_decayed: Annotated[bool | None, Field(alias="excludeDecayed")] = None
136
140
 
137
- class Config:
138
- orm_mode = True
139
-
140
141
 
141
142
  class RestoreAttributeResponse(BaseModel):
142
143
  id: str
@@ -164,29 +165,24 @@ class RestoreAttributeResponse(BaseModel):
164
165
 
165
166
  class GetDescribeTypesAttributes(BaseModel):
166
167
  sane_defaults: dict = {}
167
- for k, v in to_ids.items():
168
+ for _k, _v in to_ids.items():
168
169
  sane_defaults.update(
169
170
  {
170
- k: {
171
- "default_category": default_category[k],
172
- "to_ids": v,
171
+ _k: {
172
+ "default_category": default_category[_k],
173
+ "to_ids": "1" if _v else "0",
173
174
  }
174
175
  }
175
176
  )
176
177
 
177
178
  types: list[str] = list(mapper_val_safe_clsname.keys())
178
-
179
179
  categories: list[str] = [member.value for member in AttributeCategories]
180
-
181
180
  category_type_mappings: dict = inverted_categories
182
181
 
183
182
 
184
183
  class GetDescribeTypesResponse(BaseModel):
185
184
  result: GetDescribeTypesAttributes
186
185
 
187
- class Config:
188
- orm_mode = True
189
-
190
186
 
191
187
  class GetAttributeAttributes(BaseModel):
192
188
  id: str
@@ -413,28 +409,12 @@ class AddAttributeBody(BaseModel):
413
409
 
414
410
  GetAttributeStatisticsTypesResponseAttrs = {x: Field(default=None) for x in mapper_val_safe_clsname.keys()}
415
411
  GetAttributeStatisticsTypesResponseAttrs["__annotations__"] = {x: str | None for x in mapper_val_safe_clsname.keys()}
416
- GetAttributeStatisticsTypesResponse = type(
412
+ GetAttributeStatisticsTypesResponse = type( # type: ignore
417
413
  "GetAttributeStatisticsTypesResponse", (BaseModel,), GetAttributeStatisticsTypesResponseAttrs
418
414
  )
419
415
 
420
-
421
- class GetAttributeStatisticsCategoriesResponse(BaseModel):
422
- antivirus_detection: str = Field(alias="Antivirus detection")
423
- artifacts_dropped: str = Field(alias="Artifacts dropped")
424
- attribution: str = Field(alias="Attribution")
425
- external_analysis: str = Field(alias="External analysis")
426
- financial_fraud: str = Field(alias="Financial fraud")
427
- internal_reference: str = Field(alias="Internal reference")
428
- network_activity: str = Field(alias="Network activity")
429
- other: str = Field(alias="Other")
430
- payload_delivery: str = Field(alias="Payload delivery")
431
- payload_installation: str = Field(alias="Payload installation")
432
- payload_type: str = Field(alias="Payload type")
433
- persistence_mechanism: str = Field(alias="Persistence mechanism")
434
- person: str = Field(alias="Person")
435
- social_network: str = Field(alias="Social network")
436
- support__tool: str = Field(alias="Support Tool")
437
- targeting_data: str = Field(alias="Targeting data")
438
-
439
- class Config:
440
- orm_mode = True
416
+ GetAttributeStatisticsCategoriesResponseAttrs = {x.value: Field(default=None) for x in AttributeCategories}
417
+ GetAttributeStatisticsCategoriesResponseAttrs["__annotations__"] = {x.value: str | None for x in AttributeCategories}
418
+ GetAttributeStatisticsCategoriesResponse = type( # type: ignore
419
+ "GetAttributeStatisticsCategoriesResponse", (BaseModel,), GetAttributeStatisticsCategoriesResponseAttrs
420
+ )
@@ -1,3 +1,5 @@
1
+ from datetime import datetime
2
+
1
3
  from pydantic import BaseModel, PositiveInt, conint
2
4
 
3
5
  from mmisp.api_schemas.organisations import Organisation
@@ -89,7 +91,7 @@ class GetAllEventsGalaxyCluster(BaseModel):
89
91
  meta: AddEditGetEventGalaxyClusterMeta | None = None
90
92
  tag_id: str
91
93
  local: bool | None = None
92
- relationship_type: str | None = None
94
+ relationship_type: bool | str | None = None
93
95
 
94
96
 
95
97
  class AddEditGetEventGalaxyClusterRelationTag(BaseModel):
@@ -149,7 +151,7 @@ class AddEditGetEventGalaxyCluster(BaseModel):
149
151
  attribute_tag_id: str | None = None
150
152
  event_tag_id: str | None = None
151
153
  local: bool | None = None
152
- relationship_type: str = ""
154
+ relationship_type: bool | str = ""
153
155
 
154
156
 
155
157
  class AddEditGetEventGalaxy(BaseModel):
@@ -186,7 +188,7 @@ class AddEditGetEventTag(BaseModel):
186
188
  is_custom_galaxy: bool
187
189
  local_only: bool
188
190
  local: bool
189
- relationship_type: str | None = None
191
+ relationship_type: bool | str | None = None
190
192
 
191
193
 
192
194
  class AddEditGetEventAttribute(BaseModel):
@@ -288,7 +290,7 @@ class AddEditGetEventResponse(BaseModel):
288
290
  Event: AddEditGetEventDetails
289
291
 
290
292
  class Config:
291
- orm_mode = True
293
+ json_encoders = {datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")}
292
294
 
293
295
 
294
296
  class GetAllEventsOrg(BaseModel):
@@ -456,7 +458,7 @@ class GetAllEventsEventTag(BaseModel):
456
458
  event_id: str
457
459
  tag_id: str
458
460
  local: bool
459
- relationship_type: str | None = None
461
+ relationship_type: bool | str | None = None
460
462
  Tag: GetAllEventsEventTagTag | None = None
461
463
 
462
464
 
@@ -3,17 +3,20 @@ from datetime import datetime
3
3
  from pydantic import BaseModel
4
4
 
5
5
 
6
- class Organisation(BaseModel):
7
- id: str
8
- name: str
6
+ class BaseOrganisation(BaseModel):
7
+ id: str | None = None
8
+ name: str | None = None
9
+ nationality: str | None = None
10
+ sector: str | None = None
11
+ type: str | None = None
12
+ uuid: str | None = None
13
+
14
+
15
+ class Organisation(BaseOrganisation):
9
16
  date_created: datetime
10
17
  date_modified: datetime
11
18
  description: str | None = None
12
- type: str
13
- nationality: str | None = None
14
- sector: str | None = None
15
19
  created_by: str
16
- uuid: str
17
20
  contacts: str | None = None
18
21
  local: bool
19
22
  """organisation gains access to the local instance, otherwise treated as external"""
@@ -21,20 +24,20 @@ class Organisation(BaseModel):
21
24
  landingpage: str | None = None
22
25
 
23
26
  class Config:
24
- orm_mode = True
27
+ json_encoders = {datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")}
25
28
 
26
29
 
27
30
  class GetOrganisationResponse(BaseModel):
28
31
  id: str
29
32
  name: str
33
+ nationality: str | None = None
34
+ sector: str | None = None
35
+ type: str | None = None
36
+ uuid: str | None = None
30
37
  date_created: datetime
31
38
  date_modified: datetime
32
39
  description: str | None = None
33
- type: str | None = None
34
- nationality: str | None = None
35
- sector: str | None = None
36
40
  created_by: str
37
- uuid: str | None = None
38
41
  contacts: str | None = None
39
42
  local: bool
40
43
  restricted_to_domain: str | None = None
@@ -0,0 +1,138 @@
1
+ from pydantic import BaseModel, Json
2
+
3
+ from mmisp.api_schemas.organisations import BaseOrganisation
4
+
5
+
6
+ class NOT_Filter(BaseModel):
7
+ NOT: list
8
+
9
+
10
+ class OR_NOT_Filter(BaseModel):
11
+ OR: list
12
+ NOT: list
13
+
14
+
15
+ class PullRulesFilter(BaseModel):
16
+ tags: OR_NOT_Filter
17
+ orgs: OR_NOT_Filter
18
+ type_attributes: NOT_Filter
19
+ type_objects: NOT_Filter
20
+ url_params: str
21
+
22
+
23
+ class PushRulesFilter(BaseModel):
24
+ tags: OR_NOT_Filter
25
+ orgs: OR_NOT_Filter
26
+
27
+
28
+ default_pull_rules = PullRulesFilter(
29
+ tags=OR_NOT_Filter(OR=[], NOT=[]),
30
+ orgs=OR_NOT_Filter(OR=[], NOT=[]),
31
+ type_attributes=NOT_Filter(NOT=[]),
32
+ type_objects=NOT_Filter(NOT=[]),
33
+ url_params="",
34
+ )
35
+ default_push_rules = PushRulesFilter(
36
+ tags=OR_NOT_Filter(OR=[], NOT=[]),
37
+ orgs=OR_NOT_Filter(OR=[], NOT=[]),
38
+ )
39
+
40
+
41
+ class AddServer(BaseModel):
42
+ url: str
43
+ name: str
44
+ remote_org_id: int
45
+ authkey: str
46
+ org_id: int | None = None
47
+ priority: int = 5
48
+ internal: bool = False
49
+ push: bool = False
50
+ pull: bool = False
51
+ pull_rules: Json[PullRulesFilter] | PullRulesFilter = default_pull_rules
52
+ push_rules: Json[PushRulesFilter] | PushRulesFilter = default_push_rules
53
+ push_galaxy_clusters: bool = False
54
+ caching_enabled: bool = False
55
+ unpublish_event: bool = False
56
+ publish_without_email: bool = False
57
+ self_signed: bool = False
58
+ skip_proxy: bool = False
59
+
60
+
61
+ class EditServer(BaseModel):
62
+ name: str
63
+ url: str
64
+ priority: int
65
+ authkey: str
66
+ remote_org_id: int
67
+ internal: bool
68
+ push: bool
69
+ pull: bool
70
+ pull_rules: Json[PullRulesFilter] | PullRulesFilter = default_pull_rules
71
+ push_rules: Json[PushRulesFilter] | PushRulesFilter = default_push_rules
72
+ push_galaxy_clusters: bool
73
+ caching_enabled: bool
74
+ unpublish_event: bool
75
+ publish_without_email: bool
76
+ self_signed: bool
77
+ skip_proxy: bool
78
+
79
+
80
+ class ServerResponseBase(BaseModel):
81
+ id: int
82
+ name: str
83
+ url: str
84
+ # authkey: str
85
+ org_id: int | None = None
86
+ push: bool
87
+ pull: bool
88
+ cert_file: str | None
89
+ client_cert_file: str | None
90
+ lastpulledid: int | None
91
+ lastpushedid: int | None
92
+ organization: None
93
+ pull_analyst_data: bool
94
+ pull_rules: str
95
+ push_analyst_data: bool
96
+ push_rules: str
97
+ remove_missing_tags: bool
98
+ push_sightings: bool | None = None
99
+ push_galaxy_clusters: bool | None = None
100
+ pull_galaxy_clusters: bool | None = None
101
+ remote_org_id: int
102
+ publish_without_email: bool | None = None
103
+ unpublish_event: bool | None = None
104
+ self_signed: bool
105
+ internal: bool | None = None
106
+ skip_proxy: bool | None = None
107
+ caching_enabled: bool | None = None
108
+ priority: int | None = None
109
+
110
+
111
+ class ServerResponse(ServerResponseBase):
112
+ cache_timestamp: bool = False
113
+
114
+
115
+ class AddServerServer(ServerResponseBase):
116
+ authkey: str
117
+
118
+
119
+ class AddServerResponse(BaseModel):
120
+ Server: AddServerServer
121
+
122
+
123
+ class RemoveServer(BaseModel):
124
+ id: str
125
+ sharing_group_id: str
126
+ server_id: str
127
+ all_orgs: bool
128
+
129
+
130
+ class GetRemoteServer(BaseModel):
131
+ Server: ServerResponse
132
+ Organisation: BaseOrganisation
133
+ RemoteOrg: BaseOrganisation
134
+ User: list
135
+
136
+
137
+ class ServersGetVersion(BaseModel):
138
+ pass
@@ -0,0 +1,10 @@
1
+ from sqlalchemy import func, select
2
+ from sqlalchemy.orm import column_property
3
+
4
+ from mmisp.db.models.organisation import Organisation
5
+ from mmisp.db.models.user import User
6
+
7
+ Organisation.user_count = column_property(
8
+ select(func.count(User.id)).where(User.org_id == Organisation.id).correlate_except(User).scalar_subquery(),
9
+ deferred=False,
10
+ )
@@ -13,3 +13,5 @@ model_module_names = map(".".join, zip(itertools.repeat(model_pkg), all_models))
13
13
 
14
14
  for m in model_module_names:
15
15
  importlib.import_module(m)
16
+
17
+ importlib.import_module("mmisp.db.additional_properties")
@@ -6,9 +6,10 @@ from sqlalchemy.ext.hybrid import hybrid_property
6
6
 
7
7
  class DictMixin:
8
8
  def asdict(self: Self) -> dict:
9
+ unloaded = inspect(self).unloaded
9
10
  d = {}
10
11
  for key in self.__mapper__.c.keys(): # type:ignore[attr-defined]
11
- if not key.startswith("_"):
12
+ if not key.startswith("_") and key not in unloaded:
12
13
  d[key] = getattr(self, key)
13
14
 
14
15
  for key, prop in inspect(self.__class__).all_orm_descriptors.items(): # type:ignore[union-attr]
@@ -1,7 +1,9 @@
1
+ import typing
1
2
  from typing import Self, Type
2
3
 
3
- from sqlalchemy import BigInteger, Boolean, ForeignKey, Integer, String, Text
4
- from sqlalchemy.ext.hybrid import hybrid_property
4
+ from sqlalchemy import BigInteger, Boolean, ForeignKey, Integer, String, Text, or_
5
+ from sqlalchemy.ext.asyncio import AsyncSession
6
+ from sqlalchemy.ext.hybrid import Comparator, hybrid_property
5
7
  from sqlalchemy.orm import relationship
6
8
  from sqlalchemy.orm.decl_api import DeclarativeMeta
7
9
 
@@ -14,6 +16,20 @@ from ..database import Base
14
16
  from .event import Event
15
17
  from .tag import Tag
16
18
 
19
+ if typing.TYPE_CHECKING:
20
+ from sqlalchemy import ColumnExpressionArgument
21
+ else:
22
+ ColumnExpressionArgument = typing.Any
23
+
24
+
25
+ class AttributeComparator(Comparator):
26
+ def __init__(self: Self, cls: typing.Any) -> None:
27
+ self.cls = cls
28
+
29
+ def __eq__(self: Self, other: typing.Any) -> ColumnExpressionArgument:
30
+ # Overriding equality to check if the value matches either value1 or value1 + "|" + value2
31
+ return or_(self.cls.value1 == other, self.cls.value1 + "|" + self.cls.value2 == other)
32
+
17
33
 
18
34
  class Attribute(Base, DictMixin):
19
35
  __tablename__ = "attributes"
@@ -40,11 +56,57 @@ class Attribute(Base, DictMixin):
40
56
  last_seen: Mapped[int] = mapped_column(BigInteger, index=True)
41
57
 
42
58
  event = relationship("Event", back_populates="attributes", lazy="joined") # type:ignore[var-annotated]
59
+ mispobject = relationship(
60
+ "Object",
61
+ primaryjoin="Attribute.object_id == Object.id",
62
+ back_populates="attributes",
63
+ lazy="joined",
64
+ foreign_keys="Attribute.object_id",
65
+ ) # type:ignore[var-annotated]
66
+ tags = relationship("Tag", secondary="attribute_tags", lazy="raise_on_sql", viewonly=True)
67
+ attributetags = relationship(
68
+ "AttributeTag",
69
+ primaryjoin="Attribute.id == AttributeTag.attribute_id",
70
+ back_populates="attribute",
71
+ lazy="raise_on_sql",
72
+ viewonly=True,
73
+ )
74
+ attributetags_galaxy = relationship(
75
+ "AttributeTag",
76
+ primaryjoin="and_(Attribute.id == AttributeTag.attribute_id, Tag.is_galaxy)",
77
+ secondary="join(AttributeTag, Tag, AttributeTag.tag_id == Tag.id)",
78
+ secondaryjoin="AttributeTag.tag_id == Tag.id",
79
+ lazy="raise_on_sql",
80
+ viewonly=True,
81
+ )
82
+
83
+ galaxy_tags = relationship(
84
+ "Tag",
85
+ secondary="attribute_tags",
86
+ secondaryjoin="and_(AttributeTag.tag_id == Tag.id, Tag.is_galaxy)",
87
+ lazy="raise_on_sql",
88
+ overlaps="tags, events",
89
+ viewonly=True,
90
+ )
91
+ local_tags = relationship(
92
+ "Tag",
93
+ secondary="attribute_tags",
94
+ secondaryjoin="and_(AttributeTag.tag_id == Tag.id, AttributeTag.local)",
95
+ lazy="raise_on_sql",
96
+ viewonly=True,
97
+ )
98
+ nonlocal_tags = relationship(
99
+ "Tag",
100
+ secondary="attribute_tags",
101
+ secondaryjoin="and_(AttributeTag.tag_id == Tag.id, not_(AttributeTag.local))",
102
+ lazy="raise_on_sql",
103
+ viewonly=True,
104
+ )
43
105
 
44
106
  __mapper_args__ = {"polymorphic_on": "type"}
45
107
 
46
108
  def __init__(self: Self, *arg, **kwargs) -> None:
47
- if kwargs["value1"] is None:
109
+ if "value" in kwargs:
48
110
  split_val = kwargs["value"].split("|", 1)
49
111
  kwargs["value1"] = split_val[0]
50
112
  if len(split_val) == 2:
@@ -52,6 +114,14 @@ class Attribute(Base, DictMixin):
52
114
 
53
115
  super().__init__(*arg, **kwargs)
54
116
 
117
+ async def add_tag(self: Self, db: AsyncSession, tag: "Tag", local: bool = False) -> "AttributeTag":
118
+ if tag.local_only:
119
+ local = True
120
+ attribute_tag = AttributeTag(attribute=self, tag=tag, event_id=self.event_id, local=local)
121
+ db.add(attribute_tag)
122
+ await db.commit()
123
+ return attribute_tag
124
+
55
125
  @property
56
126
  def event_uuid(self: "Attribute") -> str:
57
127
  return self.event.uuid
@@ -69,6 +139,10 @@ class Attribute(Base, DictMixin):
69
139
  if len(split) == 2:
70
140
  self.value2 = split[1]
71
141
 
142
+ @value.comparator
143
+ def value(cls: Self) -> AttributeComparator:
144
+ return AttributeComparator(cls)
145
+
72
146
 
73
147
  class AttributeTag(Base):
74
148
  __tablename__ = "attribute_tags"
@@ -80,6 +154,10 @@ class AttributeTag(Base):
80
154
  event_id: Mapped[int] = mapped_column(Integer, ForeignKey(Event.id, ondelete="CASCADE"), nullable=False, index=True)
81
155
  tag_id: Mapped[int] = mapped_column(Integer, ForeignKey(Tag.id, ondelete="CASCADE"), nullable=False, index=True)
82
156
  local: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
157
+ relationship_type: Mapped[str] = mapped_column(String(191), nullable=True)
158
+
159
+ attribute = relationship("Attribute", back_populates="attributetags", lazy="raise_on_sql")
160
+ tag = relationship("Tag", back_populates="attributetags", lazy="raise_on_sql")
83
161
 
84
162
 
85
163
  class AttributeMeta(DeclarativeMeta):
@@ -38,6 +38,37 @@ class Event(Base):
38
38
  protected: Mapped[bool] = mapped_column(Boolean)
39
39
 
40
40
  attributes = relationship("Attribute", back_populates="event") # type:ignore[assignment,var-annotated]
41
+ mispobjects = relationship("Object", back_populates="event") # type:ignore[assignment,var-annotated]
42
+ org = relationship(
43
+ "Organisation", primaryjoin="Event.org_id == Organisation.id", back_populates="events", lazy="raise_on_sql"
44
+ ) # type:ignore[assignment,var-annotated]
45
+ orgc = relationship(
46
+ "Organisation",
47
+ primaryjoin="Event.orgc_id == Organisation.id",
48
+ back_populates="events_created",
49
+ lazy="raise_on_sql",
50
+ ) # type:ignore[assignment,var-annotated]
51
+ creator = relationship("User", primaryjoin="Event.user_id == User.id", lazy="selectin")
52
+ tags = relationship("Tag", secondary="event_tags", lazy="raise_on_sql", viewonly=True)
53
+ eventtags = relationship(
54
+ "EventTag", primaryjoin="Event.id == EventTag.event_id", lazy="raise_on_sql", viewonly=True
55
+ )
56
+ eventtags_galaxy = relationship(
57
+ "EventTag",
58
+ primaryjoin="and_(Event.id == EventTag.event_id, Tag.is_galaxy)",
59
+ secondary="join(EventTag, Tag, EventTag.tag_id == Tag.id)",
60
+ secondaryjoin="EventTag.tag_id == Tag.id",
61
+ lazy="raise_on_sql",
62
+ viewonly=True,
63
+ )
64
+ galaxy_tags = relationship(
65
+ "Tag",
66
+ secondary="event_tags",
67
+ secondaryjoin="and_(EventTag.tag_id == Tag.id, Tag.is_galaxy)",
68
+ lazy="raise_on_sql",
69
+ overlaps="tags, events",
70
+ viewonly=True,
71
+ )
41
72
 
42
73
 
43
74
  class EventReport(Base):
@@ -61,3 +92,7 @@ class EventTag(Base):
61
92
  event_id: Mapped[int] = mapped_column(Integer, ForeignKey(Event.id, ondelete="CASCADE"), nullable=False, index=True)
62
93
  tag_id: Mapped[int] = mapped_column(Integer, ForeignKey(Tag.id, ondelete="CASCADE"), nullable=False, index=True)
63
94
  local: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
95
+ relationship_type: Mapped[str] = mapped_column(String(191), nullable=True)
96
+
97
+ event = relationship("Event", back_populates="eventtags", lazy="raise_on_sql", viewonly=True)
98
+ tag = relationship("Tag", back_populates="eventtags", lazy="raise_on_sql", viewonly=True)
@@ -1,4 +1,5 @@
1
1
  from sqlalchemy import Boolean, Integer, String, Text
2
+ from sqlalchemy.orm import relationship
2
3
 
3
4
  from mmisp.db.mypy import Mapped, mapped_column
4
5
  from mmisp.lib.uuid import uuid
@@ -21,3 +22,9 @@ class Galaxy(Base):
21
22
  """must be serialized"""
22
23
  enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
23
24
  local_only: Mapped[bool] = mapped_column(Boolean, default=False)
25
+
26
+ galaxy_clusters = relationship(
27
+ "GalaxyCluster",
28
+ back_populates="galaxy",
29
+ lazy="raise_on_sql",
30
+ ) # type:ignore[assignment,var-annotated]
@@ -1,4 +1,5 @@
1
1
  from sqlalchemy import Boolean, ForeignKey, Integer, String, Text
2
+ from sqlalchemy.orm import relationship
2
3
 
3
4
  from mmisp.db.mypy import Mapped, mapped_column
4
5
  from mmisp.lib.uuid import uuid
@@ -34,6 +35,31 @@ class GalaxyCluster(Base):
34
35
  published: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
35
36
  deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
36
37
 
38
+ org = relationship(
39
+ "Organisation",
40
+ primaryjoin="GalaxyCluster.org_id == Organisation.id",
41
+ back_populates="galaxy_clusters",
42
+ lazy="raise_on_sql",
43
+ foreign_keys="GalaxyCluster.org_id",
44
+ ) # type:ignore[assignment,var-annotated]
45
+ orgc = relationship(
46
+ "Organisation",
47
+ primaryjoin="GalaxyCluster.orgc_id == Organisation.id",
48
+ back_populates="galaxy_clusters_created",
49
+ lazy="raise_on_sql",
50
+ foreign_keys="GalaxyCluster.orgc_id",
51
+ ) # type:ignore[assignment,var-annotated]
52
+ galaxy = relationship(
53
+ "Galaxy",
54
+ back_populates="galaxy_clusters",
55
+ lazy="raise_on_sql",
56
+ ) # type:ignore[assignment,var-annotated]
57
+ galaxy_elements = relationship(
58
+ "GalaxyElement",
59
+ back_populates="galaxy_cluster",
60
+ lazy="raise_on_sql",
61
+ ) # type:ignore[assignment,var-annotated]
62
+
37
63
 
38
64
  class GalaxyElement(Base):
39
65
  __tablename__ = "galaxy_elements"
@@ -45,6 +71,12 @@ class GalaxyElement(Base):
45
71
  key: Mapped[str] = mapped_column(String(255), nullable=False, default="", index=True)
46
72
  value: Mapped[str] = mapped_column(Text, nullable=False)
47
73
 
74
+ galaxy_cluster = relationship(
75
+ "GalaxyCluster",
76
+ back_populates="galaxy_elements",
77
+ lazy="raise_on_sql",
78
+ ) # type:ignore[assignment,var-annotated]
79
+
48
80
 
49
81
  class GalaxyReference(Base):
50
82
  __tablename__ = "galaxy_reference"