howler-api 3.0.0.dev351__py3-none-any.whl → 3.0.0.dev361__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.

@@ -74,7 +74,7 @@ def __sanitize_report(report: list[dict[str, Any]]) -> list[dict[str, Any]]:
74
74
  def execute(
75
75
  operation_id: str,
76
76
  query: str,
77
- user: User,
77
+ user: User | None,
78
78
  request_id: Optional[str] = None,
79
79
  **kwargs,
80
80
  ) -> list[dict[str, Any]]:
@@ -117,7 +117,8 @@ def execute(
117
117
  }
118
118
  ]
119
119
 
120
- missing_roles = set(operation.specification()["roles"]) - set(user["type"])
120
+ user_roles: set[str] = set(user["type"] if user else [])
121
+ missing_roles = set(operation.specification()["roles"]) - user_roles
121
122
  if missing_roles:
122
123
  return [
123
124
  {
howler/api/v1/action.py CHANGED
@@ -237,7 +237,7 @@ def execute_action(id: str, **kwargs) -> Response:
237
237
  return not_found(err="The specified action does not exist")
238
238
 
239
239
  reports: dict[str, list[dict]] = {}
240
- current_user = kwargs.get("user", None)
240
+ current_user: User | None = kwargs.get("user", None)
241
241
 
242
242
  for operation in action.operations:
243
243
  op_data = json.loads(operation["data_json"])
@@ -333,7 +333,7 @@ def execute_operations(**kwargs) -> Response:
333
333
  return bad_request(err="Incorrect data structure!")
334
334
 
335
335
  reports: dict[str, list[dict]] = {}
336
- current_user = kwargs.get("user", None)
336
+ current_user: User | None = kwargs.get("user", None)
337
337
  operations = execute_req["operations"]
338
338
 
339
339
  operation_ids = [o["operation_id"] for o in operations]
howler/api/v1/configs.py CHANGED
@@ -1,8 +1,11 @@
1
+ from typing import cast
2
+
1
3
  from flask import request
2
4
 
3
5
  import howler.services.config_service as config_service
4
6
  from howler.api import make_subapi_blueprint, ok
5
7
  from howler.common.swagger import generate_swagger_docs
8
+ from howler.odm.models.user import User
6
9
  from howler.security.utils import get_disco_url
7
10
 
8
11
  SUB_API = "configs"
@@ -49,7 +52,7 @@ def configs(**kwargs):
49
52
  """
50
53
  return ok(
51
54
  config_service.get_configuration(
52
- user=kwargs.get("user", None),
55
+ user=cast(User | None, kwargs.get("user", None)),
53
56
  discovery_url=get_disco_url(request.environ.get("HTTP_REFERER")),
54
57
  )
55
58
  )
howler/api/v1/hit.py CHANGED
@@ -1072,7 +1072,7 @@ def update_bundle(id, **kwargs):
1072
1072
  ...hit # The updated bundle
1073
1073
  }
1074
1074
  """
1075
- bundle_hit: Hit = kwargs.get("cached_hit", None)
1075
+ bundle_hit: Hit = cast(Hit, kwargs.get("cached_hit", None))
1076
1076
  if not bundle_hit:
1077
1077
  return not_found(err="This bundle does not exist.")
1078
1078
 
howler/api/v1/user.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import re
2
2
  from hashlib import sha256
3
- from typing import Any, Optional
3
+ from typing import Any, Optional, cast
4
4
 
5
5
  from flask import request
6
6
 
@@ -128,7 +128,9 @@ def add_user_account(username, **_):
128
128
  data["name"] = data["uname"]
129
129
 
130
130
  # Add dynamic classification group
131
- data["classification"] = user_service.get_dynamic_classification(data.get("classification", None), data["email"])
131
+ data["classification"] = user_service.get_dynamic_classification(
132
+ cast(str | None, data.get("classification", None)), data["email"]
133
+ )
132
134
 
133
135
  # Clear non user account data
134
136
  avatar = data.pop("avatar", None)
howler/common/README.md CHANGED
@@ -44,25 +44,6 @@ This file provides utility functions to merge dictionaries together, find the di
44
44
 
45
45
  Where as the unflatten does the invert by taking the dotted notation and transforming it back to it's original multiple level dictionary.
46
46
 
47
- ## hexdump.py
48
-
49
- This file provide functions to take a binary data blob and transform it into and hexadecimal dump of its bytes. The `dump(buf)` function only outputs the bytes where as the `hexdump(buf)` function outputs also the offsets and some trimmed down ascii representation.
50
-
51
- `dump("HTTP/1.1 404 Not\r\nCont")`
52
-
53
- 48 54 54 50 2F 31 2E 31 20 34 30 34 20 4E 6F 74 20 46 6F 75 6E 64 0D 0A 43 6F 6E 74
54
-
55
- `hexdump("HTTP/1.1 404 Not\r\nCont")`
56
-
57
- 00000000: 48 54 54 50 2F 31 2E 31 20 34 30 34 20 4E 6F 74 HTTP/1.1 404 Not
58
- 00000010: 20 46 6F 75 6E 64 0D 0A 43 6F 6E 74 Found..Cont
59
-
60
- ## iprange.py
61
-
62
- This file provides you with a RangeTable class that let's you determine if and IP is part of a certain CIDR definition. It also provides to quick function that let you determine if an IP is in a private CIDR (`is_private(ip)`) or if an IP is in a reserved CIDR (`is_reserved(ip)`).
63
-
64
- *Note*: only IPV4 IPs are supported.
65
-
66
47
  ## isotime.py
67
48
 
68
49
  This file provides you which methods to transform date into strings or epoch values. It support local, ISO and epoch time. It also makes sure that the local and ISO time get up to a microsecond precision.
howler/helper/oauth.py CHANGED
@@ -61,7 +61,7 @@ def parse_profile(profile: dict[str, Any], provider_config: OAuthProvider) -> di
61
61
  uname = profile.get("uname", profile.get("preferred_username", email_adr))
62
62
 
63
63
  # Did we default to email?
64
- if uname is not None and uname.lower() == email_adr.lower():
64
+ if email_adr is not None and uname is not None and uname.lower() == email_adr.lower():
65
65
  # 1. Use provided regex matcher
66
66
  if provider_config.uid_regex:
67
67
  match = re.match(provider_config.uid_regex, uname)
@@ -61,7 +61,7 @@ def _get_apikey_max_duration():
61
61
  return amount, unit
62
62
 
63
63
 
64
- def get_configuration(user: User, **kwargs):
64
+ def get_configuration(user: User | None, **kwargs):
65
65
  """Get system configration data for the Howler API
66
66
 
67
67
  Args:
@@ -314,7 +314,7 @@ def save_user_account(username: str, data: dict[str, Any], user: dict[str, Any])
314
314
  return storage.user.save(username, data)
315
315
 
316
316
 
317
- def get_dynamic_classification(current_c12n: str, email: str) -> str:
317
+ def get_dynamic_classification(current_c12n: str | None, email: str) -> str | None:
318
318
  """Get the classification of the user
319
319
 
320
320
  Args:
@@ -327,4 +327,5 @@ def get_dynamic_classification(current_c12n: str, email: str) -> str:
327
327
  if CLASSIFICATION.dynamic_groups and email:
328
328
  dyn_group = email.upper().split("@")[1]
329
329
  return CLASSIFICATION.build_user_classification(current_c12n, f"{CLASSIFICATION.UNRESTRICTED}//{dyn_group}")
330
+
330
331
  return current_c12n
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-api
3
- Version: 3.0.0.dev351
3
+ Version: 3.0.0.dev361
4
4
  Summary: Howler - API server
5
5
  License: MIT
6
6
  Keywords: howler,alerting,gc,canada,cse-cst,cse,cst,cyber,cccs
@@ -1,5 +1,5 @@
1
1
  howler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- howler/actions/__init__.py,sha256=eSV1gN0m-1uJUmqF6e--fJcnhFyGoMd7s5OcMQmKbso,5111
2
+ howler/actions/__init__.py,sha256=a9BkzoymVkCi_YciALZz7d9i4jF7AaLyJ3HZmAcsLZ0,5172
3
3
  howler/actions/add_label.py,sha256=3Vvjsn3FBPReFLGRANyoJB28xY7ZK31Zm1xIThpbq0s,3270
4
4
  howler/actions/add_to_bundle.py,sha256=SY0v5uTns5OLi_BHY50wGCLQmi1zSw1CaErbhOgAq1U,5245
5
5
  howler/actions/change_field.py,sha256=wC2n8IzfD7TtgdP3M2Kzws2hu0OuQRq1_QeQ6iNzj8M,2181
@@ -14,31 +14,29 @@ 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
- howler/api/v1/action.py,sha256=sZFihfJQFmzhg9Gc7o0A73pDZls_s8Xjf3mfzB2Nkr4,11112
17
+ howler/api/v1/action.py,sha256=5MPWdOTXtUlhl73cgndkwh9OdY2WDaekNvQjZvsQnFo,11138
18
18
  howler/api/v1/analytic.py,sha256=kN7YXSTaXEWusu5DjAC510qlDzAIzsV7j7QjNw1daoY,20146
19
19
  howler/api/v1/auth.py,sha256=fj0t6COXesgrShZQlP0zZXR12htjYlzLGGMIDsiX8nM,14069
20
20
  howler/api/v1/clue.py,sha256=QaXmk9hTIkt7Cp4oAjCZuhtGeOo_C6yeNmhQY-egVsM,3042
21
- howler/api/v1/configs.py,sha256=cjii7WY1AtTyk56O84_WR-_JVonoXpWCrh2eMEuuGro,1921
21
+ howler/api/v1/configs.py,sha256=GWomzxJMG-_llIY-eBspzP4dIchBj8_IIv2HC72wul8,2005
22
22
  howler/api/v1/dossier.py,sha256=8mfuoxAHqT9a_0BHRBO9G33KLJUa9xwcfOImb6ax8mU,5816
23
23
  howler/api/v1/help.py,sha256=hqBvzW-DYX-I4Q85dbCQgpHsXyWDXp06a1fE9zhFMH4,823
24
- howler/api/v1/hit.py,sha256=HKaI72k7VC0v4QPjE2zcAV6jizvY2ZWEpk1BiAklvgU,34031
24
+ howler/api/v1/hit.py,sha256=QNKJaics88vPg5IM0jH45WbwdpbZB2VGERUdAS-FcC8,34042
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
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
- howler/api/v1/user.py,sha256=YQh6eCAi4bsC_w9eGX0ZgnLoFL4z4efEc1knJsZhj4k,13842
30
+ howler/api/v1/user.py,sha256=De7FTPih8U44iyoxnIui9wNkxXwGSzulgbzOTfgXjFw,13880
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
34
  howler/app.py,sha256=76WSFUM4UKX2UpvDHfgKP8DI3wavLpXGlk2QLHqH1x8,7043
35
- howler/common/README.md,sha256=lgnrAdgnOADmmfRplhbfYD7jU627nr3zO-fJ6N4Nbcs,6577
35
+ howler/common/README.md,sha256=8uPpDqh14Ne7Rtn9BwPwE-JpuFkauVsTr2s0s4YG5Bg,5637
36
36
  howler/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  howler/common/classification.py,sha256=AUl33PJX6O9d9XzxHbyyJah2ffD7Q7J2yYqIwz7OqKY,39342
38
38
  howler/common/classification.yml,sha256=3VBqzKYkiqz8bCsSuqNvqxeqUPN1NmXBKHusGFO3hbg,4092
39
39
  howler/common/exceptions.py,sha256=An8MW-qB8g7EYLTxddnoIiyxNDQAqU9AmH8MrDFfnwQ,5804
40
- howler/common/hexdump.py,sha256=zo8u0SZp5Z-_0IWWmlWMmQami1FAUlkENrhKeR5nVfM,1407
41
- howler/common/iprange.py,sha256=h1wdSEalWPX_78cHpKfzxICP_qYTVJqhrk7rwZsjf4U,4258
42
40
  howler/common/loader.py,sha256=r_XMh2kZwPnIMPMRR0NUWX5X4S7RaAZpWqetSrtzy_4,5361
43
41
  howler/common/logging/__init__.py,sha256=kJ3Wi0TfB1zypeb7u5ReRzip6mxJgLR_SAMQQzvvngU,7855
44
42
  howler/common/logging/audit.py,sha256=iR42dJ8hhuXQFN60yyXcms31dPtgZSHBQlHH_VZTEZc,3528
@@ -80,7 +78,7 @@ howler/helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
78
  howler/helper/azure.py,sha256=Sbm4kpCaU1IcQQS9gtoJEF8myGnqhlAP4Lb_zJSCFvo,1543
81
79
  howler/helper/discover.py,sha256=7hSDjjIafokl0INpSeGjp76lrrInC3LC3UsyIAfTZLE,2201
82
80
  howler/helper/hit.py,sha256=YX46oxUB5mtlsrcpnmFKsokojGd7mi9mUULAeiEMe0w,7839
83
- howler/helper/oauth.py,sha256=1yzPBVgI0SbeUzit9f2T42vYpLukzc8oaWxZYyOG9YI,9497
81
+ howler/helper/oauth.py,sha256=RRvYCqTEJaVnwqZjl2s6S9gzXWh9xHRdJjCRXE_MH94,9523
84
82
  howler/helper/search.py,sha256=cU9bDPQv2LIRNQ2j-8rAqePCYq9CrgOtS76PrziSgG8,2892
85
83
  howler/helper/workflow.py,sha256=fsYhjeZo1foM0J8AW3nMjTEJOAnh9R6L0f4ZL12pE4E,4803
86
84
  howler/helper/ws.py,sha256=ONxC7DFYGQKpp0AmrFqQLeIyxOMD4nHk5i6lFyWOtqo,15911
@@ -173,7 +171,7 @@ howler/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
173
171
  howler/services/action_service.py,sha256=AuNRvZs7sFGUveaoptD8ouzs39jdZJidmsp-fIocZo4,3977
174
172
  howler/services/analytic_service.py,sha256=pOJRCDn6I523XSVLBo49fL70Mz5VDgjJ5CBYhemQeBk,4272
175
173
  howler/services/auth_service.py,sha256=TX51z-Fu4i3JvxIdU1JsJ3vzgGPVWNL1lNQJMxKpkZ8,11678
176
- howler/services/config_service.py,sha256=J5FCttgsHr6kMLGAPIW-8r8aGYwmX4YzsOyBG6yoGGM,4489
174
+ howler/services/config_service.py,sha256=XZ-UPxIuDYobWXrf8Q-0_hHZ-HRjj5qiWLyAoLFskuI,4496
177
175
  howler/services/dossier_service.py,sha256=5jq7KZMgBNh165rN5pZD_oVuZP-oBsdACHDSV74ps-I,9839
178
176
  howler/services/event_service.py,sha256=4PG2iBXjh1V8QnXcbUZSiKJeHs6V9hRWT9SKrzQFIPY,2864
179
177
  howler/services/hit_service.py,sha256=VNsEhi6Tcoqkjsw8G71FWBj7xcKwdvET9mITYAKmzsM,32278
@@ -182,7 +180,7 @@ howler/services/lucene_service.py,sha256=K_tS39hJCXUCfN_zgbIgbfcfM3gaQNheFXrwbV_
182
180
  howler/services/notebook_service.py,sha256=_MWllCnuVxt7lCcvWghXnaS926FbvBRE3DrBt--zO7U,3968
183
181
  howler/services/overview_service.py,sha256=wDIm7DGjQ6Dvt4dNQ-57jbet8v6oGHxM857VezgHf7M,1539
184
182
  howler/services/template_service.py,sha256=pwcHtYNoIkDuaXQ1bSXeDgxETP59PF1YCTwGzHsnXkA,1695
185
- howler/services/user_service.py,sha256=BWU9X75ofehRBozPrkOFlq5DIFbaPbmqC5-I-1Fv79g,12069
183
+ howler/services/user_service.py,sha256=x91KLZD43yyvQmZsbdo8mFb_TMHBtqcVTOKh60jQLPE,12084
186
184
  howler/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
187
185
  howler/utils/annotations.py,sha256=GLuDbjbXp8esDji3qhQY_uQyOWVqfIdpF_zs2t0IaMI,878
188
186
  howler/utils/chunk.py,sha256=NoVDKzZkO8O92xXk0s0Pny2g7It9BX0PqWbknmnRSFg,895
@@ -194,7 +192,7 @@ howler/utils/path.py,sha256=DfOU4i4zSs4wchHoE8iE7aWVLkTxiC_JRGepF2hBYBk,690
194
192
  howler/utils/socket_utils.py,sha256=nz1SklC9xBHUSfHyTJjpq3mbozX1GDf01WzdGxfaUII,2212
195
193
  howler/utils/str_utils.py,sha256=HE8Hqh2HlOLaj16w0H9zKOyDJLp-f1LQ50y_WeGZaEk,8389
196
194
  howler/utils/uid.py,sha256=p9dsqyvZ-lpiAuzZWCPCeEM99kdk0Ly9czf04HNdSuw,1341
197
- howler_api-3.0.0.dev351.dist-info/METADATA,sha256=miH88Z0F8VyzzfdKaXfDQXg_efAuaOxaHn5StdAYWGg,2804
198
- howler_api-3.0.0.dev351.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
199
- howler_api-3.0.0.dev351.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
200
- howler_api-3.0.0.dev351.dist-info/RECORD,,
195
+ howler_api-3.0.0.dev361.dist-info/METADATA,sha256=zsVoOU9_C2GMioaWIilcLuXlA2frF05eKdbJ_B-WZxY,2804
196
+ howler_api-3.0.0.dev361.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
197
+ howler_api-3.0.0.dev361.dist-info/entry_points.txt,sha256=Lu9SBGvwe0wczJHmc-RudC24lmQk7tv3ZBXon9RIihg,259
198
+ howler_api-3.0.0.dev361.dist-info/RECORD,,
howler/common/hexdump.py DELETED
@@ -1,48 +0,0 @@
1
- import binascii
2
-
3
- from howler.utils.chunk import chunk
4
-
5
- FILTER = b"".join([bytes([x]) if x in range(32, 127) else b"." for x in range(256)])
6
-
7
-
8
- def dump(binary: bytes, size: int = 2, sep: bytes = b" ") -> bytes:
9
- "Convert a binary file into a hexadecimal representation"
10
- hexstr = binascii.hexlify(binary)
11
- return sep.join(chunk(hexstr, size))
12
-
13
-
14
- def hexdump(
15
- binary: bytes,
16
- length: int = 16,
17
- indent: str = "",
18
- indent_size: int = 0,
19
- newline: str = "\n",
20
- prefix_offset: int = 0,
21
- ) -> str:
22
- """Create a string buffer that shows the given data in hexdump format.
23
-
24
- src -> source buffer
25
- length = 16 -> number of bytes per line
26
- indent = "" -> indentation before each lines
27
- indent_size = 0 -> number of time to repeat that indentation
28
- newline = "\n" -> chars used as newline char
29
-
30
- Example of output:
31
- 00000000: 48 54 54 50 2F 31 2E 31 20 34 30 34 20 4E 6F 74 HTTP/1.1 404 Not
32
- 00000010: 20 46 6F 75 6E 64 0D 0A 43 6F 6E 74 Found..Cont
33
- ...
34
- """
35
- generator = chunk(binary, length)
36
- line_frmt = "%%s%%08X: %%-%ss %%s" % ((length * 3) - 1)
37
-
38
- out = [
39
- line_frmt
40
- % (
41
- indent * indent_size,
42
- prefix_offset + (addr * length),
43
- dump(d).decode(),
44
- d.translate(FILTER).decode(),
45
- )
46
- for addr, d in enumerate(generator)
47
- ]
48
- return newline.join(out)
howler/common/iprange.py DELETED
@@ -1,171 +0,0 @@
1
- from math import log
2
- from socket import inet_aton
3
- from struct import pack, unpack
4
-
5
- from howler.common.exceptions import InvalidRangeException
6
-
7
- # If you are tempted to extend this module to add support for IPv6 (or some
8
- # similar invasive change) take a look at using PySubnetTree and extending it
9
- # to allow arbitrary ranges instead.
10
-
11
-
12
- def _convert(ip):
13
- return unpack("!I", inet_aton(ip))[0]
14
-
15
-
16
- def _next(lower, upper):
17
- size = 2
18
- while lower + size - 1 <= upper and _valid(lower, lower + size - 1):
19
- size *= 2
20
-
21
- return int(size / 2)
22
-
23
-
24
- def _valid(lower, upper):
25
- return lower & (upper - lower) == 0
26
-
27
-
28
- # noinspection PyPep8Naming
29
- class _dict(dict): # noqa: N801
30
- pass
31
-
32
-
33
- def ip_to_int(ip):
34
- if isinstance(ip, int):
35
- return ip
36
-
37
- return _convert(ip)
38
-
39
-
40
- # noinspection PyTypeChecker
41
- class RangeTable(object):
42
- """Efficient storage of IPv4 ranges and lookup of IPv4 addresses."""
43
-
44
- def __init__(self):
45
- self.clear()
46
- self._trie = _dict()
47
-
48
- def _add_cidr(self, lower, upper, value):
49
- if not _valid(lower, upper):
50
- # The public add_range method should ensure this never happens.
51
- raise InvalidRangeException("invalid range: %d-%d" % (lower, upper))
52
-
53
- size = upper - lower
54
- points = 3 - int(log(size + 1, 256))
55
-
56
- lower = self._to_path(lower)
57
- upper = self._to_path(upper)
58
-
59
- for x in range(lower[points], upper[points] + 1):
60
- self._add_path(lower[:points] + (x,), value)
61
-
62
- def _add_path(self, path, value):
63
- trie = self._trie
64
- for point in path[:-1]:
65
- d = trie.get(point, _dict())
66
- if not isinstance(d, _dict):
67
- prev = d
68
- d = _dict()
69
- d.update({x: prev for x in range(256)})
70
- trie[point] = d
71
- trie = d
72
- trie[path[-1]] = value
73
-
74
- def _add_range(self, lower, upper, value):
75
- while lower <= upper:
76
- size = _next(lower, upper)
77
- self._add_cidr(lower, lower + size - 1, value)
78
- lower += size
79
-
80
- def _follow_path(self, path):
81
- entry = self._trie
82
- while isinstance(entry, _dict):
83
- entry = entry.get(path[0], None)
84
- path = path[1:]
85
- return entry
86
-
87
- @staticmethod
88
- def _to_path(integer):
89
- return unpack("B" * 4, pack("!I", integer))
90
-
91
- def __getitem__(self, key):
92
- return self._follow_path(self._to_path(ip_to_int(key)))
93
-
94
- def __setitem__(self, key, value):
95
- if isinstance(key, int):
96
- self._add_cidr(key, key, value)
97
- return
98
-
99
- span = key.split("-", 1)
100
- if len(span) == 1:
101
- span = key.split("/", 1)
102
- if len(span) == 1:
103
- span.append(span[0])
104
-
105
- span[0] = _convert(span[0].strip())
106
- if span[1].find(".") == -1:
107
- mask = 2 ** (32 - int(span[1])) - 1
108
- span[0] -= span[0] & mask
109
- span[1] = span[0] | mask
110
- else:
111
- span[1] = _convert(span[1].strip())
112
-
113
- self._add_range(span[0], span[1], value)
114
-
115
- def add_range(self, lower, upper, value):
116
- lower = ip_to_int(lower)
117
- upper = ip_to_int(upper)
118
-
119
- self._add_range(lower, upper, value)
120
-
121
- while lower <= upper:
122
- size = _next(lower, upper)
123
- self._add_cidr(lower, lower + size - 1, value)
124
- lower += size
125
-
126
- def clear(self):
127
- self._trie = _dict() # pylint:disable=W0201
128
-
129
- def dump(self):
130
- from pprint import pformat
131
-
132
- return pformat(self._trie)
133
-
134
-
135
- PRIVATE_NETWORKS = [
136
- "10.0.0.0/8",
137
- "172.16.0.0/12",
138
- "192.168.0.0/16",
139
- ]
140
-
141
- RESERVED_NETWORKS = [
142
- "0.0.0.0/8",
143
- "100.64.0.0/10",
144
- "127.0.0.0/8",
145
- "169.254.0.0/16",
146
- "192.0.0.0/24",
147
- "192.0.2.0/24",
148
- "192.88.99.0/24",
149
- "198.18.0.0/15",
150
- "198.51.100.0/24",
151
- "203.0.113.0/24",
152
- "240.0.0.0/4",
153
- "224.0.0.0/4",
154
- "255.255.255.255/32",
155
- ]
156
-
157
- _private_ips = RangeTable()
158
- for cidr in PRIVATE_NETWORKS:
159
- _private_ips[cidr] = True
160
-
161
- _reserved_ips = RangeTable()
162
- for cidr in RESERVED_NETWORKS:
163
- _reserved_ips[cidr] = True
164
-
165
-
166
- def is_ip_private(ip):
167
- return _private_ips[ip] or False
168
-
169
-
170
- def is_ip_reserved(ip):
171
- return _private_ips[ip] or _reserved_ips[ip] or False