osbot-utils 1.52.0__py3-none-any.whl → 1.54.0__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.
osbot_utils/utils/Http.py CHANGED
@@ -1,15 +1,22 @@
1
1
  import json
2
2
  import os
3
+ import re
3
4
  import socket
4
5
  import ssl
6
+ import unicodedata
5
7
  from time import sleep
6
- from urllib.parse import quote, urljoin, urlparse
8
+ from urllib.parse import quote, urljoin, urlparse, urlunparse
7
9
  from urllib.request import Request, urlopen
8
10
 
11
+ from osbot_utils.utils.Str import html_decode
12
+
13
+ from osbot_utils.utils.Misc import url_decode
14
+
9
15
  from osbot_utils.utils.Files import save_bytes_as_file, file_size, file_bytes, file_open_bytes, file_create
10
16
  from osbot_utils.utils.Python_Logger import Python_Logger
11
17
 
12
- URL_CHECK_HOST_ONLINE = 'https://www.google.com'
18
+ URL_CHECK_HOST_ONLINE = 'https://www.google.com'
19
+ URL_JOIN_SAFE__MAX_ITERATIONS = 5
13
20
 
14
21
  def current_host_offline(url_to_use=URL_CHECK_HOST_ONLINE):
15
22
  return current_host_online(url_to_use=url_to_use) is False
@@ -148,15 +155,34 @@ def url_join_safe(base_path, path=''):
148
155
  if not isinstance(base_path, str) or not isinstance(path, str):
149
156
  return None
150
157
 
151
- if not base_path.endswith('/'): # Ensure that the base path ends with '/'
158
+ max_iterations = URL_JOIN_SAFE__MAX_ITERATIONS
159
+
160
+ path = unicodedata.normalize('NFC', path)
161
+ path_normalised = path
162
+ for _ in range(max_iterations):
163
+ fixed_segments = []
164
+ for segment in path_normalised.split('/'):
165
+ segment_decoded = html_decode(url_decode(segment))
166
+ fixed_segment = re.sub(r'[^a-zA-Z0-9\-_.]+', '-', segment_decoded)
167
+ fixed_segment = fixed_segment.replace("..", "-")
168
+ if fixed_segment:
169
+ fixed_segments.append(fixed_segment)
170
+ path_cleaned = '/'.join(fixed_segments)
171
+
172
+ if path_cleaned == path_normalised:
173
+ break
174
+ path_normalised = path_cleaned
175
+ else:
176
+ return None # If we exit the loop without breaking, return None
177
+
178
+ if not base_path.endswith('/'): # Ensure that the base path ends with '/'
152
179
  base_path += '/'
153
180
 
154
- if path.startswith('/'): # Remove leading '/' from path
155
- path = path[1:]
181
+ if path_normalised.startswith('/'): # Remove leading '/' from path
182
+ path_normalised = path_normalised[1:]
156
183
 
157
- path_quoted = quote(path)
158
- path_normalised = path_quoted.replace("..", "") # Quote the path to encode special characters and prevent directory traversal
159
- joined_path = urljoin(base_path, path_normalised) # Join the base path and normalized path
184
+ path_quoted = quote(path_normalised, safe='/') # Quote the path to encode special characters
185
+ joined_path = urljoin(base_path, path_quoted) # Join the base path and normalized path
160
186
  parsed_base = urlparse(base_path) # Parse and verify the result
161
187
  parsed_joined = urlparse(joined_path)
162
188
 
@@ -4,8 +4,9 @@ import pickle
4
4
  import sys
5
5
  import types
6
6
  import typing
7
- from typing import Union
8
7
 
8
+ from typing import Union
9
+ from types import SimpleNamespace
9
10
  from osbot_utils.utils.Misc import list_set
10
11
  from osbot_utils.utils.Str import str_unicode_escape, str_max_width
11
12
 
@@ -120,6 +121,32 @@ def dict_remove(data, target):
120
121
  del data[target]
121
122
  return data
122
123
 
124
+
125
+ def dict_to_obj(target, class_name="_"):
126
+ DynamicClass = type(class_name, (SimpleNamespace,), {})
127
+ if isinstance(target, dict):
128
+ new_dict = {}
129
+ for key, value in target.items():
130
+ new_dict[key] = dict_to_obj(value, class_name=class_name) # Recursively convert elements in the dict
131
+ return DynamicClass(**new_dict)
132
+ elif isinstance(target, list): # Recursively convert elements in the list
133
+ return [dict_to_obj(item, class_name=class_name) for item in target]
134
+ elif isinstance(target, tuple): # Recursively convert elements in the tuple
135
+ return tuple(dict_to_obj(item, class_name=class_name) for item in target)
136
+
137
+ return target
138
+
139
+ def obj_to_dict(target): # Recursively converts an object (SimpleNamespace) back into a dictionary."""
140
+ if isinstance(target, SimpleNamespace): # Convert SimpleNamespace attributes to a dictionary
141
+ return {key: obj_to_dict(value) for key, value in target.__dict__.items()}
142
+ elif isinstance(target, list): # Handle lists: convert each item in the list
143
+ return [obj_to_dict(item) for item in target]
144
+ elif isinstance(target, tuple): # Handle tuples: convert each item and return as a tuple
145
+ return tuple(obj_to_dict(item) for item in target)
146
+ elif isinstance(target, set): # Handle sets: convert each item and return as a set
147
+ return {obj_to_dict(item) for item in target}
148
+ return target # Return non-object types as is
149
+
123
150
  def enum_from_value(enum_type, value):
124
151
  try:
125
152
  return enum_type[value] # Attempt to convert the value to an Enum member by name
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v1.52.0
1
+ v1.54.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: osbot_utils
3
- Version: 1.52.0
3
+ Version: 1.54.0
4
4
  Summary: OWASP Security Bot - Utils
5
5
  Home-page: https://github.com/owasp-sbot/OSBot-Utils
6
6
  License: MIT
@@ -22,7 +22,7 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  Powerful Python util methods and classes that simplify common apis and tasks.
24
24
 
25
- ![Current Release](https://img.shields.io/badge/release-v1.52.0-blue)
25
+ ![Current Release](https://img.shields.io/badge/release-v1.54.0-blue)
26
26
  [![codecov](https://codecov.io/gh/owasp-sbot/OSBot-Utils/graph/badge.svg?token=GNVW0COX1N)](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
27
27
 
28
28
 
@@ -280,13 +280,13 @@ osbot_utils/utils/Env.py,sha256=XMwF5BrtpoPJdOraswAFPrcQ3tRTocjqvA8I61eOCJw,5741
280
280
  osbot_utils/utils/Exceptions.py,sha256=KyOUHkXQ_6jDTq04Xm261dbEZuRidtsM4dgzNwSG8-8,389
281
281
  osbot_utils/utils/Files.py,sha256=7fdqbfFyo6Ow5Repi_dZAzHqGb0XYh6tDALYAy42pBY,22522
282
282
  osbot_utils/utils/Functions.py,sha256=0E6alPJ0fJpBiJgFOWooCOi265wSRyxxXAJ5CELBnso,3498
283
- osbot_utils/utils/Http.py,sha256=YHHHRpy_QtH-Q_jaSuDwWRl-mmKBiC0DzfDew3l7fgg,6079
283
+ osbot_utils/utils/Http.py,sha256=vFvD-xLkkXLTJvmYGourMLoUOfkZx_KBSLmo1RX73jM,7043
284
284
  osbot_utils/utils/Int.py,sha256=PmlUdU4lSwf4gJdmTVdqclulkEp7KPCVUDO6AcISMF4,116
285
285
  osbot_utils/utils/Json.py,sha256=7COxBlZRnpxtpNqpmzMPYkcKTnCok-s686nT27oiKEQ,6489
286
286
  osbot_utils/utils/Json_Cache.py,sha256=mLPkkDZN-3ZVJiDvV1KBJXILtKkTZ4OepzOsDoBPhWg,2006
287
287
  osbot_utils/utils/Lists.py,sha256=tPz5x5s3sRO97WZ_nsxREBPC5cwaHrhgaYBhsrffTT8,5599
288
288
  osbot_utils/utils/Misc.py,sha256=nODZT6p44B4xYiIiqfEeKYEErQiKR9SGthhGtZWGhkI,16804
289
- osbot_utils/utils/Objects.py,sha256=frOLTJsIhGye1j99StuIJSkOlPmPDNI3BaWWAr98MEc,15392
289
+ osbot_utils/utils/Objects.py,sha256=oiWF75BPahRtBRhFrQi_5Mv4wrqkjJnKAc_diw9CZdk,17321
290
290
  osbot_utils/utils/Png.py,sha256=V1juGp6wkpPigMJ8HcxrPDIP4bSwu51oNkLI8YqP76Y,1172
291
291
  osbot_utils/utils/Process.py,sha256=lr3CTiEkN3EiBx3ZmzYmTKlQoPdkgZBRjPulMxG-zdo,2357
292
292
  osbot_utils/utils/Python_Logger.py,sha256=tx8N6wRKL3RDHboDRKZn8SirSJdSAE9cACyJkxrThZ8,12792
@@ -298,8 +298,8 @@ osbot_utils/utils/Toml.py,sha256=SD6IA4-mrtoBXcI0dIGKV9POMQNd6WYKvmDQq7GQ6ZQ,143
298
298
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
299
299
  osbot_utils/utils/Zip.py,sha256=G6Hk_hDcm9yvWzhTKzhT0R_6f0NBIAchHqMxGb3kfh4,14037
300
300
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
301
- osbot_utils/version,sha256=8vEHTopueL8q72Dw7rD-UnsLBahO-qnshWhrIIA_f-A,8
302
- osbot_utils-1.52.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
303
- osbot_utils-1.52.0.dist-info/METADATA,sha256=oAWX7EihUIYgMTuzzWfOEO0z4XKdrRWi-J1ap0ksrlE,1266
304
- osbot_utils-1.52.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
305
- osbot_utils-1.52.0.dist-info/RECORD,,
301
+ osbot_utils/version,sha256=hHjnHP5jok2-ZCxznWXApdBqJOijIybOEGxQ_V0SOkM,8
302
+ osbot_utils-1.54.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
303
+ osbot_utils-1.54.0.dist-info/METADATA,sha256=EeBJ0nCvQtpsIHBmWWJbR73CCF3Ex6XCDu9QBRfGbAI,1266
304
+ osbot_utils-1.54.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
305
+ osbot_utils-1.54.0.dist-info/RECORD,,