Files
yml2213 a3c3a46b9c fix(tooling): 修复 pyright 解释器配置与类型守卫,补齐 ruff 门禁与两处历史 bug
- pyrightconfig.json 钉死 Python 3.12 虚拟环境,消除由于查找系统 Python 3.9 带来的假性报错
- 修复 huya/login.py 引用不存在函数的问题并补充单元测试
- 修复 browser_harvest.py 对 set 下标访问的错误并提升报错信息质量
- 虎牙 6 个子路由显式导入依赖,消除 import * 带来的未定义变量报警
- 规范化 Pydantic Field(default=...) 默认值声明
- 完善 solver.py / app_login.py 等核心路径类型守卫与 @overload 重载
- 在 pyproject.toml 中显式锁定 ruff lint 规则集 (E4, E7, E9, F, B, I, BLE)
- 门禁脚本同步增加 ruff check 检查并在 AGENTS.md 补齐实践经验总结
2026-10-08 12:33:39 +08:00

106 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""虎牙设备绑定:画像与指纹状态解绑。"""
from fastapi import APIRouter
from ._common import (
_DEVICE_BINDINGS_PERMS_VIEW,
Depends,
HTTPException,
HuyaAccount,
HuyaDeviceBindingsBatchDeleteRequest,
Session,
User,
_fp_state_dir,
_load_profile_db,
_mask_hex,
_require_huya_perm,
_save_profile_db,
_unbind_device_accounts,
get_current_user,
get_db,
shutil,
user_has_permission,
)
router = APIRouter()
@router.get("/device-bindings")
def list_device_bindings(
db: Session = Depends(get_db), current: User = Depends(get_current_user)
):
"""列出所有账号 ↔ 设备环境绑定 (画像 + 指纹状态 + 账号表三方合并)。"""
if not any(user_has_permission(current, p) for p in _DEVICE_BINDINGS_PERMS_VIEW):
raise HTTPException(status_code=403, detail="无虎牙账号查看权限")
profiles = _load_profile_db()
accounts = {a.username: a for a in db.query(HuyaAccount).all() if a.username}
rows = []
for account, prof in sorted(profiles.items()):
acct = accounts.get(account)
state_dir = _fp_state_dir(account)
last_login = prof.get("last_login") or {}
rows.append(
{
"account": account,
"vendor": prof.get("vendor", ""),
"model": prof.get("model", ""),
"screen": prof.get("screen", ""),
"fingerprint_masked": _mask_hex(prof.get("fingerprint")),
"guid32_masked": _mask_hex(prof.get("guid32")),
"hebe_count": len(prof.get("hebe") or {}),
"hdid32": prof.get("hdid", ""), # t1.t0 app 级常量, 非敏感
"has_hydevice_state": state_dir.exists(),
"login_channel": (acct.login_channel if acct else "") or "",
"account_status": (acct.status if acct else "") or "未入库",
"bound_at": prof.get("bound_at"),
"last_login_at": last_login.get("at"),
"last_login_ok": last_login.get("ok"),
}
)
return {"items": rows, "total": len(rows)}
@router.delete("/device-bindings/{account}")
def delete_device_binding(
account: str,
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""解绑: 删除该账号的设备画像与 hydevice 指纹状态, 下次登录自动生成全新环境。"""
_require_huya_perm(current, "huya:import")
profiles = _load_profile_db()
if account not in profiles:
raise HTTPException(status_code=404, detail="该账号没有设备绑定记录")
profiles.pop(account)
_save_profile_db(profiles)
state_dir = _fp_state_dir(account)
removed_state = False
if state_dir.exists():
shutil.rmtree(state_dir, ignore_errors=True)
removed_state = True
return {
"ok": True,
"account": account,
"profile_removed": True,
"fp_state_removed": removed_state,
"message": "已解绑, 下次 App 协议登录将自动生成全新设备环境并重新注册",
}
@router.post("/device-bindings/batch-delete")
def delete_device_bindings(
req: HuyaDeviceBindingsBatchDeleteRequest,
db: Session = Depends(get_db),
current: User = Depends(get_current_user),
):
"""批量解绑: 一次删除多个账号的设备画像与指纹状态。"""
_require_huya_perm(current, "huya:import")
removed, missing = _unbind_device_accounts(req.accounts)
if not removed:
raise HTTPException(status_code=404, detail="所选账号均没有设备绑定记录")
message = f"已批量解绑 {len(removed)} 个账号"
if missing:
message += f",{len(missing)} 个账号无绑定记录已跳过"
message += ",下次 App 协议登录将自动生成全新设备环境并重新注册"
return {"ok": True, "removed": removed, "missing": missing, "message": message}