appmesh 1.4.4__py3-none-any.whl → 1.4.6__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.
appmesh/http_client.py
CHANGED
@@ -8,9 +8,9 @@ from datetime import datetime
|
|
8
8
|
from enum import Enum, unique
|
9
9
|
from http import HTTPStatus
|
10
10
|
from typing import Optional, Tuple, Union
|
11
|
-
from urllib import parse
|
12
11
|
import aniso8601
|
13
12
|
import requests
|
13
|
+
import urllib
|
14
14
|
from .app import App
|
15
15
|
from .app_run import AppRun
|
16
16
|
from .app_output import AppOutput
|
@@ -279,27 +279,46 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
279
279
|
if resp.status_code == HTTPStatus.OK:
|
280
280
|
if "Access-Token" in resp.json():
|
281
281
|
self.jwt_token = resp.json()["Access-Token"]
|
282
|
-
elif resp.status_code == HTTPStatus.
|
282
|
+
elif resp.status_code == HTTPStatus.PRECONDITION_REQUIRED and "Totp-Challenge" in resp.json():
|
283
283
|
challenge = resp.json()["Totp-Challenge"]
|
284
|
-
|
285
|
-
AppMeshClient.Method.POST,
|
286
|
-
path="/appmesh/totp/validate",
|
287
|
-
header={
|
288
|
-
"Username": base64.b64encode(user_name.encode()).decode(),
|
289
|
-
"Totp-Challenge": base64.b64encode(challenge.encode()).decode(),
|
290
|
-
"Totp": totp_code,
|
291
|
-
"Expire-Seconds": self._parse_duration(timeout_seconds),
|
292
|
-
},
|
293
|
-
)
|
294
|
-
if resp.status_code == HTTPStatus.OK:
|
295
|
-
if "Access-Token" in resp.json():
|
296
|
-
self.jwt_token = resp.json()["Access-Token"]
|
297
|
-
else:
|
298
|
-
raise Exception(resp.text)
|
284
|
+
self.validate_totp(user_name, challenge, totp_code, timeout_seconds)
|
299
285
|
else:
|
300
286
|
raise Exception(resp.text)
|
301
287
|
return self.jwt_token
|
302
288
|
|
289
|
+
def validate_totp(self, username: str, challenge: str, code: str, timeout: Union[int, str] = DURATION_ONE_WEEK_ISO) -> str:
|
290
|
+
"""Validate TOTP challenge and obtain a new JWT token.
|
291
|
+
|
292
|
+
Args:
|
293
|
+
username (str): Username to validate
|
294
|
+
challenge (str): Challenge string from server
|
295
|
+
code (str): TOTP code to validate
|
296
|
+
timeout (Union[int, str], optional): Token expiry timeout.
|
297
|
+
Accepts ISO 8601 duration format (e.g., 'P1Y2M3DT4H5M6S', 'P1W') or seconds.
|
298
|
+
Defaults to DURATION_ONE_WEEK_ISO.
|
299
|
+
|
300
|
+
Returns:
|
301
|
+
str: New JWT token if validation succeeds
|
302
|
+
|
303
|
+
Raises:
|
304
|
+
Exception: If validation fails or server returns error
|
305
|
+
"""
|
306
|
+
resp = self._request_http(
|
307
|
+
AppMeshClient.Method.POST,
|
308
|
+
path="/appmesh/totp/validate",
|
309
|
+
header={
|
310
|
+
"Username": base64.b64encode(username.encode()).decode(),
|
311
|
+
"Totp": code,
|
312
|
+
"Totp-Challenge": base64.b64encode(challenge.encode()).decode(),
|
313
|
+
"Expire-Seconds": self._parse_duration(timeout),
|
314
|
+
},
|
315
|
+
)
|
316
|
+
if resp.status_code == HTTPStatus.OK:
|
317
|
+
if "Access-Token" in resp.json():
|
318
|
+
self.jwt_token = resp.json()["Access-Token"]
|
319
|
+
return self.jwt_token
|
320
|
+
raise Exception(resp.text)
|
321
|
+
|
303
322
|
def logoff(self) -> bool:
|
304
323
|
"""Log out of the current session from the server.
|
305
324
|
|
@@ -377,7 +396,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
377
396
|
return self._parse_totp_uri(totp_uri).get("secret")
|
378
397
|
raise Exception(resp.text)
|
379
398
|
|
380
|
-
def setup_totp(self, totp_code: str) ->
|
399
|
+
def setup_totp(self, totp_code: str) -> str:
|
381
400
|
"""Set up 2FA for the current user.
|
382
401
|
|
383
402
|
Args:
|
@@ -426,13 +445,13 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
426
445
|
dict: eextract parameters
|
427
446
|
"""
|
428
447
|
parsed_info = {}
|
429
|
-
parsed_uri = parse.urlparse(totp_uri)
|
448
|
+
parsed_uri = urllib.parse.urlparse(totp_uri)
|
430
449
|
|
431
450
|
# Extract label from the path
|
432
451
|
parsed_info["label"] = parsed_uri.path[1:] # Remove the leading slash
|
433
452
|
|
434
453
|
# Extract parameters from the query string
|
435
|
-
query_params = parse.parse_qs(parsed_uri.query)
|
454
|
+
query_params = urllib.parse.parse_qs(parsed_uri.query)
|
436
455
|
for key, value in query_params.items():
|
437
456
|
parsed_info[key] = value[0]
|
438
457
|
return parsed_info
|
@@ -934,7 +953,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
934
953
|
|
935
954
|
with open(file=local_file, mode="rb") as fp:
|
936
955
|
encoder = MultipartEncoder(fields={"filename": os.path.basename(remote_file), "file": ("filename", fp, "application/octet-stream")})
|
937
|
-
header = {"File-Path": remote_file, "Content-Type": encoder.content_type}
|
956
|
+
header = {"File-Path": urllib.parse.quote(remote_file), "Content-Type": encoder.content_type}
|
938
957
|
|
939
958
|
# Include file attributes (permissions, owner, group) if requested
|
940
959
|
if apply_file_attributes:
|
@@ -1101,7 +1120,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1101
1120
|
Returns:
|
1102
1121
|
requests.Response: HTTP response
|
1103
1122
|
"""
|
1104
|
-
rest_url = parse.urljoin(self.server_url, path)
|
1123
|
+
rest_url = urllib.parse.urljoin(self.server_url, path)
|
1105
1124
|
|
1106
1125
|
header = {} if header is None else header
|
1107
1126
|
if self.jwt_token:
|
@@ -1110,7 +1129,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
|
|
1110
1129
|
if ":" in self.forward_to:
|
1111
1130
|
header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to
|
1112
1131
|
else:
|
1113
|
-
header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to + ":" + str(parse.urlsplit(self.server_url).port)
|
1132
|
+
header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to + ":" + str(urllib.parse.urlsplit(self.server_url).port)
|
1114
1133
|
header[self.HTTP_HEADER_KEY_USER_AGENT] = self.HTTP_USER_AGENT
|
1115
1134
|
|
1116
1135
|
if method is AppMeshClient.Method.GET:
|
@@ -3,11 +3,11 @@ appmesh/app.py,sha256=9Q-SOOej-MH13BU5Dv2iTa-p-sECCJQp6ZX9DjWWmwE,10526
|
|
3
3
|
appmesh/app_output.py,sha256=JK_TMKgjvaw4n_ys_vmN5S4MyWVZpmD7NlKz_UyMIM8,1015
|
4
4
|
appmesh/app_run.py,sha256=9ISKGZ3k3kkbQvSsPfRfkOLqD9xhbqNOM7ork9F4w9c,1712
|
5
5
|
appmesh/appmesh_client.py,sha256=0ltkqHZUq094gKneYmC0bEZCP0X9kHTp9fccKdWFWP0,339
|
6
|
-
appmesh/http_client.py,sha256=
|
6
|
+
appmesh/http_client.py,sha256=qM0es3dM4PM95ymNqdTAuIvTD9-Xy6jPKhDW-Sn7ehg,45180
|
7
7
|
appmesh/tcp_client.py,sha256=RkHl5s8jE333BJOgxJqJ_fvjbdRQza7ciV49vLT6YO4,10923
|
8
8
|
appmesh/tcp_messages.py,sha256=w1Kehz_aX4X2CYAUsy9mFVJRhxnLQwwc6L58W4YkQqs,969
|
9
9
|
appmesh/tcp_transport.py,sha256=UMGby2oKV4k7lyXZUMSOe2Je34fb1w7nTkxEpatKLKg,7256
|
10
|
-
appmesh-1.4.
|
11
|
-
appmesh-1.4.
|
12
|
-
appmesh-1.4.
|
13
|
-
appmesh-1.4.
|
10
|
+
appmesh-1.4.6.dist-info/METADATA,sha256=x8wWJAFfIPR3PU4nGmmZDezdmmeoCLFmkE-nrOM1lPY,11501
|
11
|
+
appmesh-1.4.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
12
|
+
appmesh-1.4.6.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
|
13
|
+
appmesh-1.4.6.dist-info/RECORD,,
|
File without changes
|
File without changes
|