fune/toolkit/components/url-classifier/tests/browser/classifierTester.js
2020-01-07 13:19:30 +00:00

452 lines
14 KiB
JavaScript

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var classifierTester = {
URL_PATH:
"/browser/toolkit/components/url-classifier/tests/browser/flash_block_frame.html",
OBJECT_ID: "testObject",
IFRAME_ID: "testFrame",
FLASHBLOCK_ENABLE_PREF: "plugins.flashBlock.enabled",
FLASH_PLUGIN_USER_SETTING_PREF: "plugin.state.flash",
URLCLASSIFIER_DISALLOW_COMPLETIONS_PREF: "urlclassifier.disallow_completions",
FISSION_PREF: "fission.autostart",
NEVER_ACTIVATE_PREF_VALUE: 0,
ASK_TO_ACTIVATE_PREF_VALUE: 1,
ALWAYS_ACTIVATE_PREF_VALUE: 2,
dbUrls: [
{
url: "flashallow.example.com/",
db: "test-flashallow-simple",
pref: "urlclassifier.flashAllowTable",
},
{
url: "exception.flashallow.example.com/",
db: "testexcept-flashallow-simple",
pref: "urlclassifier.flashAllowExceptTable",
},
{
url: "flashblock.example.com/",
db: "test-flash-simple",
pref: "urlclassifier.flashTable",
},
{
url: "exception.flashblock.example.com/",
db: "testexcept-flash-simple",
pref: "urlclassifier.flashExceptTable",
},
{
url: "subdocument.example.com/",
db: "test-flashsubdoc-simple",
pref: "urlclassifier.flashSubDocTable",
},
{
url: "exception.subdocument.example.com/",
db: "testexcept-flashsubdoc-simple",
pref: "urlclassifier.flashSubDocExceptTable",
},
],
setPrefs({
setDBs = true,
flashBlockEnable = true,
flashSetting = classifierTester.ALWAYS_ACTIVATE_PREF_VALUE,
} = {}) {
if (setDBs) {
let DBs = [];
for (let dbData of classifierTester.dbUrls) {
Services.prefs.setCharPref(dbData.pref, dbData.db);
DBs.push(dbData.db);
}
let completions = Services.prefs.getCharPref(
classifierTester.URLCLASSIFIER_DISALLOW_COMPLETIONS_PREF
);
completions += "," + DBs.join(",");
Services.prefs.setCharPref(
classifierTester.URLCLASSIFIER_DISALLOW_COMPLETIONS_PREF,
completions
);
}
Services.prefs.setBoolPref(
classifierTester.FLASHBLOCK_ENABLE_PREF,
flashBlockEnable
);
Services.prefs.setIntPref(
classifierTester.FLASH_PLUGIN_USER_SETTING_PREF,
flashSetting
);
},
unsetPrefs() {
for (let dbData of classifierTester.dbUrls) {
Services.prefs.clearUserPref(dbData.pref);
}
Services.prefs.clearUserPref(
classifierTester.URLCLASSIFIER_DISALLOW_COMPLETIONS_PREF
);
Services.prefs.clearUserPref(classifierTester.FLASHBLOCK_ENABLE_PREF);
Services.prefs.clearUserPref(
classifierTester.FLASH_PLUGIN_USER_SETTING_PREF
);
},
// The |domains| property describes the domains of the nested documents making
// up the page. |domains[0]| represents the domain in the URL bar. The last
// domain in the list is the domain of the most deeply nested iframe.
// Only the plugin in the most deeply nested document will be checked.
testCases: [
{
name: "Unknown domain",
domains: ["http://example.com"],
expectedFlashClassification: "unknown",
},
{
name: "Nested unknown domains",
domains: ["http://example.com", "http://example.org"],
expectedFlashClassification: "unknown",
},
{
name: "Allowed domain",
domains: ["http://flashallow.example.com"],
expectedFlashClassification: "allowed",
},
{
name: "Allowed nested domain",
domains: ["http://example.com", "http://flashallow.example.com"],
expectedFlashClassification: "allowed",
},
{
name: "Subdocument of allowed domain",
domains: ["http://flashallow.example.com", "http://example.com"],
expectedFlashClassification: "allowed",
},
{
name: "Exception to allowed domain",
domains: ["http://exception.flashallow.example.com"],
expectedFlashClassification: "unknown",
},
{
name: "Blocked domain",
domains: ["http://flashblock.example.com"],
expectedFlashClassification: "denied",
},
{
name: "Nested blocked domain",
domains: ["http://example.com", "http://flashblock.example.com"],
expectedFlashClassification: "denied",
},
{
name: "Subdocument of blocked subdocument",
domains: [
"http://example.com",
"http://flashblock.example.com",
"http://example.com",
],
expectedFlashClassification: "denied",
},
{
name: "Blocked subdocument nested among in allowed documents",
domains: [
"http://flashallow.example.com",
"http://flashblock.example.com",
"http://flashallow.example.com",
],
expectedFlashClassification: "denied",
},
{
name: "Exception to blocked domain",
domains: ["http://exception.flashblock.example.com"],
expectedFlashClassification: "unknown",
},
{
name: "Sub-document blocked domain in top-level context",
domains: ["http://subdocument.example.com"],
expectedFlashClassification: "unknown",
},
{
name: "Sub-document blocked domain",
domains: ["http://example.com", "http://subdocument.example.com"],
expectedFlashClassification: "denied",
},
{
name: "Sub-document blocked domain in non-Third-Party context",
domains: [
"http://subdocument.example.com",
"http://subdocument.example.com",
],
expectedFlashClassification: "unknown",
},
{
name: "Sub-document blocked domain differing only by scheme",
domains: [
"http://subdocument.example.com",
"https://subdocument.example.com",
],
expectedFlashClassification: "denied",
},
{
name: "Sub-document blocked subdocument of an allowed domain",
domains: [
"http://flashallow.example.com",
"http://subdocument.example.com",
],
expectedFlashClassification: "denied",
},
{
name: "Subdocument of Sub-document blocked domain",
domains: [
"http://example.com",
"http://subdocument.example.com",
"http://example.com",
],
expectedFlashClassification: "denied",
},
{
name: "Sub-document exception in top-level context",
domains: ["http://exception.subdocument.example.com"],
expectedFlashClassification: "unknown",
},
{
name: "Sub-document blocked domain exception",
domains: [
"http://example.com",
"http://exception.subdocument.example.com",
],
expectedFlashClassification: "unknown",
},
],
// Returns null if this value should not be verified given the combination
// of inputs
expectedPluginFallbackType(classification, flashSetting) {
switch (classification) {
case "unknown":
if (flashSetting == classifierTester.ALWAYS_ACTIVATE_PREF_VALUE) {
return null;
} else if (
flashSetting == classifierTester.ASK_TO_ACTIVATE_PREF_VALUE
) {
return Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
} else if (flashSetting == classifierTester.NEVER_ACTIVATE_PREF_VALUE) {
return Ci.nsIObjectLoadingContent.PLUGIN_DISABLED;
}
break;
case "allowed":
if (flashSetting == classifierTester.NEVER_ACTIVATE_PREF_VALUE) {
return Ci.nsIObjectLoadingContent.PLUGIN_DISABLED;
}
return null;
case "denied":
return Ci.nsIObjectLoadingContent.PLUGIN_USER_DISABLED;
}
throw new Error("Invalid classification or flash setting");
},
// Returns null if this value should not be verified given the combination
// of inputs
expectedActivated(classification, flashSetting) {
switch (classification) {
case "unknown":
return flashSetting == classifierTester.ALWAYS_ACTIVATE_PREF_VALUE;
case "allowed":
return flashSetting != classifierTester.NEVER_ACTIVATE_PREF_VALUE;
case "denied":
return false;
}
throw new Error("Invalid classification or flash setting");
},
// Returns null if this value should not be verified given the combination
// of inputs
expectedHasRunningPlugin(classification, flashSetting) {
switch (classification) {
case "unknown":
return flashSetting == classifierTester.ALWAYS_ACTIVATE_PREF_VALUE;
case "allowed":
return flashSetting != classifierTester.NEVER_ACTIVATE_PREF_VALUE;
case "denied":
return false;
}
throw new Error("Invalid classification or flash setting");
},
// Returns null if this value should not be verified given the combination
// of inputs
expectedPluginListed(classification, flashSetting) {
if (
flashSetting == classifierTester.ASK_TO_ACTIVATE_PREF_VALUE &&
Services.prefs.getCharPref("plugins.navigator.hidden_ctp_plugin") ==
"Shockwave Flash"
) {
return false;
}
switch (classification) {
case "unknown":
case "allowed":
return flashSetting != classifierTester.NEVER_ACTIVATE_PREF_VALUE;
case "denied":
return false;
}
throw new Error("Invalid classification or flash setting");
},
buildTestCaseInNewTab(browser, testCase) {
return (async function() {
let iframeDomains = testCase.domains.slice();
let pageDomain = iframeDomains.shift();
let tab = await BrowserTestUtils.openNewForegroundTab(
browser,
pageDomain + classifierTester.URL_PATH
);
let depth = 0;
for (let domain of iframeDomains) {
// Firefox does not like to load the same page in its own iframe. Put some
// bogus query strings in the URL to make it happy.
let url =
domain +
classifierTester.URL_PATH +
"?date=" +
Date.now() +
"rand=" +
Math.random();
let domainLoaded = BrowserTestUtils.browserLoaded(
tab.linkedBrowser,
true,
url
);
await SpecialPowers.spawn(
tab.linkedBrowser,
[classifierTester.IFRAME_ID, url, depth],
(iframeId, url, depth) => {
let doc = content.document;
for (let i = 0; i < depth; ++i) {
doc = doc.getElementById(iframeId).contentDocument;
}
doc.getElementById(iframeId).src = url;
}
);
await domainLoaded;
++depth;
}
return tab;
})();
},
async getPluginInfo(browser, depth) {
async function fn(frame, iframeId, depth) {
return SpecialPowers.spawn(
frame,
[iframeId, depth, fn.toString()],
async (iframeId, depth, fnSource) => {
// eslint-disable-next-line no-eval
let fnGetIframePluginInfo = eval(`(() => (${fnSource}))()`);
let doc = content.document;
let win = content.window;
let frame = doc.getElementById(iframeId);
if (!frame) {
throw new Error("Unable to find iframe!");
}
if (depth != 0) {
return fnGetIframePluginInfo(
frame.contentWindow,
iframeId,
--depth
);
}
let pluginObj = doc.getElementById("testObject");
if (!(pluginObj instanceof Ci.nsIObjectLoadingContent)) {
throw new Error("Unable to find plugin!");
}
return {
pluginFallbackType: pluginObj.pluginFallbackType,
activated: pluginObj.activated,
hasRunningPlugin: pluginObj.hasRunningPlugin,
listed: "Shockwave Flash" in win.navigator.plugins,
flashClassification: doc.documentFlashClassification,
};
}
);
}
return fn(browser, classifierTester.IFRAME_ID, depth);
},
checkPluginInfo(pluginInfo, expectedClassification, flashSetting) {
// Flashblocking is disabled when fission is enabled, so all the classifications
// should be "unknown"
if (Services.prefs.getBoolPref(classifierTester.FISSION_PREF)) {
expectedClassification = "unknown";
}
// We've stopped allowing flash to be always activated, so check
// existing tests that attempt to do so get treated as using ask-to-activate.
if (flashSetting == classifierTester.ALWAYS_ACTIVATE_PREF_VALUE) {
flashSetting = classifierTester.ASK_TO_ACTIVATE_PREF_VALUE;
}
is(
pluginInfo.flashClassification,
expectedClassification,
"Page's classification should match expected"
);
let expectedPluginFallbackType = classifierTester.expectedPluginFallbackType(
pluginInfo.flashClassification,
flashSetting
);
if (expectedPluginFallbackType != null) {
is(
pluginInfo.pluginFallbackType,
expectedPluginFallbackType,
"Plugin should have the correct fallback type"
);
}
let expectedActivated = classifierTester.expectedActivated(
pluginInfo.flashClassification,
flashSetting
);
if (expectedActivated != null) {
is(
pluginInfo.activated,
expectedActivated,
"Plugin should have the correct activation"
);
}
let expectedHasRunningPlugin = classifierTester.expectedHasRunningPlugin(
pluginInfo.flashClassification,
flashSetting
);
if (expectedHasRunningPlugin != null) {
is(
pluginInfo.hasRunningPlugin,
expectedHasRunningPlugin,
"Plugin should have the correct 'plugin running' state"
);
}
let expectedPluginListed = classifierTester.expectedPluginListed(
pluginInfo.flashClassification,
flashSetting
);
if (expectedPluginListed != null) {
is(
pluginInfo.listed,
expectedPluginListed,
"Plugin's existance in navigator.plugins should match expected"
);
}
},
};
registerCleanupFunction(classifierTester.unsetPrefs);