howler-api 2.13.0.dev341__py3-none-any.whl → 2.13.0.dev343__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.
howler/api/__init__.py CHANGED
@@ -32,7 +32,7 @@ def _make_api_response(
32
32
  ) -> Response:
33
33
  quota_user = flsk_session.pop("quota_user", None)
34
34
  quota_set = flsk_session.pop("quota_set", False)
35
- if quota_user and quota_set and not request.path.startswith("/api/v1/borealis"):
35
+ if quota_user and quota_set and not request.path.startswith("/api/v1/clue"):
36
36
  QUOTA_TRACKER.end(quota_user)
37
37
 
38
38
  if type(err) is Exception: # pragma: no cover
@@ -14,9 +14,9 @@ from howler.config import cache, config
14
14
  from howler.plugins import get_plugins
15
15
  from howler.security import api_login
16
16
 
17
- SUB_API = "borealis"
18
- borealis_api = make_subapi_blueprint(SUB_API, api_version=1)
19
- borealis_api._doc = "Proxy enrichment requests to borealis"
17
+ SUB_API = "clue"
18
+ clue_api = make_subapi_blueprint(SUB_API, api_version=1)
19
+ clue_api._doc = "Proxy enrichment requests to clue"
20
20
 
21
21
  logger = get_logger(__file__)
22
22
 
@@ -28,27 +28,27 @@ def skip_cache(*args):
28
28
 
29
29
  @cache.memoize(15 * 60, unless=skip_cache)
30
30
  def get_token(access_token: str) -> str:
31
- """Get a borealis token based on the current howler token"""
32
- get_borealis_token: Optional[Callable[[str], str]] = None
31
+ """Get a clue token based on the current howler token"""
32
+ get_clue_token: Optional[Callable[[str], str]] = None
33
33
 
34
34
  for plugin in get_plugins():
35
- if get_borealis_token := plugin.modules.token_functions.get("borealis", None):
35
+ if get_clue_token := plugin.modules.token_functions.get("clue", None):
36
36
  break
37
37
 
38
- if get_borealis_token:
39
- borealis_access_token = get_borealis_token(access_token)
38
+ if get_clue_token:
39
+ clue_access_token = get_clue_token(access_token)
40
40
  else:
41
- logger.info("No custom borealis token logic provided, continuing with howler credentials")
42
- borealis_access_token = access_token
41
+ logger.info("No custom clue token logic provided, continuing with howler credentials")
42
+ clue_access_token = access_token
43
43
 
44
- return borealis_access_token
44
+ return clue_access_token
45
45
 
46
46
 
47
47
  @generate_swagger_docs()
48
- @borealis_api.route("/<path:path>", methods=["GET", "POST"])
48
+ @clue_api.route("/<path:path>", methods=["GET", "POST"])
49
49
  @api_login(required_priv=["R"], required_method=["oauth"])
50
- def proxy_to_borealis(path, **kwargs):
51
- """Proxy enrichment requests to Borealis
50
+ def proxy_to_clue(path, **kwargs):
51
+ """Proxy enrichment requests to Clue
52
52
 
53
53
  Variables:
54
54
  None
@@ -60,11 +60,9 @@ def proxy_to_borealis(path, **kwargs):
60
60
  Any
61
61
 
62
62
  Result Example:
63
- Borealis Responses
63
+ Clue Responses
64
64
  """
65
- logger.info(
66
- "Proxying borealis request to path %s/%s?%s", config.core.borealis.url, path, request.query_string.decode()
67
- )
65
+ logger.info("Proxying clue request to path %s/%s?%s", config.core.clue.url, path, request.query_string.decode())
68
66
 
69
67
  auth_data: Optional[str] = request.headers.get("Authorization", None, type=str)
70
68
 
@@ -73,29 +71,29 @@ def proxy_to_borealis(path, **kwargs):
73
71
 
74
72
  auth_token = auth_data.split(" ")[1]
75
73
 
76
- borealis_token = get_token(auth_token)
74
+ clue_token = get_token(auth_token)
77
75
 
78
76
  start = time.perf_counter()
79
- with elasticapm.capture_span("borealis", span_type="http"):
77
+ with elasticapm.capture_span("clue", span_type="http"):
80
78
  if request.method.lower() == "get":
81
79
  response = requests.get(
82
- f"{config.core.borealis.url}/{path}",
83
- headers={"Authorization": f"Bearer {borealis_token}", "Accept": "application/json"},
80
+ f"{config.core.clue.url}/{path}",
81
+ headers={"Authorization": f"Bearer {clue_token}", "Accept": "application/json"},
84
82
  params=request.args.to_dict(),
85
83
  timeout=5 * 60,
86
84
  )
87
85
  else:
88
86
  response = requests.post(
89
- f"{config.core.borealis.url}/{path}",
87
+ f"{config.core.clue.url}/{path}",
90
88
  json=request.json,
91
- headers={"Authorization": f"Bearer {borealis_token}", "Accept": "application/json"},
89
+ headers={"Authorization": f"Bearer {clue_token}", "Accept": "application/json"},
92
90
  params=request.args.to_dict(),
93
91
  timeout=5 * 60,
94
92
  )
95
93
 
96
- logger.debug(f"Request to borealis completed in {round(time.perf_counter() - start)}ms")
94
+ logger.debug(f"Request to clue completed in {round(time.perf_counter() - start)}ms")
97
95
 
98
96
  if not response.ok:
99
- return bad_gateway(response.json(), err="Something went wrong when connecting to borealis")
97
+ return bad_gateway(response.json(), err="Something went wrong when connecting to clue")
100
98
 
101
99
  return ok(response.json()["api_response"])
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/app.py CHANGED
@@ -138,11 +138,11 @@ if HWL_USE_REST_API or DEBUG:
138
138
  logger.debug("Enabled Notebook Integration")
139
139
  app.register_blueprint(notebook_api)
140
140
 
141
- if config.core.borealis.enabled:
142
- from howler.api.v1.borealis import borealis_api
141
+ if config.core.clue.enabled:
142
+ from howler.api.v1.clue import clue_api
143
143
 
144
- logger.debug("Enabled Borealis Integration")
145
- app.register_blueprint(borealis_api)
144
+ logger.debug("Enabled Clue Integration")
145
+ app.register_blueprint(clue_api)
146
146
 
147
147
  logger.info("Checking plugins for additional routes")
148
148
  for plugin in get_plugins():
howler/odm/helper.py CHANGED
@@ -259,13 +259,13 @@ def generate_useful_hit(lookups: dict[str, dict[str, Any]], users: list[User], p
259
259
  ),
260
260
  ]
261
261
 
262
- if config.core.borealis.enabled:
262
+ if config.core.clue.enabled:
263
263
  hit.howler.dossier.append(
264
264
  Lead(
265
265
  {
266
266
  "icon": "material-symbols:image",
267
- "label": {"en": "Borealis", "fr": "Borealis"},
268
- "format": "borealis",
267
+ "label": {"en": "Clue", "fr": "Clue"},
268
+ "format": "clue",
269
269
  "content": "test-plugin.image",
270
270
  "metadata": {"type": "ip", "value": "127.0.01", "classification": "TLP:CLEAR"},
271
271
  }
@@ -276,8 +276,8 @@ def generate_useful_hit(lookups: dict[str, dict[str, Any]], users: list[User], p
276
276
  Lead(
277
277
  {
278
278
  "icon": "material-symbols:code-rounded",
279
- "label": {"en": "Borealis", "fr": "Borealis"},
280
- "format": "borealis",
279
+ "label": {"en": "Clue", "fr": "Clue"},
280
+ "format": "clue",
281
281
  "content": "test-plugin.json",
282
282
  "metadata": {"type": "ip", "value": "127.0.01", "classification": "TLP:CLEAR"},
283
283
  }
@@ -409,24 +409,24 @@ class UI(BaseModel):
409
409
  )
410
410
 
411
411
 
412
- class Borealis(BaseModel):
413
- """Borealis enrichment service integration configuration.
412
+ class Clue(BaseModel):
413
+ """Clue enrichment service integration configuration.
414
414
 
415
- Defines settings for integrating with Borealis, an external enrichment
415
+ Defines settings for integrating with Clue, an external enrichment
416
416
  service that can provide additional context and status information for
417
417
  hits displayed in the Howler UI.
418
418
  """
419
419
 
420
- enabled: bool = Field(default=False, description="Should borealis integration be enabled?")
420
+ enabled: bool = Field(default=False, description="Should clue integration be enabled?")
421
421
 
422
422
  url: str = Field(
423
423
  default="http://enrichment-rest.enrichment.svc.cluster.local:5000",
424
- description="What url should Howler connect to to interact with Borealis?",
424
+ description="What url should Howler connect to to interact with Clue?",
425
425
  )
426
426
 
427
427
  status_checks: list[str] = Field(
428
428
  default=[],
429
- description="A list of borealis fetchers that return status results given a Howler ID to show in the UI.",
429
+ description="A list of clue fetchers that return status results given a Howler ID to show in the UI.",
430
430
  )
431
431
 
432
432
 
@@ -451,7 +451,7 @@ class Core(BaseModel):
451
451
  """Core application configuration for Howler.
452
452
 
453
453
  Aggregates all core service configurations including Redis, metrics,
454
- and external integrations like Borealis and nbgallery notebooks.
454
+ and external integrations like Clue and nbgallery notebooks.
455
455
  Also manages the loading of external plugins.
456
456
  """
457
457
 
@@ -463,8 +463,8 @@ class Core(BaseModel):
463
463
  redis: Redis = Redis()
464
464
  "Configuration for Redis instances"
465
465
 
466
- borealis: Borealis = Borealis()
467
- "Configuration for Borealis Integration"
466
+ clue: Clue = Clue()
467
+ "Configuration for Clue Integration"
468
468
 
469
469
  notebook: Notebook = Notebook()
470
470
  "Configuration for Notebook Integration"
@@ -529,7 +529,7 @@ class Config(BaseSettings):
529
529
  logging: Logging = Logging()
530
530
  system: System = System()
531
531
  ui: UI = UI()
532
- mapping: dict[str, str] = Field(description="Mapping of alert keys to borealis type", default={})
532
+ mapping: dict[str, str] = Field(description="Mapping of alert keys to clue types", default={})
533
533
 
534
534
  model_config = SettingsConfigDict(
535
535
  yaml_file=config_locations,
@@ -31,7 +31,7 @@ class Pivot(odm.Model):
31
31
  description="An optional icon to use in the tab display for this dossier.", optional=True
32
32
  )
33
33
  label: LocalizedLabel = odm.Compound(LocalizedLabel, description="Labels for the pivot in the UI.")
34
- value: str = odm.Keyword(description="The link/borealis id to pivot on.")
34
+ value: str = odm.Keyword(description="The link/plugin information to pivot on.")
35
35
  format: str = odm.Keyword(description="The format of the pivot.")
36
36
  mappings: list[Mapping] = odm.List(
37
37
  odm.Compound(Mapping),
@@ -220,8 +220,8 @@ class api_login(object): # noqa: D101, N801
220
220
  user_id=user.get("uname", None),
221
221
  )
222
222
 
223
- if request.path.startswith("/api/v1/borealis"):
224
- logger.debug("Bypassing quota limits for borealis enrichment")
223
+ if request.path.startswith("/api/v1/clue"):
224
+ logger.debug("Bypassing quota limits for clue enrichment")
225
225
  elif self.enforce_quota:
226
226
  # Check current user quota
227
227
  flsk_session["quota_user"] = user["uname"]
@@ -117,11 +117,11 @@ def get_configuration(user: User, **kwargs):
117
117
  },
118
118
  "mapping": config.mapping,
119
119
  "features": {
120
- "borealis": config.core.borealis.enabled,
120
+ "clue": config.core.clue.enabled,
121
121
  "notebook": config.core.notebook.enabled,
122
122
  **plugin_features,
123
123
  },
124
- "borealis": {"status_checks": config.core.borealis.status_checks},
124
+ "clue": {"status_checks": config.core.clue.status_checks},
125
125
  },
126
126
  "c12nDef": classification_definition,
127
127
  "indexes": list_all_fields("admin" in user["type"] if user is not None else False),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 2.13.0.dev341
3
+ Version: 2.13.0.dev343
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -10,28 +10,28 @@ howler/actions/promote.py,sha256=v2lFS4WkOpX47ChbSYbhJKzwAShYE3Fg2UVQ6sbr7Yw,470
10
10
  howler/actions/remove_from_bundle.py,sha256=Tt9zPZuPrplM8lvCo2sHKORY4U4z3S6RfltXRigDvF4,4251
11
11
  howler/actions/remove_label.py,sha256=I6_4KnBgvW6OwP7tNe5LMbaOZfAVf5S9ADijBt7g-9A,3325
12
12
  howler/actions/transition.py,sha256=7gGWGY0wKZjp87-BpqfMjImAz-QXHSyDJA3bWq3RTz4,6423
13
- howler/api/__init__.py,sha256=Zc5-ldSpe2GFWoL5DYMpoEdu7VZm5KMtGI03m2tnDZk,8543
13
+ howler/api/__init__.py,sha256=Z-o_fukNO9wBpx9gLNm8OPZwFOP-4xMtY0V1sfdEn8w,8539
14
14
  howler/api/base.py,sha256=i--N7f4itJBRNVayDAqOiZYIq9thXwdblRBGfePyP1c,2689
15
15
  howler/api/socket.py,sha256=6T_gpyazIbSmA2BheZ-yUWPbdxg9C50az70-rq4o-Rc,3910
16
16
  howler/api/v1/__init__.py,sha256=lupGaCMXiiVWJjWrV7AoutAcTvZUrYommD-oUf4SFgU,3857
17
17
  howler/api/v1/action.py,sha256=sZFihfJQFmzhg9Gc7o0A73pDZls_s8Xjf3mfzB2Nkr4,11112
18
18
  howler/api/v1/analytic.py,sha256=kN7YXSTaXEWusu5DjAC510qlDzAIzsV7j7QjNw1daoY,20146
19
19
  howler/api/v1/auth.py,sha256=fj0t6COXesgrShZQlP0zZXR12htjYlzLGGMIDsiX8nM,14069
20
- howler/api/v1/borealis.py,sha256=Jn8rhVtDOGIOgf92OdiGai-1rmw0-5hBp5FFAbZ3LHY,3168
20
+ howler/api/v1/clue.py,sha256=QaXmk9hTIkt7Cp4oAjCZuhtGeOo_C6yeNmhQY-egVsM,3042
21
21
  howler/api/v1/configs.py,sha256=cjii7WY1AtTyk56O84_WR-_JVonoXpWCrh2eMEuuGro,1921
22
22
  howler/api/v1/dossier.py,sha256=8mfuoxAHqT9a_0BHRBO9G33KLJUa9xwcfOImb6ax8mU,5816
23
23
  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=o6jQCPnlmEhTF3lgtsDo4J_g0JQorJxxliNKZWG4wXo,24257
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
31
31
  howler/api/v1/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  howler/api/v1/utils/etag.py,sha256=IGB4WUkecHbBt0KKLQFCxCn0mN3T_aSPG0y45l_zT9I,3431
33
33
  howler/api/v1/view.py,sha256=VyizfGehsuoPyn7iswGPKCLcbSQoO1ipRsbr91nSDKk,8228
34
- howler/app.py,sha256=AJJ8TGMSi9hJGc7IR7xKsZuVwg-ih85-t0PRO0-ntHw,7063
34
+ howler/app.py,sha256=76WSFUM4UKX2UpvDHfgKP8DI3wavLpXGlk2QLHqH1x8,7043
35
35
  howler/common/README.md,sha256=lgnrAdgnOADmmfRplhbfYD7jU627nr3zO-fJ6N4Nbcs,6577
36
36
  howler/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  howler/common/classification.py,sha256=AUl33PJX6O9d9XzxHbyyJah2ffD7Q7J2yYqIwz7OqKY,39342
@@ -88,7 +88,7 @@ howler/odm/README.md,sha256=Ihc_DyjVQlLaIOEbPoQNPkum9Ecn8kn37-PMFQsX77s,5645
88
88
  howler/odm/__init__.py,sha256=1n6vgBOrFcCHSBFysqgODERvqP7s5DIeJe8N8UeE5pM,44
89
89
  howler/odm/base.py,sha256=UxWDNokfNIuQK-SQz8gjIznhc8lLQe6eJTF_7aIbwqQ,51620
90
90
  howler/odm/charter.txt,sha256=-Wgrv7nqugZmeQknJk0_m6klLJStjVbuqKbi_KaDinQ,15277
91
- howler/odm/helper.py,sha256=WgCpMVqVzzy2C6aasMjlQ3SrHEszx39ARNI_SKTn1RU,13955
91
+ howler/odm/helper.py,sha256=EELMg3pvE7Kb9VDeKSYJQHiq6uCO2YuS095CPRgWrEM,13927
92
92
  howler/odm/howler_enum.py,sha256=JzRK3_adlhvfkoGdMZD1jgOwlneZs8-x7OxGEj3zcpY,768
93
93
  howler/odm/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
94
94
  howler/odm/models/action.py,sha256=V9tgMCg1ewu8mOngTcA6QAPwaR0NIT71VHglpRFYmS4,1235
@@ -97,7 +97,7 @@ howler/odm/models/assemblyline.py,sha256=_wcTiX3A6bhA2SGlK9tDF0v-uwLpIabXE8j2Fw9
97
97
  howler/odm/models/aws.py,sha256=pJVadJqubdgT27riCfp7bEKVP4XsMZB0ZUnKAbmCMd0,895
98
98
  howler/odm/models/azure.py,sha256=o7MZMMo9jh1SB8xXCajl_YSKP2nnnWsjx_DPT6LnQKg,710
99
99
  howler/odm/models/cbs.py,sha256=onUiJOGUxK3iy_-4XkGGwHxFiFq9Td_p59Kum4XaR-w,1366
100
- howler/odm/models/config.py,sha256=Hp37cfobHG824AUePE19_mCKFw_sc0ZSYtjDP3bxvGI,21770
100
+ howler/odm/models/config.py,sha256=KO_-AdTLL1NPHoEHoKqwHiOYa1kCZ-7YX3IcY9-UAsI,21723
101
101
  howler/odm/models/dossier.py,sha256=Ob2qROrG2-DYzmVo2XVe4NJ8HjWGCoRAu2gPo6p9XGU,1244
102
102
  howler/odm/models/ecs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
103
  howler/odm/models/ecs/agent.py,sha256=idSooyFCLuQAB7_RyEWTYW4-x9w5a3wpy2ct_-EDRQs,713
@@ -143,7 +143,7 @@ howler/odm/models/howler_data.py,sha256=3bzKQ_vSP_rK20S_U4PkXzsmBL1uqSaIOHZmoPuR
143
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
- howler/odm/models/pivot.py,sha256=VLZl5DHnLfmCM2ZU5sAye0qu18toCaFcYLYraXct2GM,1398
146
+ howler/odm/models/pivot.py,sha256=ZewcGh91xbE64snZ5Ahz2So1onAqO8U9H4CFe6jBOXs,1405
147
147
  howler/odm/models/template.py,sha256=-Tqq_36qD_3nQ4jv13OPeH_EyyERKhc55wT03CU-Kbk,979
148
148
  howler/odm/models/user.py,sha256=3V7cLxxHJwWfTsEdZ7-QZT_-PQL7H_RJ3buQ8AraGzQ,3052
149
149
  howler/odm/models/view.py,sha256=kmaJOXhR4prki5o0gBirs1dqGcQK3b9ATysL_kNoku0,1308
@@ -166,14 +166,14 @@ howler/remote/datatypes/queues/named.py,sha256=IypPN0ZnRTlWCZ0Wm6BAyoNCoGlLxUPyG
166
166
  howler/remote/datatypes/queues/priority.py,sha256=rfIK0nVFtivY82a6Er-1CZMzvYEVGyPcUmYrks1nzfI,7554
167
167
  howler/remote/datatypes/set.py,sha256=iJ-QrrkKRhEUyOYmRz21TUTitatvrNyp5aMJwXkCdqc,3538
168
168
  howler/remote/datatypes/user_quota_tracker.py,sha256=butA5RlV0XU9y6GtqoEryaJJZq-LAgoDhCJpdbHBFm0,1920
169
- howler/security/__init__.py,sha256=gIMv9AZ6bR-442X__cMuQmfkmSh6HqFUWl6Ot9IWThk,11676
169
+ howler/security/__init__.py,sha256=v5gQi5TUA4W4vlU3Adzxw8Tq3gCBzQPSF3F9kLDnZgc,11668
170
170
  howler/security/socket.py,sha256=zEyWQh7IMINNpYMynV-PLy_-HQLpgouUvztAKrTHEfU,3714
171
171
  howler/security/utils.py,sha256=MweKs9T--Z2w6hZNUfEAik4FsvXPNCskYF1vaQVt6_8,5309
172
172
  howler/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
173
  howler/services/action_service.py,sha256=AuNRvZs7sFGUveaoptD8ouzs39jdZJidmsp-fIocZo4,3977
174
174
  howler/services/analytic_service.py,sha256=pOJRCDn6I523XSVLBo49fL70Mz5VDgjJ5CBYhemQeBk,4272
175
175
  howler/services/auth_service.py,sha256=TX51z-Fu4i3JvxIdU1JsJ3vzgGPVWNL1lNQJMxKpkZ8,11678
176
- howler/services/config_service.py,sha256=R-NvCplIo-42sLwhrWkhiq8FDlTIdrpKoMy4dDGobjU,4505
176
+ howler/services/config_service.py,sha256=J5FCttgsHr6kMLGAPIW-8r8aGYwmX4YzsOyBG6yoGGM,4489
177
177
  howler/services/dossier_service.py,sha256=5jq7KZMgBNh165rN5pZD_oVuZP-oBsdACHDSV74ps-I,9839
178
178
  howler/services/event_service.py,sha256=4PG2iBXjh1V8QnXcbUZSiKJeHs6V9hRWT9SKrzQFIPY,2864
179
179
  howler/services/hit_service.py,sha256=VNsEhi6Tcoqkjsw8G71FWBj7xcKwdvET9mITYAKmzsM,32278
@@ -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.dev341.dist-info/METADATA,sha256=cux4ZHkfTdsGSV37O9Me-4EB98FVXSCF3_SXsMGMdVA,2805
198
- howler_api-2.13.0.dev341.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
199
- howler_api-2.13.0.dev341.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
200
- howler_api-2.13.0.dev341.dist-info/RECORD,,
197
+ howler_api-2.13.0.dev343.dist-info/METADATA,sha256=w8tdTek4q5qOcYrGXknBA5mbX0wvBVdvgciHKtPg56A,2805
198
+ howler_api-2.13.0.dev343.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
199
+ howler_api-2.13.0.dev343.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
200
+ howler_api-2.13.0.dev343.dist-info/RECORD,,