🐛 修正 Firefox USER_SCRIPT 的分離 realm 沙盒相容性 - #1706
Conversation
|
改动这么大吗,很担心会产生回归问题 |
看過是合理的。但要人手仔細檢查 |
#1697 的呢?也能解决这个问题,这个pr是为了更干净的重构修复? 如果是的话 这个 pr 我觉得可以等下个大版本的beta再更新和验证,现在我先将1.5.0转正式版本了 |
Firefox 版的Bug肯定會有的。Firefox底層用xray, 跟chrome不一樣。 沙盒問題不必急於修正 我有看過1697 . 那個看起來只有結果正確。 |
#1697 不修的话,Firefox无法正常使用,我先合了 #1697 这个留到下个版本验证吧,肯定是要干净的处理的,#1697 相当于是一个临时方案 不过说实话,我对这块不熟,交给你啦 😄 |
|
補一個說明文檔 create_context_technical_guide.html 補回一個 userscript |
|
@CodFrm 已针对 TM Chrome, TM Firefox, TM Firefox + 确认PR代码正确无误。 |
Checklist / 檢查清單
背景
對應 issue #1701:Firefox 的
USER_SCRIPTworld 中,globalThis與頁面window屬於不同 JavaScript realm。原有 sandbox snapshot 將 JavaScript realm 的 intrinsic、頁面 Window 的 DOM/WebIDL 成員,以及 userscript 自己的 global 混在同一條 descriptor chain 中。這會造成
window、self、globalThisalias 不一致,讓 DOM/EventTarget method 使用錯誤 receiver,並可能在 constructor/interface 被 bind 後遺失prototype或 static properties。本次改動
window尚未有 ownglobalThis,先補上指回 hostwindow的 fallback,確保unsafeWindow.globalThis在 Firefox split-realm 下可用。realmGlobal:只收集 userscript realm 的 own descriptors,保留 JavaScript intrinsics,並對同名 descriptor 取得優先權。hostWindow:收集 host Window 的 own/prototype descriptors,補齊 DOM、Window accessor、EventTarget method 與 host constructor/interface。createProxyContext()的 roots 建模為RealmRoots;生產路徑維持預設的global/window,測試則可注入 split-realm roots。Function.prototype.bindmaterialize 需要 receiver 的 host function、getter/setter;constructor/interface 不 bind,以保留prototype和 static members。window、self、globalThis始終指向目前 sandbox;top、parent、frames在 host 指向自身時折回目前 sandbox,非自身的 iframe reference 則保留。on*event property 的註冊與移除統一作用在 host Window,callback 的this保持為 sandbox;function replacement 不重複註冊,object/primitive/null handler 不作為 function listener。window.onurlchange的 grant gate,並使用 host navigation channel;未授權時不建立 accessor 或 listener。onurlchange。example/tests/sandbox_compatibility_test.js黑盒診斷 userscript,提供頁面隔離、global alias、descriptor、host receiver、constructor/interface、事件、onurlchange、GM API 檢查,以及面板、重跑和 JSON 報告功能。sandbox_test.js重命名為sandbox_function_test.js,並同步更新e2e/gm-api.spec.ts的 fixture 名稱與輸出標籤。實現考慮
descriptor source 的順序固定為:
realmGlobal own descriptors→hostWindow own/prototype descriptors→PseudoWindow descriptors→ sandbox-specific descriptors同一來源的 prototype chain 以較近的 descriptor 優先;realm own descriptor 也優先於 host 的同名 descriptor。host own properties 會納入 snapshot,host prototype 只用來補齊尚未被前一階段取得的成員,因此可同時保留必要 host surface 與 realm intrinsic identity。
bind 目標跟隨 descriptor 的來源:realm function/accessor 綁定到
realmGlobal,host function/accessor 綁定到hostWindow。有prototype或以大寫名稱識別的 constructor/interface 不綁定,避免bind剝掉其 prototype 或 static surface;binding 使用已保存的Function.prototype.bind,不依賴 Xray callable 自身的.bindlookup。事件 property 維持既有 lifecycle 契約:註冊與移除作用在同一個 host event target,handler 的
this仍是目前 sandbox;window.onurlchange只有在對應 grant 存在時才建立。已知限制
createContext()/createProxyContext()的 split-realm sandbox model;沒有改變@grant none是否建立 sandbox 的既有 policy。sandbox_compatibility_test.js是可在瀏覽器中執行的黑盒診斷工具,目前未接入 Playwright 自動測試;自動 E2E 仍執行重命名後的sandbox_function_test.js。Cu.Sandbox/ Xray runtime 中手動驗證;Vitest 使用 deterministic roots fixture 模擬 split-realm、host receiver 與事件 contract。window.onurlchange與其他 host API 的完整 browser coverage 仍受實際瀏覽器/管理器暴露面影響,診斷器會將不可用項目標為SKIP,將可選差異標為WARN。pnpm run test:ci曾因環境禁止監聽127.0.0.1收到listen EPERM,結果為 343/344 test files、4316/4317 tests 通過;這不是本 PR 的 assertion failure。建議審查重點
realmGlobal/hostWindow的 descriptor precedence,以及 host own/prototype 成員的預期暴露邊界。prototype、static constants 與 pseudo-window 的toStringTag/constructor/__proto__identity。window、self、globalThis、top、parent、frames的 sandbox identity 與 iframe 非自身 reference 語義。on*property 的 register/remove/replace lifecycle、window.onurlchangegrant gate,以及每個 sandbox 的 state isolation。參考
src/app/service/content/create_context.tssrc/app/service/content/create_context.test.tsexample/tests/sandbox_compatibility_test.jsexample/tests/sandbox_function_test.js(由sandbox_test.js重命名)e2e/gm-api.spec.ts驗證
7b54e85c6e03cdbf75a94040ca59a546e0eb4043):Lint、Run test shard (1/2)、Run test shard (2/2)、Run E2E tests (1/4)至(4/4)、Run tests、License Compliance、codecov/project均為成功。pnpm exec vitest run src/app/service/content/create_context.test.ts src/app/service/content/exec_script.test.ts src/app/service/content/exec_warp.test.ts --reporter=dot— 3 files / 72 tests passedpnpm run typecheck— passedpnpm run lint— passedpnpm exec eslint . --cache --cache-location .eslintcache— passedpnpm exec prettier --check src/app/service/content/create_context.ts— passedpnpm run test:ci— 343/344 files、4316/4317 tests passed;唯一失敗為上述 localhostEPERM環境限制