howler-api 2.13.0.dev332__py3-none-any.whl → 2.13.0.dev342__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.
Potentially problematic release.
This version of howler-api might be problematic. Click here for more details.
- howler/api/v1/search.py +74 -1
- howler/odm/models/lead.py +1 -10
- {howler_api-2.13.0.dev332.dist-info → howler_api-2.13.0.dev342.dist-info}/METADATA +1 -1
- {howler_api-2.13.0.dev332.dist-info → howler_api-2.13.0.dev342.dist-info}/RECORD +6 -6
- {howler_api-2.13.0.dev332.dist-info → howler_api-2.13.0.dev342.dist-info}/WHEEL +0 -0
- {howler_api-2.13.0.dev332.dist-info → howler_api-2.13.0.dev342.dist-info}/entry_points.txt +0 -0
howler/api/v1/search.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from copy import deepcopy
|
|
1
3
|
from typing import Any, Union
|
|
2
4
|
|
|
3
5
|
from elasticsearch import BadRequestError
|
|
6
|
+
from elasticsearch._sync.client.indices import IndicesClient
|
|
4
7
|
from flask import request
|
|
5
8
|
from sigma.backends.elasticsearch import LuceneBackend
|
|
6
9
|
from sigma.rule import SigmaRule
|
|
@@ -14,7 +17,7 @@ from howler.common.swagger import generate_swagger_docs
|
|
|
14
17
|
from howler.datastore.exceptions import SearchException
|
|
15
18
|
from howler.helper.search import get_collection, get_default_sort, has_access_control, list_all_fields
|
|
16
19
|
from howler.security import api_login
|
|
17
|
-
from howler.services import hit_service
|
|
20
|
+
from howler.services import hit_service, lucene_service
|
|
18
21
|
|
|
19
22
|
SUB_API = "search"
|
|
20
23
|
search_api = make_subapi_blueprint(SUB_API, api_version=1)
|
|
@@ -146,6 +149,76 @@ def search(index, **kwargs):
|
|
|
146
149
|
return bad_request(err=f"SearchException: {e}")
|
|
147
150
|
|
|
148
151
|
|
|
152
|
+
@generate_swagger_docs()
|
|
153
|
+
@search_api.route("/<index>/explain", methods=["GET", "POST"])
|
|
154
|
+
@api_login(required_priv=["R"])
|
|
155
|
+
def explain_query(index, **kwargs):
|
|
156
|
+
"""Search through specified index for a given Lucene query. Uses Lucene search syntax for query.
|
|
157
|
+
|
|
158
|
+
Variables:
|
|
159
|
+
index => Index to explain against (hit, user,...)
|
|
160
|
+
|
|
161
|
+
Arguments:
|
|
162
|
+
query => Lucene Query to explain
|
|
163
|
+
|
|
164
|
+
Data Block:
|
|
165
|
+
# Note that the data block is for POST requests only!
|
|
166
|
+
{
|
|
167
|
+
"query": "id:*", # Lucene Query to explain
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
Result Example:
|
|
172
|
+
{
|
|
173
|
+
'valid': True,
|
|
174
|
+
'explanations': [
|
|
175
|
+
{
|
|
176
|
+
'valid': True,
|
|
177
|
+
'explanation': 'ConstantScore(FieldExistsQuery [field=id])'
|
|
178
|
+
}
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
"""
|
|
182
|
+
user = kwargs["user"]
|
|
183
|
+
collection = get_collection(index, user)
|
|
184
|
+
|
|
185
|
+
if collection is None:
|
|
186
|
+
return bad_request(err=f"Not a valid index to explain: {index}")
|
|
187
|
+
|
|
188
|
+
fields = ["query"]
|
|
189
|
+
multi_fields: list[str] = []
|
|
190
|
+
|
|
191
|
+
params, req_data = generate_params(request, fields, multi_fields)
|
|
192
|
+
|
|
193
|
+
params["as_obj"] = False
|
|
194
|
+
|
|
195
|
+
query = req_data.get("query", None)
|
|
196
|
+
if not query:
|
|
197
|
+
return bad_request(err="There was no query.")
|
|
198
|
+
|
|
199
|
+
# This regex checks for lucene phrases (i.e. the "Example Analytic" part of howler.analytic:"Example Analytic")
|
|
200
|
+
# And then escapes them.
|
|
201
|
+
# https://regex101.com/r/8u5F6a/1
|
|
202
|
+
escaped_lucene = re.sub(r'((:\()?(".+?")(\)?))', lucene_service.replace_lucene_phrase, query)
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
indices_client = IndicesClient(datastore().hit.datastore.client)
|
|
206
|
+
|
|
207
|
+
result = deepcopy(
|
|
208
|
+
indices_client.validate_query(q=escaped_lucene, explain=True, index=collection().index_name).body
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
del result["_shards"]
|
|
212
|
+
|
|
213
|
+
for explanation in result["explanations"]:
|
|
214
|
+
del explanation["index"]
|
|
215
|
+
|
|
216
|
+
return ok(result)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.exception("Exception on query explanation")
|
|
219
|
+
return bad_request(err=f"Exception: {e}")
|
|
220
|
+
|
|
221
|
+
|
|
149
222
|
@generate_swagger_docs()
|
|
150
223
|
@search_api.route("/<index>/eql", methods=["GET", "POST"])
|
|
151
224
|
@api_login(required_priv=["R"])
|
howler/odm/models/lead.py
CHANGED
|
@@ -2,18 +2,9 @@
|
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
4
|
from howler import odm
|
|
5
|
-
from howler.odm.howler_enum import HowlerEnum
|
|
6
5
|
from howler.odm.models.localized_label import LocalizedLabel
|
|
7
6
|
|
|
8
7
|
|
|
9
|
-
class Formats(str, HowlerEnum):
|
|
10
|
-
BOREALIS = "borealis"
|
|
11
|
-
MARKDOWN = "markdown"
|
|
12
|
-
|
|
13
|
-
def __str__(self) -> str:
|
|
14
|
-
return self.value
|
|
15
|
-
|
|
16
|
-
|
|
17
8
|
@odm.model(
|
|
18
9
|
index=False,
|
|
19
10
|
store=True,
|
|
@@ -24,7 +15,7 @@ class Lead(odm.Model):
|
|
|
24
15
|
description="An optional icon to use in the tab display for this dossier.", optional=True
|
|
25
16
|
)
|
|
26
17
|
label: LocalizedLabel = odm.Compound(LocalizedLabel, description="Labels for the lead in the UI.")
|
|
27
|
-
format: str = odm.
|
|
18
|
+
format: str = odm.Keyword(description="The format of the lead.")
|
|
28
19
|
content: str = odm.Text(
|
|
29
20
|
description="The data for the content. Could be a link, raw markdown text, or other valid lead format.",
|
|
30
21
|
)
|
|
@@ -24,7 +24,7 @@ howler/api/v1/help.py,sha256=hqBvzW-DYX-I4Q85dbCQgpHsXyWDXp06a1fE9zhFMH4,823
|
|
|
24
24
|
howler/api/v1/hit.py,sha256=HKaI72k7VC0v4QPjE2zcAV6jizvY2ZWEpk1BiAklvgU,34031
|
|
25
25
|
howler/api/v1/notebook.py,sha256=-cahdJ9u1lAB_nheztayHKtXvoPZcj04N8nqQ2U-HLo,2015
|
|
26
26
|
howler/api/v1/overview.py,sha256=e-WiHuMvOPy8Y7xIGnceagdI0_jebqlgDxi6GE6tfaA,4999
|
|
27
|
-
howler/api/v1/search.py,sha256=
|
|
27
|
+
howler/api/v1/search.py,sha256=24r1vaYaxDhddzDR-c5dBdRKyag6aIggvHSWPWudqN8,26372
|
|
28
28
|
howler/api/v1/template.py,sha256=oexzUpAMVdgI6IOXITPx0iEfZIVP-kvlExRdFd6QVdk,5769
|
|
29
29
|
howler/api/v1/tool.py,sha256=6CN5LIXgxaAvxEHE6s4IFtAEhQo_zBLtl6ghbM8whjE,6737
|
|
30
30
|
howler/api/v1/user.py,sha256=YQh6eCAi4bsC_w9eGX0ZgnLoFL4z4efEc1knJsZhj4k,13842
|
|
@@ -140,7 +140,7 @@ howler/odm/models/ecs/vulnerability.py,sha256=iX2TUmCZTJjwyMcOmxiHg-pfoEwX8Wx-h8
|
|
|
140
140
|
howler/odm/models/gcp.py,sha256=FLwaQVcfFeE5AbIhEB_Ge2UL-HjPdldY04Nrm9Mq7kk,675
|
|
141
141
|
howler/odm/models/hit.py,sha256=kgzk3RzgKGvHdtNG0iMRxCtLPD73-BFFU9A_IxJcOHI,13396
|
|
142
142
|
howler/odm/models/howler_data.py,sha256=3bzKQ_vSP_rK20S_U4PkXzsmBL1uqSaIOHZmoPuRkS8,12473
|
|
143
|
-
howler/odm/models/lead.py,sha256=
|
|
143
|
+
howler/odm/models/lead.py,sha256=lqapGWZ4u22Asib48o7wAzramnFY9EkRybmb4olsyrA,904
|
|
144
144
|
howler/odm/models/localized_label.py,sha256=G7gfQ1cngiI4KprqldHWE1KHkAgK4AG_JsfHxVRdsRs,361
|
|
145
145
|
howler/odm/models/overview.py,sha256=kvZcMYPDlkJEGa0L1jq9pG0RFjLOVudC64-2GTWVu2w,684
|
|
146
146
|
howler/odm/models/pivot.py,sha256=VLZl5DHnLfmCM2ZU5sAye0qu18toCaFcYLYraXct2GM,1398
|
|
@@ -194,7 +194,7 @@ howler/utils/path.py,sha256=DfOU4i4zSs4wchHoE8iE7aWVLkTxiC_JRGepF2hBYBk,690
|
|
|
194
194
|
howler/utils/socket_utils.py,sha256=nz1SklC9xBHUSfHyTJjpq3mbozX1GDf01WzdGxfaUII,2212
|
|
195
195
|
howler/utils/str_utils.py,sha256=HE8Hqh2HlOLaj16w0H9zKOyDJLp-f1LQ50y_WeGZaEk,8389
|
|
196
196
|
howler/utils/uid.py,sha256=p9dsqyvZ-lpiAuzZWCPCeEM99kdk0Ly9czf04HNdSuw,1341
|
|
197
|
-
howler_api-2.13.0.
|
|
198
|
-
howler_api-2.13.0.
|
|
199
|
-
howler_api-2.13.0.
|
|
200
|
-
howler_api-2.13.0.
|
|
197
|
+
howler_api-2.13.0.dev342.dist-info/METADATA,sha256=k-G9s9TnSg4YhLHLrWrci6m16oU21RbtaJ1kwD_F-3M,2805
|
|
198
|
+
howler_api-2.13.0.dev342.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
199
|
+
howler_api-2.13.0.dev342.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
|
|
200
|
+
howler_api-2.13.0.dev342.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|