зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1599139 - Add API to control whether extensions can run in private browsing. r=snorp,esawin
Differential Revision: https://phabricator.services.mozilla.com/D65551 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f6f2f88fa3
Коммит
97c5dd8d40
|
@ -93,6 +93,7 @@ GeckoViewStartup.prototype = {
|
|||
"GeckoView:WebExtension:List",
|
||||
"GeckoView:WebExtension:PortDisconnect",
|
||||
"GeckoView:WebExtension:PortMessageFromApp",
|
||||
"GeckoView:WebExtension:SetPBAllowed",
|
||||
"GeckoView:WebExtension:Uninstall",
|
||||
"GeckoView:WebExtension:Update",
|
||||
],
|
||||
|
|
|
@ -1565,6 +1565,7 @@ package org.mozilla.geckoview {
|
|||
|
||||
public class WebExtension.MetaData {
|
||||
ctor protected MetaData();
|
||||
field public final boolean allowedInPrivateBrowsing;
|
||||
field @NonNull public final String baseUrl;
|
||||
field public final int blocklistState;
|
||||
field @Nullable public final String creatorName;
|
||||
|
@ -1643,6 +1644,7 @@ package org.mozilla.geckoview {
|
|||
method @UiThread @Nullable @Deprecated public WebExtensionController.TabDelegate getTabDelegate();
|
||||
method @NonNull @AnyThread public GeckoResult<WebExtension> install(@NonNull String);
|
||||
method @AnyThread @NonNull public GeckoResult<List<WebExtension>> list();
|
||||
method @NonNull @AnyThread public GeckoResult<WebExtension> setAllowedInPrivateBrowsing(@NonNull WebExtension, boolean);
|
||||
method @UiThread public void setDebuggerDelegate(@NonNull WebExtensionController.DebuggerDelegate);
|
||||
method @UiThread public void setPromptDelegate(@Nullable WebExtensionController.PromptDelegate);
|
||||
method @AnyThread public void setTabActive(@NonNull GeckoSession, boolean);
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.AssertCalled
|
|||
import org.mozilla.geckoview.test.util.Callbacks
|
||||
import org.mozilla.geckoview.WebExtension.DisabledFlags
|
||||
import org.mozilla.geckoview.WebExtensionController.EnableSource
|
||||
import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.Setting
|
||||
|
||||
import java.util.UUID
|
||||
|
||||
|
@ -221,6 +222,58 @@ class WebExtensionTest : BaseSessionTest() {
|
|||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
@Test
|
||||
@Setting.List(Setting(key = Setting.Key.USE_PRIVATE_MODE, value = "true"))
|
||||
fun runInPrivateBrowsing() {
|
||||
mainSession.loadUri("example.com")
|
||||
sessionRule.waitForPageStop()
|
||||
|
||||
// Make sure border is empty before running the extension
|
||||
assertBodyBorderEqualTo("")
|
||||
|
||||
sessionRule.delegateDuringNextWait(object : WebExtensionController.PromptDelegate {
|
||||
@AssertCalled(count=1)
|
||||
override fun onInstallPrompt(extension: WebExtension): GeckoResult<AllowOrDeny> {
|
||||
return GeckoResult.fromValue(AllowOrDeny.ALLOW)
|
||||
}
|
||||
})
|
||||
|
||||
var borderify = sessionRule.waitForResult(
|
||||
controller.install("resource://android/assets/web_extensions/borderify.xpi"))
|
||||
|
||||
// Make sure private mode is enabled
|
||||
assertTrue(mainSession.settings.usePrivateMode)
|
||||
assertFalse(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was not applied to a private mode page
|
||||
assertBodyBorderEqualTo("")
|
||||
|
||||
borderify = sessionRule.waitForResult(
|
||||
controller.setAllowedInPrivateBrowsing(borderify, true))
|
||||
|
||||
assertTrue(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was applied to a private mode page now that the extension
|
||||
// is enabled in private mode
|
||||
mainSession.reload();
|
||||
sessionRule.waitForPageStop()
|
||||
assertBodyBorderEqualTo("red")
|
||||
|
||||
borderify = sessionRule.waitForResult(
|
||||
controller.setAllowedInPrivateBrowsing(borderify, false))
|
||||
|
||||
assertFalse(borderify.metaData!!.allowedInPrivateBrowsing)
|
||||
// Check that the WebExtension was not applied to a private mode page after being
|
||||
// not allowed to run in private mode
|
||||
mainSession.reload();
|
||||
sessionRule.waitForPageStop()
|
||||
assertBodyBorderEqualTo("")
|
||||
|
||||
// Unregister WebExtension and check again
|
||||
sessionRule.waitForResult(controller.uninstall(borderify))
|
||||
mainSession.reload();
|
||||
sessionRule.waitForPageStop()
|
||||
assertBodyBorderEqualTo("")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun optionsPageMetadata() {
|
||||
// dummy.xpi is not signed, but it could be
|
||||
|
|
|
@ -1783,6 +1783,12 @@ public class WebExtension {
|
|||
*/
|
||||
public final @NonNull String baseUrl;
|
||||
|
||||
/**
|
||||
* Whether this extension is allowed to run in private browsing or not.
|
||||
* To modify this value use {@link WebExtensionController#setAllowedInPrivateBrowsing}.
|
||||
*/
|
||||
public final boolean allowedInPrivateBrowsing;
|
||||
|
||||
/**
|
||||
* Whether this extension is enabled or not.
|
||||
*/
|
||||
|
@ -1807,6 +1813,7 @@ public class WebExtension {
|
|||
disabledFlags = 0;
|
||||
enabled = true;
|
||||
baseUrl = null;
|
||||
allowedInPrivateBrowsing = false;
|
||||
}
|
||||
|
||||
/* package */ MetaData(final GeckoBundle bundle) {
|
||||
|
@ -1824,6 +1831,7 @@ public class WebExtension {
|
|||
blocklistState = bundle.getInt("blocklistState", BlocklistStateFlags.NOT_BLOCKED);
|
||||
enabled = bundle.getBoolean("enabled", false);
|
||||
baseUrl = bundle.getString("baseURL");
|
||||
allowedInPrivateBrowsing = bundle.getBoolean("privateBrowsingAllowed", false);
|
||||
|
||||
int signedState = bundle.getInt("signedState", SignedStateFlags.UNKNOWN);
|
||||
if (signedState <= SignedStateFlags.LAST) {
|
||||
|
|
|
@ -492,6 +492,35 @@ public class WebExtensionController {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether an extension should be allowed to run in private browsing or not.
|
||||
*
|
||||
* @param extension the {@link WebExtension} instance to modify.
|
||||
* @param allowed true if this extension should be allowed to run in private browsing pages,
|
||||
* false otherwise.
|
||||
* @return the updated {@link WebExtension} instance.
|
||||
*/
|
||||
@NonNull
|
||||
@AnyThread
|
||||
public GeckoResult<WebExtension> setAllowedInPrivateBrowsing(
|
||||
final @NonNull WebExtension extension,
|
||||
final boolean allowed) {
|
||||
final WebExtensionController.WebExtensionResult result =
|
||||
new WebExtensionController.WebExtensionResult("extension");
|
||||
|
||||
final GeckoBundle bundle = new GeckoBundle(2);
|
||||
bundle.putString("extensionId", extension.id);
|
||||
bundle.putBoolean("allowed", allowed);
|
||||
|
||||
EventDispatcher.getInstance().dispatch("GeckoView:WebExtension:SetPBAllowed",
|
||||
bundle, result);
|
||||
|
||||
return result.then(newExtension -> {
|
||||
registerWebExtension(newExtension);
|
||||
return GeckoResult.fromValue(newExtension);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Bug 1601067 make public
|
||||
GeckoResult<WebExtension> installBuiltIn(final String uri) {
|
||||
final WebExtensionResult result = new WebExtensionResult("extension");
|
||||
|
|
|
@ -56,6 +56,12 @@ exclude: true
|
|||
- Added [`baseUrl`][75.24] to [`WebExtension.MetaData`][75.25] to expose the
|
||||
base URL for all WebExtension pages for a given extension.
|
||||
([bug 1560048]({{bugzilla}}1560048))
|
||||
- Added [`allowedInPrivateBrowsing`][75.26] and
|
||||
[`setAllowedInPrivateBrowsing`][75.27] to control whether an extension can
|
||||
run in private browsing or not. Extensions installed with
|
||||
[`registerWebExtension`][67.15] will always be allowed to run in private
|
||||
browsing.
|
||||
([bug 1599139]({{bugzilla}}1599139))
|
||||
|
||||
[75.1]: {{javadoc_uri}}/GeckoRuntimeSettings.Builder.html#useMultiprocess-boolean-
|
||||
[75.2]: {{javadoc_uri}}/WebExtensionController.DebuggerDelegate.html#onExtensionListUpdated--
|
||||
|
@ -82,6 +88,8 @@ exclude: true
|
|||
[75.23]: {{javadoc_uri}}/GeckoResult.CancellationDelegate.html
|
||||
[75.24]: {{javadoc_uri}}/WebExtension.MetaData.html#baseUrl
|
||||
[75.25]: {{javadoc_uri}}/WebExtension.MetaData.html
|
||||
[75.26]: {{javadoc_uri}}/WebExtension.MetaData.html#allowedInPrivateBrowsing
|
||||
[75.27]: {{javadoc_uri}}/WebExtensionController.html#setAllowedInPrivateBrowsing-org.mozilla.geckoview.WebExtension-boolean-
|
||||
|
||||
## v74
|
||||
- Added [`WebExtensionController.enable`][74.1] and [`disable`][74.2] to
|
||||
|
@ -645,4 +653,4 @@ exclude: true
|
|||
[65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
|
||||
[65.25]: {{javadoc_uri}}/GeckoResult.html
|
||||
|
||||
[api-version]: 9a5f829b35bacd2c1f1a6f94c394ffb93b1b0513
|
||||
[api-version]: 6b0849430f800a3e2226c1a87d26830d1cbe73ee
|
||||
|
|
|
@ -22,10 +22,16 @@ const { EventEmitter } = ChromeUtils.import(
|
|||
);
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const PRIVATE_BROWSING_PERMISSION = {
|
||||
permissions: ["internal:privateBrowsingAllowed"],
|
||||
origins: [],
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
AddonManager: "resource://gre/modules/AddonManager.jsm",
|
||||
EventDispatcher: "resource://gre/modules/Messaging.jsm",
|
||||
Extension: "resource://gre/modules/Extension.jsm",
|
||||
ExtensionPermissions: "resource://gre/modules/ExtensionPermissions.jsm",
|
||||
GeckoViewTabBridge: "resource://gre/modules/GeckoViewTab.jsm",
|
||||
Management: "resource://gre/modules/Extension.jsm",
|
||||
});
|
||||
|
@ -268,9 +274,11 @@ function exportExtension(aAddon, aPermissions, aSourceURI) {
|
|||
disabledFlags.push("appDisabled");
|
||||
}
|
||||
let baseURL = "";
|
||||
let privateBrowsingAllowed = false;
|
||||
const policy = WebExtensionPolicy.getByID(id);
|
||||
if (policy) {
|
||||
baseURL = policy.getURL();
|
||||
privateBrowsingAllowed = policy.privateBrowsingAllowed;
|
||||
}
|
||||
return {
|
||||
webExtensionId: id,
|
||||
|
@ -294,6 +302,7 @@ function exportExtension(aAddon, aPermissions, aSourceURI) {
|
|||
signedState,
|
||||
icons,
|
||||
baseURL,
|
||||
privateBrowsingAllowed,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -488,6 +497,8 @@ var GeckoViewWebExtension = {
|
|||
|
||||
const scope = Extension.getBootstrapScope(aId, file);
|
||||
scope.allowContentMessaging = allowContentMessaging;
|
||||
// Always allow built-in extensions to run in private browsing
|
||||
ExtensionPermissions.add(aId, PRIVATE_BROWSING_PERMISSION);
|
||||
this.extensionScopes.set(aId, scope);
|
||||
|
||||
await scope.startup(params, undefined);
|
||||
|
@ -509,7 +520,7 @@ var GeckoViewWebExtension = {
|
|||
},
|
||||
|
||||
async extensionById(aId) {
|
||||
let scope = this.extensionScopes.get(aId);
|
||||
const scope = this.extensionScopes.get(aId);
|
||||
if (!scope) {
|
||||
// Check if this is an installed extension we haven't seen yet
|
||||
const addon = await AddonManager.getAddonByID(aId);
|
||||
|
@ -517,10 +528,7 @@ var GeckoViewWebExtension = {
|
|||
debug`Could not find extension with id=${aId}`;
|
||||
return null;
|
||||
}
|
||||
scope = {
|
||||
allowContentMessaging: false,
|
||||
extension: addon,
|
||||
};
|
||||
return addon;
|
||||
}
|
||||
|
||||
return scope.extension;
|
||||
|
@ -544,6 +552,23 @@ var GeckoViewWebExtension = {
|
|||
return promise;
|
||||
},
|
||||
|
||||
async setPrivateBrowsingAllowed(aId, aAllowed) {
|
||||
if (aAllowed) {
|
||||
await ExtensionPermissions.add(aId, PRIVATE_BROWSING_PERMISSION);
|
||||
} else {
|
||||
await ExtensionPermissions.remove(aId, PRIVATE_BROWSING_PERMISSION);
|
||||
}
|
||||
|
||||
// Reload the extension if it is already enabled. This ensures any change
|
||||
// on the private browsing permission is properly handled.
|
||||
const addon = await this.extensionById(aId);
|
||||
if (addon.isActive) {
|
||||
await addon.reload();
|
||||
}
|
||||
|
||||
return exportExtension(addon, addon.userPermissions, /* aSourceURI */ null);
|
||||
},
|
||||
|
||||
async uninstallWebExtension(aId) {
|
||||
const extension = await this.extensionById(aId);
|
||||
if (!extension) {
|
||||
|
@ -756,6 +781,20 @@ var GeckoViewWebExtension = {
|
|||
break;
|
||||
}
|
||||
|
||||
case "GeckoView:WebExtension:SetPBAllowed": {
|
||||
const { extensionId, allowed } = aData;
|
||||
try {
|
||||
const extension = await this.setPrivateBrowsingAllowed(
|
||||
extensionId,
|
||||
allowed
|
||||
);
|
||||
aCallback.onSuccess({ extension });
|
||||
} catch (ex) {
|
||||
aCallback.onError(`Unexpected error: ${ex}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "GeckoView:WebExtension:Install": {
|
||||
const uri = Services.io.newURI(aData.locationUri);
|
||||
if (uri == null) {
|
||||
|
|
|
@ -3118,7 +3118,7 @@
|
|||
# Private browsing opt-in is only supported on Firefox desktop.
|
||||
- name: extensions.allowPrivateBrowsingByDefault
|
||||
type: bool
|
||||
value: @IS_ANDROID@
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# This pref governs whether we enable content script CSP in extensions.
|
||||
|
|
Загрузка…
Ссылка в новой задаче