173 lines
5.1 KiB
Python
173 lines
5.1 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import json
|
|
from dataclasses import dataclass
|
|
from typing import Any
|
|
|
|
from .enc_data import kwsg_10400_raw, load_kwsg_10400_tables
|
|
from .sig3 import Kwsg10418State
|
|
|
|
|
|
REWARD_SDK = "95147564-9763-4413-a937-6f0e3c12caf1"
|
|
APP_NAME = "\u5feb\u624b\u6781\u901f\u7248"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RewardBody:
|
|
enc_data: str
|
|
sign: str
|
|
sdk_id: str
|
|
sign_counter: int
|
|
|
|
|
|
def _safe_int(value: Any, default: int = 0) -> int:
|
|
try:
|
|
if value in (None, ""):
|
|
return default
|
|
return int(str(value))
|
|
except Exception:
|
|
return default
|
|
|
|
|
|
def _android_release(api_params: dict[str, str]) -> str:
|
|
sys_value = str(api_params.get("sys") or "")
|
|
if sys_value.startswith("ANDROID_"):
|
|
return sys_value.split("_", 1)[1]
|
|
return str(api_params.get("androidApiLevel") or "16")
|
|
|
|
|
|
def _screen_size(api_params: dict[str, str]) -> dict[str, int]:
|
|
width = _safe_int(api_params.get("sw"), 1080)
|
|
height = _safe_int(api_params.get("sh"), 2376)
|
|
status_bar = _safe_int(api_params.get("sbh"), 120)
|
|
content_height = max(1, height - status_bar - 48)
|
|
return {"width": width, "height": content_height}
|
|
|
|
|
|
def _connection_type(api_params: dict[str, str]) -> int:
|
|
net = str(api_params.get("net") or "").upper()
|
|
if net in {"5G", "NR"}:
|
|
return 5
|
|
if net in {"WIFI", "WI-FI"}:
|
|
return 100
|
|
return 100
|
|
|
|
|
|
def _json_bytes(value: dict[str, Any]) -> bytes:
|
|
return json.dumps(value, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
|
|
|
|
|
|
def build_reward_str_e(
|
|
*,
|
|
kind: str,
|
|
cookie_dict: dict[str, str],
|
|
api_params: dict[str, str],
|
|
oaid: str,
|
|
scene: tuple[int, int, int],
|
|
business_id: int,
|
|
neo_params: str = "",
|
|
now_ms: int,
|
|
network_ip: str = "172.31.230.147",
|
|
ipdx_ip: str = "106.178.190.155",
|
|
) -> bytes:
|
|
user_id = cookie_dict.get("userId") or cookie_dict.get("ud") or api_params.get("ud") or ""
|
|
page_id, sub_page_id, _pos_id = scene
|
|
imp_ext: dict[str, Any] = {
|
|
"openH5AdCount": 0,
|
|
"sessionLookedCompletedCount": "0",
|
|
"sessionType": "1",
|
|
}
|
|
if neo_params:
|
|
imp_ext["neoParams"] = neo_params
|
|
|
|
session_id = f"adNeo-{user_id}-{sub_page_id}-{now_ms}"
|
|
request_scene_type = 1 if business_id != 606 else 7
|
|
|
|
data = {
|
|
"appInfo": {
|
|
"appId": "kuaishou_nebula",
|
|
"name": APP_NAME,
|
|
"packageName": "com.kuaishou.nebula",
|
|
"version": api_params.get("appver") or cookie_dict.get("appver") or "14.5.50.11631",
|
|
"versionCode": -1,
|
|
},
|
|
"deviceInfo": {
|
|
"oaid": oaid,
|
|
"osType": 1,
|
|
"osVersion": _android_release(api_params),
|
|
"language": "zh",
|
|
"deviceId": cookie_dict.get("did") or api_params.get("did") or "",
|
|
"screenSize": _screen_size(api_params),
|
|
"ftt": api_params.get("ftt", ""),
|
|
"supportGyroscope": True,
|
|
},
|
|
"networkInfo": {
|
|
"ip": network_ip,
|
|
"connectionType": _connection_type(api_params),
|
|
},
|
|
"geoInfo": {"latitude": 0, "longitude": 0},
|
|
"userInfo": {"userId": user_id, "age": 0, "gender": ""},
|
|
"impInfo": [
|
|
{
|
|
"pageId": page_id,
|
|
"subPageId": sub_page_id,
|
|
"action": 0,
|
|
"width": 0,
|
|
"height": 0,
|
|
"browseType": _safe_int(api_params.get("browseType"), 3),
|
|
"requestSceneType": request_scene_type,
|
|
"lastReceiveAmount": 0,
|
|
"impExtData": json.dumps(imp_ext, ensure_ascii=False, separators=(",", ":")),
|
|
"mediaExtData": "{}",
|
|
"session": json.dumps({"id": session_id}, ensure_ascii=False, separators=(",", ":")),
|
|
}
|
|
],
|
|
"adClientInfo": json.dumps(
|
|
{"ipdxIP": ipdx_ip},
|
|
ensure_ascii=False,
|
|
separators=(",", ":"),
|
|
),
|
|
"recoReportContext": json.dumps(
|
|
{"adClientInfo": {"shouldShowAdProfileSectionBanner": None, "profileAuthorId": 0}},
|
|
ensure_ascii=False,
|
|
separators=(",", ":"),
|
|
),
|
|
}
|
|
return _json_bytes(data)
|
|
|
|
|
|
def build_reward_body(
|
|
str_e: bytes,
|
|
state: Kwsg10418State,
|
|
*,
|
|
t1: bytes | None = None,
|
|
t2: bytes | None = None,
|
|
sdk_id: str = REWARD_SDK,
|
|
unix_time: int | None = None,
|
|
enc_epoch_seconds: int | None = None,
|
|
) -> RewardBody:
|
|
if t1 is None and t2 is None:
|
|
t1, t2 = load_kwsg_10400_tables()
|
|
if t1 is None or t2 is None:
|
|
raise ValueError("t1 and t2 must be provided together")
|
|
|
|
enc_raw = kwsg_10400_raw(str_e, sdk_id, t1, t2, epoch_seconds=enc_epoch_seconds)
|
|
enc_data = base64.b64encode(enc_raw).decode("ascii")
|
|
sign = state.reward_sign(str_e, sdk_id, unix_time=unix_time, t1=t1, t2=t2)
|
|
return RewardBody(
|
|
enc_data=enc_data,
|
|
sign=sign,
|
|
sdk_id=sdk_id,
|
|
sign_counter=state.counter,
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"APP_NAME",
|
|
"REWARD_SDK",
|
|
"RewardBody",
|
|
"build_reward_body",
|
|
"build_reward_str_e",
|
|
]
|