Files
live-hub-py/docs/HUYA_BROWSER_EXCHANGE.md
T
yml2213 4518b726ac feat(huya): 浏览器兑换三目标直达并收窄扩展注入范围
- 操作列改为「直播间 / 精英宝典 / 电竞宝典」三个直达按钮,点哪个就按哪个目标写入登录态并打开,去掉弹窗内选择
- 新增 services/huya_exchange_targets.py 统一三个目标地址,接口支持可选 body {"target": "..."}(不传=精英宝典)
- 扩展内容脚本从 <all_urls> 收窄到后台站点白名单,service worker 校验 sender.tab.url,拒绝其它来源的注入
- 注入改为 Cookie 写完后回执(ok/written/failed/error),前端按回执提示成功或失败,不再静默
- 扩展图标兜底改用 world:'MAIN' 读取;一个 Cookie 都没写成功时不打开目标页
- 兑换材料签发写审计 huya:exchange:kit(含账号与目标)
- 控制台脚本增加 huya.com 域校验与 Secure,与扩展路径保持一致
- 修复兑换记录轮询的跨账号串扰与卸载后 setState;兑换请求加 epoch 防止过期结果覆盖弹窗
- 新增 tests/test_huya_browser_exchange.py(13 项)并同步 docs/HUYA_BROWSER_EXCHANGE.md
2026-09-11 10:31:46 +08:00

8.2 KiB
Raw Blame History

虎牙浏览器兑换(本机浏览器)

人工兑换在操作者自己的 Chrome/Edge 中完成:后端下发目标页地址和登录材料,登录态自动(扩展)或手动(控制台脚本)写入本机浏览器,兑换本身始终由人工点击,服务端不托管任何浏览器会话。

入口与账号范围

独立页面:虎牙 → 浏览器兑换。导航按角色区分:客服只看到浏览器兑换一个入口;管理员/运营仍显示完整的虎牙菜单(账号管理、精英宝典等)。

  • 页面维护一份「兑换账号列表」,通过「导入账号」从自己可见的账号池勾选加入;客服只能看到分配给自己的账号。
  • 列表按用户隔离保存(工作台 scope browser_exchange),与精英宝典的账号集合互不影响。
  • 账号需已有 Cookie 才能执行兑换;账号的 App 协议登录由管理员在账号管理页(直链 /huya/accounts)完成,客服遇到无 Cookie 账号时联系管理员处理。

目标页三个直达按钮

操作列直接提供三个目标按钮(直播间 / 精英宝典 / 电竞宝典),点哪个就按哪个目标写入登录态并打开对应页面;接口不传 target 时用「精英宝典」(与历史行为一致)。

key 名称 地址
live_room 直播间 https://www.huya.com/30596253
elite 精英宝典(默认) https://zt.huya.com/b02faae1/pc/index.html?sourceId=yellowcarlist&pid={room_pid}&anchorUid={room_pid}&roomid=30596253
esports 电竞宝典 https://zt.huya.com/50ea007f/pc/index.html?sourceId=yellowcarlist&pid={room_pid}&anchorUid={room_pid}&roomid=30596253
  • {room_pid} 取虎牙配置的 room_pid;配置为空时用默认 1199650619883(web/backend/huya_defaults.py)。直播间地址与 room_pid 无关。
  • 每次点击都会按该目标重新取一次兑换材料(登录脚本里的跳转地址跟着目标变)。
  • 新增目标:在 web/backend/services/huya_exchange_targets.py 加常量与地址,并在 web/backend/schemas.py 的 HuyaBrowserExchangeRequest.target 正则里补上 key(tests/test_huya_browser_exchange.py 会校验两处不漂移)。

一键自动注入(推荐):安装内置扩展

项目自带 Chrome/Edge 扩展 web/extension/huya-exchange-helper/,安装一次后即可自动注入:

  1. 打开扩展管理页:Chrome 为 chrome://extensions,Edge 为 edge://extensions。
  2. 开启「开发者模式」,点击「加载已解压的扩展程序」,选择仓库目录 web/extension/huya-exchange-helper。
  3. 刷新后台页面(扩展的内容脚本需要对当前页生效)。
  • 已装过旧版扩展时,升级后必须回到 chrome://extensions 点一次「刷新」;否则浏览器里跑的还是旧版(旧版会注入所有网站,本次安全收窄不生效)。

之后的流程:

  1. 在兑换列表操作列点击目标按钮(直播间 / 精英宝典 / 电竞宝典)→ 后端返回兑换材料 → 扩展自动把该账号 Cookie 写入 .huya.com 域并在新标签页打开该页面;若一个 Cookie 都没写成功,扩展不会打开目标页(避免打开未登录或上一个账号的页面),弹窗显示失败原因。
  2. 弹窗会显示本次注入结果(写入 / 失败条数);失败时按提示处理后点「注入登录态并打开」重试。
  3. 确认页面右上角账号无误后,手动完成兑换,回到后台点击「完成」。

扩展只在注入时覆盖与登录态同名的旧 Cookie,其余虎牙 Cookie 不动;扩展图标点击可作为兜底(读取当前后台页签留存的材料),未检测到材料时图标显示「无任务」角标。

内容脚本只注入后台站点白名单(manifest.json 的 content_scripts.matches):生产 https://live.khhao.com、开发隧道 https://www.u499731.nyat.app、本地 http://localhost:5174、http://127.0.0.1:5174、http://localhost:8800、http://127.0.0.1:8800。若后台使用其它域名,需要把该域名加进名单再重新加载扩展——service worker 从这份名单推导允许触发注入的来源,其它站点派发的注入请求会被拒绝。

查询兑换记录

兑换列表每行的「兑换记录」按钮会为该账号创建 query_exchange_records 精英宝典任务(活动 SID 取精英宝典配置),前端轮询任务完成后:

  • 表格新增的「兑换记录」列直接展示奖品名(多条时显示"xxx 等 N 条",悬停可看全部名称),未查询显示"未查询",查询中显示加载图标,失败显示"查询失败"及原因。
  • 点击单元格中的奖品名可打开详情弹窗,查看每条记录的奖品、消耗积分、发放状态、兑换时间与订单号。

任务失败(如 SID 未配置、Cookie 失效)时弹窗内直接显示原因,可点击「重新查询」。

手动方式(未装扩展时的兜底)

  1. 在兑换列表操作列点击目标按钮(直播间 / 精英宝典 / 电竞宝典)→ 未装扩展时目标页会直接在新标签页打开,并弹出「浏览器兑换」窗口给出手动兜底。
  2. 在虎牙域下的页面按 F12 打开控制台,粘贴脚本并回车执行。Chrome/Edge 首次粘贴需先手动输入 allow pasting 再回车。脚本会先校验当前页面在 huya.com 域下(不满足会弹窗提示并中止),写入带 Secure(与扩展路径一致)的 Cookie 后跳转目标页。
  3. 确认登录态正确后完成兑换,回到系统点击「完成」。

没有控制台操作习惯时,可安装 Cookie-editor 类扩展,使用「复制 Cookie 字符串」在 .huya.com 域下导入。

接口

POST /api/huya/accounts/{account_id}/browser-exchange(权限 huya:task),可选 body {"target": "live_room" | "elite" | "esports"}:

{
  "account_id": 1,
  "username": "xxx",
  "target": "elite",
  "targets": [
    { "key": "live_room", "label": "直播间", "url": "https://www.huya.com/30596253" },
    { "key": "elite", "label": "精英宝典", "url": "https://zt.huya.com/b02faae1/pc/index.html?..." },
    { "key": "esports", "label": "电竞宝典", "url": "https://zt.huya.com/50ea007f/pc/index.html?..." }
  ],
  "target_url": "https://...",
  "cookie_string": "yyuid=...; ...",
  "cookie_script": "(function(){...})();"
}
  • targets 固定返回三个可选目标(顺序:直播间、精英宝典、电竞宝典),前端据此渲染选择器;非法 target 由 Pydantic 正则拦下(422)。
  • 脚本由 core.huya.cookie_utils.browser_login_script 生成:先校验 location.hostname 属于 huya.com,Cookie 以 JSON 数组内联(自动转义),逐条 document.cookie 写入 domain=.huya.com; path=/; secure,有效期 180 天,最后跳转 target_url。
  • 扩展注入走同一条接口:前端解析 cookie_string 后通过 DOM 事件交给扩展,由 chrome.cookies API 写入,并把写入结果回执给页面(前端据此提示成功/失败,不再静默)。
  • 兑换账号列表复用 /api/huya/workbench-accounts(handbook_scope=browser_exchange)。
  • 每次签发都会留审计日志:audit_logs.action = huya:exchange:kit,target = huya_account:{id},detail 含 account_id 与 target。
  • 服务端不保存任何会话状态。

安全说明

  • 接口受 huya:task 权限与账号可见范围约束;脚本、Cookie 字符串与扩展注入等同账号凭证,仅在授权用户点击时下发,且逐次留痕。
  • 登录态只写入操作者自己的浏览器,不会在服务器留存浏览器进程或 Profile。
  • 扩展为内部工具,通过开发者模式加载;内容脚本只注入后台站点白名单,service worker 二次校验消息来源站点,且只写 huya.com 域的 Cookie。
  • 仍存在的边界:注入请求由后台页面用 CustomEvent 派发,页面内其它脚本理论上可以监听或伪造同名事件(页面派发的事件 isTrusted 恒为 false,无法据此区分真伪);因此不要把不受信任的脚本引入后台页面。
  • 扩展写入的 Cookie 非 HttpOnly(chrome.cookies 限制),虎牙域内脚本可读,这是本方案的固有取舍。
  • 请勿把脚本、Cookie 或扩展转给无关人员;如需共享操作,建议使用系统的账号授权机制而非转发凭证。