Bug 1345474 - Add policy flags to support incognito settings r=rpl,kmag

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Shane Caraveo 2018-12-10 21:27:22 +00:00
Родитель d9995b9edc
Коммит ed2e4c07aa
15 изменённых файлов: 171 добавлений и 15 удалений

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

@ -94,6 +94,23 @@ interface WebExtensionPolicy {
*/
static readonly attribute boolean isExtensionProcess;
/**
* Set based on the manifest.incognito value:
* If "spanning" or "split" will be true.
* If "not_allowed" will be false.
*/
[Pure]
attribute boolean privateBrowsingAllowed;
/**
* Returns true if the extension can access a window. Access is
* determined by matching the windows private browsing context
* with privateBrowsingMode. This does not, and is not meant to
* handle specific differences between spanning and split mode.
*/
[Affects=Nothing]
boolean canAccessWindow(WindowProxy window);
/**
* Returns true if the extension has cross-origin access to the given URI.
*/
@ -193,4 +210,6 @@ dictionary WebExtensionInit {
DOMString? contentSecurityPolicy = null;
sequence<DOMString>? backgroundScripts = null;
boolean privateBrowsingAllowed = true;
};

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

@ -636,6 +636,7 @@ class ExtensionData {
schemaURLs: null,
type: this.type,
webAccessibleResources,
privateBrowsingAllowed: manifest.incognito !== "not_allowed",
};
if (this.type === "extension") {
@ -1599,6 +1600,14 @@ class Extension extends ExtensionData {
return this.manifest.optional_permissions;
}
get privateBrowsingAllowed() {
return this.policy.privateBrowsingAllowed;
}
canAccessWindow(window) {
return this.policy.canAccessWindow(window);
}
// Representation of the extension to send to content
// processes. This should include anything the content process might
// need.
@ -1615,6 +1624,7 @@ class Extension extends ExtensionData {
whiteListedHosts: this.whiteListedHosts.patterns.map(pat => pat.pattern),
permissions: this.permissions,
optionalPermissions: this.optionalPermissions,
privateBrowsingAllowed: this.privateBrowsingAllowed,
};
}
@ -1850,6 +1860,12 @@ class Extension extends ExtensionData {
return;
}
if (this.addonData && this.addonData.incognitoOverride !== undefined) {
this.policy.privateBrowsingAllowed = this.addonData.incognitoOverride !== "not_allowed";
} else {
this.policy.privateBrowsingAllowed = this.manifest.incognito !== "not_allowed";
}
GlobalManager.init(this);
this.initSharedData();

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

@ -712,6 +712,14 @@ class BrowserExtensionContent extends EventEmitter {
return this._manifest;
}
get privateBrowsingAllowed() {
return this.policy.privateBrowsingAllowed;
}
canAccessWindow(window) {
return this.policy.canAccessWindow(window);
}
getAPIManager() {
let apiManagers = [ExtensionPageChild.apiManager];

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

@ -445,6 +445,14 @@ class BaseContext {
return this.cloneScopePromise || this.cloneScope.Promise;
}
get privateBrowsingAllowed() {
return this.extension.privateBrowsingAllowed;
}
canAccessWindow(window) {
return this.extension.canAccessWindow(window);
}
setContentWindow(contentWindow) {
this.innerWindowID = getInnerWindowID(contentWindow);
this.messageManager = contentWindow.docShell.messageManager;

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

@ -368,6 +368,7 @@ var ExtensionTestCommon = class ExtensionTestCommon {
resourceURI: jarURI,
cleanupFile: file,
signedState,
incognitoOverride: data.incognitoOverride,
temporarilyInstalled: !!data.temporarilyInstalled,
TEST_NO_ADDON_MANAGER: true,
});

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

@ -18,6 +18,7 @@
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupports.h"
#include "nsIDocShell.h"
#include "nsWrapperCache.h"
class nsILoadInfo;
@ -67,6 +68,18 @@ class MOZ_STACK_CLASS DocInfo final {
return nullptr;
}
already_AddRefed<nsILoadContext> GetLoadContext() const {
nsCOMPtr<nsILoadContext> loadContext;
if (nsPIDOMWindowOuter* window = GetWindow()) {
nsIDocShell* docShell = window->GetDocShell();
loadContext = do_QueryInterface(docShell);
} else if (nsILoadInfo* loadInfo = GetLoadInfo()) {
nsCOMPtr<nsISupports> requestingContext = loadInfo->GetLoadingContext();
loadContext = do_QueryInterface(requestingContext);
}
return loadContext.forget();
}
private:
void SetURL(const URLInfo& aURL);

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

@ -11,7 +11,6 @@
#include "mozilla/AddonManagerWebAPI.h"
#include "mozilla/ResultExtensions.h"
#include "nsEscape.h"
#include "nsIDocShell.h"
#include "nsIObserver.h"
#include "nsISubstitutingProtocolHandler.h"
#include "nsNetUtil.h"
@ -133,7 +132,8 @@ WebExtensionPolicy::WebExtensionPolicy(GlobalObject& aGlobal,
mName(aInit.mName),
mContentSecurityPolicy(aInit.mContentSecurityPolicy),
mLocalizeCallback(aInit.mLocalizeCallback),
mPermissions(new AtomSet(aInit.mPermissions)) {
mPermissions(new AtomSet(aInit.mPermissions)),
mPrivateBrowsingAllowed(aInit.mPrivateBrowsingAllowed) {
if (!ParseGlobs(aGlobal, aInit.mWebAccessibleResources, mWebAccessiblePaths,
aRv)) {
return;
@ -440,6 +440,21 @@ void WebExtensionPolicy::GetContentScripts(
aScripts.AppendElements(mContentScripts);
}
bool WebExtensionPolicy::CanAccessContext(nsILoadContext* aContext) const {
MOZ_ASSERT(aContext);
return mPrivateBrowsingAllowed || !aContext->UsePrivateBrowsing();
}
bool WebExtensionPolicy::CanAccessWindow(nsPIDOMWindowOuter* aWindow) const {
if (mPrivateBrowsingAllowed) {
return true;
}
// match browsing mode with policy
nsIDocShell* docShell = aWindow->GetDocShell();
nsCOMPtr<nsILoadContext> loadContext = do_QueryInterface(docShell);
return !(loadContext && loadContext->UsePrivateBrowsing());
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebExtensionPolicy, mParent,
mLocalizeCallback, mHostPermissions,
mWebAccessiblePaths, mContentScripts)
@ -545,6 +560,12 @@ bool MozDocumentMatcher::Matches(const DocInfo& aDoc) const {
}
}
// match browsing mode with policy
nsCOMPtr<nsILoadContext> loadContext = aDoc.GetLoadContext();
if (loadContext && mExtension && !mExtension->CanAccessContext(loadContext)) {
return false;
}
if (!mMatchAboutBlank && aDoc.URL().InheritsPrincipal()) {
return false;
}

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

@ -121,6 +121,15 @@ class WebExtensionPolicy final : public nsISupports,
bool Active() const { return mActive; }
void SetActive(bool aActive, ErrorResult& aRv);
bool PrivateBrowsingAllowed() const { return mPrivateBrowsingAllowed; }
void SetPrivateBrowsingAllowed(bool aPrivateBrowsingAllowed) {
mPrivateBrowsingAllowed = aPrivateBrowsingAllowed;
};
bool CanAccessContext(nsILoadContext* aContext) const;
bool CanAccessWindow(nsPIDOMWindowOuter* aWindow) const;
static void GetActiveExtensions(
dom::GlobalObject& aGlobal,
nsTArray<RefPtr<WebExtensionPolicy>>& aResults);
@ -173,6 +182,8 @@ class WebExtensionPolicy final : public nsISupports,
RefPtr<MatchPatternSet> mHostPermissions;
MatchGlobSet mWebAccessiblePaths;
bool mPrivateBrowsingAllowed = false;
dom::Nullable<nsTArray<nsString>> mBackgroundScripts;
nsTArray<RefPtr<WebExtensionContentScript>> mContentScripts;

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

@ -145,6 +145,8 @@ ExtensionManager = {
allowedOrigins: extension.whiteListedHosts,
webAccessibleResources: extension.webAccessibleResources,
privateBrowsingAllowed: extension.privateBrowsingAllowed,
contentSecurityPolicy: extension.contentSecurityPolicy,
localizeCallback,

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

@ -9,11 +9,11 @@ this.extension = class extends ExtensionAPI {
},
isAllowedIncognitoAccess() {
return Promise.resolve(true);
return context.privateBrowsingAllowed;
},
isAllowedFileSchemeAccess() {
return Promise.resolve(false);
return false;
},
},
};

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

@ -102,8 +102,8 @@
"incognito": {
"type": "string",
"enum": ["spanning"],
"optional": true,
"onError": "warn"
"default": "spanning",
"optional": true
},
"background": {

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

@ -12,7 +12,6 @@ add_task(async function test_is_allowed_incognito_access() {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {},
});
await extension.startup();
@ -20,6 +19,24 @@ add_task(async function test_is_allowed_incognito_access() {
await extension.unload();
});
add_task(async function test_is_denied_incognito_access() {
async function background() {
let allowed = await browser.extension.isAllowedIncognitoAccess();
browser.test.assertEq(false, allowed, "isAllowedIncognitoAccess is false");
browser.test.notifyPass("isNotAllowedIncognitoAccess");
}
let extension = ExtensionTestUtils.loadExtension({
background,
incognitoOverride: "not_allowed",
});
await extension.startup();
await extension.awaitFinish("isNotAllowedIncognitoAccess");
await extension.unload();
});
add_task(async function test_in_incognito_context_false() {
function background() {
browser.test.assertEq(false, browser.extension.inIncognitoContext, "inIncognitoContext returned false");
@ -28,7 +45,6 @@ add_task(async function test_in_incognito_context_false() {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {},
});
await extension.startup();
@ -46,7 +62,6 @@ add_task(async function test_is_allowed_file_scheme_access() {
let extension = ExtensionTestUtils.loadExtension({
background,
manifest: {},
});
await extension.startup();

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

@ -0,0 +1,30 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function test_extension_incognito_spanning() {
let wrapper = ExtensionTestUtils.loadExtension({});
await wrapper.startup();
let extension = wrapper.extension;
let data = extension.serialize();
equal(data.privateBrowsingAllowed, true, "Should have privateBrowsingAllowed in serialized extension");
equal(extension.privateBrowsingAllowed, true, "Should have privateBrowsingAllowed");
equal(extension.policy.privateBrowsingAllowed, true, "Should have privateBrowsingAllowed on policy");
await wrapper.unload();
});
// This tests setting an extension to private-only mode which is useful for testing.
add_task(async function test_extension_incognito_test_mode() {
let wrapper = ExtensionTestUtils.loadExtension({
incognitoOverride: "not_allowed",
});
await wrapper.startup();
let extension = wrapper.extension;
let data = extension.serialize();
equal(data.privateBrowsingAllowed, false, "Should not have privateBrowsingAllowed in serialized extension");
equal(extension.privateBrowsingAllowed, false, "Should not have privateBrowsingAllowed");
equal(extension.policy.privateBrowsingAllowed, false, "Should not have privateBrowsingAllowed on policy");
await wrapper.unload();
});

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

@ -14,14 +14,25 @@ add_task(async function test_manifest_incognito() {
"spanning",
"Should have the expected incognito string");
normalized = await ExtensionTestUtils.normalizeManifest({
"incognito": "not_allowed",
});
equal(normalized.error,
'Error processing incognito: Invalid enumeration value "not_allowed"',
"Should have an error");
Assert.deepEqual(normalized.errors, [], "Should not have a warning");
equal(normalized.value, undefined,
"Invalid incognito string should be undefined");
normalized = await ExtensionTestUtils.normalizeManifest({
"incognito": "split",
});
equal(normalized.error, undefined, "Should not have an error");
Assert.deepEqual(normalized.errors,
['Error processing incognito: Invalid enumeration value "split"'],
"Should have the expected warning");
equal(normalized.value.incognito, null,
"Invalid incognito string should be omitted");
equal(normalized.error,
'Error processing incognito: Invalid enumeration value "split"',
"Should have an error");
Assert.deepEqual(normalized.errors, [], "Should not have a warning");
equal(normalized.value, undefined,
"Invalid incognito string should be undefined");
});

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

@ -60,6 +60,7 @@ skip-if = os == "android" # checking for telemetry needs to be updated: 1384923
[test_ext_extension_startup_telemetry.js]
[test_ext_geturl.js]
[test_ext_idle.js]
[test_ext_incognito.js]
[test_ext_localStorage.js]
[test_ext_management.js]
skip-if = (os == "win" && !debug) #Bug 1419183 disable on Windows