"""IM 凭证规范化(独立版,不依赖客服系统 backend)。""" from __future__ import annotations import json import re from urllib.parse import parse_qs, unquote, urlparse def _parse_tea_from_ls(origins: list) -> tuple[str, str]: my_uid = "" web_id = "" ordered = sorted(origins or [], key=lambda o: 0 if "www.douyin.com" in (o.get("origin") or "") else 1) for origin in ordered: for entry in origin.get("localStorage") or []: name = entry.get("name") or "" if "tea_cache" not in name.lower(): continue try: parsed = json.loads(entry.get("value") or "{}") except Exception: continue uid = str(parsed.get("user_unique_id") or "").strip() wid = str(parsed.get("web_id") or "").strip() if uid and wid and uid == wid and len(uid) > 12: continue if uid and uid.isdigit() and not my_uid: my_uid = uid if wid and wid.isdigit() and not web_id: web_id = wid if my_uid and web_id: return my_uid, web_id or my_uid return my_uid, web_id or my_uid def _ws_device_id(url: str) -> str: m = re.search(r"[?&]device_id=([^&\s]+)", url or "") return unquote(m.group(1)) if m else "" def normalize_storage_state_for_im(data: dict) -> dict: if not isinstance(data, dict) or not isinstance(data.get("cookies"), list): return data data = dict(data) origins = data.get("origins") or [] tea_uid, _tea_web_id = _parse_tea_from_ls(origins) ws_url = str(data.get("frontier_ws_url") or "") is_creator_ws = "aid=2906" in ws_url and "sdk_cert=" in ws_url if is_creator_ws: ws_dev = _ws_device_id(ws_url) if ws_dev and ws_dev.isdigit(): data["my_uid"] = int(ws_dev) my_uid = ws_dev else: my_uid = str(data.get("my_uid") or tea_uid or "") if my_uid.isdigit(): data["my_uid"] = int(my_uid) else: my_uid = "" elif tea_uid: data["my_uid"] = int(tea_uid) my_uid = tea_uid else: my_uid = str(data.get("my_uid") or "") if my_uid.isdigit(): data["my_uid"] = int(my_uid) else: my_uid = "" if ws_url and my_uid and not is_creator_ws: ws_dev = _ws_device_id(ws_url) token = "" try: token = parse_qs(urlparse(ws_url).query).get("token", [""])[0] except Exception: pass looks_built = bool(token) and len(token) < 40 if ws_dev and ws_dev.isdigit() and ws_dev != my_uid and looks_built: data.pop("frontier_ws_url", None) data.pop("sdk_cert", None) data.pop("ts_sign", None) data.pop("frontier_ws_built", None) for origin in origins: ls = origin.get("localStorage") or [] fixed = False for entry in ls: if entry.get("name") == "web_runtime_security_uid": fixed = True val = str(entry.get("value") or "") if not val.isdigit() and my_uid: entry["value"] = my_uid break if not fixed and my_uid: ls.append({"name": "web_runtime_security_uid", "value": my_uid}) origin["localStorage"] = ls data["origins"] = origins return data