From 17abcc48c0ce62936424fd0f811040f71185c442 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Wed, 9 Sep 2026 19:15:19 +0000 Subject: [PATCH] Replace ua-parser wrapper with uarite uaparse --- paskia/fastapi/remote.py | 7 +++---- paskia/util/apistructs.py | 4 ++-- paskia/util/useragent.py | 29 ----------------------------- pyproject.toml | 2 +- 4 files changed, 6 insertions(+), 36 deletions(-) delete mode 100644 paskia/util/useragent.py diff --git a/paskia/fastapi/remote.py b/paskia/fastapi/remote.py index 95036ee..8633273 100644 --- a/paskia/fastapi/remote.py +++ b/paskia/fastapi/remote.py @@ -15,6 +15,7 @@ from uuid import UUID import base64url from fastapi import FastAPI, WebSocket, WebSocketDisconnect +from uarite import uaparse from paskia import authcode, db, remoteauth from paskia.authcode import CookieCode @@ -23,7 +24,7 @@ from paskia.domains import current_domain, registry from paskia.fastapi.session import AUTH_COOKIE, infodict from paskia.fastapi.wschat import authenticate_and_login from paskia.fastapi.wsutil import validate_origin, websocket_error_handler -from paskia.util import pow, useragent +from paskia.util import pow # Create a FastAPI subapp for remote auth WebSocket endpoints app = FastAPI(docs_url=None, redoc_url=None, openapi_url=None) @@ -458,9 +459,7 @@ async def websocket_remote_auth_permit(ws: WebSocket, auth=AUTH_COOKIE): if requesting_domain else request.rp_id ), - "user_agent_pretty": useragent.compact_user_agent( - request.user_agent - ), + "user_agent_pretty": uaparse(request.user_agent).pretty, "client_ip": request.ip, "action": request.action, "pow": { diff --git a/paskia/util/apistructs.py b/paskia/util/apistructs.py index 6e5eecc..8455929 100644 --- a/paskia/util/apistructs.py +++ b/paskia/util/apistructs.py @@ -11,10 +11,10 @@ from datetime import datetime from uuid import UUID import msgspec +from uarite import uaparse from paskia import db from paskia.db.structs import Credential, Org, OriginEntry, Permission, Role, User -from paskia.util import useragent # ------------------------------------------------------------------------- # API structs - inherit from db structs, add uuid for serialization @@ -124,7 +124,7 @@ class ApiUserSession(msgspec.Struct, omit_defaults=True): credential_uuid=s.credential_uuid, host=s.host, ip=s.ip, - user_agent=useragent.compact_user_agent(s.user_agent), + user_agent=uaparse(s.user_agent).pretty, validated=s.validated, last_renewed=s.validated, is_current=s.key == current_key, diff --git a/paskia/util/useragent.py b/paskia/util/useragent.py deleted file mode 100644 index fdb8e1d..0000000 --- a/paskia/util/useragent.py +++ /dev/null @@ -1,29 +0,0 @@ -from ua_parser import parse - - -def compact_user_agent(ua: str | None) -> str: - """Format user agent string into a compact display format. - - Returns empty string for empty/missing user agents. - Returns original UA for unrecognized ones. - """ - if not ua or not ua.strip() or ua == "-": - return "" - r = parse(ua) - browser = r.user_agent.family if r.user_agent else None - ver = r.user_agent.major if r.user_agent else "" - os_name = r.os.family if r.os else None - dev = r.device.family if r.device else None - # If browser is unrecognized, return original UA - if browser in (None, "Other") and os_name in (None, "Other"): - return ua - # Filter out "Other" values - browser = browser if browser and browser != "Other" else "" - os_name = os_name if os_name and os_name != "Other" else "" - # Exclude device if it's "Other" or matches browser family (parser bug) - if dev in (None, "Other") or dev == browser: - dev = "" - # Build compact string, filtering empty parts - parts = [f"{browser}/{ver}" if browser else "", os_name, dev] - result = " ".join(p for p in parts if p).strip() - return result diff --git a/pyproject.toml b/pyproject.toml index 395306b..aab438f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,8 +22,8 @@ dependencies = [ "jsondiff>=2.2.1", "msgspec>=0.20.0", "fastapi-vue~=1.4.2", - "ua-parser[regex]>=1.0.1", "kanta>=0.7.0", + "uarite>=0.2.1", ] [dependency-groups] dev = [