Bug 1376865 Automatically decline the canvas permission if it is not in response to user input r?baku draft
authorTom Ritter <tom@mozilla.com>
Sat, 17 Feb 2018 13:53:05 -0600
changeset 759711 1469702b25a192df821a4615c4b94235c41a105c
parent 756717 dde7eb1a589f1ec5221ad2a8c78007094f3b3b01
child 759712 a61d4d74ce8ae8c6c41c2ab9049ca531e5595014
push id100437
push userbmo:tom@mozilla.com
push dateMon, 26 Feb 2018 13:40:15 +0000
reviewersbaku
bugs1376865
milestone60.0a1
Bug 1376865 Automatically decline the canvas permission if it is not in response to user input r?baku The canvas prompt is extremely annoying. It happens everyone, automatically. And in 99.9% (not scientific) of cases it is not triggered by user input, but my automatic tracking scripts. This commit will automatically decline the canvas read if it was not triggered by user input. Just in case this breaks something irrepairably, we have a cutoff pref. We don't intend to keep this pref forever, and have asked anyone who sets it to tell us why. MozReview-Commit-ID: CxNkuraRWpV
dom/base/DOMPrefsInternal.h
dom/canvas/CanvasUtils.cpp
dom/ipc/ContentPrefs.cpp
modules/libpref/init/all.js
--- a/dom/base/DOMPrefsInternal.h
+++ b/dom/base/DOMPrefsInternal.h
@@ -33,16 +33,17 @@ DOM_PREF(PromiseRejectionEventsEnabled, 
 DOM_PREF(PushEnabled, "dom.push.enabled")
 DOM_PREF(StreamsEnabled, "dom.streams.enabled")
 DOM_PREF(RequestContextEnabled, "dom.requestcontext.enabled")
 DOM_PREF(OffscreenCanvasEnabled, "gfx.offscreencanvas.enabled")
 DOM_PREF(WebkitBlinkDirectoryPickerEnabled, "dom.webkitBlink.dirPicker.enabled")
 DOM_PREF(NetworkInformationEnabled, "dom.netinfo.enabled")
 DOM_PREF(FetchObserverEnabled, "dom.fetchObserver.enabled")
 DOM_PREF(ResistFingerprintingEnabled, "privacy.resistFingerprinting")
+DOM_PREF(EnableAutoDeclineCanvasPrompts, "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts")
 DOM_PREF(DevToolsEnabled, "devtools.enabled")
 DOM_PREF(PerformanceObserverEnabled, "dom.enable_performance_observer")
 
 DOM_WEBIDL_PREF(ImageBitmapExtensionsEnabled)
 DOM_WEBIDL_PREF(DOMCachesEnabled)
 DOM_WEBIDL_PREF(NotificationEnabledInServiceWorkers)
 DOM_WEBIDL_PREF(NotificationRIEnabled)
 DOM_WEBIDL_PREF(ServiceWorkersEnabled)
--- a/dom/canvas/CanvasUtils.cpp
+++ b/dom/canvas/CanvasUtils.cpp
@@ -9,16 +9,17 @@
 #include "nsIServiceManager.h"
 
 #include "nsIConsoleService.h"
 #include "nsIDOMCanvasRenderingContext2D.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsIHTMLCollection.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/TabChild.h"
+#include "mozilla/EventStateManager.h"
 #include "nsIPrincipal.h"
 
 #include "nsGfxCIID.h"
 
 #include "nsTArray.h"
 
 #include "CanvasUtils.h"
 #include "mozilla/gfx/Matrix.h"
@@ -137,18 +138,33 @@ bool IsImageExtractionAllowed(nsIDocumen
         return true;
     case nsIPermissionManager::DENY_ACTION:
         return false;
     default:
         break;
     }
 
     // At this point, permission is unknown (nsIPermissionManager::UNKNOWN_ACTION).
+
+    // Check if the request is in response to user input
+    if (DOMPrefs::EnableAutoDeclineCanvasPrompts() && !EventStateManager::IsHandlingUserInput()) {
+        nsAutoCString message;
+        message.AppendPrintf("Blocked %s in page %s from extracting canvas data because no user input was detected.",
+                             docURISpec.get(), topLevelDocURISpec.get());
+        if (isScriptKnown) {
+            message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine);
+        }
+        nsContentUtils::LogMessageToConsole(message.get());
+
+        return false;
+    }
+
+    // It was in response to user input, so log and display the prompt.
     nsAutoCString message;
-    message.AppendPrintf("Blocked %s in page %s from extracting canvas data.",
+    message.AppendPrintf("Blocked %s in page %s from extracting canvas data, but prompting the user.",
                          docURISpec.get(), topLevelDocURISpec.get());
     if (isScriptKnown) {
         message.AppendPrintf(" %s:%u.", scriptFile.get(), scriptLine);
     }
     nsContentUtils::LogMessageToConsole(message.get());
 
     // Prompt the user (asynchronous).
     if (XRE_IsContentProcess()) {
--- a/dom/ipc/ContentPrefs.cpp
+++ b/dom/ipc/ContentPrefs.cpp
@@ -283,16 +283,17 @@ const char* mozilla::dom::ContentPrefs::
   "network.tcp.keepalive.retry_interval",
   "network.tcp.sendbuffer",
   "nglayout.debug.invalidation",
   "privacy.donottrackheader.enabled",
   "privacy.firstparty.isolate",
   "privacy.firstparty.isolate.restrict_opener_access",
   "privacy.reduceTimerPrecision",
   "privacy.resistFingerprinting",
+  "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts",
   "privacy.resistFingerprinting.reduceTimerPrecision.microseconds",
   "privacy.resistFingerprinting.target_video_res",
   "privacy.resistFingerprinting.video_dropped_ratio",
   "privacy.resistFingerprinting.video_frames_per_sec",
   "privacy.trackingprotection.lower_network_priority",
   "privacy.window.maxInnerHeight",
   "privacy.window.maxInnerWidth",
   "security.csp.enable",
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1395,16 +1395,22 @@ pref("privacy.trackingprotection.annotat
 // First Party Isolation (double keying), disabled by default
 pref("privacy.firstparty.isolate",                        false);
 // If false, two windows in the same domain with different first party domains
 // (top level URLs) can access resources through window.opener.
 // This pref is effective only when "privacy.firstparty.isolate" is true.
 pref("privacy.firstparty.isolate.restrict_opener_access", true);
 // Anti-fingerprinting, disabled by default
 pref("privacy.resistFingerprinting", false);
+// We automatically decline canvas permission requests if they are not initiated
+// from user input. Just in case that breaks something, we allow the user to revert
+// this behaior with this obscure pref. We do not intend to support this long term.
+// If you do set it, to work around some broken website, please file a bug with
+// information so we can understand why it is needed.
+pref("privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts", true);
 // A subset of Resist Fingerprinting protections focused specifically on timers for testing
 // This affects the Animation API, the performance APIs, Date.getTime, Event.timestamp,
 //   File.lastModified, audioContext.currentTime, canvas.captureStream.currentTime
 pref("privacy.reduceTimerPrecision", true);
 // Dynamically tune the resolution of the timer reduction for both of the two above prefs
 pref("privacy.resistFingerprinting.reduceTimerPrecision.microseconds", 2000);
 // Lower the priority of network loads for resources on the tracking protection list.
 // Note that this requires the privacy.trackingprotection.annotate_channels pref to be on in order to have any effect.