"""纯 Python 复现 ``new mf(context, event).a()`` 的设备状态 JSON。""" from __future__ import annotations import hashlib import json import time from dataclasses import dataclass from typing import Any, Mapping from .device_profile import DeviceProfile from .weapon_vimg import generate_passport_account_image @dataclass(frozen=True) class WeaponRuntimeSnapshot: """一次 WeaponHI 上报使用的易变 Android 运行时状态。""" now_ms: int elapsed_realtime_ms: int uptime_ms: int boot_count: int report_counter: int = 1 def __post_init__(self) -> None: if self.now_ms < 0: raise ValueError("now_ms must not be negative") if self.elapsed_realtime_ms < 0: raise ValueError("elapsed_realtime_ms must not be negative") if not 0 <= self.uptime_ms <= self.elapsed_realtime_ms: raise ValueError("uptime_ms must be between 0 and elapsed_realtime_ms") if self.boot_count < 0 or self.report_counter < 1: raise ValueError("boot_count/report_counter out of range") @classmethod def fresh( cls, profile: DeviceProfile, *, now_ms: int | None = None, report_counter: int = 1, ) -> "WeaponRuntimeSnapshot": current_ms = int(time.time() * 1000) if now_ms is None else int(now_ms) seed = _profile_seed(profile) boot_age_ms = 6 * 60 * 60 * 1000 + seed % (5 * 24 * 60 * 60 * 1000) sleep_ms = (seed >> 17) % max(1, boot_age_ms // 3) return cls( now_ms=current_ms, elapsed_realtime_ms=boot_age_ms, uptime_ms=boot_age_ms - sleep_ms, boot_count=1 + ((seed >> 29) % 180), report_counter=report_counter, ) def _profile_seed(profile: DeviceProfile) -> int: material = "|".join( ( profile.android_id, profile.local_did, profile.sid, str(profile.install_time_ms), ) ) return int.from_bytes(hashlib.sha256(material.encode("utf-8")).digest()[:8], "big") def _installation_id(profile: DeviceProfile) -> str: source = profile.sid.replace("-", "") if len(source) < 16: source = hashlib.sha256(profile.android_id.encode("ascii")).hexdigest() random_half = "".join(source[index * 2] for index in range(8)) created_ms = profile.install_time_ms or profile.cold_launch_time_ms time_half = f"{created_ms:x}"[-8:].zfill(8) return f"a_{random_half}{time_half}" def build_mf_payload( profile: DeviceProfile, *, event: int = 1, snapshot: WeaponRuntimeSnapshot | None = None, field_overrides: Mapping[str, Any] | None = None, ) -> dict[str, Any]: """按 ``mf.a()`` 的插入顺序构建设备状态对象。""" runtime = snapshot or WeaponRuntimeSnapshot.fresh(profile) seed = _profile_seed(profile) battery_level = 40 + seed % 61 storage_bytes = profile.runtime_hints.storage_available_bytes or 491_765_592_064 boot_epoch_seconds = (runtime.now_ms - runtime.elapsed_realtime_ms) // 1000 payload: dict[str, Any] = { "0": 1, "3": 1, "8": 0, "24": 0, "35": 0, "30": 0, "31": 0, "65": 0, "66": 0, "68": 0, "101": 0, "102": 0, "1021": _installation_id(profile), "6": "0", "47": "0", "48": "0", "37": "0", "38": "0", "45": "0", "91": "0", "54": "0", "55": "0", "79": "0", "80": "1", "83": '["{\\"1\\":1}","{\\"2\\":1}"]', "87": "0", "89": "0", "75": "0", "88": "0", "92": "0", "98": "0", "100": "0", "02001": profile.manufacturer, "02002": profile.manufacturer, "02003": profile.model, "02008": profile.build_display, "02016": profile.android_release, "03014": True, "03113": "1970-01-01", "07025": "0", "03020": "USB charger", "03033": False, "03043": runtime.elapsed_realtime_ms, "03044": runtime.uptime_ms, "03045": boot_epoch_seconds, "03085": str(runtime.boot_count), "03086": str(runtime.boot_count), "02029": f"{280 + seed % 40}.{(seed >> 8) % 100:02d}", "03128": str(storage_bytes), "03030": 20 + ((seed >> 16) % 100), "03006": (seed >> 24) % 8, "03007": f"{battery_level}%", "03015": "0", "03115": (seed >> 7) % 1_000_000_000, # 主 APP 在云 DID 更新后调用 WeaponHI.setG,mf 的 ne.k() 读取当前 DID。 "03000": profile.did, "20000": int(event), "11113": 0, "11111": runtime.now_ms // 1000, "11112": runtime.report_counter, "07069": 0, "07070": 0, } if field_overrides: for key, value in field_overrides.items(): payload[str(key)] = value return payload def serialize_mf_payload(payload: Mapping[str, Any]) -> str: """复现 Android ``JSONObject.toString()`` 的紧凑 JSON。""" return json.dumps(payload, ensure_ascii=False, separators=(",", ":")) def generate_profile_passport_account_image( profile: DeviceProfile, *, event: int = 1, snapshot: WeaponRuntimeSnapshot | None = None, field_overrides: Mapping[str, Any] | None = None, ) -> str: payload = build_mf_payload( profile, event=event, snapshot=snapshot, field_overrides=field_overrides, ) return generate_passport_account_image(serialize_mf_payload(payload))