Bug 1509047 - Part 5: Add heuristics to the storage access API for automatically granting temporary session-scoped storage access without displaying a doorhanger prompt r=johannh
☠☠ backed out by 0f4be93319f6 ☠ ☠
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 28 Nov 2018 22:02:52 +0000
changeset 505088 7bfa4179a341674e066171c33a8bad746b68cd92
parent 505087 37172d2d6f99802975761c9e26bac9f2b94d8c44
child 505089 53f6c4e1f112024f662351dd346a966f0fb77f8e
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1509047
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1509047 - Part 5: Add heuristics to the storage access API for automatically granting temporary session-scoped storage access without displaying a doorhanger prompt r=johannh Depends on D12865 Differential Revision: https://phabricator.services.mozilla.com/D12866
browser/app/profile/firefox.js
browser/modules/PermissionUI.jsm
browser/modules/test/browser/browser_PermissionUI_prompts.js
toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1527,16 +1527,19 @@ pref("network.cookie.cookieBehavior", 4 
 
 pref("browser.contentblocking.allowlist.storage.enabled", true);
 
 #ifdef NIGHTLY_BUILD
 // Enable the Storage Access API in Nightly
 pref("dom.storage_access.enabled", true);
 #endif
 
+pref("dom.storage_access.auto_grants", true);
+pref("dom.storage_access.max_concurrent_auto_grants", 5);
+
 // Define a set of default features for the Content Blocking UI.
 pref("browser.contentblocking.trackingprotection.control-center.ui.enabled", true);
 pref("browser.contentblocking.rejecttrackers.control-center.ui.enabled", true);
 
 // Enable the Report Breakage UI on Nightly and Beta but not on Release yet.
 #ifdef EARLY_BETA_OR_EARLIER
 pref("browser.contentblocking.reportBreakage.enabled", true);
 #else
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -63,16 +63,18 @@ var EXPORTED_SYMBOLS = [
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 
 ChromeUtils.defineModuleGetter(this, "Services",
   "resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "SitePermissions",
   "resource:///modules/SitePermissions.jsm");
 ChromeUtils.defineModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
+ChromeUtils.defineModuleGetter(this, "URICountListener",
+  "resource:///modules/BrowserUsageTelemetry.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings
                  .createBundle("chrome://browser/locale/browser.properties");
 });
 
 var PermissionUI = {};
 
@@ -917,16 +919,21 @@ AutoplayPermissionPrompt.prototype = {
     return true;
   },
 };
 
 PermissionUI.AutoplayPermissionPrompt = AutoplayPermissionPrompt;
 
 function StorageAccessPermissionPrompt(request) {
   this.request = request;
+
+  XPCOMUtils.defineLazyPreferenceGetter(this, "_autoGrants",
+                                        "dom.storage_access.auto_grants");
+  XPCOMUtils.defineLazyPreferenceGetter(this, "_maxConcurrentAutoGrants",
+                                        "dom.storage_access.max_concurrent_auto_grants");
 }
 
 StorageAccessPermissionPrompt.prototype = {
   __proto__: PermissionPromptForRequestPrototype,
 
   get usePermissionManager() {
     return false;
   },
@@ -1007,11 +1014,43 @@ StorageAccessPermissionPrompt.prototype 
           self.allow({"storage-access": "allow-on-any-site"});
         },
     }];
   },
 
   get topLevelPrincipal() {
     return this.request.topLevelPrincipal;
   },
+
+  get maxConcurrentAutomaticGrants() {
+    // one percent of the number of top-levels origins visited in the current
+    // session (but not to exceed 24 hours), or the value of the
+    // dom.storage_access.max_concurrent_auto_grants preference, whichever is
+    // higher.
+    return Math.max(Math.max(Math.floor(URICountListener.uniqueOriginsVisitedInPast24Hours / 100),
+                             this._maxConcurrentAutoGrants), 0);
+  },
+
+  getOriginsThirdPartyHasAccessTo(thirdPartyOrigin) {
+    let prefix = `3rdPartyStorage^${thirdPartyOrigin}`;
+    let perms = Services.perms.getAllWithTypePrefix(prefix);
+    let origins = new Set();
+    while (perms.length) {
+      let perm = perms.shift();
+      origins.add(perm.principal.origin);
+    }
+    return origins.size;
+  },
+
+  onBeforeShow() {
+    let thirdPartyOrigin = this.request.principal.origin;
+    if (this._autoGrants &&
+        this.getOriginsThirdPartyHasAccessTo(thirdPartyOrigin) <
+          this.maxConcurrentAutomaticGrants) {
+      // Automatically accept the prompt
+      this.allow({"storage-access": "allow-auto-grant"});
+      return false;
+    }
+    return true;
+  },
 };
 
 PermissionUI.StorageAccessPermissionPrompt = StorageAccessPermissionPrompt;
--- a/browser/modules/test/browser/browser_PermissionUI_prompts.js
+++ b/browser/modules/test/browser/browser_PermissionUI_prompts.js
@@ -34,17 +34,19 @@ add_task(async function test_midi_permis
 add_task(async function test_autoplay_permission_prompt() {
   Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.PROMPT);
   await testPrompt(PermissionUI.AutoplayPermissionPrompt);
   Services.prefs.clearUserPref("media.autoplay.default");
 });
 
 // Tests that AutoplayPermissionPrompt works as expected
 add_task(async function test_storage_access_permission_prompt() {
+  Services.prefs.setBoolPref("dom.storage_access.auto_grants", false);
   await testPrompt(PermissionUI.StorageAccessPermissionPrompt);
+  Services.prefs.clearUserPref("dom.storage_access.auto_grants");
 });
 
 async function testPrompt(Prompt) {
   await BrowserTestUtils.withNewTab({
     gBrowser,
     url: "http://example.com",
   }, async function(browser) {
     let mockRequest = makeMockPermissionRequest(browser);
--- a/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
+++ b/toolkit/components/antitracking/test/browser/browser_storageAccessDoorHanger.js
@@ -7,16 +7,17 @@ Services.scriptloader.loadSubScript(CHRO
 async function testDoorHanger(choice) {
   info(`Running doorhanger test with choice #${choice}`);
 
   await SpecialPowers.flushPrefEnv();
   await SpecialPowers.pushPrefEnv({"set": [
     ["browser.contentblocking.allowlist.annotations.enabled", true],
     ["browser.contentblocking.allowlist.storage.enabled", true],
     [ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS],
+    ["dom.storage_access.auto_grants", false],
     ["dom.storage_access.enabled", true],
     ["dom.storage_access.prompt.testing", false],
     ["network.cookie.cookieBehavior", Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER],
     ["privacy.trackingprotection.enabled", false],
     ["privacy.trackingprotection.pbmode.enabled", false],
     ["privacy.trackingprotection.annotate_channels", true],
     ["privacy.restrict3rdpartystorage.userInteractionRequiredForHosts", "tracking.example.com,tracking.example.org"],
   ]});