@cryptotaxi247 / CoPilot / commits / e930dd6b

POST instead of get and removed range on query (#60)

taylor_socfortress committed Jul 24, 2023 at 17:00 UTC e930dd6b3960a7d61c99f3b7a6241dbbdabc840a
3 files changed +177 -144
backend/app/routes/alerts.py
+41 -14
@@ -7,7 +7,7 @@ from app.services.WazuhIndexer.alerts import AlertsService
7 bp = Blueprint("alerts", __name__)
8
9
10 -@bp.route("/alerts", methods=["GET"])
10 +@bp.route("/alerts", methods=["POST"])
11 def get_alerts() -> jsonify:
12 """
13 Retrieves all alerts from the AlertsService.
@@ -20,15 +20,20 @@ def get_alerts() -> jsonify:
20 jsonify: A JSON response containing a list of alerts. Each item in the list is a dictionary representing an alert,
21 containing all its associated data.
22 """
23 - size = request.args.get("size", default=10, type=int)
24 - timerange = request.args.get("timerange", default="24h", type=str)
23 + data = request.json
24 +
25 + size = int(data.get("size", 10))
26 + timerange = str(data.get("timerange", "24h"))
27 + alert_field = str(data.get("alert_field", "syslog_level"))
28 + alert_value = str(data.get("alert_value", "ALERT"))
29 +
30 service = AlertsService()
26 - alerts = service.collect_alerts(size=size, timerange=timerange) # replace `collect_all_alerts` with `collect_alerts(size=1000)`
31 + alerts = service.collect_alerts(size=size, timerange=timerange, alert_field=alert_field, alert_value=alert_value)
32 return jsonify(alerts)
33
34
30 -@bp.route("/alerts/<agent_name>", methods=["GET"])
31 -def get_alerts_by_agent(agent_name: str) -> jsonify:
35 +@bp.route("/alerts/agent", methods=["POST"])
36 +def get_alerts_by_agent() -> jsonify:
37 """
38 Retrieves all alerts from the AlertsService by agent name.
39
@@ -40,15 +45,27 @@ def get_alerts_by_agent(agent_name: str) -> jsonify:
45 jsonify: A JSON response containing a list of alerts. Each item in the list is a dictionary representing an alert,
46 containing all its associated data.
47 """
48 + data = request.json
49 + size = int(data.get("size", 10))
50 + timerange = str(data.get("timerange", "24h"))
51 + agent_name = str(data.get("agent_name", "WIN-HFOU106TD7K"))
52 + alert_field = str(data.get("alert_field", "syslog_level"))
53 + alert_value = str(data.get("alert_value", "ALERT"))
54 service = AlertsService()
44 - size = request.args.get("size", default=10, type=int)
45 - timerange = request.args.get("timerange", default="24h", type=str)
46 - alerts = service.collect_alerts_by_agent_name(agent_name=agent_name, size=size, timerange=timerange)
55 + # size = request.args.get("size", default=10, type=int)
56 + # timerange = request.args.get("timerange", default="24h", type=str)
57 + alerts = service.collect_alerts_by_agent_name(
58 + agent_name=agent_name,
59 + size=size,
60 + timerange=timerange,
61 + alert_field=alert_field,
62 + alert_value=alert_value,
63 + )
64 return jsonify(alerts)
65
66
50 -@bp.route("/alerts/index/<index_name>", methods=["GET"])
51 -def get_alerts_by_index(index_name: str) -> jsonify:
67 +@bp.route("/alerts/index", methods=["POST"])
68 +def get_alerts_by_index() -> jsonify:
69 """
70 Retrieves all alerts from the AlertsService by index name.
71
@@ -60,10 +77,20 @@ def get_alerts_by_index(index_name: str) -> jsonify:
77 jsonify: A JSON response containing a list of alerts. Each item in the list is a dictionary representing an alert,
78 containing all its associated data.
79 """
63 - size = request.args.get("size", default=10, type=int)
64 - timerange = request.args.get("timerange", default="24h", type=str)
80 + data = request.json
81 + size = int(data.get("size", 10))
82 + timerange = str(data.get("timerange", "24h"))
83 + index_name = str(data.get("index_name", "wazuh*"))
84 + alert_field = str(data.get("alert_field", "syslog_level"))
85 + alert_value = str(data.get("alert_value", "ALERT"))
86 service = AlertsService()
66 - alerts = service.collect_alerts_by_index(index_name=index_name, size=size, timerange=timerange)
87 + alerts = service.collect_alerts_by_index(
88 + index_name=index_name,
89 + size=size,
90 + timerange=timerange,
91 + alert_field=alert_field,
92 + alert_value=alert_value,
93 + )
94 return jsonify(alerts)
95
96
backend/app/services/WazuhIndexer/alerts.py
+22 -42
@@ -73,14 +73,15 @@ class AlertsService:
73
74 return {"success": True, "indices": valid_indices}
75
76 - def collect_alerts(self, size: int, timerange: str) -> Dict[str, object]:
76 + def collect_alerts(self, size: int, timerange: str, alert_field: str, alert_value: str) -> Dict[str, object]:
77 """
78 Collects alerts from the Wazuh-Indexer.
79
80 Args:
81 size (int): The maximum number of alerts to return.
82 timerange (str): The time range to collect alerts from. This is a string like "24h", "1w", etc.
83 -
83 + alert_field (str): The field to match.
84 + alert_value (str): The value to match.
85 Returns:
86 Dict[str, object]: A dictionary containing success status and alerts or an error message.
87 """
@@ -90,7 +91,8 @@ class AlertsService:
91
92 alerts_summary = []
93 # matches = [("syslog_level", "ALERT"), ("agent_name", "WIN-39O01J5F7G5")]
93 - matches = [("syslog_level", "ALERT")]
94 + # matches = [("syslog_level", "ALERT")]
95 + matches = [(alert_field, alert_value)]
96 for index_name in indices_validation["indices"]:
97 alerts = self._collect_alerts(index_name, size=size, timerange=timerange, matches=matches)
98 if alerts["success"] and len(alerts["alerts"]) > 0:
@@ -132,7 +134,7 @@ class AlertsService:
134 "alerts_summary": alerts_summary,
135 }
136
135 - def collect_alerts_by_index(self, index_name: str, size: int, timerange: str) -> Dict[str, Any]:
137 + def collect_alerts_by_index(self, index_name: str, size: int, timerange: str, alert_field: str, alert_value: str) -> Dict[str, Any]:
138 """
139 Collects alerts from the given index.
140
@@ -140,6 +142,8 @@ class AlertsService:
142 index_name (str): The name of the index to query.
143 size (int): The maximum number of alerts to return.
144 timerange (str): The time range to collect alerts from. This is a string like "24h", "1w", etc.
145 + alert_field (str): The field to match.
146 + alert_value (str): The value to match.
147
148 Returns:
149 Dict[str, Any]: A dictionary containing success status, a message, and potentially the alerts from the given index.
@@ -147,7 +151,8 @@ class AlertsService:
151 if not self.is_valid_index(index_name):
152 return self._error_response("Invalid index name")
153
150 - alerts = self._collect_alerts(index_name=index_name, size=size, timerange=timerange)
154 + matches = [(alert_field, alert_value)]
155 + alerts = self._collect_alerts(index_name=index_name, size=size, timerange=timerange, matches=matches)
156 if not alerts["success"]:
157 return alerts
158
@@ -158,7 +163,14 @@ class AlertsService:
163 "total_alerts": len(alerts["alerts"]),
164 }
165
161 - def collect_alerts_by_agent_name(self, agent_name: str, size: int, timerange: str) -> Dict[str, Any]:
166 + def collect_alerts_by_agent_name(
167 + self,
168 + agent_name: str,
169 + size: int,
170 + timerange: str,
171 + alert_field: str,
172 + alert_value: str,
173 + ) -> Dict[str, Any]:
174 """
175 Collects alerts associated with a given agent name.
176
@@ -166,6 +178,8 @@ class AlertsService:
178 agent_name (str): The agent name associated with the alerts.
179 size (int): The maximum number of alerts to return.
180 timerange (str): The time range to collect alerts from. This is a string like "24h", "1w", etc.
181 + alert_field (str): The field to match.
182 + alert_value (str): The value to match.
183
184 Returns:
185 Dict[str, Any]: A dictionary containing success status, a message, and potentially the alerts associated with the agent.
@@ -175,7 +189,7 @@ class AlertsService:
189 return indices_validation
190
191 alerts_by_agent_dict = {}
178 - matches = [("syslog_level", "ALERT"), ("agent_name", f"{agent_name}")]
192 + matches = [(alert_field, alert_value), ("agent_name", f"{agent_name}")]
193 for index_name in indices_validation["indices"]:
194 alerts = self._collect_alerts(index_name=index_name, size=size, timerange=timerange, matches=matches)
195 if alerts["success"]:
@@ -296,40 +310,6 @@ class AlertsService:
310 """
311 return {"message": message, "success": False}
312
299 - # def _collect_alerts(self, index_name: str, size: int = None, timerange: str = "24h") -> Dict[str, object]:
300 - # """
301 - # Elasticsearch query to get the most recent alerts where the `rule_level` is 12 or higher or the
302 - # `syslog_level` field is `ALERT` and return the results in descending order by the `timestamp_utc` field.
303 - # The number of alerts to return can be limited by the `size` parameter.
304 -
305 - # Args:
306 - # index_name (str): The name of the index to query.
307 - # size (int, optional): The maximum number of alerts to return. If None, all alerts are returned.
308 - # timerange (str, optional): The time range to collect alerts from. This is a string like "24h", "1w", etc.
309 -
310 - # Returns:
311 - # Dict[str, object]: A dictionary containing success status and alerts or an error message.
312 - # """
313 - # logger.info(f"Collecting alerts from {index_name}")
314 - # query = self._build_query(timerange=timerange) # Use the provided query
315 - # try:
316 - # alerts = self.es.search(index=index_name, body=query, size=size)
317 - # alerts_list = [alert for alert in alerts["hits"]["hits"]]
318 -
319 - # # Iterate over each alert and invoke invoke_socfortress function
320 - # for alert in alerts_list:
321 - # ask_socfortress = self.asksocfortress_service.invoke_asksocfortress(alert["_source"]["rule_description"])
322 - # alert["ask_socfortress"] = ask_socfortress # Add the result to the alert
323 -
324 - # return {
325 - # "message": "Successfully collected alerts",
326 - # "success": True,
327 - # "alerts": alerts_list, # Return the alerts list with the added results
328 - # }
329 - # except Exception as e:
330 - # logger.error(f"Failed to collect alerts: {e}")
331 - # return {"message": "Failed to collect alerts", "success": False}
332 -
313 def _collect_alerts(
314 self,
315 index_name: str,
@@ -361,7 +341,7 @@ class AlertsService:
341 query_builder.add_matches(matches)
342 else:
343 query_builder.add_matches([("syslog_level", "ALERT")])
364 - query_builder.add_range("rule_level", "12")
344 + # query_builder.add_range("rule_level", "12") # removed to get all alerts regardless of rule level
345 query_builder.add_sort("timestamp_utc")
346
347 # Get the final query
backend/app/static/swagger.json
+114 -88
@@ -947,31 +947,41 @@
947 }
948 },
949 "/alerts": {
950 - "get": {
951 - "summary": "Get alerts",
952 - "description": "Endpoint to get alerts. Retrieves all alerts from the AlertsService.",
953 - "parameters": [
954 - {
955 - "name": "size",
956 - "in": "query",
957 - "description": "The number of alerts to return. Defaults to 10.",
958 - "required": false,
959 - "schema": {
960 - "type": "integer",
961 - "default": 10
962 - }
963 - },
964 - {
965 - "name": "timerange",
966 - "in": "query",
967 - "description": "The time range to consider for alerts. Defaults to '24h'.",
968 - "required": false,
969 - "schema": {
970 - "type": "string",
971 - "default": "24h"
950 + "post": {
951 + "summary": "Create and get alerts",
952 + "description": "Endpoint to create and get alerts. Retrieves all available alerts from the AlertsService based on the provided parameters.",
953 + "requestBody": {
954 + "content": {
955 + "application/json": {
956 + "schema": {
957 + "type": "object",
958 + "properties": {
959 + "size": {
960 + "type": "integer",
961 + "default": 10,
962 + "description": "The number of alerts to return. Defaults to 10."
963 + },
964 + "timerange": {
965 + "type": "string",
966 + "default": "24h",
967 + "description": "The time range to consider for alerts. Defaults to '24h'."
968 + },
969 + "alert_field": {
970 + "type": "string",
971 + "default": "syslog_level",
972 + "description": "Field to filter alerts on. Defaults to 'syslog_level'."
973 + },
974 + "alert_value": {
975 + "type": "string",
976 + "default": "ALERT",
977 + "description": "Value to filter alerts on. Defaults to 'ALERT'."
978 + }
979 + },
980 + "required": []
981 + }
982 }
983 }
974 - ],
984 + },
985 "responses": {
986 "200": {
987 "description": "Successful operation",
@@ -1003,43 +1013,51 @@
1013 }
1014 }
1015 },
1006 - "operationId": "getAlerts",
1016 + "operationId": "createAndGetAlerts",
1017 "tags": ["Wazuh-Indexer"]
1018 }
1019 },
1010 - "/alerts/{agent_name}": {
1011 - "get": {
1012 - "summary": "Get alerts from a specific agent",
1013 - "description": "Endpoint to get alerts from a specific agent.",
1014 - "parameters": [
1015 - {
1016 - "name": "agent_name",
1017 - "in": "path",
1018 - "description": "The name of the host to get alerts from.",
1019 - "required": true,
1020 - "type": "string"
1021 - },
1022 - {
1023 - "name": "size",
1024 - "in": "query",
1025 - "description": "The number of alerts to return. Defaults to 10.",
1026 - "required": false,
1027 - "schema": {
1028 - "type": "integer",
1029 - "default": 10
1030 - }
1031 - },
1032 - {
1033 - "name": "timerange",
1034 - "in": "query",
1035 - "description": "The time range to consider for alerts. Defaults to '24h'.",
1036 - "required": false,
1037 - "schema": {
1038 - "type": "string",
1039 - "default": "24h"
1020 + "/alerts/agent": {
1021 + "post": {
1022 + "summary": "Create and get alerts from a specific agent",
1023 + "description": "Endpoint to create and get alerts from a specific agent. Retrieves all available alerts from the AlertsService based on the provided parameters.",
1024 + "requestBody": {
1025 + "content": {
1026 + "application/json": {
1027 + "schema": {
1028 + "type": "object",
1029 + "properties": {
1030 + "agent_name": {
1031 + "type": "string",
1032 + "default": "WIN-HFOU106TD7K",
1033 + "description": "The name of the host to get alerts from."
1034 + },
1035 + "size": {
1036 + "type": "integer",
1037 + "default": 10,
1038 + "description": "The number of alerts to return. Defaults to 10."
1039 + },
1040 + "timerange": {
1041 + "type": "string",
1042 + "default": "24h",
1043 + "description": "The time range to consider for alerts. Defaults to '24h'."
1044 + },
1045 + "alert_field": {
1046 + "type": "string",
1047 + "default": "syslog_level",
1048 + "description": "Field to filter alerts on. Defaults to 'syslog_level'."
1049 + },
1050 + "alert_value": {
1051 + "type": "string",
1052 + "default": "ALERT",
1053 + "description": "Value to filter alerts on. Defaults to 'ALERT'."
1054 + }
1055 + },
1056 + "required": []
1057 + }
1058 }
1059 }
1042 - ],
1060 + },
1061 "responses": {
1062 "200": {
1063 "description": "Successful operation",
@@ -1107,43 +1125,51 @@
1125 }
1126 }
1127 },
1110 - "operationId": "getAlertsFromAgent",
1128 + "operationId": "createAndGetAlertsByAgent",
1129 "tags": ["Wazuh-Indexer"]
1130 }
1131 },
1114 - "/alerts/index/{index_name}": {
1115 - "get": {
1116 - "summary": "Get alerts from an index",
1117 - "description": "Endpoint to get alerts from an index.",
1118 - "parameters": [
1119 - {
1120 - "name": "index_name",
1121 - "in": "path",
1122 - "description": "The name of the index to get alerts from.",
1123 - "required": true,
1124 - "type": "string"
1125 - },
1126 - {
1127 - "name": "size",
1128 - "in": "query",
1129 - "description": "The number of alerts to return. Defaults to 10.",
1130 - "required": false,
1131 - "schema": {
1132 - "type": "integer",
1133 - "default": 10
1134 - }
1135 - },
1136 - {
1137 - "name": "timerange",
1138 - "in": "query",
1139 - "description": "The time range to consider for alerts. Defaults to '24h'.",
1140 - "required": false,
1141 - "schema": {
1142 - "type": "string",
1143 - "default": "24h"
1132 + "/alerts/index": {
1133 + "post": {
1134 + "summary": "Create and get alerts from an index",
1135 + "description": "Endpoint to create and get alerts from an index. Retrieves all available alerts from the AlertsService based on the provided parameters.",
1136 + "requestBody": {
1137 + "content": {
1138 + "application/json": {
1139 + "schema": {
1140 + "type": "object",
1141 + "properties": {
1142 + "index_name": {
1143 + "type": "string",
1144 + "default": "wazuh*",
1145 + "description": "The name of the index to get alerts from."
1146 + },
1147 + "size": {
1148 + "type": "integer",
1149 + "default": 10,
1150 + "description": "The number of alerts to return. Defaults to 10."
1151 + },
1152 + "timerange": {
1153 + "type": "string",
1154 + "default": "24h",
1155 + "description": "The time range to consider for alerts. Defaults to '24h'."
1156 + },
1157 + "alert_field": {
1158 + "type": "string",
1159 + "default": "syslog_level",
1160 + "description": "Field to filter alerts on. Defaults to 'syslog_level'."
1161 + },
1162 + "alert_value": {
1163 + "type": "string",
1164 + "default": "ALERT",
1165 + "description": "Value to filter alerts on. Defaults to 'ALERT'."
1166 + }
1167 + },
1168 + "required": []
1169 + }
1170 }
1171 }
1146 - ],
1172 + },
1173 "responses": {
1174 "200": {
1175 "description": "Successful operation",
@@ -1211,7 +1237,7 @@
1237 }
1238 }
1239 },
1214 - "operationId": "getAlertsFromIndex",
1240 + "operationId": "createAndGetAlertsFromIndex",
1241 "tags": ["Wazuh-Indexer"]
1242 }
1243 },