- 操作列改为「直播间 / 精英宝典 / 电竞宝典」三个直达按钮,点哪个就按哪个目标写入登录态并打开,去掉弹窗内选择
- 新增 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
59 lines
2.4 KiB
JavaScript
59 lines
2.4 KiB
JavaScript
// 内容脚本:只注入后台管理系统页面(站点白名单见 manifest.content_scripts.matches)。
|
||
// 职责:① 标记扩展可用;② 把后台页面派发的兑换材料转发给 service worker;
|
||
// ③ 把写入结果回执给页面(修复"注入失败但界面仍提示成功")。
|
||
// 安全边界:不再注入 <all_urls>,页面侧只能通过固定事件名提交材料;
|
||
// service worker 仍会二次校验消息来源站点,Cookie 只写入 .huya.com 域。
|
||
// document_start 阶段可能拿到非 HTML 文档(XML/图片等)而没有 documentElement,
|
||
// 这里判空,避免异常连带杀死后面的监听注册(会导致自动注入永久失效)。
|
||
if (document.documentElement) {
|
||
document.documentElement.dataset.huyaExchangeHelper = '1';
|
||
}
|
||
|
||
function dispatchResult(payload) {
|
||
try {
|
||
window.dispatchEvent(
|
||
new CustomEvent('huya-exchange-result', { detail: JSON.stringify(payload) })
|
||
);
|
||
} catch (e) { /* 页面已卸载等场景忽略 */ }
|
||
}
|
||
|
||
window.addEventListener('huya-exchange-kit', (event) => {
|
||
// 后台页面用页面脚本派发的 CustomEvent,isTrusted 恒为 false,
|
||
// 所以这里不能校验 isTrusted;拦截点是 manifest 站点白名单 + service worker 的来源校验。
|
||
const detail = event.detail;
|
||
if (typeof detail !== 'string') return;
|
||
let kit;
|
||
try {
|
||
kit = JSON.parse(detail);
|
||
} catch (e) {
|
||
return; // 忽略非法消息
|
||
}
|
||
if (!kit || !kit.target_url || !Array.isArray(kit.cookies)) return;
|
||
const requestId = typeof kit.request_id === 'string' ? kit.request_id : '';
|
||
try {
|
||
chrome.runtime.sendMessage({ type: 'inject', kit }, (response) => {
|
||
const lastError = chrome.runtime.lastError ? chrome.runtime.lastError.message : '';
|
||
if (lastError) {
|
||
dispatchResult({ request_id: requestId, ok: false, written: 0, failed: 0, error: lastError });
|
||
return;
|
||
}
|
||
const result = response || {};
|
||
dispatchResult({
|
||
request_id: requestId,
|
||
ok: Boolean(result.ok),
|
||
written: Number(result.written) || 0,
|
||
failed: Number(result.failed) || 0,
|
||
error: typeof result.error === 'string' ? result.error : '',
|
||
});
|
||
});
|
||
} catch (e) {
|
||
dispatchResult({
|
||
request_id: requestId,
|
||
ok: false,
|
||
written: 0,
|
||
failed: 0,
|
||
error: '扩展上下文失效,请在扩展管理页重新加载扩展',
|
||
});
|
||
}
|
||
}, true);
|