From 65c6963a0e04d242ff10180fba6f4aa9f1a2de9e Mon Sep 17 00:00:00 2001 From: Dylan Roeh Date: Mon, 17 May 2021 15:55:21 +0000 Subject: [PATCH] Bug 1699480 - Deprecate most existing TP exception API in GV and migrate it to new permissions API; also allow for importing/exporting ContentPermissions as JSONObjects. r=agi,geckoview-reviewers,aklotz Differential Revision: https://phabricator.services.mozilla.com/D113134 --- .../geckoview/ContentBlockingController.java | 7 +++ .../org/mozilla/geckoview/GeckoSession.java | 48 ++++++++++++++++++- .../mozilla/geckoview/StorageController.java | 8 ++++ 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlockingController.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlockingController.java index 575902906051..db2d833829e8 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlockingController.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/ContentBlockingController.java @@ -31,6 +31,7 @@ import java.util.List; public class ContentBlockingController { private static final String LOGTAG = "GeckoContentBlocking"; + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @AnyThread public static class ContentBlockingException { private final @NonNull String mEncodedPrincipal; @@ -98,6 +99,7 @@ public class ContentBlockingController { * @param session A {@link GeckoSession} whose site will be removed from the content * blocking exceptions list. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @UiThread public void removeException(final @NonNull GeckoSession session) { final GeckoBundle msg = new GeckoBundle(1); @@ -113,6 +115,7 @@ public class ContentBlockingController { * @param exception A {@link ContentBlockingException} which will be removed from the * content blocking exception list. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @AnyThread public void removeException(final @NonNull ContentBlockingException exception) { final GeckoBundle msg = new GeckoBundle(1); @@ -130,6 +133,7 @@ public class ContentBlockingController { * @return A {@link GeckoResult} which resolves to a Boolean indicating whether or * not the current site is on the exception list. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @UiThread public @NonNull GeckoResult checkException(final @NonNull GeckoSession session) { final GeckoBundle msg = new GeckoBundle(1); @@ -161,6 +165,7 @@ public class ContentBlockingController { * @return A List of {@link ContentBlockingException} which can be used to restore or * inspect the current exception list. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @UiThread public @NonNull GeckoResult> saveExceptionList() { return EventDispatcher.getInstance() @@ -173,6 +178,7 @@ public class ContentBlockingController { * * @param list A List of {@link ContentBlockingException} originally created by {@link #saveExceptionList}. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @AnyThread public void restoreExceptionList(final @NonNull List list) { final GeckoBundle bundle = new GeckoBundle(2); @@ -193,6 +199,7 @@ public class ContentBlockingController { /** * Clear the content blocking exception list entirely. */ + @DeprecationSchedule(version = 93, id = "content-blocking-exception") @UiThread public void clearExceptionList() { EventDispatcher.getInstance().dispatch("ContentBlocking:ClearList", null); diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java index 6946dee12dab..5818681d6617 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java @@ -5429,6 +5429,12 @@ public class GeckoSession { */ int PERMISSION_MEDIA_KEY_SYSTEM_ACCESS = 6; + /** + * Permission for trackers to operate on the page -- disables all tracking protection + * features for a given site. + */ + int PERMISSION_TRACKING = 7; + /** * Represents a content permission -- including the type of permission, * the present value of the permission, the URL the permission pertains to, @@ -5504,6 +5510,40 @@ public class GeckoSession { this.contextId = StorageController.retrieveUnsafeSessionContextId(bundle.getString("contextId")); } + /** + * Converts a JSONObject to a ContentPermission -- should only be used on the output of + * {@link #toJson()}. + * + * @param perm A JSONObject representing a ContentPermission, output by {@link #toJson()}. + * + * @return The corresponding ContentPermission. + */ + @AnyThread + public static @Nullable ContentPermission fromJson(final @NonNull JSONObject perm) { + ContentPermission res = null; + try { + res = new ContentPermission(GeckoBundle.fromJSONObject(perm)); + } catch (final JSONException e) { + Log.w(LOGTAG, "Failed to create ContentPermission; invalid JSONObject.", e); + } + return res; + } + + /** + * Converts a ContentPermission to a JSONObject that can be converted back to + * a ContentPermission by {@link #fromJson(JSONObject)}. + * + * @return A JSONObject representing this ContentPermission. Modifying any of + * the fields may result in undefined behavior when converted back + * to a ContentPermission and used. + * + * @throws JSONException if the conversion fails for any reason. + */ + @AnyThread + public @NonNull JSONObject toJson() throws JSONException { + return toGeckoBundle().toJSONObject(); + } + private static int convertType(final @NonNull String type) { if ("geolocation".equals(type)) { return PERMISSION_GEOLOCATION; @@ -5519,12 +5559,14 @@ public class GeckoSession { return PERMISSION_AUTOPLAY_AUDIBLE; } else if ("media-key-system-access".equals(type)) { return PERMISSION_MEDIA_KEY_SYSTEM_ACCESS; + } else if ("trackingprotection".equals(type) || "trackingprotection-pb".equals(type)) { + return PERMISSION_TRACKING; } else { return -1; } } - private static String convertType(final int type) { + private static String convertType(final int type, final boolean privateMode) { switch (type) { case PERMISSION_GEOLOCATION: return "geolocation"; @@ -5540,6 +5582,8 @@ public class GeckoSession { return "autoplay-media-audible"; case PERMISSION_MEDIA_KEY_SYSTEM_ACCESS: return "media-key-system-access"; + case PERMISSION_TRACKING: + return privateMode ? "trackingprotection-pb" : "trackingprotection"; default: return ""; } @@ -5566,7 +5610,7 @@ public class GeckoSession { res.putString("uri", uri); res.putString("principal", mPrincipal); res.putBoolean("privateMode", privateMode); - res.putString("perm", convertType(permission)); + res.putString("perm", convertType(permission, privateMode)); res.putInt("value", value); res.putString("contextId", contextId); return res; diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/StorageController.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/StorageController.java index 179e7870ac89..5a6583f10cfc 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/StorageController.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/StorageController.java @@ -18,6 +18,8 @@ import androidx.annotation.LongDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import android.util.Log; + import org.mozilla.gecko.EventDispatcher; import org.mozilla.gecko.util.GeckoBundle; import org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission; @@ -28,6 +30,7 @@ import org.mozilla.geckoview.GeckoSession.PermissionDelegate.ContentPermission; * Retrieve an instance via {@link GeckoRuntime#getStorageController}. */ public final class StorageController { + private static final String LOGTAG = "StorageController"; // Keep in sync with GeckoViewStorageController.ClearFlags. /** @@ -252,6 +255,11 @@ public final class StorageController { */ @AnyThread public void setPermission(final @NonNull ContentPermission perm, final @ContentPermission.Value int value) { + if (perm.permission == GeckoSession.PermissionDelegate.PERMISSION_TRACKING && + value == ContentPermission.VALUE_PROMPT) { + Log.w(LOGTAG, "Cannot set a tracking permission to VALUE_PROMPT, aborting."); + return; + } final GeckoBundle msg = perm.toGeckoBundle(); msg.putInt("newValue", value); EventDispatcher.getInstance().dispatch("GeckoView:SetPermission", msg);