From 04323e1f5c5a1e468c968349481226b2211deb8f Mon Sep 17 00:00:00 2001 From: Zed <124834187+zZedix@users.noreply.github.com> Date: Sun, 5 Oct 2025 01:52:45 +0330 Subject: [PATCH 1/4] Handle socket.gaierror for invalid hostnames --- main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index e3043aa60..3cd4ff8ed 100644 --- a/main.py +++ b/main.py @@ -45,7 +45,7 @@ def check_and_modify_ip(ip_address: str) -> str: Raises: ValueError: If the provided IP address is invalid, return localhost. """ - try: + try: # Attempt to resolve hostname to IP address resolved_ip = socket.gethostbyname(ip_address) @@ -59,7 +59,7 @@ def check_and_modify_ip(ip_address: str) -> str: else: return "localhost" - except ValueError: + except (ValueError, socket.gaierror): return "localhost" From 55e27f4f212c33ac000f267f5c593bd94aeda65d Mon Sep 17 00:00:00 2001 From: Zed <124834187+zZedix@users.noreply.github.com> Date: Sun, 5 Oct 2025 11:26:10 +0330 Subject: [PATCH 2/4] Update main.py --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index 3cd4ff8ed..03dd0e69a 100644 --- a/main.py +++ b/main.py @@ -45,7 +45,7 @@ def check_and_modify_ip(ip_address: str) -> str: Raises: ValueError: If the provided IP address is invalid, return localhost. """ - try: + try: # Attempt to resolve hostname to IP address resolved_ip = socket.gethostbyname(ip_address) From 37042eb6c18a5717e1e30d24bf0936e257579979 Mon Sep 17 00:00:00 2001 From: Zed <124834187+zZedix@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:22:07 +0330 Subject: [PATCH 3/4] safely detect global IPv4 and close socket properly --- app/utils/system.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/utils/system.py b/app/utils/system.py index 5fbc20717..a615fbc87 100644 --- a/app/utils/system.py +++ b/app/utils/system.py @@ -70,6 +70,7 @@ def get_public_ip(): except httpx.RequestError: pass + sock = None try: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.connect(("8.8.8.8", 80)) @@ -79,11 +80,10 @@ def get_public_ip(): except (socket.error, IndexError): pass finally: - sock.close() + if sock: + sock.close() return "127.0.0.1" - - def get_public_ipv6(): try: resp = httpx.get("http://api6.ipify.org/", timeout=5).text.strip() From e27a03a04dfc4e7aaf312ce8b16ca3c4fb48391e Mon Sep 17 00:00:00 2001 From: Zed <124834187+zZedix@users.noreply.github.com> Date: Sun, 5 Oct 2025 12:24:50 +0330 Subject: [PATCH 4/4] Harden get_subscription_payload against malformed tokens --- app/utils/jwt.py | 72 ++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/app/utils/jwt.py b/app/utils/jwt.py index 54adf2c99..504690aae 100644 --- a/app/utils/jwt.py +++ b/app/utils/jwt.py @@ -60,34 +60,52 @@ async def get_subscription_payload(token: str) -> dict | None: return if token.startswith("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."): - payload = jwt.decode(token, await get_secret_key(), algorithms=["HS256"]) + try: + payload = jwt.decode(token, await get_secret_key(), algorithms=["HS256"]) + except jwt.exceptions.PyJWTError: + return + if payload.get("access") == "subscription": return { - "username": payload["sub"], - "created_at": datetime.fromtimestamp(payload["iat"], tz=timezone.utc), + "username": payload.get("sub"), + "created_at": datetime.fromtimestamp(payload.get("iat", 0), tz=timezone.utc), } - else: - return - else: - u_token = token[:-10] - u_signature = token[-10:] - try: - u_token_dec = b64decode( - (u_token.encode("utf-8") + b"=" * (-len(u_token.encode("utf-8")) % 4)), - altchars=b"-_", - validate=True, - ) - u_token_dec_str = u_token_dec.decode("utf-8") - except Exception: - return - u_token_resign = b64encode( - sha256((u_token + await get_secret_key()).encode("utf-8")).digest(), altchars=b"-_" - ).decode("utf-8")[:10] - if u_signature == u_token_resign: - u_username = u_token_dec_str.split(",")[0] - u_created_at = int(u_token_dec_str.split(",")[1]) - return {"username": u_username, "created_at": datetime.fromtimestamp(u_created_at, tz=timezone.utc)} - else: - return - except jwt.exceptions.PyJWTError: + return + + u_token = token[:-10] + u_signature = token[-10:] + + try: + u_token_dec = b64decode( + (u_token.encode("utf-8") + b"=" * (-len(u_token.encode("utf-8")) % 4)), + altchars=b"-_", + validate=True, + ) + u_token_dec_str = u_token_dec.decode("utf-8") + except Exception: + return + + u_token_resign = b64encode( + sha256((u_token + await get_secret_key()).encode("utf-8")).digest(), + altchars=b"-_", + ).decode("utf-8")[:10] + + if u_signature != u_token_resign: + return + + parts = u_token_dec_str.split(",") + if len(parts) != 2: + return + + u_username, u_created_at_str = parts + if not u_created_at_str.isdigit(): + return + + u_created_at = int(u_created_at_str) + return { + "username": u_username, + "created_at": datetime.fromtimestamp(u_created_at, tz=timezone.utc), + } + + except Exception: return