Bug 1459204: Have about:privatebrowsing rely on RemotePageManager instead of AboutCapabilities. r=mossop,baku

This commit is contained in:
Christoph Kerschbaumer 2018-06-07 11:32:27 +02:00
Родитель b986ba77dd
Коммит 2c105d2ff5
16 изменённых файлов: 184 добавлений и 233 удалений

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

@ -1314,7 +1314,6 @@ var gBrowserInit = {
LanguageDetectionListener.init();
BrowserOnClick.init();
FeedHandler.init();
AboutCapabilitiesListener.init();
TrackingProtection.init();
CaptivePortalWatcher.init();
ZoomUI.init(window);
@ -1875,8 +1874,6 @@ var gBrowserInit = {
FeedHandler.uninit();
AboutCapabilitiesListener.uninit();
TrackingProtection.uninit();
CaptivePortalWatcher.uninit();
@ -8361,39 +8358,6 @@ var PanicButtonNotifier = {
},
};
var AboutCapabilitiesListener = {
_topics: [
"AboutCapabilities:OpenPrivateWindow",
"AboutCapabilities:DontShowIntroPanelAgain",
],
init() {
let mm = window.messageManager;
for (let topic of this._topics) {
mm.addMessageListener(topic, this);
}
},
uninit() {
let mm = window.messageManager;
for (let topic of this._topics) {
mm.removeMessageListener(topic, this);
}
},
receiveMessage(aMsg) {
switch (aMsg.name) {
case "AboutCapabilities:OpenPrivateWindow":
OpenBrowserWindow({private: true});
break;
case "AboutCapabilities:DontShowIntroPanelAgain":
TrackingProtection.dontShowIntroPanelAgain();
break;
}
},
};
const SafeBrowsingNotificationBox = {
_currentURIBaseDomain: null,
show(title, buttons) {

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

@ -0,0 +1,46 @@
/* 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/. */
"use strict";
var EXPORTED_SYMBOLS = ["AboutPrivateBrowsingHandler"];
ChromeUtils.import("resource://gre/modules/RemotePageManager.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
var AboutPrivateBrowsingHandler = {
_topics: [
"DontShowIntroPanelAgain",
"OpenPrivateWindow",
],
init() {
this.pageListener = new RemotePages("about:privatebrowsing");
for (let topic of this._topics) {
this.pageListener.addMessageListener(topic, this.receiveMessage.bind(this));
}
},
uninit() {
for (let topic of this._topics) {
this.pageListener.removeMessageListener(topic);
}
this.pageListener.destroy();
},
receiveMessage(aMessage) {
switch (aMessage.name) {
case "OpenPrivateWindow": {
let win = aMessage.target.browser.ownerGlobal;
win.OpenBrowserWindow({private: true});
break;
}
case "DontShowIntroPanelAgain": {
let win = aMessage.target.browser.ownerGlobal;
win.TrackingProtection.dontShowIntroPanelAgain();
break;
}
}
},
};

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

@ -1,2 +0,0 @@
component {4c2b1f46-e637-4a91-8108-8a9fb7aab91d} nsAboutCapabilities.js
contract @mozilla.org/aboutcapabilities;1 {4c2b1f46-e637-4a91-8108-8a9fb7aab91d}

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

@ -17,9 +17,8 @@ SOURCES += [
'AboutRedirector.cpp',
]
EXTRA_COMPONENTS += [
'aboutcapabilities.manifest',
'nsAboutCapabilities.js',
EXTRA_JS_MODULES.aboutpages = [
'AboutPrivateBrowsingHandler.jsm',
]
FINAL_LIBRARY = 'browsercomps'

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

@ -1,73 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
/* 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/. */
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
ChromeUtils.defineModuleGetter(this, "AsyncPrefs",
"resource://gre/modules/AsyncPrefs.jsm");
function nsAboutCapabilities() {
}
nsAboutCapabilities.prototype = {
init(window) {
this.window = window;
try {
let docShell = window.document.docShell
.QueryInterface(Ci.nsIInterfaceRequestor);
this.mm = docShell.getInterface(Ci.nsIContentFrameMessageManager);
} catch (e) {
Cu.reportError(e);
}
},
getBoolPref(aPref, aDefaultValue) {
return Services.prefs.getBoolPref(aPref, aDefaultValue);
},
setBoolPref(aPref, aValue) {
return new this.window.Promise(function(resolve) {
AsyncPrefs.set(aPref, aValue).then(function() {
resolve();
});
});
},
getCharPref(aPref, aDefaultValue) {
return Services.prefs.getCharPref(aPref, aDefaultValue);
},
setCharPref(aPref, aValue) {
return new this.window.Promise(function(resolve) {
AsyncPrefs.set(aPref, aValue).then(function() {
resolve();
});
});
},
getStringFromBundle(aStrBundle, aStr) {
let bundle = Services.strings.createBundle(aStrBundle);
return bundle.GetStringFromName(aStr);
},
formatURLPref(aFormatURL) {
return Services.urlFormatter.formatURLPref(aFormatURL);
},
sendAsyncMessage(aMessage, aParams) {
this.mm.sendAsyncMessage("AboutCapabilities:" + aMessage, aParams);
},
isWindowPrivate() {
return PrivateBrowsingUtils.isContentWindowPrivate(this.window);
},
contractID: "@mozilla.org/aboutcapabilities;1",
classID: Components.ID("{4c2b1f46-e637-4a91-8108-8a9fb7aab91d}"),
QueryInterface: ChromeUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsAboutCapabilities]);

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

@ -89,6 +89,7 @@ XPCOMUtils.defineLazyGetter(this, "WeaveService", () =>
// lazy module getters
XPCOMUtils.defineLazyModuleGetters(this, {
AboutPrivateBrowsingHandler: "resource:///modules/aboutpages/AboutPrivateBrowsingHandler.jsm",
AddonManager: "resource://gre/modules/AddonManager.jsm",
AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.jsm",
AsyncPrefs: "resource://gre/modules/AsyncPrefs.jsm",
@ -1054,6 +1055,8 @@ BrowserGlue.prototype = {
NewTabUtils.init();
AboutPrivateBrowsingHandler.init();
PageActions.init();
this._firstWindowTelemetry(aWindow);
@ -1106,6 +1109,7 @@ BrowserGlue.prototype = {
PageThumbs.uninit();
NewTabUtils.uninit();
AboutPrivateBrowsingHandler.uninit();
AutoCompletePopup.uninit();
DateTimePickerHelper.uninit();

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

@ -2,22 +2,21 @@
* 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/. */
/* eslint-env mozilla/frame-script */
const FAVICON_QUESTION = "chrome://global/skin/icons/question-32.png";
const STRING_BUNDLE = "chrome://browser/locale/aboutPrivateBrowsing.properties";
const TP_ENABLED_PREF = "privacy.trackingprotection.enabled";
const TP_PB_ENABLED_PREF = "privacy.trackingprotection.pbmode.enabled";
function updateTPInfo() {
let aboutCapabilities = document.aboutCapabilities;
let tpButton = document.getElementById("tpButton");
let tpToggle = document.getElementById("tpToggle");
let title = document.getElementById("title");
let titleTracking = document.getElementById("titleTracking");
let tpSubHeader = document.getElementById("tpSubHeader");
let globalTrackingEnabled = aboutCapabilities.getBoolPref(TP_ENABLED_PREF, null);
let trackingEnabled = globalTrackingEnabled ||
aboutCapabilities.getBoolPref(TP_PB_ENABLED_PREF, null);
let globalTrackingEnabled = RPMGetBoolPref(TP_ENABLED_PREF);
let trackingEnabled = globalTrackingEnabled || RPMGetBoolPref(TP_PB_ENABLED_PREF);
// if tracking protection is enabled globally we don't even give the user
// a choice here by hiding the toggle completely.
@ -29,31 +28,31 @@ function updateTPInfo() {
}
document.addEventListener("DOMContentLoaded", function() {
let aboutCapabilities = document.aboutCapabilities;
if (!aboutCapabilities.isWindowPrivate()) {
if (!RPMIsWindowPrivate()) {
document.documentElement.classList.remove("private");
document.documentElement.classList.add("normal");
document.getElementById("favicon").setAttribute("href", FAVICON_QUESTION);
document.getElementById("startPrivateBrowsing").addEventListener("click", function() {
aboutCapabilities.sendAsyncMessage("OpenPrivateWindow", null);
sendAsyncMessage("OpenPrivateWindow");
});
return;
}
document.getElementById("startTour").addEventListener("click", function() {
aboutCapabilities.sendAsyncMessage("DontShowIntroPanelAgain", null);
sendAsyncMessage("DontShowIntroPanelAgain");
});
document.getElementById("startTour").setAttribute("href",
aboutCapabilities.formatURLPref("privacy.trackingprotection.introURL"));
RPMGetFormatURLPref("privacy.trackingprotection.introURL"));
document.getElementById("learnMore").setAttribute("href",
aboutCapabilities.formatURLPref("app.support.baseURL") + "private-browsing");
RPMGetFormatURLPref("app.support.baseURL") + "private-browsing");
let tpToggle = document.getElementById("tpToggle");
document.getElementById("tpButton").addEventListener("click", () => {
tpToggle.click();
});
tpToggle.addEventListener("change", function() {
aboutCapabilities.setBoolPref(TP_PB_ENABLED_PREF, tpToggle.checked).then(function() {
RPMSetBoolPref(TP_PB_ENABLED_PREF, tpToggle.checked).then(function() {
updateTPInfo();
});
});

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

@ -189,8 +189,6 @@
@RESPATH@/browser/components/aboutdevtools.manifest
@RESPATH@/browser/components/aboutdevtoolstoolbox-registration.js
@RESPATH@/browser/components/aboutdevtoolstoolbox.manifest
@RESPATH@/browser/components/nsAboutCapabilities.js
@RESPATH@/browser/components/aboutcapabilities.manifest
@RESPATH@/browser/components/aboutNewTabService.js
@RESPATH@/browser/components/NewTabComponents.manifest
@RESPATH@/browser/components/EnterprisePolicies.js

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

@ -52,7 +52,6 @@
#include "nsScreen.h"
#include "ChildIterator.h"
#include "mozilla/dom/AboutCapabilitiesBinding.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/EventListenerManager.h"
@ -1860,7 +1859,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDisplayDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAboutCapabilities)
// Traverse all nsDocument nsCOMPtrs.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
@ -2015,7 +2013,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAboutCapabilities)
tmp->mParentDocument = nullptr;
@ -3297,62 +3294,6 @@ nsIDocument::GetAllowPlugins()
return true;
}
bool
nsDocument::CallerIsTrustedAboutPage(JSContext* aCx, JSObject* aObject)
{
/*
* If you want an about: page to have access to AboutCapabilities,
* please add it to the list of trusted about: pages underneath.
*/
static const char* kTrustedAboutPages[] = {
"about:privatebrowsing",
};
nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(aCx);
if (!principal) {
return false;
}
nsCOMPtr<nsIURI> uri;
principal->GetURI(getter_AddRefs(uri));
if (!uri) {
return false;
}
// getSpec is an expensive operation, hence we first check the scheme
// to see if the caller is actually an about: page.
bool isAboutScheme = false;
uri->SchemeIs("about", &isAboutScheme);
if (!isAboutScheme) {
return false;
}
nsAutoCString aboutSpec;
uri->GetSpec(aboutSpec);
for (auto & aboutPageEntry : kTrustedAboutPages) {
if (aboutSpec.EqualsIgnoreCase(aboutPageEntry)) {
return true;
}
}
return false;
}
already_AddRefed<AboutCapabilities>
nsIDocument::GetAboutCapabilities(ErrorResult& aRv)
{
if (!mAboutCapabilities) {
AutoJSContext cx;
JS::Rooted<JSObject*> jsImplObj(cx);
nsIGlobalObject* sgo = GetScopeObject();
ConstructJSImplementation("@mozilla.org/aboutcapabilities;1", sgo, &jsImplObj, aRv);
if (aRv.Failed()) {
return nullptr;
}
mAboutCapabilities = new AboutCapabilities(jsImplObj, sgo);
}
RefPtr<AboutCapabilities> aboutCapabilities =
static_cast<AboutCapabilities*>(mAboutCapabilities.get());
return aboutCapabilities.forget();
}
bool
nsDocument::IsElementAnimateEnabled(JSContext* aCx, JSObject* /*unused*/)
{

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

@ -158,7 +158,6 @@ public:
virtual void StopDocumentLoad() override;
static bool CallerIsTrustedAboutPage(JSContext* aCx, JSObject* aObject);
static bool IsElementAnimateEnabled(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(JSContext* aCx, JSObject* aObject);
static bool IsWebAnimationsEnabled(mozilla::dom::CallerType aCallerType);

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

@ -137,7 +137,6 @@ class Rule;
} // namespace css
namespace dom {
class AboutCapabilities;
class Animation;
class AnonymousContent;
class Attr;
@ -3142,9 +3141,6 @@ public:
void GetLastModified(nsAString& aLastModified) const;
void GetReadyState(nsAString& aReadyState) const;
already_AddRefed<mozilla::dom::AboutCapabilities> GetAboutCapabilities(
ErrorResult& aRv);
void GetTitle(nsAString& aTitle);
void SetTitle(const nsAString& aTitle, mozilla::ErrorResult& rv);
void GetDir(nsAString& aDirection) const;
@ -3817,8 +3813,6 @@ protected:
RefPtr<mozilla::dom::Promise> mReadyForIdle;
RefPtr<mozilla::dom::AboutCapabilities> mAboutCapabilities;
// True if BIDI is enabled.
bool mBidiEnabled : 1;
// True if a MathML element has ever been owned by this document.

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

@ -1,32 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[NoInterfaceObject, JSImplementation="@mozilla.org/aboutcapabilities;1"]
interface AboutCapabilities
{
/**
* When using setBoolPref, one also has to whitelist the
* pref to be updated within AsyncPrefs.jsm
*/
Promise<void> setBoolPref(DOMString aPref, boolean aValue);
boolean getBoolPref(DOMString aPref, boolean? aDefaultValue);
/**
* When using setCharPref, one also has to whitelist the
* pref to be updated within AsyncPrefs.jsm
*/
Promise<void> setCharPref(DOMString aPref, DOMString aValue);
DOMString getCharPref(DOMString aPref, DOMString? aDefaultValue);
DOMString getStringFromBundle(DOMString aStrBundle, DOMString aStr);
DOMString formatURLPref(DOMString aFormatURL);
void sendAsyncMessage(DOMString aMessage, object? aParams);
/* about:privatebrowsing */
boolean isWindowPrivate();
};

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

@ -497,11 +497,6 @@ partial interface Document {
readonly attribute FlashClassification documentFlashClassification;
};
// Allows about: pages to query aboutCapabilities
partial interface Document {
[Throws, Func="nsDocument::CallerIsTrustedAboutPage"] readonly attribute AboutCapabilities aboutCapabilities;
};
Document implements XPathEvaluator;
Document implements GlobalEventHandlers;
Document implements DocumentAndElementEventHandlers;

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

@ -358,7 +358,6 @@ PREPROCESSED_WEBIDL_FILES = [
WEBIDL_FILES = [
'AbortController.webidl',
'AbortSignal.webidl',
'AboutCapabilities.webidl',
'AbstractWorker.webidl',
'AddonManager.webidl',
'AnalyserNode.webidl',

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

@ -6,8 +6,80 @@
var EXPORTED_SYMBOLS = ["RemotePages", "RemotePageManager", "PageListener"];
/*
* Using the RemotePageManager:
* * Create a new page listener by calling 'new RemotePages(URI)' which
* then injects functions like RPMGetBoolPref() into the registered page.
* One can then use those exported functions to communicate between
* child and parent.
*
* * When adding a new consumer of RPM that relies on other functionality
* then simple message passing provided by the RPM, then one has to
* whitelist permissions for the new URI within the RPMAccessManager.
*
* Please note that prefs that one wants to update need to be whitelisted
* within AsyncPrefs.jsm.
*/
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(this, "AsyncPrefs",
"resource://gre/modules/AsyncPrefs.jsm");
ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
"resource://gre/modules/PrivateBrowsingUtils.jsm");
/*
* Used for all kinds of permissions checks which requires explicit
* whitelisting of specific permissions granted through RPM.
*/
let RPMAccessManager = {
accessMap: {
"about:privatebrowsing": {
// "sendAsyncMessage": handled within AboutPrivateBrowsingHandler.jsm
// "setBoolPref": handled within AsyncPrefs.jsm and uses the pref
// ["privacy.trackingprotection.pbmode.enabled"],
"getBoolPref": ["privacy.trackingprotection.enabled",
"privacy.trackingprotection.pbmode.enabled"],
"getFormatURLPref": ["privacy.trackingprotection.introURL",
"app.support.baseURL"],
"isWindowPrivate": ["yes"],
},
},
checkAllowAccess(aPrincipal, aFeature, aValue) {
// if there is no content principal; deny access
if (!aPrincipal || !aPrincipal.URI) {
return false;
}
let uri = aPrincipal.URI.asciiSpec;
// check if there is an entry for that requestying URI in the accessMap;
// if not, deny access.
let accessMapForURI = this.accessMap[uri];
if (!accessMapForURI) {
Cu.reportError("RPMAccessManager does not allow access to Feature: " + aFeature + " for: " + uri);
return false;
}
// check if the feature is allowed to be accessed for that URI;
// if not, deny access.
let accessMapForFeature = accessMapForURI[aFeature];
if (!accessMapForFeature) {
Cu.reportError("RPMAccessManager does not allow access to Feature: " + aFeature + " for: " + uri);
return false;
}
// if the actual value is in the whitelist for that feature;
// allow access
if (accessMapForFeature.includes(aValue)) {
return true;
}
// otherwise deny access
Cu.reportError("RPMAccessManager does not allow access to Feature: " + aFeature + " for: " + uri);
return false;
},
};
function MessageListener() {
this.listeners = new Map();
@ -304,6 +376,38 @@ MessagePort.prototype = {
this.portID = null;
this.listener = null;
},
getBoolPref(aPref) {
let principal = this.window.document.nodePrincipal;
if (!RPMAccessManager.checkAllowAccess(principal, "getBoolPref", aPref)) {
throw new Error("RPMAccessManager does not allow access to getBoolPref");
}
return Services.prefs.getBoolPref(aPref);
},
setBoolPref(aPref, aVal) {
return new this.window.Promise(function(resolve) {
AsyncPrefs.set(aPref, aVal).then(function() {
resolve();
});
});
},
getFormatURLPref(aFormatURL) {
let principal = this.window.document.nodePrincipal;
if (!RPMAccessManager.checkAllowAccess(principal, "getFormatURLPref", aFormatURL)) {
throw new Error("RPMAccessManager does not allow access to getFormatURLPref");
}
return Services.urlFormatter.formatURLPref(aFormatURL);
},
isWindowPrivate() {
let principal = this.window.document.nodePrincipal;
if (!RPMAccessManager.checkAllowAccess(principal, "isWindowPrivate", "yes")) {
throw new Error("RPMAccessManager does not allow access to isWindowPrivate");
}
return PrivateBrowsingUtils.isContentWindowPrivate(this.window);
},
};
@ -418,6 +522,18 @@ function ChildMessagePort(contentFrame, window) {
defineAs: "removeMessageListener",
allowCallbacks: true,
});
Cu.exportFunction(this.getBoolPref.bind(this), window, {
defineAs: "RPMGetBoolPref",
});
Cu.exportFunction(this.setBoolPref.bind(this), window, {
defineAs: "RPMSetBoolPref",
});
Cu.exportFunction(this.getFormatURLPref.bind(this), window, {
defineAs: "RPMGetFormatURLPref",
});
Cu.exportFunction(this.isWindowPrivate.bind(this), window, {
defineAs: "RPMIsWindowPrivate",
});
// Send a message for load events
let loadListener = () => {

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

@ -23,6 +23,10 @@ module.exports = {
sendAsyncMessage: false,
sendSyncMessage: false,
sendRpcMessage: false,
tabEventTarget: false
tabEventTarget: false,
RPMGetBoolPref: false,
RPMSetBoolPref: false,
RPMGetFormatURLPref: false,
RPMIsWindowPrivate: false
}
};