atomicshop 2.3.10__py3-none-any.whl → 2.4.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.

Potentially problematic release.


This version of atomicshop might be problematic. Click here for more details.

atomicshop/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.3.10'
4
+ __version__ = '2.4.0'
@@ -355,3 +355,20 @@ def check_if_suffix_is_in_string(string: str, suffix: str) -> bool:
355
355
  """
356
356
 
357
357
  return string.endswith(suffix)
358
+
359
+
360
+ def convert_string_to_colon_separated(string: str, number_of_characters: int = 2) -> str:
361
+ """
362
+ Function converts string to colon separated string.
363
+ :param string: string, to convert.
364
+ :param number_of_characters: integer, number of characters to separate.
365
+
366
+ Example:
367
+ convert_string_to_colon_separated('1234567890', 2)
368
+ Result:
369
+ '12:34:56:78:90'
370
+
371
+ :return: string.
372
+ """
373
+
374
+ return ':'.join([string[i:i+number_of_characters] for i in range(0, len(string), number_of_characters)])
@@ -3,7 +3,85 @@ Site for checking OIDs:
3
3
  https://oidref.com/1.3.6.1.5.5.7.3.1
4
4
  """
5
5
 
6
+
7
+ import ssl
8
+
9
+ from .wrappers import cryptographyw
10
+ from .print_api import print_api
11
+
12
+
6
13
  # Valid for 3 years from now
7
14
  # Max validity is 39 months:
8
15
  # https://casecurity.org/2015/02/19/ssl-certificate-validity-periods-limited-to-39-months-starting-in-april/
9
16
  SECONDS_NOT_AFTER_3_YEARS = 3 * 365 * 24 * 60 * 60
17
+
18
+
19
+ def is_certificate_in_store(certificate, issuer_only: bool = False, thumbprint_only: bool = False):
20
+ """
21
+ The function will check if the certificate is installed in the Windows certificate store.
22
+
23
+ :param certificate: x509 object, certificate to check.
24
+ :param issuer_only: bool, if True, will check only by the certificate issuer common name is installed in the store.
25
+ The problem that the issuer common name is not unique, so it can be installed multiple times.
26
+ :param thumbprint_only: bool, if True, will check only by the certificate thumbprint is installed in the store.
27
+ The problem that searching by the thumbprint will not tell you if there are multiple certificates with the same
28
+ issuer name.
29
+ :return: bool, True if certificate is installed, False if not.
30
+ """
31
+
32
+ # Make sure the certificate is x509.Certificate object.
33
+ certificate = cryptographyw.convert_object_to_x509(certificate)
34
+ # Get the certificate thumbprint.
35
+ thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate)
36
+ issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(certificate)
37
+
38
+ # for store in ["CA", "ROOT", "MY"]:
39
+ for cert, encoding, trust in ssl.enum_certificates("ROOT"):
40
+ store_certificate = cryptographyw.convert_object_to_x509(cert)
41
+ store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
42
+ store_thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(store_certificate)
43
+
44
+ if issuer_only:
45
+ if store_issuer_common_name == issuer_common_name:
46
+ return True, certificate
47
+ elif thumbprint_only:
48
+ if store_thumbprint == thumbprint:
49
+ return True, certificate
50
+ elif not issuer_only and not thumbprint_only:
51
+ if store_thumbprint == thumbprint and store_issuer_common_name == issuer_common_name:
52
+ return True, certificate
53
+
54
+
55
+ def get_certificates_by_issuer_name(issuer_name: str, print_kwargs: dict = None):
56
+ """
57
+ The function will return all certificates with the specified issuer name.
58
+
59
+ :param issuer_name: string, issuer name to search for.
60
+ :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
61
+
62
+ :return: list, of certificates with the specified issuer name.
63
+ """
64
+
65
+ if not print_kwargs:
66
+ print_kwargs = {}
67
+
68
+ certificates_list = []
69
+
70
+ for cert, encoding, trust in ssl.enum_certificates("ROOT"):
71
+ store_certificate = cryptographyw.convert_object_to_x509(cert)
72
+ store_issuer_common_name: str = cryptographyw.get_issuer_common_name_from_x509(store_certificate)
73
+
74
+ if store_issuer_common_name == issuer_name:
75
+ certificates_list.append(store_certificate)
76
+
77
+ if certificates_list:
78
+ for certificate_single in certificates_list:
79
+ issuer_name = cryptographyw.get_issuer_common_name_from_x509(certificate_single)
80
+ thumbprint = cryptographyw.get_sha1_thumbprint_from_x509(certificate_single)
81
+ message = f'Issuer name: {issuer_name} | Thumbprint: {thumbprint}'
82
+ print_api(message, **print_kwargs)
83
+ else:
84
+ message = f'No certificates with issuer name: {issuer_name}'
85
+ print_api(message, **print_kwargs)
86
+
87
+ return certificates_list
atomicshop/hashing.py CHANGED
@@ -1,10 +1,19 @@
1
1
  import hashlib
2
2
  import sys
3
+ from typing import Literal, Union
3
4
 
4
5
  from . import web
5
6
 
6
7
 
7
- def hash_bytes(bytes_object: bytes, hash_algo: str = 'sha256'):
8
+ # def hash_bytes(bytes_object: bytes, hash_algo: Union[Literal['sha256', 'md5', 'sha1'], str] = 'sha256') -> str:
9
+ def hash_bytes(bytes_object: bytes, hash_algo: str = 'sha256') -> str:
10
+ """
11
+ The function will return hash of the bytes object with specified algorithm.
12
+ :param bytes_object: bytes object to hash.
13
+ :param hash_algo: string, file hashing algorithm. Default is 'sha256'. Basically the string can be any algorithm
14
+ that hashlib supports. Example: hashlib.sha256(), hashlib.md5(), hashlib.sha1()
15
+ :return: string, hash of the bytes object.
16
+ """
8
17
  # Equivalent to sha256 example: hashlib.sha256(bytes_object).hexdigest()
9
18
  return getattr(hashlib, hash_algo)(bytes_object).hexdigest()
10
19
 
atomicshop/print_api.py CHANGED
@@ -209,7 +209,12 @@ def print_status(
209
209
 
210
210
 
211
211
  def print_status_of_list(
212
- list_instance: list, prefix_string: str, current_state, suffix_string: str = str(), **kwargs):
212
+ list_instance: list,
213
+ prefix_string: str,
214
+ current_state,
215
+ suffix_string: str = str(),
216
+ same_line: bool = True,
217
+ **kwargs):
213
218
  """
214
219
  The function will print specified variables in a specific format on the same line, based on 'same_line' parameter.
215
220
 
@@ -219,6 +224,8 @@ def print_status_of_list(
219
224
  :param current_state: numeric representation of current state.
220
225
  :param suffix_string: string, since the lines are printed on the same line, it can happen that one line can be
221
226
  longer than the other. If shorter line come after the longer one, it will align on top of the longer line.
227
+ :param same_line: Boolean, if True, the lines will be printed on the same line (but not the last line),
228
+ otherwise on different lines.
222
229
 
223
230
  For example check the 'print_status' function.
224
231
 
@@ -228,15 +235,11 @@ def print_status_of_list(
228
235
 
229
236
  final_state = len(list_instance)
230
237
 
231
- if final_state:
232
- message = f'{prefix_string}{current_state} / {final_state}{suffix_string}'
233
- else:
234
- message = f'{prefix_string}{current_state}{suffix_string}'
235
-
236
- if current_state != final_state:
237
- same_line = True
238
- else:
239
- same_line = False
238
+ if same_line:
239
+ if current_state != final_state:
240
+ same_line = True
241
+ else:
242
+ same_line = False
240
243
 
241
244
  print_status(prefix_string=prefix_string, current_state=current_state, final_state=final_state,
242
245
  suffix_string=suffix_string, same_line=same_line, **kwargs)
@@ -1,6 +1,11 @@
1
+ from typing import Union
2
+ import os
3
+
1
4
  from ..print_api import print_api
5
+ from ..file_io import file_io
2
6
 
3
7
  from cryptography import x509
8
+ from cryptography.x509 import Certificate
4
9
  from cryptography.hazmat.primitives.asymmetric import rsa
5
10
  from cryptography.hazmat.primitives import serialization
6
11
  from cryptography.hazmat.primitives import hashes
@@ -17,7 +22,50 @@ OID_TO_BUILDER_CLASS_EXTENSION_NAME: dict = {
17
22
  }
18
23
 
19
24
 
20
- def convert_pem_to_x509_object(certificate):
25
+ def convert_object_to_x509(certificate):
26
+ """Convert certificate to x509 object.
27
+
28
+ :param certificate: any object that can be converted to x509 object.
29
+ Supported types:
30
+ string that is path to file will be imported as bytes object abd converted to x509.Certificate
31
+ After check if it's PEM or DER format.
32
+ string that is PEM certificate will be converted to bytes, then x509.Certificate
33
+ bytes of PEM or DER will be converted to x509.Certificate.
34
+ x509.Certificate will be returned as is.
35
+ :return: certificate in x509 object of 'cryptography' module.
36
+ """
37
+
38
+ # Check if 'certificate' is a string and a path.
39
+ if isinstance(certificate, str) and os.path.isfile(certificate):
40
+ # Import the certificate from the path.
41
+ certificate = file_io.read_file(certificate, file_mode='rb')
42
+
43
+ # Check if 'certificate' is a bytes object and PEM format.
44
+ # We're checking if it starts with '-----BEGIN ' since the pem certificate can include PRIVATE KEY and will be
45
+ # in the beginning of the file.
46
+ if (isinstance(certificate, bytes) and certificate.startswith(b'-----BEGIN ') and
47
+ b'-----BEGIN CERTIFICATE-----' in certificate):
48
+ # Convert the PEM certificate to x509 object.
49
+ certificate = convert_pem_to_x509_object(certificate)
50
+ # Check if 'certificate' is a bytes object and DER format.
51
+ elif isinstance(certificate, bytes) and certificate.startswith(b'\x30'):
52
+ # Convert the DER certificate to x509 object.
53
+ certificate = convert_der_to_x509_object(certificate)
54
+ # Check if 'certificate' is a string object and PEM format.
55
+ elif (isinstance(certificate, str) and certificate.startswith('-----BEGIN ') and
56
+ '-----BEGIN CERTIFICATE-----' in certificate):
57
+ # Convert the PEM certificate to x509 object.
58
+ certificate = convert_pem_to_x509_object(certificate)
59
+ # Check if 'certificate' is a x509 object.
60
+ elif isinstance(certificate, Certificate):
61
+ pass
62
+ else:
63
+ raise ValueError(f'Unsupported certificate type: {type(certificate)}')
64
+
65
+ return certificate
66
+
67
+
68
+ def convert_pem_to_x509_object(certificate: Union[str, bytes]) -> x509.Certificate:
21
69
  """Convert PEM certificate to x509 object.
22
70
 
23
71
  :param certificate: string or bytes - certificate to convert.
@@ -51,6 +99,16 @@ def convert_x509_object_to_pem_bytes(certificate) -> bytes:
51
99
  return certificate.public_bytes(serialization.Encoding.PEM)
52
100
 
53
101
 
102
+ def convert_x509_object_to_der_bytes(certificate) -> bytes:
103
+ """Convert x509 object to DER certificate.
104
+
105
+ :param certificate: certificate in x509 object of 'cryptography' module.
106
+ :return: bytes of certificate in DER byte string format.
107
+ """
108
+
109
+ return certificate.public_bytes(serialization.Encoding.DER)
110
+
111
+
54
112
  def generate_private_key(public_exponent: int = 65537, bits: int = 2048):
55
113
  private_key = rsa.generate_private_key(
56
114
  public_exponent=public_exponent,
@@ -186,3 +244,41 @@ def _get_extensions_properties(certificate):
186
244
  sub_keys = vars(ext._value)
187
245
 
188
246
  print(f'{ext.oid._name}: {sub_keys}')
247
+
248
+
249
+ def get_sha1_thumbprint_from_x509(certificate) -> str:
250
+ """Get SHA1 thumbprint of the certificate.
251
+
252
+ :param certificate: certificate in x509 object of cryptography module.
253
+ :return: string, SHA1 thumbprint of the certificate.
254
+ """
255
+
256
+ return certificate.fingerprint(hashes.SHA1()).hex()
257
+
258
+
259
+ def get_sha1_thumbprint_from_pem(pem_certificate: bytes) -> str:
260
+ """Get SHA1 thumbprint of the certificate.
261
+
262
+ :param pem_certificate: bytes of PEM certificate.
263
+ :return: string, SHA1 thumbprint of the certificate.
264
+ """
265
+
266
+ # Convert PEM certificate to x509 object.
267
+ certificate = convert_pem_to_x509_object(pem_certificate)
268
+
269
+ return get_sha1_thumbprint_from_x509(certificate)
270
+
271
+
272
+ def get_issuer_common_name_from_x509(certificate) -> str:
273
+ """Get issuer common name from x509 certificate.
274
+
275
+ :param certificate: certificate in x509 object of cryptography module.
276
+ :return: string, issuer common name.
277
+ """
278
+
279
+ try:
280
+ issuer = certificate.issuer.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value
281
+ except IndexError:
282
+ issuer = certificate.issuer.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)[0].value
283
+
284
+ return issuer
@@ -2,3 +2,4 @@ FACT_ADDRESS: str = 'http://localhost:5000'
2
2
  FIRMWARE_ENDPOINT: str = '/rest/firmware'
3
3
  FILE_OBJECT_ENDPOINT: str = '/rest/file_object'
4
4
  STATUS_ENDPOINT: str = '/rest/status'
5
+ STATISTICS_ENDPOINT: str = '/rest/statistics'
@@ -0,0 +1,14 @@
1
+ from .import rest_firmware, rest_statistics
2
+
3
+
4
+ def endpoint_router(config: dict):
5
+ """
6
+ Route the endpoint.
7
+ :param config: dict, configuration dictionary.
8
+ :return:
9
+ """
10
+
11
+ if config['method'] == 'upload_firmware':
12
+ rest_firmware.upload_files(config['firmwares_path'], config['data'])
13
+ elif config['method'] == 'stats':
14
+ rest_statistics.get_statistics()
@@ -0,0 +1,25 @@
1
+ # noinspection PyPackageRequirements
2
+ import requests
3
+
4
+ from . import fact_config
5
+ from ... print_api import print_api
6
+
7
+
8
+ def get_statistics():
9
+ """
10
+ Get statistics of the FACT service.
11
+ :return:
12
+ """
13
+
14
+ url: str = f'{fact_config.FACT_ADDRESS}{fact_config.STATISTICS_ENDPOINT}'
15
+ response: requests.Response = requests.get(url)
16
+
17
+ # Check response status code.
18
+ if response.status_code == 200:
19
+ # Print response.
20
+ print_api(response.json())
21
+ else:
22
+ # Print error.
23
+ print_api('Error: ' + str(response.status_code), error_type=True, logger_method='critical')
24
+
25
+ return response
@@ -5,7 +5,7 @@ from . import fact_config
5
5
  from ... print_api import print_api
6
6
 
7
7
 
8
- def get_global_status():
8
+ def get_status():
9
9
  """
10
10
  Get status of the FACT service.
11
11
  :return:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.3.10
3
+ Version: 2.4.0
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,8 +1,8 @@
1
- atomicshop/__init__.py,sha256=cSWQrIYXEBH2eRRcq8COHKP9DdkxYb9aTv-LT2Qbt70,123
1
+ atomicshop/__init__.py,sha256=EVyUsXjC3TAEyHm-m9w_eqPpPjqt2ZZwkU-s8sUyUAo,122
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/appointment_management.py,sha256=N3wVGJgrqJfsj_lqiRfaL3FxMEe57by5Stzanh189mk,7263
4
4
  atomicshop/archiver.py,sha256=E4dgAuh6ARtAWRW6Q0RdnMRMzsE_S1NjMiajHRIVG9s,5537
5
- atomicshop/certificates.py,sha256=nxuq6HPBT7RfwRTSipOxoRHBS-nZLsaHR9m6UdHmDn4,297
5
+ atomicshop/certificates.py,sha256=J-cmd6Rpq3zZyzsOH-GcdqIXdg2UwM8_E9mg7XtUph8,3787
6
6
  atomicshop/command_line_processing.py,sha256=u5yT9Ger_cu7ni5ID0VFlRbVD46ARHeNC9tRM-_YXrQ,1038
7
7
  atomicshop/console_output.py,sha256=G-6jxnWooT1nJSaPxcCqIuw8S22R_0lOJcfrdovRhwE,1372
8
8
  atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
@@ -14,14 +14,14 @@ atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
14
14
  atomicshop/filesystem.py,sha256=mS7o_o01HiC12G79z2_txvzM6YLNAWrfNC9IhOJRq6w,23684
15
15
  atomicshop/functions.py,sha256=VqLjxAxhaxUr-Ad8P1cw9bZGdZpbtqfCaXQyHf3CM9g,509
16
16
  atomicshop/github_wrapper.py,sha256=7pZkhliP4vdcdeVtbgTDEzBS3lUw3-mp5PMWUDA19V0,4347
17
- atomicshop/hashing.py,sha256=6523xFxuW0Cm1pcJCE63NWeiwt3al3t-FXLv0f0Kzpg,2989
17
+ atomicshop/hashing.py,sha256=k_HXR7FnPUzLUKk8EiewJ_gLFBlWncZluiBwzplFMWs,3548
18
18
  atomicshop/http_parse.py,sha256=nrf2rZcprLqtW8HVrV7TCZ1iTBcWRRy-mXIlAOzcaJs,9703
19
19
  atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
20
20
  atomicshop/ip_addresses.py,sha256=fvBwLFGbcNV87s_UzZZs0MO-TPwDEak_0SB4_syhefM,691
21
21
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
22
22
  atomicshop/pbtkmultifile_argparse.py,sha256=aEk8nhvoQVu-xyfZosK3ma17CwIgOjzO1erXXdjwtS4,4574
23
23
  atomicshop/permissions.py,sha256=CYTDVOI0jh9ks0ZLnnOuPzppgCszFEc9-92DTkVTYi4,522
24
- atomicshop/print_api.py,sha256=IQo5wIJBUXcgz_asYQbAJIhKrA1JP5CEIoVqwqDRJ9c,11402
24
+ atomicshop/print_api.py,sha256=3n1CoiXvDcDGg00n5gEmQYInHryIhWbcpNjVobO1Gao,11468
25
25
  atomicshop/process.py,sha256=Jn0CQRGt962hhq6CHz2LCtA0Jf3o13r-l5mHTcLvGFg,7064
26
26
  atomicshop/process_name_cmd.py,sha256=TNAK6kQZm5JKWzEW6QLqVHEG98ZLNDQiSS4YwDk8V8c,3830
27
27
  atomicshop/process_poller.py,sha256=t79SwTX_4scH2WIH_ziw27aodG1ibhEFWbsVsmTyOVA,10846
@@ -68,7 +68,7 @@ atomicshop/basics/lists.py,sha256=ZyTjHyvkta-4_xCG1P-LFMENELmgAYlDdPq4hMRAOR8,25
68
68
  atomicshop/basics/multiprocesses.py,sha256=GVeyF-r9Q6SAjpJ46eqkZQ4QUli554n-CAIE_W8pij8,958
69
69
  atomicshop/basics/numbers.py,sha256=FRjAH1Thk3z3ayxq0Ik6Wh93ELDRk1geyDYTv8amZBE,165
70
70
  atomicshop/basics/randoms.py,sha256=DmYLtnIhDK29tAQrGP1Nt-A-v8WC7WIEB8Edi-nk3N4,282
71
- atomicshop/basics/strings.py,sha256=e_jq1huII_JnE82fUnMPqirZIKfbS6axnxhxK6jJzkM,12919
71
+ atomicshop/basics/strings.py,sha256=fufYRPe-JUiwm_ENy7bmz-avQ6svAS0yEJ1Tuo3gXVA,13457
72
72
  atomicshop/basics/threads.py,sha256=xvgdDJdmgN0wmmARoZ-H7Kvl1GOcEbvgaeGL4M3Hcx8,2819
73
73
  atomicshop/basics/timeit_template.py,sha256=fYLrk-X_dhdVtnPU22tarrhhvlggeW6FdKCXM8zkX68,405
74
74
  atomicshop/basics/tracebacks.py,sha256=cNfh_oAwF55kSIdqtv3boHZQIoQI8TajxkTnwJwpweI,535
@@ -117,7 +117,7 @@ atomicshop/wrappers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
117
117
  atomicshop/wrappers/_process_wrapper_curl.py,sha256=XkZZXYl7D0Q6UfdWqy-18AvpU0yVp9i2BVD2qRcXlkk,841
118
118
  atomicshop/wrappers/_process_wrapper_tar.py,sha256=WUMZFKNrlG4nJP9tWZ51W7BR1j_pIjsjgyAStmWjRGs,655
119
119
  atomicshop/wrappers/configparserw.py,sha256=Li2yb3SL8p1GMRRd_r9dNVYuEKGdlQRPIwAHBc5YF1A,17201
120
- atomicshop/wrappers/cryptographyw.py,sha256=vOsDqyn4_aMOqYfArw5gB5bFNW21KJBDAcw22e80uxo,9239
120
+ atomicshop/wrappers/cryptographyw.py,sha256=H5NaHHDkr97QYhUrHFO9vY218u8k3N3Zgh6bQRnicUE,13140
121
121
  atomicshop/wrappers/ffmpegw.py,sha256=YKptcdNQC1wyPLRLvc24fIPr4_rj8IHH01UUzt6XFO0,6039
122
122
  atomicshop/wrappers/numpyw.py,sha256=sBV4gSKyr23kXTalqAb1oqttzE_2XxBooCui66jbAqc,1025
123
123
  atomicshop/wrappers/process_wrapper_pbtk.py,sha256=rB3izJqJxs4cv6aNi1mryxrfNqHClH6GywmGSlyI_5Y,688
@@ -127,11 +127,13 @@ atomicshop/wrappers/certauthw/certauth.py,sha256=hKedW0DOWlEigSNm8wu4SqHkCQsGJ1t
127
127
  atomicshop/wrappers/certauthw/certauthw.py,sha256=4WvhjANI7Kzqrr_nKmtA8Kf7B6rute_5wfP65gwQrjw,8082
128
128
  atomicshop/wrappers/ctyping/process_winapi.py,sha256=QcXL-ETtlSSkoT8F7pYle97ubGWsjYp8cx8HxkVMgAc,2762
129
129
  atomicshop/wrappers/factw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
130
- atomicshop/wrappers/factw/fact_config.py,sha256=rHraVpYAzTdR5RD1nhXmj3I4fT-k44VxT3FS4hyvyX0,176
130
+ atomicshop/wrappers/factw/fact_config.py,sha256=IbjM5MqjnTAi7iD--FJnC6pyNVrH9eruTRQFiideZY8,223
131
131
  atomicshop/wrappers/factw/get_file_data.py,sha256=ChKC0OjgjFlNubZQBwcGhRO3L2pccc27RLRlAMIUix4,1641
132
132
  atomicshop/wrappers/factw/rest_file_object.py,sha256=_utxe0-hQNKwBFFP3cmsLKmGlhU0UuJo67SCRfQ2aAk,2433
133
133
  atomicshop/wrappers/factw/rest_firmware.py,sha256=k2YvgH7qi_-oBDutoRUiEJ-2N_we2XOguCSmuC7UNDk,9486
134
- atomicshop/wrappers/factw/rest_status.py,sha256=1LmMniq3r5joCNj1RG2BaDUfDwTbK8-9iitkfKB69Ec,646
134
+ atomicshop/wrappers/factw/rest_router.py,sha256=xpVriLljpRAtUnEaxtVd5UDafHGJ1pFlMH8FqSl1pq8,402
135
+ atomicshop/wrappers/factw/rest_statistics.py,sha256=0no4yDZ5GSJbb8Hl8ZMyTahvNV1o7tilXJ9ifl7v4j4,651
136
+ atomicshop/wrappers/factw/rest_status.py,sha256=iWpn6RpaQEKDavKTaTTsolCJ-HGzIEeNyQxVyMQRUYQ,639
135
137
  atomicshop/wrappers/loggingw/checks.py,sha256=AGFsTsLxHQd1yAraa5popqLaGO9VM0KpcPGuSLn5ptU,719
136
138
  atomicshop/wrappers/loggingw/formatters.py,sha256=mUtcJJfmhLNrwUVYShXTmdu40dBaJu4TS8FiuTXI7ys,7189
137
139
  atomicshop/wrappers/loggingw/handlers.py,sha256=qm5Fbu8eDmlstMduUe5nKUlJU5IazFkSnQizz8Qt2os,5479
@@ -165,8 +167,8 @@ atomicshop/wrappers/socketw/socket_server_tester.py,sha256=VfNthyBvgI5tL9v3Qprh4
165
167
  atomicshop/wrappers/socketw/socket_wrapper.py,sha256=aXBwlEIJhFT0-c4i8iNlFx2It9VpCEpsv--5Oqcpxao,11624
166
168
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
167
169
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=t3dtDEfN47CfYVi0CW6Kc2QHTEeZVyYhc57IYYh5nmA,826
168
- atomicshop-2.3.10.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
169
- atomicshop-2.3.10.dist-info/METADATA,sha256=ib2ohSgt3uAj5QyzJZjeY-hissi7-YB24aRzYTV79DM,9586
170
- atomicshop-2.3.10.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
171
- atomicshop-2.3.10.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
172
- atomicshop-2.3.10.dist-info/RECORD,,
170
+ atomicshop-2.4.0.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
171
+ atomicshop-2.4.0.dist-info/METADATA,sha256=Ig9gE-rTTo9oTVxlzPiTaLPYLFaAc2R-jISyK_U1yJc,9585
172
+ atomicshop-2.4.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
173
+ atomicshop-2.4.0.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
174
+ atomicshop-2.4.0.dist-info/RECORD,,