[英]CustomEvent.detail “tainted”?
我正在開發Chrome擴展程序,以增加網站的便利性。
我可以訪問頁面的DOM,但是我還需要與該頁面上的“第一方” JS進行交互,而我無法通過其擴展程序進行此操作。
我可以在頁面中注入任意標簽(最著名的是<script>
標簽),但是由於轉義了像
{
html: '<div onclick="doSomething(this, \'someName\')"></div>'
}
是一個真正的痛苦,我想將注入的代碼保持在絕對最低限度。
我嘗試將事件偵聽器注入頁面中,以便從頁面中獲取JS變量,但是遇到了問題。
看來,如果CustomEvent
從擴展名傳遞到網站或返回,又或者CustomEvent.detail
在某處包含某些類型的對象(至少是函數和錯誤),則將清除整個CustomEvent.detail
,即設置為null。
腳本(extension.js):
(function()
{
var script = document.createElement('script');
script.innerHTML = [
"window.addEventListener('xyz', function(ev)",
" { ",
" console.log('after dispatch:'); ",
" console.log(ev.detail); ",
" }); ",
].join('\n');
document.head.appendChild(script);
// JSON-serializable data
var e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger' } });
console.log('before dispatch:')
console.log(e.detail);
window.dispatchEvent(e);
// non-JSON-serializable data
var detail = { x: 42, name: 'Schroedinger' };
detail.detail = detail; // Create circular reference
e = new CustomEvent('xyz', { detail: detail });
console.log('before dispatch:')
console.log(e.detail);
window.dispatchEvent(e);
// data with function
e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', func: function(){} } });
console.log('before dispatch:');
console.log(e.detail);
window.dispatchEvent(e);
// data with error object
e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', err: new Error() } });
console.log('before dispatch:');
console.log(e.detail);
window.dispatchEvent(e);
})();
輸出(為便於閱讀而分類):
before dispatch:
Object {x: 42, name: "Schroedinger"}
after dispatch:
Object {x: 42, name: "Schroedinger"}
before dispatch:
Object {x: 42, name: "Schroedinger", detail: Object}
after dispatch:
Object {x: 42, name: "Schroedinger", detail: Object}
before dispatch:
Object {x: 42, name: "Schroedinger", func: function (){}}
after dispatch:
null
before dispatch:
Object {x: 42, name: "Schroedinger", err: Error at chrome-extension://...}
after dispatch:
null
我最初以為JSON可序列化是問題所在,但是循環引用在事件中傳遞得很好,如果JSON序列化會破壞循環引用。
感覺某些對象“污染”事件的細節與非跨域圖像污染畫布的方式相同,只是控制台中什么也沒有。
我找不到有關此行為的任何文檔,並且(如Paul S.建議的那樣), Chrome權限列表上似乎沒有該權限的“特權”。
已在Chrome 40.0.2214.115m,43.0.2357.124m和48.0.2547.0-dev中測試。
我最初以為這是一種安全功能,主要是因為Firefox的行為方式如此。
通過將事件偵聽器放置在可以通過
mozIJSSubScriptLoader
加載的單獨文件中,在Firefox中進行了等效測試:test.js:
(function() { window.addEventListener('xyz', function(ev) { console.log('after dispatch:'); console.log(ev.detail); }); })();
firefox.js:
(function() { var mozIJSSubScriptLoader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader); window.addEventListener('load', function load(event) { window.removeEventListener('load', load); window.gBrowser.addEventListener('DOMContentLoaded', function(event) { mozIJSSubScriptLoader.loadSubScript('chrome://my-extension/content/test.js', window.content, 'UTF-8'); // JSON-serializable data var e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger' } }); console.log('before dispatch:') console.log(e.detail); window.content.dispatchEvent(e); // non-JSON-serializable data e = new CustomEvent('xyz', { detail: { x: 42, name: 'Schroedinger', func: function(){} } }); console.log('before dispatch:'); console.log(e.detail); window.content.dispatchEvent(e); }); }); })();
結果:
(請注意該錯誤發生兩次。)
因此,在Firefox中,甚至包含什么
detail
都不重要-只要它來自擴展程序,就不允許該頁面訪問它。
在我看來,這是一項安全功能。
我將以上內容引用為引號的原因是,這在Chrome中有些不同!
經過更深入的研究后,盡管擴展名和頁面共享DOM樹,但它們存在於兩個不同的上下文中。
我不知道這實際上是安全功能還是技術上的后果,但這當然會導致只能來回傳遞可克隆對象的結果。
不過,令我感到困惑的是,該操作默默地失敗了,根據HTML標准§2.7.5(結構化克隆) ,整個操作應該失敗並出現錯誤:
input如果輸入是另一種本機對象類型(例如,錯誤,函數)
input如果輸入是宿主對象(例如DOM節點)
引發DataCloneError異常並中止整體結構化克隆算法。
我最終使用了一個相當簡單(盡管不是很漂亮)的解決方法:
在Chrome瀏覽器中,沒有等效於mozIJSSubScriptLoader
,但是您可以在擴展程序內將<script>
標記附加到頁面上(不允許在FF中執行此操作)。
與chrome.extension.getURL
一起,可用於在頁面上下文中運行與擴展名打包在一起的JS文件:
(function()
{
var script = document.createElement('script');
script.src = chrome.extension.getURL('extension.js');
document.head.appendChild(script);
})();
當然需要
"web_accessible_resources": [ "extension.js" ]
是在manifest.json
中設置的,雖然不漂亮,但這不是實際問題。
當然,這樣做的缺點是,在extension.js
您不再有權訪問您的擴展程序可以訪問的任何chrome API,但就我而言,我並不需要它。 它不會是太難通過設立一個代理CustomEvent
的,雖然,作為Chrome的API中最重要的部分只需要返回的數據是可克隆的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.