246 lines
6.2 KiB
Python
246 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
import base64
|
|
import time
|
|
import uuid
|
|
from dataclasses import asdict, dataclass
|
|
from urllib.parse import quote_plus, urlencode
|
|
|
|
from .device_profile import DeviceProfile
|
|
from .dfp_knn import build_full_knn, build_lite_knn
|
|
from .dfp_sign import DFP_SDK_ID, sign_dfp_form
|
|
from .dfp_sq0 import encode_sq0_device_info
|
|
from .enc_data import KWSG_10400_DEFAULT_CFG9, kwsg_10400_raw, load_kwsg_10400_tables
|
|
|
|
|
|
UNIFIED_FETCH_URL = "https://gdfpsec.ksapisrv.com/rest/infra/unifiedId/fetch/android"
|
|
UNIFIED_CHECK_REPAIR_URL = "https://gdfpsec.ksapisrv.com/rest/infra/unifiedId/checkRepair"
|
|
GDFP_REPORT_URL = "https://gdfpsec.ksapisrv.com/rest/infra/gdfp/report/kuaishou/android"
|
|
|
|
UNIFIED_FETCH_FORM_ORDER = [
|
|
"aegon",
|
|
"appVersion",
|
|
"deviceInfo",
|
|
"did",
|
|
"didTag",
|
|
"hgidReportId",
|
|
"platform",
|
|
"productName",
|
|
"rdid",
|
|
"requestId",
|
|
"sdkVersion",
|
|
"sv",
|
|
"ts",
|
|
"sign",
|
|
]
|
|
|
|
UNIFIED_CHECK_REPAIR_FORM_ORDER = [
|
|
"appVersion",
|
|
"did",
|
|
"didTag",
|
|
"from",
|
|
"lastDidTs",
|
|
"platform",
|
|
"productName",
|
|
"sdkVersion",
|
|
"ts",
|
|
"sign",
|
|
]
|
|
|
|
GDFP_REPORT_FORM_ORDER = [
|
|
"productName",
|
|
"ts",
|
|
"deviceInfo",
|
|
"sign",
|
|
"sv",
|
|
"rdid",
|
|
"didtag",
|
|
]
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DfpRequestSpec:
|
|
method: str
|
|
url: str
|
|
headers: dict[str, str]
|
|
form_order: list[str]
|
|
form: dict[str, str]
|
|
body: str
|
|
|
|
def to_dict(self) -> dict[str, object]:
|
|
return asdict(self)
|
|
|
|
|
|
def android_base64_default(data: bytes) -> str:
|
|
text = base64.b64encode(data).decode()
|
|
return "\n".join(text[i : i + 76] for i in range(0, len(text), 76)) + "\n"
|
|
|
|
|
|
def java_urlencode(text: str) -> str:
|
|
return quote_plus(text, safe="*-._")
|
|
|
|
|
|
def _headers(url: str) -> dict[str, str]:
|
|
host = url.split("/", 3)[2]
|
|
return {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
"Host": host,
|
|
"Connection": "Keep-Alive",
|
|
"Accept-Encoding": "gzip",
|
|
"User-Agent": "okhttp/3.12.13",
|
|
}
|
|
|
|
|
|
def _device_info_encoded(
|
|
sq0_raw: bytes,
|
|
*,
|
|
epoch_seconds: int | None,
|
|
sdk_id: str = DFP_SDK_ID,
|
|
) -> str:
|
|
t1, t2 = load_kwsg_10400_tables()
|
|
raw = kwsg_10400_raw(
|
|
sq0_raw,
|
|
sdk_id,
|
|
t1,
|
|
t2,
|
|
epoch_seconds=epoch_seconds,
|
|
cfg9=KWSG_10400_DEFAULT_CFG9,
|
|
)
|
|
return java_urlencode(android_base64_default(raw))
|
|
|
|
|
|
def _request_from_order(url: str, form: dict[str, str], form_order: list[str]) -> DfpRequestSpec:
|
|
ordered_pairs = [(key, form[key]) for key in form_order]
|
|
body = urlencode(ordered_pairs)
|
|
return DfpRequestSpec(
|
|
method="POST",
|
|
url=url,
|
|
headers=_headers(url),
|
|
form_order=list(form_order),
|
|
form={key: value for key, value in ordered_pairs},
|
|
body=body,
|
|
)
|
|
|
|
|
|
def _now_millis() -> str:
|
|
return str(int(time.time() * 1000))
|
|
|
|
|
|
def _request_id() -> str:
|
|
return uuid.uuid4().hex[:16]
|
|
|
|
|
|
def build_unified_fetch_request(
|
|
profile: DeviceProfile,
|
|
*,
|
|
counter: int,
|
|
unix_time: int,
|
|
session_seed: int,
|
|
ts_millis: str | None = None,
|
|
epoch_seconds: int | None = None,
|
|
) -> DfpRequestSpec:
|
|
sq0_raw = encode_sq0_device_info(build_lite_knn(profile), mode="lite")
|
|
device_info = _device_info_encoded(sq0_raw, epoch_seconds=epoch_seconds)
|
|
unsigned = {
|
|
"aegon": "false",
|
|
"appVersion": "14.5.50.11631",
|
|
"deviceInfo": device_info,
|
|
"did": profile.did,
|
|
"didTag": "-1",
|
|
"hgidReportId": _request_id(),
|
|
"platform": "1",
|
|
"productName": "NEBULA",
|
|
"rdid": profile.rdid,
|
|
"requestId": _request_id(),
|
|
"sdkVersion": "9.5.4lite.79.137a838b",
|
|
"sv": "2",
|
|
"ts": ts_millis or _now_millis(),
|
|
}
|
|
signed = sign_dfp_form(
|
|
"unified_fetch",
|
|
unsigned,
|
|
counter,
|
|
unix_time,
|
|
session_seed=session_seed,
|
|
)
|
|
form = {key: signed[key] for key in UNIFIED_FETCH_FORM_ORDER}
|
|
return _request_from_order(UNIFIED_FETCH_URL, form, UNIFIED_FETCH_FORM_ORDER)
|
|
|
|
|
|
def build_unified_check_repair_request(
|
|
profile: DeviceProfile,
|
|
*,
|
|
counter: int,
|
|
unix_time: int,
|
|
session_seed: int,
|
|
ts_millis: str | None = None,
|
|
from_value: str = "1",
|
|
last_did_ts: str | None = None,
|
|
) -> DfpRequestSpec:
|
|
unsigned = {
|
|
"appVersion": profile.app_version,
|
|
"did": profile.did,
|
|
"didTag": str(profile.cdid_tag),
|
|
"from": str(from_value),
|
|
"lastDidTs": str(last_did_ts if last_did_ts is not None else profile.install_time_ms),
|
|
"platform": "1",
|
|
"productName": "NEBULA",
|
|
"sdkVersion": "9.5.4lite.79.137a838b",
|
|
"ts": ts_millis or _now_millis(),
|
|
}
|
|
signed = sign_dfp_form(
|
|
"unified_check_repair",
|
|
unsigned,
|
|
counter,
|
|
unix_time,
|
|
session_seed=session_seed,
|
|
)
|
|
form = {key: signed[key] for key in UNIFIED_CHECK_REPAIR_FORM_ORDER}
|
|
return _request_from_order(UNIFIED_CHECK_REPAIR_URL, form, UNIFIED_CHECK_REPAIR_FORM_ORDER)
|
|
|
|
|
|
def build_gdfp_report_request(
|
|
profile: DeviceProfile,
|
|
*,
|
|
counter: int,
|
|
unix_time: int,
|
|
session_seed: int,
|
|
ts_millis: str | None = None,
|
|
epoch_seconds: int | None = None,
|
|
) -> DfpRequestSpec:
|
|
sq0_raw = encode_sq0_device_info(build_full_knn(profile), mode="full")
|
|
device_info = _device_info_encoded(sq0_raw, epoch_seconds=epoch_seconds)
|
|
unsigned = {
|
|
"productName": "NEBULA",
|
|
"ts": ts_millis or _now_millis(),
|
|
"deviceInfo": device_info,
|
|
"sv": "2",
|
|
"rdid": profile.rdid,
|
|
"didtag": "-1",
|
|
}
|
|
signed = sign_dfp_form(
|
|
"gdfp_report",
|
|
unsigned,
|
|
counter,
|
|
unix_time,
|
|
session_seed=session_seed,
|
|
)
|
|
form = {key: signed[key] for key in GDFP_REPORT_FORM_ORDER}
|
|
return _request_from_order(GDFP_REPORT_URL, form, GDFP_REPORT_FORM_ORDER)
|
|
|
|
|
|
__all__ = [
|
|
"DfpRequestSpec",
|
|
"UNIFIED_CHECK_REPAIR_FORM_ORDER",
|
|
"UNIFIED_CHECK_REPAIR_URL",
|
|
"GDFP_REPORT_FORM_ORDER",
|
|
"GDFP_REPORT_URL",
|
|
"UNIFIED_FETCH_FORM_ORDER",
|
|
"UNIFIED_FETCH_URL",
|
|
"android_base64_default",
|
|
"build_gdfp_report_request",
|
|
"build_unified_check_repair_request",
|
|
"build_unified_fetch_request",
|
|
"java_urlencode",
|
|
]
|