Bug 1525125 block newtab and homepage overrides in private windows r=rpl,Gijs

Differential Revision: https://phabricator.services.mozilla.com/D18730

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Shane Caraveo 2019-02-14 12:44:07 +00:00
Родитель eca9e717dd
Коммит 40e0ac9225
9 изменённых файлов: 369 добавлений и 13 удалений

Просмотреть файл

@ -2174,7 +2174,7 @@ function BrowserHome(aEvent) {
aEvent.button == 2) // right-click: do nothing
return;
var homePage = HomePage.get();
var homePage = HomePage.get(window);
var where = whereToOpenLink(aEvent, false, true);
var urls;
var notifyObservers;

Просмотреть файл

@ -24,10 +24,19 @@ XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
Object.defineProperty(this, "BROWSER_NEW_TAB_URL", {
enumerable: true,
get() {
if (PrivateBrowsingUtils.isWindowPrivate(window) &&
!PrivateBrowsingUtils.permanentPrivateBrowsing &&
!aboutNewTabService.overridden) {
return "about:privatebrowsing";
if (PrivateBrowsingUtils.isWindowPrivate(window)) {
if (!PrivateBrowsingUtils.permanentPrivateBrowsing &&
!aboutNewTabService.overridden) {
return "about:privatebrowsing";
}
// If the extension does not have private browsing permission,
// use about:privatebrowsing.
if (aboutNewTabService.newTabURL.startsWith("moz-extension")) {
let url = new URL(aboutNewTabService.newTabURL);
if (!WebExtensionPolicy.getByHostname(url.hostname).privateBrowsingAllowed) {
return "about:privatebrowsing";
}
}
}
return aboutNewTabService.newTabURL;
},

Просмотреть файл

@ -31,6 +31,8 @@ ChromeUtils.defineModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
let {
makeWidgetId,
@ -195,6 +197,12 @@ class ExtensionControlledPopup {
extensionId = item && item.id;
}
let win = targetWindow || this.topWindow;
let isPrivate = PrivateBrowsingUtils.isWindowPrivate(win);
if (isPrivate && extensionId && !WebExtensionPolicy.getByID(extensionId).privateBrowsingAllowed) {
return;
}
// The item should have an extension and the user shouldn't have confirmed
// the change here, but just to be sure check that it is still controlled
// and the user hasn't already confirmed the change.
@ -203,7 +211,6 @@ class ExtensionControlledPopup {
return;
}
let win = targetWindow || this.topWindow;
// If the window closes while waiting for focus, this might reject/throw,
// and we should stop trying to show the popup.
try {

Просмотреть файл

@ -191,8 +191,13 @@ this.windows = class extends ExtensionAPI {
args.appendElement(mkstr(createData.url));
}
} else {
let url = createData.incognito && !PrivateBrowsingUtils.permanentPrivateBrowsing ?
"about:privatebrowsing" : HomePage.get().split("|", 1)[0];
let url;
if (createData.incognito) {
url = PrivateBrowsingUtils.permanentPrivateBrowsing ?
HomePage.getPrivate().split("|", 1)[0] : "about:privatebrowsing";
} else {
url = HomePage.get().split("|", 1)[0];
}
args.appendElement(mkstr(url));
if (url.startsWith("about:") &&

Просмотреть файл

@ -422,3 +422,127 @@ add_task(async function test_doorhanger_new_window() {
ok(!isConfirmed(ext1Id), "The confirmation is cleaned up on uninstall");
});
add_task(async function test_overriding_home_page_incognito_not_allowed() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {"homepage": "home.html"},
name: "extension",
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
},
files: {"home.html": "<h1>1</h1>"},
useAddonManager: "temporary",
});
await extension.startup();
let url = await extension.awaitMessage("url");
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow({url});
let win = OpenBrowserWindow();
await windowOpenedPromise;
let doc = win.document;
let description = doc.getElementById("extension-homepage-notification-description");
let panel = doc.getElementById("extension-notification-panel");
await promisePopupShown(panel);
let popupnotification = description.closest("popupnotification");
is(description.textContent,
"An extension, extension, changed what you see when you open your homepage and new windows.Learn more",
"The extension name is in the popup");
is(popupnotification.hidden, false, "The expected popup notification is visible");
ok(win.gURLBar.value.endsWith("home.html"), "extension is in control");
await BrowserTestUtils.closeWindow(win);
// Verify a private window does not open the extension page.
windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
win.BrowserHome();
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(win.gURLBar.value, "", "home page not used in private window");
await BrowserTestUtils.closeWindow(win);
// Verify manually setting the pref to the extension page does not work.
Services.prefs.setStringPref(HOMEPAGE_URL_PREF, url);
windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
win.BrowserHome();
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(win.gURLBar.value, "", "home page not used in private window");
Services.prefs.clearUserPref(HOMEPAGE_URL_PREF);
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_home_page_incognito_not_allowed_bypass() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "extension",
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("home.html"));
},
files: {"home.html": "<h1>1</h1>"},
useAddonManager: "temporary",
});
await extension.startup();
let url = await extension.awaitMessage("url");
// Verify manually setting the pref to the extension page does not work.
Services.prefs.setStringPref(HOMEPAGE_URL_PREF, url);
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
win.BrowserHome();
await BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
is(win.gURLBar.value, "", "home page not used in private window");
Services.prefs.clearUserPref(HOMEPAGE_URL_PREF);
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_home_page_incognito_spanning() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
chrome_settings_overrides: {"homepage": "home.html"},
name: "private extension",
applications: {
gecko: {id: "@spanning-home"},
},
},
files: {"home.html": "<h1>1</h1>"},
useAddonManager: "permanent",
incognitoOverride: "spanning",
});
await extension.startup();
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
let doc = win.document;
let panel = doc.getElementById("extension-notification-panel");
win.BrowserHome();
await promisePopupShown(panel);
ok(win.gURLBar.value.endsWith("home.html"), "extension is in control in private window");
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});

Просмотреть файл

@ -5,6 +5,9 @@
ChromeUtils.defineModuleGetter(this, "ExtensionSettingsStore",
"resource://gre/modules/ExtensionSettingsStore.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
const NEWTAB_URI_1 = "webext-newtab-1.html";
@ -522,3 +525,183 @@ add_task(async function dontTemporarilyShowAboutExtensionPath() {
BrowserTestUtils.removeTab(tab);
await extension.unload();
});
add_task(async function test_overriding_newtab_incognito_not_allowed() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let panel = getNewTabDoorhanger().closest("panel");
let extension = ExtensionTestUtils.loadExtension({
manifest: {
chrome_url_overrides: {"newtab": "newtab.html"},
name: "extension",
applications: {
gecko: {id: "@not-allowed-newtab"},
},
},
files: {
"newtab.html": `
<!DOCTYPE html>
<head>
<meta charset="utf-8"/></head>
<html>
<body>
<script src="newtab.js"></script>
</body>
</html>
`,
"newtab.js": function() {
window.onload = () => {
browser.test.sendMessage("from-newtab-page", window.location.href);
};
},
},
useAddonManager: "permanent",
});
await extension.startup();
let popupShown = promisePopupShown(panel);
BrowserOpenTab();
await popupShown;
let url = await extension.awaitMessage("from-newtab-page");
ok(url.endsWith("newtab.html"),
"Newtab url is overridden by the extension.");
// This will show a confirmation doorhanger, make sure we don't leave it open.
let popupHidden = promisePopupHidden(panel);
panel.hidePopup();
await popupHidden;
BrowserTestUtils.removeTab(gBrowser.selectedTab);
// Verify a private window does not open the extension page. We would
// get an extra notification that we don't listen for if it gets loaded.
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
let newTabOpened = waitForNewTab();
win.BrowserOpenTab();
await newTabOpened;
is(win.gURLBar.value, "", "newtab not used in private window");
// Verify setting the pref directly doesn't bypass permissions.
aboutNewTabService.newTabURL = url;
newTabOpened = waitForNewTab();
win.BrowserOpenTab();
await newTabOpened;
is(win.gURLBar.value, "", "directly set newtab not used in private window");
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_newtab_incognito_not_allowed_bypass() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
name: "extension",
applications: {
gecko: {id: "@not-allowed-newtab"},
},
},
background() {
browser.test.sendMessage("url", browser.runtime.getURL("newtab.html"));
},
files: {
"newtab.html": `
<!DOCTYPE html>
<head>
<meta charset="utf-8"/></head>
<html>
<body>
</body>
</html>
`,
},
useAddonManager: "permanent",
});
await extension.startup();
let url = await extension.awaitMessage("url");
// Verify setting the pref directly doesn't bypass permissions.
aboutNewTabService.newTabURL = url;
// Verify a private window does not open the extension page. We would
// get an extra notification that we don't listen for if it gets loaded.
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
let newTabOpened = waitForNewTab();
win.BrowserOpenTab();
await newTabOpened;
is(win.gURLBar.value, "", "directly set newtab not used in private window");
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});
add_task(async function test_overriding_newtab_incognito_spanning() {
await SpecialPowers.pushPrefEnv({set: [["extensions.allowPrivateBrowsingByDefault", false]]});
let extension = ExtensionTestUtils.loadExtension({
manifest: {
chrome_url_overrides: {"newtab": "newtab.html"},
name: "extension",
applications: {
gecko: {id: "@spanning-newtab"},
},
},
files: {
"newtab.html": `
<!DOCTYPE html>
<head>
<meta charset="utf-8"/></head>
<html>
<body>
<script src="newtab.js"></script>
</body>
</html>
`,
"newtab.js": function() {
window.onload = () => {
browser.test.sendMessage("from-newtab-page", window.location.href);
};
},
},
useAddonManager: "permanent",
incognitoOverride: "spanning",
});
await extension.startup();
let windowOpenedPromise = BrowserTestUtils.waitForNewWindow();
let win = OpenBrowserWindow({private: true});
await windowOpenedPromise;
let panel = win.document.getElementById("extension-new-tab-notification").closest("panel");
let popupShown = promisePopupShown(panel);
win.BrowserOpenTab();
await popupShown;
let url = await extension.awaitMessage("from-newtab-page");
ok(url.endsWith("newtab.html"),
"Newtab url is overridden by the extension.");
// This will show a confirmation doorhanger, make sure we don't leave it open.
let popupHidden = promisePopupHidden(panel);
panel.hidePopup();
await popupHidden;
await extension.unload();
await BrowserTestUtils.closeWindow(win);
});

Просмотреть файл

@ -207,7 +207,7 @@ function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData
let args;
if (!urlOrUrlList) {
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
args = [gBrowserContentHandler.defaultArgs];
args = [gBrowserContentHandler.getDefaultArgs(forcePrivate)];
} else {
let pService = Cc["@mozilla.org/toolkit/profile-service;1"].
getService(Ci.nsIToolkitProfileService);
@ -522,7 +522,7 @@ nsBrowserContentHandler.prototype = {
/* nsIBrowserHandler */
get defaultArgs() {
getDefaultArgs(forcePrivate = false) {
var prefb = Services.prefs;
if (!gFirstWindow) {
@ -607,7 +607,7 @@ nsBrowserContentHandler.prototype = {
try {
var choice = prefb.getIntPref("browser.startup.page");
if (choice == 1 || choice == 3)
startPage = HomePage.get();
startPage = forcePrivate ? HomePage.getPrivate() : HomePage.get();
} catch (e) {
Cu.reportError(e);
}
@ -625,6 +625,10 @@ nsBrowserContentHandler.prototype = {
return overridePage || startPage || "about:blank";
},
get defaultArgs() {
return this.getDefaultArgs(PrivateBrowsingUtils.permanentPrivateBrowsing);
},
mFeatures: null,
getFeatures: function bch_features(cmdLine) {

Просмотреть файл

@ -3299,7 +3299,7 @@ var SessionStoreInternal = {
let tabbrowser = aWindow.gBrowser;
let startupPref = this._prefBranch.getIntPref("startup.page");
if (startupPref == 1)
homePages = homePages.concat(HomePage.get().split("|"));
homePages = homePages.concat(HomePage.get(aWindow).split("|"));
for (let i = tabbrowser._numPinnedTabs; i < tabbrowser.tabs.length; i++) {
let tab = tabbrowser.tabs[i];

Просмотреть файл

@ -10,6 +10,8 @@
var EXPORTED_SYMBOLS = ["HomePage"];
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
const kPrefName = "browser.startup.homepage";
@ -43,7 +45,11 @@ function getHomepagePref(useDefault) {
}
let HomePage = {
get() {
get(aWindow) {
if (PrivateBrowsingUtils.permanentPrivateBrowsing ||
(aWindow && PrivateBrowsingUtils.isWindowPrivate(aWindow))) {
return this.getPrivate();
}
return getHomepagePref();
},
@ -51,6 +57,24 @@ let HomePage = {
return getHomepagePref(true);
},
getPrivate() {
let homePages = getHomepagePref();
if (!homePages.includes("moz-extension")) {
return homePages;
}
// Verify private access and build a new list.
let privateHomePages = homePages.split("|").filter(page => {
let url = new URL(page);
if (url.protocol !== "moz-extension:") {
return true;
}
let policy = WebExtensionPolicy.getByHostname(url.hostname);
return policy && policy.privateBrowsingAllowed;
});
// Extensions may not be ready on startup, fallback to defaults.
return privateHomePages.join("|") || this.getDefault();
},
get overridden() {
return Services.prefs.prefHasUserValue(kPrefName);
},