howler-api 3.0.0.dev374__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.
Files changed (198) hide show
  1. howler/__init__.py +0 -0
  2. howler/actions/__init__.py +168 -0
  3. howler/actions/add_label.py +111 -0
  4. howler/actions/add_to_bundle.py +159 -0
  5. howler/actions/change_field.py +76 -0
  6. howler/actions/demote.py +160 -0
  7. howler/actions/example_plugin.py +104 -0
  8. howler/actions/prioritization.py +93 -0
  9. howler/actions/promote.py +147 -0
  10. howler/actions/remove_from_bundle.py +133 -0
  11. howler/actions/remove_label.py +111 -0
  12. howler/actions/transition.py +200 -0
  13. howler/api/__init__.py +249 -0
  14. howler/api/base.py +88 -0
  15. howler/api/socket.py +114 -0
  16. howler/api/v1/__init__.py +97 -0
  17. howler/api/v1/action.py +372 -0
  18. howler/api/v1/analytic.py +748 -0
  19. howler/api/v1/auth.py +382 -0
  20. howler/api/v1/clue.py +99 -0
  21. howler/api/v1/configs.py +58 -0
  22. howler/api/v1/dossier.py +222 -0
  23. howler/api/v1/help.py +28 -0
  24. howler/api/v1/hit.py +1181 -0
  25. howler/api/v1/notebook.py +82 -0
  26. howler/api/v1/overview.py +191 -0
  27. howler/api/v1/search.py +788 -0
  28. howler/api/v1/template.py +206 -0
  29. howler/api/v1/tool.py +183 -0
  30. howler/api/v1/user.py +416 -0
  31. howler/api/v1/utils/__init__.py +0 -0
  32. howler/api/v1/utils/etag.py +84 -0
  33. howler/api/v1/view.py +288 -0
  34. howler/app.py +235 -0
  35. howler/common/README.md +125 -0
  36. howler/common/__init__.py +0 -0
  37. howler/common/classification.py +979 -0
  38. howler/common/classification.yml +107 -0
  39. howler/common/exceptions.py +167 -0
  40. howler/common/loader.py +154 -0
  41. howler/common/logging/__init__.py +241 -0
  42. howler/common/logging/audit.py +138 -0
  43. howler/common/logging/format.py +38 -0
  44. howler/common/net.py +79 -0
  45. howler/common/net_static.py +1494 -0
  46. howler/common/random_user.py +316 -0
  47. howler/common/swagger.py +117 -0
  48. howler/config.py +64 -0
  49. howler/cronjobs/__init__.py +29 -0
  50. howler/cronjobs/retention.py +61 -0
  51. howler/cronjobs/rules.py +274 -0
  52. howler/cronjobs/view_cleanup.py +88 -0
  53. howler/datastore/README.md +112 -0
  54. howler/datastore/__init__.py +0 -0
  55. howler/datastore/bulk.py +72 -0
  56. howler/datastore/collection.py +2342 -0
  57. howler/datastore/constants.py +119 -0
  58. howler/datastore/exceptions.py +41 -0
  59. howler/datastore/howler_store.py +105 -0
  60. howler/datastore/migrations/fix_process.py +41 -0
  61. howler/datastore/operations.py +130 -0
  62. howler/datastore/schemas.py +90 -0
  63. howler/datastore/store.py +231 -0
  64. howler/datastore/support/__init__.py +0 -0
  65. howler/datastore/support/build.py +215 -0
  66. howler/datastore/support/schemas.py +90 -0
  67. howler/datastore/types.py +22 -0
  68. howler/error.py +91 -0
  69. howler/external/__init__.py +0 -0
  70. howler/external/generate_mitre.py +96 -0
  71. howler/external/generate_sigma_rules.py +31 -0
  72. howler/external/generate_tlds.py +47 -0
  73. howler/external/reindex_data.py +66 -0
  74. howler/external/wipe_databases.py +58 -0
  75. howler/gunicorn_config.py +25 -0
  76. howler/healthz.py +47 -0
  77. howler/helper/__init__.py +0 -0
  78. howler/helper/azure.py +50 -0
  79. howler/helper/discover.py +59 -0
  80. howler/helper/hit.py +236 -0
  81. howler/helper/oauth.py +247 -0
  82. howler/helper/search.py +92 -0
  83. howler/helper/workflow.py +110 -0
  84. howler/helper/ws.py +378 -0
  85. howler/odm/README.md +102 -0
  86. howler/odm/__init__.py +1 -0
  87. howler/odm/base.py +1543 -0
  88. howler/odm/charter.txt +146 -0
  89. howler/odm/helper.py +416 -0
  90. howler/odm/howler_enum.py +25 -0
  91. howler/odm/models/__init__.py +0 -0
  92. howler/odm/models/action.py +33 -0
  93. howler/odm/models/analytic.py +90 -0
  94. howler/odm/models/assemblyline.py +48 -0
  95. howler/odm/models/aws.py +23 -0
  96. howler/odm/models/azure.py +16 -0
  97. howler/odm/models/cbs.py +44 -0
  98. howler/odm/models/config.py +558 -0
  99. howler/odm/models/dossier.py +33 -0
  100. howler/odm/models/ecs/__init__.py +0 -0
  101. howler/odm/models/ecs/agent.py +17 -0
  102. howler/odm/models/ecs/autonomous_system.py +16 -0
  103. howler/odm/models/ecs/client.py +149 -0
  104. howler/odm/models/ecs/cloud.py +141 -0
  105. howler/odm/models/ecs/code_signature.py +27 -0
  106. howler/odm/models/ecs/container.py +32 -0
  107. howler/odm/models/ecs/dns.py +62 -0
  108. howler/odm/models/ecs/egress.py +10 -0
  109. howler/odm/models/ecs/elf.py +74 -0
  110. howler/odm/models/ecs/email.py +122 -0
  111. howler/odm/models/ecs/error.py +14 -0
  112. howler/odm/models/ecs/event.py +140 -0
  113. howler/odm/models/ecs/faas.py +24 -0
  114. howler/odm/models/ecs/file.py +84 -0
  115. howler/odm/models/ecs/geo.py +30 -0
  116. howler/odm/models/ecs/group.py +18 -0
  117. howler/odm/models/ecs/hash.py +16 -0
  118. howler/odm/models/ecs/host.py +17 -0
  119. howler/odm/models/ecs/http.py +37 -0
  120. howler/odm/models/ecs/ingress.py +12 -0
  121. howler/odm/models/ecs/interface.py +21 -0
  122. howler/odm/models/ecs/network.py +30 -0
  123. howler/odm/models/ecs/observer.py +45 -0
  124. howler/odm/models/ecs/organization.py +12 -0
  125. howler/odm/models/ecs/os.py +21 -0
  126. howler/odm/models/ecs/pe.py +17 -0
  127. howler/odm/models/ecs/process.py +216 -0
  128. howler/odm/models/ecs/registry.py +26 -0
  129. howler/odm/models/ecs/related.py +45 -0
  130. howler/odm/models/ecs/rule.py +51 -0
  131. howler/odm/models/ecs/server.py +24 -0
  132. howler/odm/models/ecs/threat.py +247 -0
  133. howler/odm/models/ecs/tls.py +58 -0
  134. howler/odm/models/ecs/url.py +51 -0
  135. howler/odm/models/ecs/user.py +57 -0
  136. howler/odm/models/ecs/user_agent.py +20 -0
  137. howler/odm/models/ecs/vulnerability.py +41 -0
  138. howler/odm/models/gcp.py +16 -0
  139. howler/odm/models/hit.py +356 -0
  140. howler/odm/models/howler_data.py +328 -0
  141. howler/odm/models/lead.py +24 -0
  142. howler/odm/models/localized_label.py +13 -0
  143. howler/odm/models/overview.py +16 -0
  144. howler/odm/models/pivot.py +40 -0
  145. howler/odm/models/template.py +24 -0
  146. howler/odm/models/user.py +83 -0
  147. howler/odm/models/view.py +34 -0
  148. howler/odm/random_data.py +888 -0
  149. howler/odm/randomizer.py +609 -0
  150. howler/patched.py +5 -0
  151. howler/plugins/__init__.py +25 -0
  152. howler/plugins/config.py +123 -0
  153. howler/remote/__init__.py +0 -0
  154. howler/remote/datatypes/README.md +355 -0
  155. howler/remote/datatypes/__init__.py +98 -0
  156. howler/remote/datatypes/counters.py +63 -0
  157. howler/remote/datatypes/events.py +66 -0
  158. howler/remote/datatypes/hash.py +206 -0
  159. howler/remote/datatypes/lock.py +42 -0
  160. howler/remote/datatypes/queues/__init__.py +0 -0
  161. howler/remote/datatypes/queues/comms.py +59 -0
  162. howler/remote/datatypes/queues/multi.py +32 -0
  163. howler/remote/datatypes/queues/named.py +93 -0
  164. howler/remote/datatypes/queues/priority.py +215 -0
  165. howler/remote/datatypes/set.py +118 -0
  166. howler/remote/datatypes/user_quota_tracker.py +54 -0
  167. howler/security/__init__.py +253 -0
  168. howler/security/socket.py +108 -0
  169. howler/security/utils.py +185 -0
  170. howler/services/__init__.py +0 -0
  171. howler/services/action_service.py +111 -0
  172. howler/services/analytic_service.py +128 -0
  173. howler/services/auth_service.py +323 -0
  174. howler/services/config_service.py +128 -0
  175. howler/services/dossier_service.py +252 -0
  176. howler/services/event_service.py +93 -0
  177. howler/services/hit_service.py +893 -0
  178. howler/services/jwt_service.py +158 -0
  179. howler/services/lucene_service.py +286 -0
  180. howler/services/notebook_service.py +119 -0
  181. howler/services/overview_service.py +44 -0
  182. howler/services/template_service.py +45 -0
  183. howler/services/user_service.py +331 -0
  184. howler/utils/__init__.py +0 -0
  185. howler/utils/annotations.py +28 -0
  186. howler/utils/chunk.py +38 -0
  187. howler/utils/dict_utils.py +200 -0
  188. howler/utils/isotime.py +17 -0
  189. howler/utils/list_utils.py +11 -0
  190. howler/utils/lucene.py +77 -0
  191. howler/utils/path.py +27 -0
  192. howler/utils/socket_utils.py +61 -0
  193. howler/utils/str_utils.py +256 -0
  194. howler/utils/uid.py +47 -0
  195. howler_api-3.0.0.dev374.dist-info/METADATA +71 -0
  196. howler_api-3.0.0.dev374.dist-info/RECORD +198 -0
  197. howler_api-3.0.0.dev374.dist-info/WHEEL +4 -0
  198. howler_api-3.0.0.dev374.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,222 @@
1
+ from flask import request
2
+
3
+ from howler.api import bad_request, created, forbidden, internal_error, make_subapi_blueprint, no_content, not_found, ok
4
+ from howler.common.exceptions import ForbiddenException, HowlerException, InvalidDataException, NotFoundException
5
+ from howler.common.loader import datastore
6
+ from howler.common.logging import get_logger
7
+ from howler.common.swagger import generate_swagger_docs
8
+ from howler.odm.models.dossier import Dossier
9
+ from howler.odm.models.user import User
10
+ from howler.security import api_login
11
+ from howler.services import dossier_service
12
+
13
+ SUB_API = "dossier"
14
+ dossier_api = make_subapi_blueprint(SUB_API, api_version=1)
15
+ dossier_api._doc = "Manage the different dossiers created for filtering hits"
16
+
17
+ logger = get_logger(__file__)
18
+
19
+
20
+ @generate_swagger_docs()
21
+ @dossier_api.route("/", methods=["GET"])
22
+ @api_login(required_priv=["R"])
23
+ def get_dossiers(user: User, **kwargs):
24
+ """Get a list of dossiers the user can see
25
+
26
+ Variables:
27
+ None
28
+
29
+ Optional Arguments:
30
+ None
31
+
32
+ Result Example:
33
+ [
34
+ ...dossiers # A list of dossiers the user can use
35
+ ]
36
+ """
37
+ try:
38
+ return ok(
39
+ datastore().dossier.search(
40
+ f"type:global OR owner:({user['uname']} OR none)",
41
+ as_obj=False,
42
+ rows=1000,
43
+ )["items"]
44
+ )
45
+ except ValueError as e:
46
+ return bad_request(err=str(e))
47
+
48
+
49
+ @generate_swagger_docs()
50
+ @dossier_api.route("/", methods=["POST"])
51
+ @api_login(required_priv=["R", "W"])
52
+ def create_dossier(**kwargs):
53
+ """Create a new dossier
54
+
55
+ Variables:
56
+ None
57
+
58
+ Optional Arguments:
59
+ None
60
+
61
+ Data Block:
62
+ {
63
+ "title": "New dossier" # The name of this dossier
64
+ "query": "howler.id:*" # The query to run
65
+ "type": "global" # The type of dossier - personal or global
66
+ }
67
+
68
+ Result Example:
69
+ {
70
+ ...dossier # The new dossier data
71
+ }
72
+ """
73
+ dossier_data = request.json
74
+
75
+ try:
76
+ return created(dossier_service.create_dossier(dossier_data, username=kwargs["user"]["uname"]))
77
+ except InvalidDataException as e:
78
+ return bad_request(err=str(e))
79
+ except HowlerException:
80
+ logger.exception("Exception on create dossier")
81
+ return internal_error(err="An unknown error occured when creating the dossier.")
82
+
83
+
84
+ @generate_swagger_docs()
85
+ @dossier_api.route("/<id>", methods=["GET"])
86
+ @api_login(required_priv=["R"])
87
+ def get_dossier(id: str, user: User, **kwargs):
88
+ """Get a specific dossier
89
+
90
+ Variables:
91
+ id => The id of the dossier to get
92
+
93
+ Optional Arguments:
94
+ None
95
+
96
+ Result Example:
97
+ [
98
+ ...dossiers # A list of dossiers the user can use
99
+ ]
100
+ """
101
+ try:
102
+ results = datastore().dossier.search(
103
+ f"dossier_id:{id}",
104
+ as_obj=False,
105
+ rows=1,
106
+ )["items"]
107
+
108
+ if len(results) < 1:
109
+ return not_found(err="Dossier not found")
110
+
111
+ return ok(results[0])
112
+ except ValueError as e:
113
+ return bad_request(err=str(e))
114
+
115
+
116
+ @generate_swagger_docs()
117
+ @dossier_api.route("/hit/<id>", methods=["GET"])
118
+ @api_login(required_priv=["R"])
119
+ def get_dossier_for_hit(id: str, user: User, **kwargs):
120
+ """Get dossiers matching a given hit
121
+
122
+ Variables:
123
+ id => The id of the dossier to get
124
+
125
+ Optional Arguments:
126
+ None
127
+
128
+ Result Example:
129
+ [
130
+ ...dossiers # A list of dossiers the user can use
131
+ ]
132
+ """
133
+ storage = datastore()
134
+ try:
135
+ response = storage.hit.search(f"howler.id:{id}", rows=1, as_obj=False)
136
+
137
+ if response["total"] < 1:
138
+ return not_found(err="Hit does not exist.")
139
+
140
+ hit = response["items"][0]
141
+
142
+ return ok(dossier_service.get_matching_dossiers(hit))
143
+ except ValueError as e:
144
+ return bad_request(err=str(e))
145
+
146
+
147
+ @generate_swagger_docs()
148
+ @dossier_api.route("/<id>", methods=["DELETE"])
149
+ @api_login(required_priv=["W"])
150
+ def delete_dossier(id: str, user: User, **kwargs):
151
+ """Delete a dossier
152
+
153
+ Variables:
154
+ id => The id of the dossier to delete
155
+
156
+ Optional Arguments:
157
+ None
158
+
159
+ Data Block:
160
+ None
161
+
162
+ Result Example:
163
+ {
164
+ "success": true # Did the deletion succeed?
165
+ }
166
+ """
167
+ storage = datastore()
168
+
169
+ existing_dossier: Dossier = storage.dossier.get_if_exists(id)
170
+ if not existing_dossier:
171
+ return not_found(err="This dossier does not exist")
172
+
173
+ if existing_dossier.owner != user.uname and "admin" not in user.type:
174
+ return forbidden(err="You cannot delete a dossier unless you are an administrator, or the owner.")
175
+
176
+ success = storage.dossier.delete(id)
177
+
178
+ storage.dossier.commit()
179
+
180
+ return no_content({"success": success})
181
+
182
+
183
+ @generate_swagger_docs()
184
+ @dossier_api.route("/<id>", methods=["PUT"])
185
+ @api_login(required_priv=["R", "W"])
186
+ def update_dossier(id: str, user: User, **kwargs):
187
+ """Update a dossier
188
+
189
+ Variables:
190
+ id => The id of the dossier to modify
191
+
192
+ Optional Arguments:
193
+ None
194
+
195
+ Data Block:
196
+ {
197
+ "title": "New dossier Name" # The name of this dossier
198
+ "query": "howler.id:*" # The query to run
199
+ }
200
+
201
+ Result Example:
202
+ {
203
+ ...dossier # The updated dossier data
204
+ }
205
+ """
206
+ new_data = request.json
207
+ if not isinstance(new_data, dict):
208
+ return bad_request(err="Invalid data format")
209
+
210
+ try:
211
+ updated_dossier = dossier_service.update_dossier(id, new_data, user)
212
+
213
+ return ok(updated_dossier)
214
+ except ForbiddenException as e:
215
+ return forbidden(err=e.message)
216
+ except InvalidDataException as e:
217
+ return bad_request(err=e.message)
218
+ except NotFoundException as e:
219
+ return not_found(err=e.message)
220
+ except HowlerException as e:
221
+ logger.exception("Unknown error on dossier update:")
222
+ return internal_error(err=e.message)
howler/api/v1/help.py ADDED
@@ -0,0 +1,28 @@
1
+ from howler.api import make_subapi_blueprint, ok
2
+ from howler.common.swagger import generate_swagger_docs
3
+ from howler.config import CLASSIFICATION
4
+ from howler.security import api_login
5
+
6
+ SUB_API = "help"
7
+ classification_definition = CLASSIFICATION.get_parsed_classification_definition()
8
+
9
+ help_api = make_subapi_blueprint(SUB_API, api_version=1)
10
+ help_api._doc = "Provide information about the system configuration"
11
+
12
+
13
+ @generate_swagger_docs()
14
+ @help_api.route("/classification_definition")
15
+ @api_login(audit=False, check_xsrf_token=False)
16
+ def get_classification_definition(**_):
17
+ """Return the current system classification definition
18
+
19
+ Variables:
20
+ None
21
+
22
+ Arguments:
23
+ None
24
+
25
+ Result Example:
26
+ A parsed classification definition. (This is more for internal use)
27
+ """
28
+ return ok(classification_definition)