PyFunceble-dev 4.3.0a5__py3-none-any.whl → 4.3.0a10__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.
- PyFunceble/checker/availability/base.py +0 -1
- PyFunceble/checker/availability/domain.py +0 -1
- PyFunceble/checker/availability/extras/base.py +18 -18
- PyFunceble/checker/availability/extras/etoxic.py +0 -1
- PyFunceble/checker/availability/extras/parked.py +1 -2
- PyFunceble/checker/availability/extras/rules.py +64 -5
- PyFunceble/checker/availability/extras/subject_switch.py +1 -1
- PyFunceble/checker/availability/ip.py +0 -1
- PyFunceble/checker/availability/url.py +0 -1
- PyFunceble/checker/reputation/base.py +0 -1
- PyFunceble/cli/processes/migrator.py +0 -1
- PyFunceble/cli/processes/workers/base.py +5 -3
- PyFunceble/cli/processes/workers/dir_files_sorter.py +0 -1
- PyFunceble/cli/processes/workers/file_sorter.py +0 -1
- PyFunceble/cli/processes/workers/file_sorter_base.py +0 -1
- PyFunceble/cli/processes/workers/migrator.py +0 -1
- PyFunceble/cli/processes/workers/miner.py +7 -9
- PyFunceble/cli/processes/workers/tester.py +2 -6
- PyFunceble/cli/scripts/iana.py +11 -1
- PyFunceble/cli/scripts/public_suffix.py +14 -1
- PyFunceble/cli/system/launcher.py +27 -14
- PyFunceble/cli/utils/version.py +27 -15
- PyFunceble/config/loader.py +43 -12
- PyFunceble/downloader/base.py +13 -3
- PyFunceble/helpers/download.py +147 -20
- PyFunceble/helpers/hash.py +10 -18
- PyFunceble/query/dns/nameserver.py +12 -6
- PyFunceble/query/dns/query_tool.py +3 -1
- PyFunceble/query/http_status_code.py +9 -7
- PyFunceble/query/platform.py +7 -8
- PyFunceble/query/requests/adapter/base.py +36 -4
- PyFunceble/query/requests/adapter/http.py +2 -3
- PyFunceble/query/requests/adapter/https.py +2 -2
- PyFunceble/query/requests/requester.py +70 -41
- PyFunceble/storage.py +1 -4
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/METADATA +173 -68
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/RECORD +41 -41
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/WHEEL +1 -1
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/LICENSE +0 -0
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/entry_points.txt +0 -0
- {PyFunceble_dev-4.3.0a5.dist-info → PyFunceble_dev-4.3.0a10.dist-info}/top_level.txt +0 -0
PyFunceble/config/loader.py
CHANGED
@@ -66,6 +66,7 @@ from yaml.error import MarkedYAMLError
|
|
66
66
|
import PyFunceble.cli.storage
|
67
67
|
import PyFunceble.storage
|
68
68
|
from PyFunceble.config.compare import ConfigComparison
|
69
|
+
from PyFunceble.dataset.user_agent import UserAgentDataset
|
69
70
|
from PyFunceble.downloader.iana import IANADownloader
|
70
71
|
from PyFunceble.downloader.public_suffix import PublicSuffixDownloader
|
71
72
|
from PyFunceble.downloader.user_agents import UserAgentsDownloader
|
@@ -438,19 +439,20 @@ class ConfigLoader:
|
|
438
439
|
else:
|
439
440
|
destination = dest
|
440
441
|
|
441
|
-
DownloadHelper(
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
442
|
+
DownloadHelper(
|
443
|
+
src,
|
444
|
+
certificate_validation=(
|
445
|
+
PyFunceble.storage.CONFIGURATION.verify_ssl_certificate
|
446
|
+
if PyFunceble.storage.CONFIGURATION
|
447
|
+
else True
|
448
|
+
),
|
449
|
+
own_proxy_handler=True,
|
450
|
+
proxies=config["proxies"],
|
451
|
+
).download_text(destination=destination)
|
450
452
|
|
451
453
|
try:
|
452
454
|
config = self.dict_helper.from_yaml_file(self.path_to_config)
|
453
|
-
except MarkedYAMLError:
|
455
|
+
except (MarkedYAMLError, FileNotFoundError):
|
454
456
|
self.file_helper.set_path(self.path_to_default_config).copy(
|
455
457
|
self.path_to_config
|
456
458
|
)
|
@@ -474,6 +476,32 @@ class ConfigLoader:
|
|
474
476
|
|
475
477
|
self.dict_helper.set_subject(config).to_yaml_file(self.path_to_config)
|
476
478
|
|
479
|
+
if self.file_helper.set_path(self.path_to_overwrite_config).exists():
|
480
|
+
# Early load of the overwrite configuration to allow usage of defined
|
481
|
+
# proxy settings.
|
482
|
+
overwrite_data = self.dict_helper.from_yaml_file(
|
483
|
+
self.path_to_overwrite_config
|
484
|
+
)
|
485
|
+
|
486
|
+
if isinstance(overwrite_data, dict):
|
487
|
+
config = Merge(overwrite_data).into(config)
|
488
|
+
else: # pragma: no cover ## Just make it visible to end-user.
|
489
|
+
self.file_helper.write("")
|
490
|
+
|
491
|
+
# Now we preset the storage to enforce the usage of the configuration
|
492
|
+
# in any downloads.
|
493
|
+
PyFunceble.storage.CONFIGURATION = Box(
|
494
|
+
config,
|
495
|
+
)
|
496
|
+
|
497
|
+
if not self.is_already_loaded():
|
498
|
+
self.install_missing_infrastructure_files()
|
499
|
+
self.download_dynamic_infrastructure_files()
|
500
|
+
download_remote_config(
|
501
|
+
self.remote_config_location, self.path_to_remote_config
|
502
|
+
)
|
503
|
+
download_remote_config(self.path_to_config)
|
504
|
+
|
477
505
|
if (
|
478
506
|
self.path_to_remote_config
|
479
507
|
and self.file_helper.set_path(self.path_to_remote_config).exists()
|
@@ -484,14 +512,14 @@ class ConfigLoader:
|
|
484
512
|
config = Merge(remote_data).into(config)
|
485
513
|
|
486
514
|
if self.file_helper.set_path(self.path_to_overwrite_config).exists():
|
515
|
+
# Load the overwrite configuration again to ensure that user defined
|
516
|
+
# settings are always applied - last one wins.
|
487
517
|
overwrite_data = self.dict_helper.from_yaml_file(
|
488
518
|
self.path_to_overwrite_config
|
489
519
|
)
|
490
520
|
|
491
521
|
if isinstance(overwrite_data, dict):
|
492
522
|
config = Merge(overwrite_data).into(config)
|
493
|
-
else: # pragma: no cover ## Just make it visible to end-user.
|
494
|
-
self.file_helper.write("")
|
495
523
|
|
496
524
|
return config
|
497
525
|
|
@@ -562,6 +590,9 @@ class ConfigLoader:
|
|
562
590
|
if "proxy" in config and config["proxy"]:
|
563
591
|
PyFunceble.storage.PROXY = Box(config["proxy"])
|
564
592
|
|
593
|
+
# Early load user agents to allow usage of defined user agents.
|
594
|
+
UserAgentDataset().get_latest()
|
595
|
+
|
565
596
|
return self
|
566
597
|
|
567
598
|
def destroy(self, keep_custom: bool = False) -> "ConfigLoader":
|
PyFunceble/downloader/base.py
CHANGED
@@ -107,6 +107,7 @@ class DownloaderBase:
|
|
107
107
|
_config_dir: Optional[str] = None
|
108
108
|
_destination: Optional[str] = None
|
109
109
|
_download_link: Optional[str] = None
|
110
|
+
_download_helper: Optional[DownloadHelper] = None
|
110
111
|
|
111
112
|
dict_helper: Optional[DictHelper] = None
|
112
113
|
|
@@ -130,6 +131,17 @@ class DownloaderBase:
|
|
130
131
|
if self.DEFAULT_FILENAME is not None:
|
131
132
|
self.destination = os.path.join(self.config_dir, self.DEFAULT_FILENAME)
|
132
133
|
|
134
|
+
self._download_helper = DownloadHelper(
|
135
|
+
self.download_link,
|
136
|
+
own_proxy_handler=True,
|
137
|
+
proxies=PyFunceble.storage.PROXY,
|
138
|
+
certificate_validation=(
|
139
|
+
PyFunceble.storage.CONFIGURATION.verify_ssl_certificate
|
140
|
+
if PyFunceble.storage.CONFIGURATION
|
141
|
+
else True
|
142
|
+
),
|
143
|
+
)
|
144
|
+
|
133
145
|
@property
|
134
146
|
def authorized(self) -> bool:
|
135
147
|
"""
|
@@ -343,8 +355,6 @@ class DownloaderBase:
|
|
343
355
|
if not hasattr(self, "download_link") or not self.download_link:
|
344
356
|
raise PyFunceble.downloader.exceptions.NoDownloadLinkGiven()
|
345
357
|
|
346
|
-
if
|
347
|
-
destination=self.destination
|
348
|
-
):
|
358
|
+
if self._download_helper.download_text(destination=self.destination):
|
349
359
|
self.set_current_downtime()
|
350
360
|
self.save_all_downtimes()
|
PyFunceble/helpers/download.py
CHANGED
@@ -65,13 +65,29 @@ class DownloadHelper:
|
|
65
65
|
Simplification of the downloads.
|
66
66
|
|
67
67
|
:param str url:
|
68
|
-
:param int
|
68
|
+
:param int retries:
|
69
69
|
The number of time we have to retry before raising an exception.
|
70
|
+
:param bool certificate_validation:
|
71
|
+
The state of the certificate validation.
|
72
|
+
:param bool own_proxy_handler:
|
73
|
+
Whether we should use our own proxy handler or not.
|
74
|
+
:param dict proxies:
|
75
|
+
The proxy to use.
|
76
|
+
|
77
|
+
When :code:`own_proxy_handler` is set to :code:`True`, the proxies
|
78
|
+
are expected to come from the global configuration.
|
79
|
+
Otherwise, the proxies are expected to be a dictionary as defined
|
80
|
+
by the requests library.
|
70
81
|
"""
|
71
82
|
|
72
83
|
_url: Optional[str] = None
|
73
84
|
_certificate_validation: bool = True
|
74
85
|
_retries: int = 3
|
86
|
+
_proxies: Optional[dict] = None
|
87
|
+
|
88
|
+
_session = None
|
89
|
+
_own_proxy_handler: Optional[bool] = True
|
90
|
+
_proxies: Optional[dict] = None
|
75
91
|
|
76
92
|
def __init__(
|
77
93
|
self,
|
@@ -79,15 +95,42 @@ class DownloadHelper:
|
|
79
95
|
*,
|
80
96
|
certificate_validation: bool = True,
|
81
97
|
retries: int = 3,
|
98
|
+
own_proxy_handler: Optional[bool] = True,
|
99
|
+
proxies: Optional[dict] = None,
|
82
100
|
) -> None:
|
83
|
-
if url:
|
101
|
+
if url is not None:
|
84
102
|
self.url = url
|
85
103
|
|
86
|
-
if
|
87
|
-
self.
|
104
|
+
if proxies is not None:
|
105
|
+
self.proxies = proxies
|
88
106
|
|
89
|
-
|
90
|
-
|
107
|
+
self.retries = retries
|
108
|
+
self.certificate_validation = bool(certificate_validation)
|
109
|
+
self.own_proxy_handler = own_proxy_handler
|
110
|
+
|
111
|
+
@property
|
112
|
+
def session(self) -> requests.Session:
|
113
|
+
"""
|
114
|
+
Provides the current state of the :code:`_session` attribute.
|
115
|
+
"""
|
116
|
+
|
117
|
+
if not self._session:
|
118
|
+
if self.own_proxy_handler:
|
119
|
+
# pylint: disable=import-outside-toplevel
|
120
|
+
from PyFunceble.query.requests.requester import Requester
|
121
|
+
|
122
|
+
self._session = Requester(proxy_pattern=self.proxies)
|
123
|
+
else:
|
124
|
+
self._session = requests.Session()
|
125
|
+
self._session.proxies = self.proxies
|
126
|
+
|
127
|
+
retries = Retry(total=self.retries, backoff_factor=3)
|
128
|
+
adapter = HTTPAdapter(max_retries=retries)
|
129
|
+
|
130
|
+
self._session.mount("http://", adapter)
|
131
|
+
self._session.mount("https://", adapter)
|
132
|
+
|
133
|
+
return self._session
|
91
134
|
|
92
135
|
@property
|
93
136
|
def url(self) -> Optional[str]:
|
@@ -208,7 +251,103 @@ class DownloadHelper:
|
|
208
251
|
|
209
252
|
return self
|
210
253
|
|
211
|
-
|
254
|
+
@property
|
255
|
+
def own_proxy_handler(self) -> Optional[bool]:
|
256
|
+
"""
|
257
|
+
Provides the current state of the :code:`own_proxy_handler` attribute.
|
258
|
+
"""
|
259
|
+
|
260
|
+
return self._own_proxy_handler
|
261
|
+
|
262
|
+
@own_proxy_handler.setter
|
263
|
+
def own_proxy_handler(self, value: bool) -> None:
|
264
|
+
"""
|
265
|
+
Sets the state of the own proxy handler.
|
266
|
+
|
267
|
+
:param value:
|
268
|
+
The value to set.
|
269
|
+
|
270
|
+
:raise TypeError:
|
271
|
+
When :code:`value` is not a :py:class:`bool`.
|
272
|
+
"""
|
273
|
+
|
274
|
+
if not isinstance(value, bool):
|
275
|
+
raise TypeError(f"<value> should be {bool}, {type(value)} given.")
|
276
|
+
|
277
|
+
self._own_proxy_handler = value
|
278
|
+
|
279
|
+
if value:
|
280
|
+
# We force the recreation of the session.
|
281
|
+
self._session = None
|
282
|
+
|
283
|
+
def set_own_proxy_handler(self, value: bool) -> "DownloadHelper":
|
284
|
+
"""
|
285
|
+
Sets the state of the own proxy handler.
|
286
|
+
|
287
|
+
:param value:
|
288
|
+
The value to set.
|
289
|
+
"""
|
290
|
+
|
291
|
+
self.own_proxy_handler = value
|
292
|
+
|
293
|
+
return self
|
294
|
+
|
295
|
+
@property
|
296
|
+
def proxies(self) -> Optional[dict]:
|
297
|
+
"""
|
298
|
+
Provides the current state of the :code:`_proxies` attribute.
|
299
|
+
"""
|
300
|
+
|
301
|
+
return self._proxies
|
302
|
+
|
303
|
+
@proxies.setter
|
304
|
+
def proxies(self, value: Optional[dict]) -> None:
|
305
|
+
"""
|
306
|
+
Sets the proxy to use.
|
307
|
+
|
308
|
+
:param value:
|
309
|
+
The proxy to use.
|
310
|
+
|
311
|
+
When :code:`own_proxy_handler` is set to :code:`True`, the proxies
|
312
|
+
are expected to come from the global configuration.
|
313
|
+
Otherwise, the proxies are expected to be a dictionary as defined
|
314
|
+
by the requests library.
|
315
|
+
|
316
|
+
:raise TypeError:
|
317
|
+
When :code:`value` is not a :py:class:`dict`.
|
318
|
+
"""
|
319
|
+
|
320
|
+
if not isinstance(value, dict):
|
321
|
+
raise TypeError(f"<value> should be {dict}, {type(value)} given.")
|
322
|
+
|
323
|
+
self._proxies = value
|
324
|
+
|
325
|
+
if value:
|
326
|
+
# We force the recreation of the session.
|
327
|
+
self._session = None
|
328
|
+
|
329
|
+
def set_proxies(self, value: Optional[dict]) -> "DownloadHelper":
|
330
|
+
"""
|
331
|
+
Sets the proxy to use.
|
332
|
+
|
333
|
+
:param value:
|
334
|
+
The proxy to use.
|
335
|
+
|
336
|
+
When :code:`own_proxy_handler` is set to :code:`True`, the proxies
|
337
|
+
are expected to come from the global configuration.
|
338
|
+
Otherwise, the proxies are expected to be a dictionary as defined
|
339
|
+
by the requests library.
|
340
|
+
"""
|
341
|
+
|
342
|
+
self.proxies = value
|
343
|
+
|
344
|
+
return self
|
345
|
+
|
346
|
+
def download_text(
|
347
|
+
self,
|
348
|
+
*,
|
349
|
+
destination: Optional[str] = None,
|
350
|
+
) -> str:
|
212
351
|
"""
|
213
352
|
Download the body of the set url.
|
214
353
|
|
@@ -224,15 +363,7 @@ class DownloadHelper:
|
|
224
363
|
:raise UnableToDownload: When could not unable to download the URL.
|
225
364
|
"""
|
226
365
|
|
227
|
-
|
228
|
-
|
229
|
-
retries = Retry(total=self.retries, backoff_factor=3)
|
230
|
-
adapter = HTTPAdapter(max_retries=retries)
|
231
|
-
|
232
|
-
session.mount("http://", adapter)
|
233
|
-
session.mount("https://", adapter)
|
234
|
-
|
235
|
-
req = session.get(self.url, verify=self.certificate_validation)
|
366
|
+
req = self.session.get(self.url, verify=self.certificate_validation)
|
236
367
|
|
237
368
|
if req.status_code == 200:
|
238
369
|
response = req.text
|
@@ -240,12 +371,8 @@ class DownloadHelper:
|
|
240
371
|
if destination and isinstance(destination, str):
|
241
372
|
FileHelper(destination).write(req.text, overwrite=True)
|
242
373
|
|
243
|
-
adapter.close()
|
244
|
-
req.close()
|
245
374
|
return response
|
246
375
|
|
247
|
-
adapter.close()
|
248
|
-
session.close()
|
249
376
|
raise PyFunceble.helpers.exceptions.UnableToDownload(
|
250
377
|
f"{req.url} (retries: {self.retries} | status code: {req.status_code})"
|
251
378
|
)
|
PyFunceble/helpers/hash.py
CHANGED
@@ -50,11 +50,9 @@ License:
|
|
50
50
|
limitations under the License.
|
51
51
|
"""
|
52
52
|
|
53
|
+
import hashlib
|
53
54
|
from typing import Optional, Union
|
54
55
|
|
55
|
-
from cryptography.hazmat.backends import default_backend
|
56
|
-
from cryptography.hazmat.primitives import hashes
|
57
|
-
|
58
56
|
from PyFunceble.helpers.file import FileHelper
|
59
57
|
|
60
58
|
|
@@ -68,7 +66,7 @@ class HashHelper:
|
|
68
66
|
:raise ValueError: When the given algo is not known.
|
69
67
|
"""
|
70
68
|
|
71
|
-
_algo: str = "
|
69
|
+
_algo: str = "sha512_224"
|
72
70
|
|
73
71
|
def __init__(self, algo: Optional[str] = None):
|
74
72
|
if algo is not None:
|
@@ -97,11 +95,12 @@ class HashHelper:
|
|
97
95
|
if not isinstance(value, str):
|
98
96
|
raise TypeError(f"<value> should be {str}, {type(value)} given.")
|
99
97
|
|
100
|
-
value = value.
|
98
|
+
value = value.lower()
|
101
99
|
|
102
|
-
if not
|
100
|
+
if value not in hashlib.algorithms_available:
|
103
101
|
raise ValueError(
|
104
|
-
f"<value> ({value!r}) in an unknown algorithm
|
102
|
+
f"<value> ({value!r}) in an unknown algorithm "
|
103
|
+
f"({hashlib.algorithms_available})."
|
105
104
|
)
|
106
105
|
|
107
106
|
self._algo = value
|
@@ -118,13 +117,6 @@ class HashHelper:
|
|
118
117
|
|
119
118
|
return self
|
120
119
|
|
121
|
-
def __get_hash(self) -> hashes.Hash:
|
122
|
-
"""
|
123
|
-
Provides the Hash to use.
|
124
|
-
"""
|
125
|
-
|
126
|
-
return hashes.Hash(getattr(hashes, self.algo)(), backend=default_backend())
|
127
|
-
|
128
120
|
def hash_file(self, file_path: str) -> str:
|
129
121
|
"""
|
130
122
|
Hashes the content of the given file.
|
@@ -135,7 +127,7 @@ class HashHelper:
|
|
135
127
|
|
136
128
|
block_size = 4096
|
137
129
|
|
138
|
-
digest = self.
|
130
|
+
digest = hashlib.new(self.algo)
|
139
131
|
|
140
132
|
with FileHelper(file_path).open("rb") as file_stream:
|
141
133
|
block = file_stream.read(block_size)
|
@@ -144,7 +136,7 @@ class HashHelper:
|
|
144
136
|
digest.update(block)
|
145
137
|
block = file_stream.read(block_size)
|
146
138
|
|
147
|
-
return digest.
|
139
|
+
return digest.hexdigest()
|
148
140
|
|
149
141
|
def hash_data(self, data: Union[str, bytes]) -> str:
|
150
142
|
"""
|
@@ -163,7 +155,7 @@ class HashHelper:
|
|
163
155
|
if isinstance(data, str):
|
164
156
|
data = data.encode()
|
165
157
|
|
166
|
-
digest = self.
|
158
|
+
digest = hashlib.new(self.algo)
|
167
159
|
digest.update(data)
|
168
160
|
|
169
|
-
return digest.
|
161
|
+
return digest.hexdigest()
|
@@ -50,6 +50,7 @@ License:
|
|
50
50
|
limitations under the License.
|
51
51
|
"""
|
52
52
|
|
53
|
+
import ipaddress
|
53
54
|
from typing import List, Optional, Tuple
|
54
55
|
|
55
56
|
import dns.exception
|
@@ -79,15 +80,19 @@ class Nameservers:
|
|
79
80
|
|
80
81
|
protocol: Optional[str] = None
|
81
82
|
|
82
|
-
domain_syntax_checker: DomainSyntaxChecker =
|
83
|
-
url_syntax_checker: URLSyntaxChecker =
|
84
|
-
url2netloc: Url2Netloc =
|
83
|
+
domain_syntax_checker: Optional[DomainSyntaxChecker] = None
|
84
|
+
url_syntax_checker: Optional[URLSyntaxChecker] = None
|
85
|
+
url2netloc: Optional[Url2Netloc] = None
|
85
86
|
|
86
87
|
def __init__(
|
87
88
|
self, nameserver: Optional[List[str]] = None, protocol: str = "TCP"
|
88
89
|
) -> None:
|
89
90
|
self.protocol = protocol
|
90
91
|
|
92
|
+
self.domain_syntax_checker = DomainSyntaxChecker()
|
93
|
+
self.url_syntax_checker = URLSyntaxChecker()
|
94
|
+
self.url2netloc = Url2Netloc()
|
95
|
+
|
91
96
|
if nameserver is not None:
|
92
97
|
self.set_nameservers(nameserver)
|
93
98
|
|
@@ -141,7 +146,10 @@ class Nameservers:
|
|
141
146
|
|
142
147
|
result = []
|
143
148
|
|
144
|
-
|
149
|
+
try:
|
150
|
+
_ = ipaddress.ip_address(nameserver)
|
151
|
+
result.append(nameserver)
|
152
|
+
except ValueError:
|
145
153
|
try:
|
146
154
|
result.extend(
|
147
155
|
[
|
@@ -161,8 +169,6 @@ class Nameservers:
|
|
161
169
|
)
|
162
170
|
except dns.exception.DNSException:
|
163
171
|
pass
|
164
|
-
else:
|
165
|
-
result.append(nameserver)
|
166
172
|
|
167
173
|
PyFunceble.facility.Logger.debug(
|
168
174
|
"IP from nameserver (%r):\n%r", nameserver, result
|
@@ -96,7 +96,7 @@ class DNSQueryTool:
|
|
96
96
|
x.name: x.value for x in dns.rdatatype.RdataType
|
97
97
|
}
|
98
98
|
|
99
|
-
nameservers: Nameservers =
|
99
|
+
nameservers: Optional[Nameservers] = None
|
100
100
|
_query_record_type: int = dns.rdatatype.RdataType.ANY
|
101
101
|
|
102
102
|
_subject: Optional[str] = None
|
@@ -120,6 +120,8 @@ class DNSQueryTool:
|
|
120
120
|
trust_server: Optional[bool] = None,
|
121
121
|
delay: Optional[bool] = None,
|
122
122
|
) -> None:
|
123
|
+
self.nameservers = Nameservers()
|
124
|
+
|
123
125
|
if nameservers is not None:
|
124
126
|
self.nameservers.set_nameservers(nameservers)
|
125
127
|
else: # pragma: no cover ## I'm not playing with system resolver.
|
@@ -55,9 +55,9 @@ import socket
|
|
55
55
|
from typing import Optional, Union
|
56
56
|
|
57
57
|
import PyFunceble.facility
|
58
|
-
import PyFunceble.factory
|
59
58
|
import PyFunceble.storage
|
60
59
|
from PyFunceble.converter.url2netloc import Url2Netloc
|
60
|
+
from PyFunceble.query.requests.requester import Requester
|
61
61
|
|
62
62
|
|
63
63
|
class HTTPStatusCode:
|
@@ -75,6 +75,7 @@ class HTTPStatusCode:
|
|
75
75
|
_verify_certificate: bool = True
|
76
76
|
_allow_redirects: bool = False
|
77
77
|
_url2netloc: Optional[Url2Netloc] = None
|
78
|
+
requester: Optional[Requester] = None
|
78
79
|
|
79
80
|
def __init__(
|
80
81
|
self,
|
@@ -103,6 +104,7 @@ class HTTPStatusCode:
|
|
103
104
|
self.allow_redirects = self.STD_ALLOW_REDIRECTS
|
104
105
|
|
105
106
|
self._url2netloc = Url2Netloc()
|
107
|
+
self.requester = Requester(config=PyFunceble.storage.CONFIGURATION)
|
106
108
|
|
107
109
|
def ensure_subject_is_given(func): # pylint: disable=no-self-argument
|
108
110
|
"""
|
@@ -334,7 +336,7 @@ class HTTPStatusCode:
|
|
334
336
|
""" # pylint: disable=line-too-long
|
335
337
|
|
336
338
|
try:
|
337
|
-
req =
|
339
|
+
req = self.requester.get(
|
338
340
|
self.subject,
|
339
341
|
timeout=self.timeout,
|
340
342
|
verify=self.verify_certificate,
|
@@ -363,12 +365,12 @@ class HTTPStatusCode:
|
|
363
365
|
|
364
366
|
return req.status_code
|
365
367
|
except (
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
368
|
+
self.requester.exceptions.RequestException,
|
369
|
+
self.requester.exceptions.InvalidSchema,
|
370
|
+
self.requester.exceptions.InvalidURL,
|
371
|
+
self.requester.exceptions.MissingSchema,
|
370
372
|
socket.timeout,
|
371
|
-
|
373
|
+
self.requester.urllib3_exceptions.InvalidHeader,
|
372
374
|
):
|
373
375
|
pass
|
374
376
|
|
PyFunceble/query/platform.py
CHANGED
@@ -702,9 +702,7 @@ class PlatformQueryTool:
|
|
702
702
|
"shuffle": True,
|
703
703
|
}
|
704
704
|
|
705
|
-
if "none" in self.checker_priority:
|
706
|
-
params["shuffle"] = True
|
707
|
-
else:
|
705
|
+
if "none" not in self.checker_priority:
|
708
706
|
params["checker_type_priority"] = ",".join(self.checker_priority)
|
709
707
|
|
710
708
|
if "none" not in self.checker_exclude:
|
@@ -717,9 +715,9 @@ class PlatformQueryTool:
|
|
717
715
|
timeout=self.timeout * 10,
|
718
716
|
)
|
719
717
|
|
720
|
-
response_json = response.json()
|
721
|
-
|
722
718
|
if response.status_code == 200:
|
719
|
+
response_json = response.json()
|
720
|
+
|
723
721
|
PyFunceble.facility.Logger.debug(
|
724
722
|
"Successfully pulled next %r contracts. Response: %r", response_json
|
725
723
|
)
|
@@ -772,9 +770,9 @@ class PlatformQueryTool:
|
|
772
770
|
timeout=self.timeout * 10,
|
773
771
|
)
|
774
772
|
|
775
|
-
|
773
|
+
if response.status_code in (202, 200):
|
774
|
+
response_json = response.json()
|
776
775
|
|
777
|
-
if response.status_code == 200:
|
778
776
|
PyFunceble.facility.Logger.debug(
|
779
777
|
"Successfully delivered contract: %r. Response: %r",
|
780
778
|
contract_data,
|
@@ -786,6 +784,7 @@ class PlatformQueryTool:
|
|
786
784
|
)
|
787
785
|
|
788
786
|
return response_json
|
787
|
+
response_json = {}
|
789
788
|
except (requests.RequestException, json.decoder.JSONDecodeError):
|
790
789
|
response_json = {}
|
791
790
|
|
@@ -796,7 +795,7 @@ class PlatformQueryTool:
|
|
796
795
|
"Finished to deliver contract: %r", contract_data
|
797
796
|
)
|
798
797
|
|
799
|
-
return
|
798
|
+
return response_json
|
800
799
|
|
801
800
|
@ensure_modern_api
|
802
801
|
def push(
|
@@ -50,12 +50,13 @@ License:
|
|
50
50
|
limitations under the License.
|
51
51
|
"""
|
52
52
|
|
53
|
+
import secrets
|
53
54
|
from typing import Optional
|
54
55
|
|
55
56
|
import requests.adapters
|
57
|
+
import requests.exceptions
|
56
58
|
import requests.models
|
57
59
|
|
58
|
-
import PyFunceble.storage
|
59
60
|
from PyFunceble.checker.syntax.ip import IPSyntaxChecker
|
60
61
|
from PyFunceble.query.dns.query_tool import DNSQueryTool
|
61
62
|
|
@@ -66,10 +67,15 @@ class RequestAdapterBase(requests.adapters.HTTPAdapter):
|
|
66
67
|
adapter.
|
67
68
|
"""
|
68
69
|
|
70
|
+
NOT_RESOLVED_STD_HOSTNAME: str = (
|
71
|
+
f"{secrets.token_hex(12)}.mock-resolver.pyfunceble.com"
|
72
|
+
)
|
73
|
+
|
69
74
|
resolving_cache: dict = {}
|
70
75
|
resolving_use_cache: bool = False
|
71
76
|
timeout: float = 5.0
|
72
77
|
proxy_pattern: dict = {}
|
78
|
+
ssl_context: Optional[dict] = None
|
73
79
|
|
74
80
|
def __init__(self, *args, **kwargs):
|
75
81
|
if "timeout" in kwargs:
|
@@ -93,6 +99,10 @@ class RequestAdapterBase(requests.adapters.HTTPAdapter):
|
|
93
99
|
else:
|
94
100
|
self.proxy_pattern = {}
|
95
101
|
|
102
|
+
if "ssl_context" in kwargs:
|
103
|
+
self.ssl_context = kwargs["ssl_context"]
|
104
|
+
del kwargs["ssl_context"]
|
105
|
+
|
96
106
|
super().__init__(*args, **kwargs)
|
97
107
|
|
98
108
|
@staticmethod
|
@@ -102,9 +112,7 @@ class RequestAdapterBase(requests.adapters.HTTPAdapter):
|
|
102
112
|
given domain.
|
103
113
|
"""
|
104
114
|
|
105
|
-
raise
|
106
|
-
"Could not resolve."
|
107
|
-
)
|
115
|
+
raise requests.exceptions.ConnectionError("Could not resolve.")
|
108
116
|
|
109
117
|
@staticmethod
|
110
118
|
def extract_extension(subject: str) -> Optional[str]:
|
@@ -286,3 +294,27 @@ class RequestAdapterBase(requests.adapters.HTTPAdapter):
|
|
286
294
|
return self.resolve_with_cache(hostname)
|
287
295
|
return self.resolve_without_cache(hostname)
|
288
296
|
return None
|
297
|
+
|
298
|
+
def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs):
|
299
|
+
"""
|
300
|
+
Overwrite the upstream :code:`init_poolmanager` method to ensure that we
|
301
|
+
use our own ssl context - when given.
|
302
|
+
"""
|
303
|
+
|
304
|
+
_ = pool_kwargs.pop("ssl_context", None)
|
305
|
+
|
306
|
+
return super().init_poolmanager(
|
307
|
+
connections, maxsize, block, ssl_context=self.ssl_context, **pool_kwargs
|
308
|
+
)
|
309
|
+
|
310
|
+
def proxy_manager_for(self, proxy, **proxy_kwargs):
|
311
|
+
"""
|
312
|
+
Overwrite the upstream :code:`proxy_manager_for` method to ensure that we
|
313
|
+
use our own ssl context - when given.
|
314
|
+
"""
|
315
|
+
|
316
|
+
_ = proxy_kwargs.pop("ssl_context", None)
|
317
|
+
|
318
|
+
return super().proxy_manager_for(
|
319
|
+
proxy, ssl_context=self.ssl_context, **proxy_kwargs
|
320
|
+
)
|