Files
kefu/wechat_rpa/contact_relation.py
T
2026-09-21 10:34:06 +08:00

73 lines
3.6 KiB
Python

"""Current account's customer relation snapshot; never infers by name or chat text."""
from pathlib import Path
import math
import sqlite3
from review_assistant_contacts import recipient_peer
def unknown_relation(account, conv_id, reason="unavailable"):
return {"account": str(account), "conv_id": str(conv_id),
"peer_id": recipient_peer(account, conv_id), "state": "unknown",
"added_at": 0.0, "reason": reason}
def read_contact_relation(path, account, conv_id):
"""Read only a supplied, account-bound current snapshot, never search caches.
An active local customer entry is not proof of successful remote delivery.
The protocol engine combines it with a genuinely new customer event before
reconsidering a past rejection, and still requires the native send receipt.
"""
result = unknown_relation(account, conv_id)
peer = result["peer_id"]
if not peer or not path:
return result
path = Path(path)
try:
if path.name != "user.db" or path.resolve().parent.name != str(account):
return {**result, "reason": "account_mismatch"}
connection = sqlite3.connect(path.resolve().as_uri() + "?mode=ro", uri=True, timeout=.2)
try:
connection.execute("PRAGMA query_only=ON")
connection.execute("BEGIN")
required = {
"external_user_relation_v3": {"user_id", "status", "stranger_type", "add_customer_time"},
"delete_external_userV1": {"user_id"},
"blacklist_external_userids": {"value"},
}
for table, fields in required.items():
columns = {row[1] for row in connection.execute(f'PRAGMA table_info("{table}")')}
if not fields.issubset(columns):
return {**result, "reason": "schema_unverified"}
deleted = connection.execute("SELECT 1 FROM delete_external_userV1 WHERE user_id=? LIMIT 1", (peer,)).fetchone()
denied = connection.execute("SELECT 1 FROM blacklist_external_userids WHERE value=? LIMIT 1", (peer,)).fetchone()
if deleted or denied:
return {**result, "state": "blocked", "reason": "deleted_or_blocklisted"}
rows = connection.execute(
"SELECT status,stranger_type,add_customer_time FROM external_user_relation_v3 WHERE user_id=? LIMIT 2",
(peer,)).fetchall()
if len(rows) != 1:
return {**result, "reason": "relation_missing_or_ambiguous"}
status, stranger, added = rows[0]
# The allowlist matches the supported WeCom build. Unknown flags
# never grant recovery, and a prior add time is not a re-add time.
if type(status) is not int or type(stranger) is not int:
return {**result, "reason": "status_unverified"}
if stranger != 0:
return {**result, "state": "blocked", "reason": "stranger"}
if status not in {2049, 2057}:
return {**result, "reason": "status_unverified"}
if not isinstance(added, (int, float)) or isinstance(added, bool):
return {**result, "reason": "add_time_unverified"}
added = float(added)
if added > 10**12:
added /= 1000
if not math.isfinite(added) or added <= 0:
return {**result, "reason": "add_time_unverified"}
return {**result, "state": "active", "added_at": added, "reason": "current_customer"}
finally:
connection.close()
except (OSError, ValueError, sqlite3.Error):
return result