diff --git a/yunke-server/app/scraper/wechat.py b/yunke-server/app/scraper/wechat.py index 0b4e6df..5a33cfe 100644 --- a/yunke-server/app/scraper/wechat.py +++ b/yunke-server/app/scraper/wechat.py @@ -346,11 +346,21 @@ def _normalize_message(record: dict[str, Any]) -> dict[str, Any]: if timestamp is None: timestamp = record.get("createTime") + # talker_id = the message's sender/peer FULL id (the timeline join key). + # 1:1 (empty roomid): upstream `talker` is masked, the full peer is + # `oriTalker`. group (roomid set): `talker` is the sending member, while + # `oriTalker` is the chatroom id — so the member is in `talker`. + roomid = record.get("roomid") or "" + if roomid: + talker_id = record.get("talker") + else: + talker_id = record.get("oriTalker") or record.get("talker") + return { "msg_id": record.get("msgSvrId"), "channel": "wechat", "owner_account_id": record.get("wechatId"), - "talker_id": record.get("talker"), + "talker_id": talker_id, "ori_talker": record.get("oriTalker"), "room_id": record.get("roomid"), "is_send": is_send, diff --git a/yunke-server/app/session/yunke_client.py b/yunke-server/app/session/yunke_client.py index 6476002..b393de2 100644 --- a/yunke-server/app/session/yunke_client.py +++ b/yunke-server/app/session/yunke_client.py @@ -42,10 +42,13 @@ from app.session.login import ( pc_login, ) -# The 4 constant auth headers. ``userid`` + ``company`` come from the -# LoginResult and are merged in separately. +# Constant auth headers. ``userid`` + ``company`` come from the LoginResult +# and are merged in separately. NOTE: ``source`` is intentionally NOT sent — +# the real CRM session cookie authenticates data APIs (confirmed in Phase 0), +# and several endpoints (e.g. ``msg/chats``) bind a ``source`` parameter as +# Integer, so a ``source: "yunkepc"`` header makes them 500. Cookie-only auth +# works for all data endpoints. _STATIC_AUTH_HEADERS: dict[str, str] = { - "source": "yunkepc", "channel": "4", "content-type": "application/json", } diff --git a/yunke-server/tests/test_yunke_client.py b/yunke-server/tests/test_yunke_client.py index 53ba5b2..19d8fe4 100644 --- a/yunke-server/tests/test_yunke_client.py +++ b/yunke-server/tests/test_yunke_client.py @@ -127,7 +127,10 @@ async def test_post_injects_auth_headers(client: YunkeClient): # The 5 known auth headers must be on every outgoing request. assert sent.headers["userid"] == USERID assert sent.headers["company"] == COMPANY - assert sent.headers["source"] == "yunkepc" + # NOTE: ``source`` is intentionally NOT sent — several endpoints (msg/chats) + # bind a ``source`` param as Integer, so ``source: "yunkepc"`` 500s. Cookie + # auth suffices for all data endpoints (Phase 0). + assert "source" not in sent.headers assert sent.headers["channel"] == "4" assert sent.headers["content-type"] == "application/json" # And the session cookie travels along too. diff --git a/yunke-server/tests/test_yunke_client_stealth.py b/yunke-server/tests/test_yunke_client_stealth.py index e742ff3..f5e3434 100644 --- a/yunke-server/tests/test_yunke_client_stealth.py +++ b/yunke-server/tests/test_yunke_client_stealth.py @@ -113,7 +113,7 @@ async def test_browser_headers_present_on_every_request(client: YunkeClient): assert sent["sec-ch-ua-platform"] == '"Windows"' assert sent["referer"] == "https://crm2.yunkecn.com/" # The existing auth headers still ride along unchanged. - assert sent["source"] == "yunkepc" + assert "source" not in sent # omitted: breaks msg/chats Integer binding assert sent["channel"] == "4" assert sent["userid"] == USERID assert sent["company"] == COMPANY