зеркало из https://github.com/mozilla/gecko-dev.git
Back out 3 changesets (bug 1214658) for b2g emulator timeouts in test_ext_contentscript_*
CLOSED TREE Backed out changeset b76ab3324cd2 (bug 1214658) Backed out changeset aee8341f15c7 (bug 1214658) Backed out changeset 743d7567b280 (bug 1214658) --HG-- rename : toolkit/components/extensions/test/mochitest/file_ext_test_api_injection.js => toolkit/components/extensions/test/mochitest/file_ext_background_api_injection.js
This commit is contained in:
Родитель
efa26893a5
Коммит
102023d0a0
|
@ -363,16 +363,12 @@ GlobalManager = {
|
|||
Schemas.inject(chromeObj, schemaWrapper);
|
||||
};
|
||||
|
||||
let id = ExtensionManagement.getAddonIdForWindow(contentWindow);
|
||||
|
||||
// We don't inject privileged APIs into sub-frames of a UI page.
|
||||
const { FULL_PRIVILEGES } = ExtensionManagement.API_LEVELS;
|
||||
if (ExtensionManagement.getAPILevelForWindow(contentWindow, id) !== FULL_PRIVILEGES) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't inject privileged APIs if the addonId is null
|
||||
// or doesn't exist.
|
||||
// Find the add-on associated with this document via the
|
||||
// principal's originAttributes. This value is computed by
|
||||
// extensionURIToAddonID, which ensures that we don't inject our
|
||||
// API into webAccessibleResources or remote web pages.
|
||||
let principal = contentWindow.document.nodePrincipal;
|
||||
let id = principal.originAttributes.addonId;
|
||||
if (!this.extensionMap.has(id)) {
|
||||
return;
|
||||
}
|
||||
|
@ -391,6 +387,10 @@ GlobalManager = {
|
|||
return;
|
||||
}
|
||||
|
||||
// We don't inject into sub-frames of a UI page.
|
||||
if (contentWindow != contentWindow.top) {
|
||||
return;
|
||||
}
|
||||
let extension = this.extensionMap.get(id);
|
||||
let uri = contentWindow.document.documentURIObject;
|
||||
let incognito = PrivateBrowsingUtils.isContentWindowPrivate(contentWindow);
|
||||
|
|
|
@ -216,10 +216,7 @@ var ExtensionManager;
|
|||
// Scope in which extension content script code can run. It uses
|
||||
// Cu.Sandbox to run the code. There is a separate scope for each
|
||||
// frame.
|
||||
function ExtensionContext(extensionId, contentWindow, contextOptions = {}) {
|
||||
let { isExtensionPage } = contextOptions;
|
||||
|
||||
this.isExtensionPage = isExtensionPage;
|
||||
function ExtensionContext(extensionId, contentWindow) {
|
||||
this.extension = ExtensionManager.get(extensionId);
|
||||
this.extensionId = extensionId;
|
||||
this.contentWindow = contentWindow;
|
||||
|
@ -246,27 +243,12 @@ function ExtensionContext(extensionId, contentWindow, contextOptions = {}) {
|
|||
prin = [contentPrincipal, extensionPrincipal];
|
||||
}
|
||||
|
||||
if (isExtensionPage) {
|
||||
if (ExtensionManagement.getAddonIdForWindow(this.contentWindow) != extensionId) {
|
||||
throw new Error("Invalid target window for this extension context");
|
||||
}
|
||||
// This is an iframe with content script API enabled and its principal should be the
|
||||
// contentWindow itself. (we create a sandbox with the contentWindow as principal and with X-rays disabled
|
||||
// because it enables us to create the APIs object in this sandbox object and then copying it
|
||||
// into the iframe's window, see Bug 1214658 for rationale)
|
||||
this.sandbox = Cu.Sandbox(contentWindow, {
|
||||
sandboxPrototype: contentWindow,
|
||||
wantXrays: false,
|
||||
isWebExtensionContentScript: true,
|
||||
});
|
||||
} else {
|
||||
this.sandbox = Cu.Sandbox(prin, {
|
||||
sandboxPrototype: contentWindow,
|
||||
wantXrays: true,
|
||||
isWebExtensionContentScript: true,
|
||||
wantGlobalProperties: ["XMLHttpRequest"],
|
||||
});
|
||||
}
|
||||
this.sandbox = Cu.Sandbox(prin, {
|
||||
sandboxPrototype: contentWindow,
|
||||
wantXrays: true,
|
||||
isWebExtensionContentScript: true,
|
||||
wantGlobalProperties: ["XMLHttpRequest"],
|
||||
});
|
||||
|
||||
let delegate = {
|
||||
getSender(context, target, sender) {
|
||||
|
@ -283,19 +265,12 @@ function ExtensionContext(extensionId, contentWindow, contextOptions = {}) {
|
|||
let filter = {extensionId, frameId};
|
||||
this.messenger = new Messenger(this, broker, sender, filter, delegate);
|
||||
|
||||
this.chromeObj = Cu.createObjectIn(this.sandbox, {defineAs: "browser"});
|
||||
let chromeObj = Cu.createObjectIn(this.sandbox, {defineAs: "browser"});
|
||||
|
||||
// Sandboxes don't get Xrays for some weird compatibility
|
||||
// reason. However, we waive here anyway in case that changes.
|
||||
Cu.waiveXrays(this.sandbox).chrome = this.chromeObj;
|
||||
|
||||
injectAPI(api(this), this.chromeObj);
|
||||
|
||||
// This is an iframe with content script API enabled. (See Bug 1214658 for rationale)
|
||||
if (isExtensionPage) {
|
||||
Cu.waiveXrays(this.contentWindow).chrome = this.chromeObj;
|
||||
Cu.waiveXrays(this.contentWindow).browser = this.chromeObj;
|
||||
}
|
||||
Cu.waiveXrays(this.sandbox).chrome = Cu.waiveXrays(this.sandbox).browser;
|
||||
injectAPI(api(this), chromeObj);
|
||||
}
|
||||
|
||||
ExtensionContext.prototype = {
|
||||
|
@ -319,17 +294,7 @@ ExtensionContext.prototype = {
|
|||
for (let obj of this.onClose) {
|
||||
obj.close();
|
||||
}
|
||||
|
||||
// Overwrite the content script APIs with an empty object if the APIs objects are still
|
||||
// defined in the content window (See Bug 1214658 for rationale).
|
||||
if (this.isExtensionPage && !Cu.isDeadWrapper(this.contentWindow) &&
|
||||
Cu.waiveXrays(this.contentWindow).browser === this.chromeObj) {
|
||||
Cu.createObjectIn(this.contentWindow, { defineAs: "browser" });
|
||||
Cu.createObjectIn(this.contentWindow, { defineAs: "chrome" });
|
||||
}
|
||||
|
||||
Cu.nukeSandbox(this.sandbox);
|
||||
this.sandbox = null;
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -345,10 +310,7 @@ var DocumentManager = {
|
|||
extensionCount: 0,
|
||||
|
||||
// Map[windowId -> Map[extensionId -> ExtensionContext]]
|
||||
contentScriptWindows: new Map(),
|
||||
|
||||
// Map[windowId -> ExtensionContext]
|
||||
extensionPageWindows: new Map(),
|
||||
windows: new Map(),
|
||||
|
||||
init() {
|
||||
Services.obs.addObserver(this, "document-element-inserted", false);
|
||||
|
@ -386,40 +348,23 @@ var DocumentManager = {
|
|||
return;
|
||||
}
|
||||
|
||||
// Enable the content script APIs should be available in subframes' window
|
||||
// if it is recognized as a valid addon id (see Bug 1214658 for rationale).
|
||||
const { CONTENTSCRIPT_PRIVILEGES } = ExtensionManagement.API_LEVELS;
|
||||
let extensionId = ExtensionManagement.getAddonIdForWindow(window);
|
||||
|
||||
if (ExtensionManagement.getAPILevelForWindow(window, extensionId) == CONTENTSCRIPT_PRIVILEGES &&
|
||||
ExtensionManager.get(extensionId)) {
|
||||
DocumentManager.getExtensionPageContext(extensionId, window);
|
||||
}
|
||||
|
||||
this.trigger("document_start", window);
|
||||
/* eslint-disable mozilla/balanced-listeners */
|
||||
window.addEventListener("DOMContentLoaded", this, true);
|
||||
window.addEventListener("load", this, true);
|
||||
/* eslint-enable mozilla/balanced-listeners */
|
||||
} else if (topic == "inner-window-destroyed") {
|
||||
let windowId = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
|
||||
// Close any existent content-script context for the destroyed window.
|
||||
if (this.contentScriptWindows.has(windowId)) {
|
||||
let extensions = this.contentScriptWindows.get(windowId);
|
||||
for (let [, context] of extensions) {
|
||||
context.close();
|
||||
}
|
||||
|
||||
this.contentScriptWindows.delete(windowId);
|
||||
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
if (!this.windows.has(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Close any existent iframe extension page context for the destroyed window.
|
||||
if (this.extensionPageWindows.has(windowId)) {
|
||||
let context = this.extensionWindows.get(windowId);
|
||||
let extensions = this.windows.get(id);
|
||||
for (let [, context] of extensions) {
|
||||
context.close();
|
||||
this.extensionPageWindows.delete(windowId);
|
||||
}
|
||||
|
||||
this.windows.delete(id);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -444,7 +389,7 @@ var DocumentManager = {
|
|||
|
||||
executeScript(global, extensionId, script) {
|
||||
let window = global.content;
|
||||
let context = this.getContentScriptContext(extensionId, window);
|
||||
let context = this.getContext(extensionId, window);
|
||||
if (!context) {
|
||||
return;
|
||||
}
|
||||
|
@ -468,33 +413,19 @@ var DocumentManager = {
|
|||
}
|
||||
},
|
||||
|
||||
getContentScriptContext(extensionId, window) {
|
||||
getContext(extensionId, window) {
|
||||
let winId = windowId(window);
|
||||
if (!this.contentScriptWindows.has(winId)) {
|
||||
this.contentScriptWindows.set(winId, new Map());
|
||||
if (!this.windows.has(winId)) {
|
||||
this.windows.set(winId, new Map());
|
||||
}
|
||||
|
||||
let extensions = this.contentScriptWindows.get(winId);
|
||||
let extensions = this.windows.get(winId);
|
||||
if (!extensions.has(extensionId)) {
|
||||
let context = new ExtensionContext(extensionId, window);
|
||||
extensions.set(extensionId, context);
|
||||
}
|
||||
|
||||
return extensions.get(extensionId);
|
||||
},
|
||||
|
||||
getExtensionPageContext(extensionId, window) {
|
||||
let winId = windowId(window);
|
||||
|
||||
let context = this.extensionPageWindows.get(winId);
|
||||
if (!context) {
|
||||
let context = new ExtensionContext(extensionId, window, { isExtensionPage: true });
|
||||
this.extensionPageWindows.set(winId, context);
|
||||
}
|
||||
|
||||
return context;
|
||||
},
|
||||
|
||||
startupExtension(extensionId) {
|
||||
if (this.extensionCount == 0) {
|
||||
this.init();
|
||||
|
@ -509,7 +440,7 @@ var DocumentManager = {
|
|||
for (let [window, state] of this.enumerateWindows(global.docShell)) {
|
||||
for (let script of extension.scripts) {
|
||||
if (script.matches(window)) {
|
||||
let context = this.getContentScriptContext(extensionId, window);
|
||||
let context = this.getContext(extensionId, window);
|
||||
context.execute(script, scheduled => isWhenBeforeOrSame(scheduled, state));
|
||||
}
|
||||
}
|
||||
|
@ -518,8 +449,7 @@ var DocumentManager = {
|
|||
},
|
||||
|
||||
shutdownExtension(extensionId) {
|
||||
// Clean up content-script contexts on extension shutdown.
|
||||
for (let [, extensions] of this.contentScriptWindows) {
|
||||
for (let [, extensions] of this.windows) {
|
||||
let context = extensions.get(extensionId);
|
||||
if (context) {
|
||||
context.close();
|
||||
|
@ -527,14 +457,6 @@ var DocumentManager = {
|
|||
}
|
||||
}
|
||||
|
||||
// Clean up iframe extension page contexts on extension shutdown.
|
||||
for (let [winId, context] of this.extensionPageWindows) {
|
||||
if (context.extensionId == extensionId) {
|
||||
context.close();
|
||||
this.extensionPageWindows.delete(winId);
|
||||
}
|
||||
}
|
||||
|
||||
this.extensionCount--;
|
||||
if (this.extensionCount == 0) {
|
||||
this.uninit();
|
||||
|
@ -546,7 +468,7 @@ var DocumentManager = {
|
|||
for (let [extensionId, extension] of ExtensionManager.extensions) {
|
||||
for (let script of extension.scripts) {
|
||||
if (script.matches(window)) {
|
||||
let context = this.getContentScriptContext(extensionId, window);
|
||||
let context = this.getContext(extensionId, window);
|
||||
context.execute(script, scheduled => scheduled == state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,58 +202,18 @@ var Service = {
|
|||
// This is used to set the addonId on the originAttributes for the
|
||||
// nsIPrincipal attached to the URI.
|
||||
extensionURIToAddonID(uri) {
|
||||
if (this.extensionURILoadableByAnyone(uri)) {
|
||||
// We don't want webAccessibleResources to be associated with
|
||||
// the add-on. That way they don't get any special privileges.
|
||||
return null;
|
||||
}
|
||||
|
||||
let uuid = uri.host;
|
||||
let extension = this.uuidMap.get(uuid);
|
||||
return extension ? extension.id : undefined;
|
||||
},
|
||||
};
|
||||
|
||||
// API Levels Helpers
|
||||
|
||||
// Find the add-on associated with this document via the
|
||||
// principal's originAttributes. This value is computed by
|
||||
// extensionURIToAddonID, which ensures that we don't inject our
|
||||
// API into webAccessibleResources or remote web pages.
|
||||
function getAddonIdForWindow(window) {
|
||||
let principal = window.document.nodePrincipal;
|
||||
return principal.originAttributes.addonId;
|
||||
}
|
||||
|
||||
const API_LEVELS = Object.freeze({
|
||||
NO_PRIVILEGES: 0,
|
||||
CONTENTSCRIPT_PRIVILEGES: 1,
|
||||
FULL_PRIVILEGES: 2,
|
||||
});
|
||||
|
||||
// Finds the API Level ("FULL_PRIVILEGES", "CONTENTSCRIPT_PRIVILEGES", "NO_PRIVILEGES")
|
||||
// with a given a window object.
|
||||
function getAPILevelForWindow(window, addonId) {
|
||||
const { NO_PRIVILEGES, CONTENTSCRIPT_PRIVILEGES, FULL_PRIVILEGES } = API_LEVELS;
|
||||
|
||||
// Non WebExtension URLs and WebExtension URLs from a different extension
|
||||
// has no access to APIs.
|
||||
if (!addonId && getAddonIdForWindow(window) != addonId) {
|
||||
return NO_PRIVILEGES;
|
||||
}
|
||||
|
||||
let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell);
|
||||
|
||||
// WebExtension URLs loaded into sub-frame UI have "content script API level privileges".
|
||||
// (see Bug 1214658 for rationale)
|
||||
if (docShell.sameTypeParent) {
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
// Extension pages running in the content process defaults to "content script API level privileges".
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
return CONTENTSCRIPT_PRIVILEGES;
|
||||
}
|
||||
|
||||
// WebExtension URLs loaded into top frames UI could have full API level privileges.
|
||||
return FULL_PRIVILEGES;
|
||||
}
|
||||
|
||||
this.ExtensionManagement = {
|
||||
startupExtension: Service.startupExtension.bind(Service),
|
||||
shutdownExtension: Service.shutdownExtension.bind(Service),
|
||||
|
@ -266,9 +226,4 @@ this.ExtensionManagement = {
|
|||
|
||||
getFrameId: Frames.getId.bind(Frames),
|
||||
getParentFrameId: Frames.getParentId.bind(Frames),
|
||||
|
||||
// exported API Level Helpers
|
||||
getAddonIdForWindow,
|
||||
getAPILevelForWindow,
|
||||
API_LEVELS,
|
||||
};
|
||||
|
|
|
@ -20,15 +20,13 @@ support-files =
|
|||
file_sample.html
|
||||
redirection.sjs
|
||||
file_privilege_escalation.html
|
||||
file_ext_test_api_injection.js
|
||||
file_ext_background_api_injection.js
|
||||
file_permission_xhr.html
|
||||
|
||||
[test_ext_simple.html]
|
||||
[test_ext_geturl.html]
|
||||
[test_ext_contentscript.html]
|
||||
skip-if = buildapp == 'b2g' # runat != document_idle is not supported.
|
||||
[test_ext_contentscript_create_iframe.html]
|
||||
[test_ext_contentscript_api_injection.html]
|
||||
[test_ext_i18n_css.html]
|
||||
[test_ext_generate.html]
|
||||
[test_ext_localStorage.html]
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(function* testBackgroundWindow() {
|
|||
|
||||
let awaitConsole = new Promise(resolve => {
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
|
||||
SimpleTest.getTestFileURL("file_ext_background_api_injection.js"));
|
||||
|
||||
chromeScript.addMessageListener("console-message", resolve);
|
||||
});
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for privilege escalation into iframe with content script APIs</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
|
||||
<textarea id="test-asset">
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="./content_script_iframe.js">
|
||||
</script>
|
||||
</head>
|
||||
</html>
|
||||
</textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_api_injection() {
|
||||
function contentScript() {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function contentScriptIframe() {
|
||||
const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
|
||||
window.location = `${BASE}/file_privilege_escalation.html`;
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_end",
|
||||
},
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
"content_script_iframe.html",
|
||||
],
|
||||
},
|
||||
|
||||
files: {
|
||||
"content_script.js": "new " + contentScript,
|
||||
"content_script_iframe.js": "new " + contentScriptIframe,
|
||||
"content_script_iframe.html": document.querySelector("#test-asset").textContent,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let awaitConsole = new Promise(resolve => {
|
||||
let chromeScript = SpecialPowers.loadChromeScript(
|
||||
SimpleTest.getTestFileURL("file_ext_test_api_injection.js"));
|
||||
|
||||
chromeScript.addMessageListener("console-message", resolve);
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
info("extension loaded");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
let message = yield awaitConsole;
|
||||
|
||||
ok(message.message.includes("WebExt Privilege Escalation: typeof(browser) = undefined"),
|
||||
"Document does not have `browser` APIs.");
|
||||
|
||||
win.close();
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -1,163 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for content script</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
|
||||
<script type="text/javascript" src="head.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- WORKAROUND: this textarea hack is used to contain the html page source without escaping it -->
|
||||
<textarea id="test-asset">
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="content_script_iframe.js"></script>
|
||||
</head>
|
||||
</html>
|
||||
</textarea>
|
||||
|
||||
<script type="text/javascript">
|
||||
"use strict";
|
||||
|
||||
add_task(function* test_contentscript_create_iframe() {
|
||||
function backgroundScript() {
|
||||
browser.runtime.onMessage.addListener((msg, sender) => {
|
||||
let { name, availableAPIs, manifest, testGetManifest } = msg;
|
||||
let hasExtTabsAPI = availableAPIs.indexOf("tabs") > 0;
|
||||
let hasExtWindowsAPI = availableAPIs.indexOf("windows") > 0;
|
||||
|
||||
browser.test.assertFalse(hasExtTabsAPI, "the created iframe should not be able to use privileged APIs (tabs)");
|
||||
browser.test.assertFalse(hasExtWindowsAPI, "the created iframe should not be able to use privileged APIs (windows)");
|
||||
|
||||
let { applications: { gecko: { id: expectedManifestGeckoId } } } = chrome.runtime.getManifest();
|
||||
let { applications: { gecko: { id: actualManifestGeckoId } } } = manifest;
|
||||
|
||||
browser.test.assertEq(actualManifestGeckoId, expectedManifestGeckoId,
|
||||
"the add-on manifest should be accessible from the created iframe"
|
||||
);
|
||||
|
||||
let { applications: { gecko: { id: testGetManifestGeckoId } } } = testGetManifest;
|
||||
|
||||
browser.test.assertEq(testGetManifestGeckoId, expectedManifestGeckoId,
|
||||
"GET_MANIFEST() returns manifest data before extension unload"
|
||||
);
|
||||
|
||||
browser.test.sendMessage(name);
|
||||
});
|
||||
}
|
||||
|
||||
function contentScript() {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("src", browser.runtime.getURL("content_script_iframe.html"));
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
function contentScriptIframe() {
|
||||
window.GET_MANIFEST = browser.runtime.getManifest.bind(null);
|
||||
|
||||
window.testGetManifestException = () => {
|
||||
try {
|
||||
window.GET_MANIFEST();
|
||||
} catch (exception) {
|
||||
return String(exception);
|
||||
}
|
||||
};
|
||||
|
||||
let testGetManifest = window.GET_MANIFEST();
|
||||
|
||||
let manifest = browser.runtime.getManifest();
|
||||
let availableAPIs = Object.keys(browser);
|
||||
|
||||
browser.runtime.sendMessage({
|
||||
name: "content-script-iframe-loaded",
|
||||
availableAPIs,
|
||||
manifest,
|
||||
testGetManifest,
|
||||
});
|
||||
}
|
||||
|
||||
let extensionData = {
|
||||
manifest: {
|
||||
content_scripts: [
|
||||
{
|
||||
"matches": ["http://mochi.test/*/file_sample.html"],
|
||||
"js": ["content_script.js"],
|
||||
"run_at": "document_end",
|
||||
},
|
||||
],
|
||||
web_accessible_resources: [
|
||||
"content_script_iframe.html",
|
||||
],
|
||||
},
|
||||
|
||||
background: "(" + backgroundScript + ")()",
|
||||
|
||||
files: {
|
||||
"content_script.js": "new " + contentScript,
|
||||
"content_script_iframe.html": document.querySelector("#test-asset").textContent,
|
||||
"content_script_iframe.js": "new " + contentScriptIframe,
|
||||
},
|
||||
};
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension(extensionData);
|
||||
|
||||
let contentScriptIframeCreatedPromise = new Promise(resolve => {
|
||||
extension.onMessage("content-script-iframe-loaded", () => { resolve(); });
|
||||
});
|
||||
|
||||
yield extension.startup();
|
||||
info("extension loaded");
|
||||
|
||||
let win = window.open("file_sample.html");
|
||||
|
||||
yield Promise.all([waitForLoad(win), contentScriptIframeCreatedPromise]);
|
||||
info("content script privileged iframe loaded and executed");
|
||||
|
||||
info("testing APIs availability once the extension is unloaded...");
|
||||
|
||||
let iframeWindow = SpecialPowers.wrap(win)[0];
|
||||
|
||||
ok(iframeWindow, "content script enabled iframe found");
|
||||
ok(/content_script_iframe\.html$/.test(iframeWindow.location), "the found iframe has the expected URL");
|
||||
|
||||
yield extension.unload();
|
||||
info("extension unloaded");
|
||||
|
||||
info("test content script APIs not accessible from the frame once the extension is unloaded");
|
||||
|
||||
let ww = SpecialPowers.Cu.waiveXrays(iframeWindow);
|
||||
let isDeadWrapper = SpecialPowers.Cu.isDeadWrapper(ww.browser);
|
||||
ok(!isDeadWrapper, "the API object should not be a dead object");
|
||||
|
||||
let manifest;
|
||||
let manifestException;
|
||||
|
||||
try {
|
||||
manifest = ww.browser.runtime.getManifest();
|
||||
} catch (e) {
|
||||
manifestException = e;
|
||||
}
|
||||
|
||||
ok(!manifest, "manifest should be undefined");
|
||||
|
||||
is(String(manifestException), "TypeError: ww.browser.runtime is undefined",
|
||||
"expected \"TypeError: ... is undefined\" exception received");
|
||||
|
||||
let getManifestException = ww.testGetManifestException();
|
||||
|
||||
is(getManifestException, "TypeError: window.GET_MANIFEST is not a function",
|
||||
"expected \"TypeError: ... is not a function\" exception received");
|
||||
|
||||
win.close();
|
||||
|
||||
info("done");
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче