appmesh 1.6.9__py3-none-any.whl → 1.6.10__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/__init__.py CHANGED
@@ -11,6 +11,7 @@ Example:
11
11
 
12
12
  import sys
13
13
  from types import ModuleType
14
+ from typing import TYPE_CHECKING
14
15
 
15
16
  __all__ = ["App", "AppMeshClient", "AppMeshClientTCP", "AppMeshClientOAuth", "AppMeshServer", "AppMeshServerTCP"]
16
17
 
@@ -24,6 +25,17 @@ _LAZY_IMPORTS = {
24
25
  }
25
26
 
26
27
 
28
+ if TYPE_CHECKING:
29
+ # Provide explicit imports for static analyzers and type checkers
30
+ # These imports are only executed during type checking and won't affect runtime.
31
+ from .app import App # noqa: F401
32
+ from .client_http import AppMeshClient # noqa: F401
33
+ from .client_tcp import AppMeshClientTCP # noqa: F401
34
+ from .client_http_oauth import AppMeshClientOAuth # noqa: F401
35
+ from .server_http import AppMeshServer # noqa: F401
36
+ from .server_tcp import AppMeshServerTCP # noqa: F401
37
+
38
+
27
39
  def _lazy_import(name):
28
40
  """Helper function for lazy importing."""
29
41
  if name in _LAZY_IMPORTS:
appmesh/client_http.py CHANGED
@@ -129,6 +129,10 @@ class AppMeshClient(metaclass=abc.ABCMeta):
129
129
  HTTP_HEADER_KEY_USER_AGENT = "User-Agent"
130
130
  HTTP_HEADER_KEY_X_TARGET_HOST = "X-Target-Host"
131
131
  HTTP_HEADER_KEY_X_FILE_PATH = "X-File-Path"
132
+ HTTP_HEADER_JWT_set_cookie = "X-Set-Cookie"
133
+ HTTP_HEADER_NAME_CSRF_TOKEN = "X-CSRF-Token"
134
+ COOKIE_TOKEN = "appmesh_auth_token"
135
+ COOKIE_CSRF_TOKEN = "appmesh_csrf_token"
132
136
 
133
137
  @unique
134
138
  class Method(Enum):
@@ -234,16 +238,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
234
238
  # Session and cookie management
235
239
  self._lock = threading.Lock()
236
240
  self.session = requests.Session()
237
- self.cookie_file = rest_cookie_file
238
- if self.cookie_file:
239
- self.session.cookies = cookiejar.MozillaCookieJar(self.cookie_file)
240
- if os.path.exists(self.cookie_file):
241
- self.session.cookies.load(ignore_discard=True, ignore_expires=True)
242
- else:
243
- os.makedirs(os.path.dirname(self.cookie_file), exist_ok=True)
244
- self.session.cookies.save(ignore_discard=True, ignore_expires=True)
245
- if os.name == "posix":
246
- os.chmod(self.cookie_file, 0o600) # User read/write only
241
+ self.cookie_file = self._load_cookies(rest_cookie_file)
247
242
 
248
243
  # Token auto-refresh
249
244
  self._token_refresh_timer = None
@@ -259,6 +254,44 @@ class AppMeshClient(metaclass=abc.ABCMeta):
259
254
  def _get_access_token(self) -> str:
260
255
  return self.jwt_token
261
256
 
257
+ def _load_cookies(self, cookie_file: Optional[str]) -> str:
258
+ """Load cookies from the cookie file and return the file path ."""
259
+ if not cookie_file:
260
+ return ""
261
+
262
+ self.session.cookies = cookiejar.MozillaCookieJar(cookie_file)
263
+ if os.path.exists(cookie_file):
264
+ self.session.cookies.load(ignore_discard=True, ignore_expires=True)
265
+ else:
266
+ os.makedirs(os.path.dirname(cookie_file), exist_ok=True)
267
+ self.session.cookies.save(ignore_discard=True, ignore_expires=True)
268
+ if os.name == "posix":
269
+ os.chmod(cookie_file, 0o600) # User read/write only
270
+ return cookie_file
271
+
272
+ @staticmethod
273
+ def _get_cookie_value(cookies, name, check_expiry=True) -> Optional[str]:
274
+ """Get cookie value by name, checking expiry if requested."""
275
+ # If it's a RequestsCookieJar, use .get() but check expiry manually if requested
276
+ if hasattr(cookies, "get") and not isinstance(cookies, list):
277
+ cookie = cookies.get(name)
278
+ if cookie is None:
279
+ return None
280
+ if check_expiry and getattr(cookie, "expires", None):
281
+ if cookie.expires < time.time():
282
+ return None # expired
283
+ return cookie.value if hasattr(cookie, "value") else cookie
284
+
285
+ # Otherwise, assume it's a MozillaCookieJar — iterate manually
286
+ for c in cookies:
287
+ if c.name == name:
288
+ if check_expiry and getattr(c, "expires", None):
289
+ if c.expires < time.time():
290
+ return None # expired
291
+ return c.value
292
+
293
+ return None
294
+
262
295
  def _check_and_refresh_token(self):
263
296
  """Check and refresh token if needed, then schedule next check.
264
297
 
@@ -407,6 +440,8 @@ class AppMeshClient(metaclass=abc.ABCMeta):
407
440
  - Refresh tokens before expiration
408
441
  - Validate token format before setting
409
442
  """
443
+ if self._jwt_token == token:
444
+ return # No change
410
445
  self._jwt_token = token
411
446
 
412
447
  # handle refresh
@@ -499,6 +534,7 @@ class AppMeshClient(metaclass=abc.ABCMeta):
499
534
  self.HTTP_HEADER_KEY_AUTH: "Basic " + base64.b64encode(f"{user_name}:{user_pwd}".encode()).decode(),
500
535
  "X-Expire-Seconds": str(self._parse_duration(timeout_seconds)),
501
536
  **({"X-Audience": audience} if audience else {}),
537
+ **({self.HTTP_HEADER_JWT_set_cookie: "true"} if self.cookie_file else {}),
502
538
  # **({"X-Totp-Code": totp_code} if totp_code else {}),
503
539
  },
504
540
  )
@@ -1422,9 +1458,13 @@ class AppMeshClient(metaclass=abc.ABCMeta):
1422
1458
 
1423
1459
  # Prepare headers
1424
1460
  header = {} if header is None else header
1425
- token = self._get_access_token()
1426
- if token:
1427
- header[self.HTTP_HEADER_KEY_AUTH] = f"Bearer {token}"
1461
+
1462
+ # JWT or Cookie token
1463
+ if self.cookie_file and self._get_cookie_value(self.session.cookies, self.COOKIE_CSRF_TOKEN):
1464
+ header[self.HTTP_HEADER_NAME_CSRF_TOKEN] = self._get_cookie_value(self.session.cookies, self.COOKIE_CSRF_TOKEN)
1465
+ elif self._get_access_token():
1466
+ header[self.HTTP_HEADER_KEY_AUTH] = f"Bearer {self._get_access_token()}"
1467
+
1428
1468
  if self.forward_to and len(self.forward_to) > 0:
1429
1469
  if ":" in self.forward_to:
1430
1470
  header[self.HTTP_HEADER_KEY_X_TARGET_HOST] = self.forward_to
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: appmesh
3
- Version: 1.6.9
3
+ Version: 1.6.10
4
4
  Summary: Client SDK for App Mesh
5
5
  Home-page: https://github.com/laoshanxi/app-mesh
6
6
  Author: laoshanxi
@@ -1,16 +1,16 @@
1
- appmesh/__init__.py,sha256=TY1y5B5cE57uhraEzCFOZRWuo9SY1R-fYNRan8hCZOM,1670
1
+ appmesh/__init__.py,sha256=uJ5LOadwZW2nOXkSuPOy2S3WH9Bx0BUn5wUvPBeFzoc,2217
2
2
  appmesh/app.py,sha256=crD4DRFZJuHtZMfSsz7C-EwvjPmGZbFXYXvA_wCdvdI,10734
3
3
  appmesh/app_output.py,sha256=vfn322AyixblI8DbXds08h6L_ybObiaRSifsA1-Xcoo,1035
4
4
  appmesh/app_run.py,sha256=aYq852a29OThIi32Xtx5s0sTXZ97T0lHD5WXH8yfPoc,2018
5
5
  appmesh/appmesh_client.py,sha256=ywB2222PtJUffdfdxZcBfdhZs1KYyc7JvzMxwuK2qyI,378
6
- appmesh/client_http.py,sha256=OiYM4CXn21S4e_jx71X5_31krLes6UuHHueEYk6UIu4,58690
6
+ appmesh/client_http.py,sha256=KD4AMcMbHqaLJWSrra0J03kMqWAiwYHiyusUc5kpr6o,60443
7
7
  appmesh/client_http_oauth.py,sha256=1d51o0JX_xtB8d2bEuM7_XJHcwMnhcjkbIq7GE1Zxm8,6120
8
8
  appmesh/client_tcp.py,sha256=aq6UUzytZA4ibE9WQMMWdo1uW8sHETEhJjsbM6IYSno,11457
9
9
  appmesh/server_http.py,sha256=rBIYO9rbR-r3x1Jcry440Sp--IM-OWKRaOhNpGdkxh8,4299
10
10
  appmesh/server_tcp.py,sha256=-CU5tw97WJmDcUNsNPWqpdZ0wxRzRD6kUP3XyNZUTHc,1444
11
11
  appmesh/tcp_messages.py,sha256=H9S_iCy0IuufY2v50_SUgRvcyQmJsySG65tBe_xb3Ko,1878
12
12
  appmesh/tcp_transport.py,sha256=0hRSp5fpL9wKB05JIyIRIuyBC8w1IdokryhMDHqtN4M,8946
13
- appmesh-1.6.9.dist-info/METADATA,sha256=aT2BPT5BM_5FkkFKhR-h_NBWMQMeVBP3-Wo2QwA-j6Y,11763
14
- appmesh-1.6.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- appmesh-1.6.9.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
- appmesh-1.6.9.dist-info/RECORD,,
13
+ appmesh-1.6.10.dist-info/METADATA,sha256=do80dYMa4qK9tg1qKDM4M0klzIgzfcEGlWo6w1OIBfg,11764
14
+ appmesh-1.6.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ appmesh-1.6.10.dist-info/top_level.txt,sha256=-y0MNQOGJxUzLdHZ6E_Rfv5_LNCkV-GTmOBME_b6pg8,8
16
+ appmesh-1.6.10.dist-info/RECORD,,