Bug 1330467 - part 8. Make canvas permission respect FPI; r=johannh,jrmuizel
authorLiang-Heng Chen <xeonchen@gmail.com>
Tue, 07 May 2019 22:19:02 +0000
changeset 535282 4686eebd8962db7d03d7fbca124cca28069f4a72
parent 535281 b43fa07d5756d6206f41a4f4a7da6758b2a09690
child 535283 2648f5bb180463e213b55a0f1434c51c9853f213
push id2082
push userffxbld-merge
push dateMon, 01 Jul 2019 08:34:18 +0000
treeherdermozilla-release@2fb19d0466d2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh, jrmuizel
bugs1330467
milestone68.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 1330467 - part 8. Make canvas permission respect FPI; r=johannh,jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D19929
browser/base/content/browser.js
dom/canvas/CanvasUtils.cpp
dom/ipc/BrowserParent.cpp
dom/ipc/BrowserParent.h
dom/ipc/PBrowser.ipdl
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -7250,75 +7250,78 @@ var CanvasPermissionPromptHelper = {
   },
 
   uninit() {
     Services.obs.removeObserver(this, this._permissionsPrompt);
     Services.obs.removeObserver(this, this._permissionsPromptHideDoorHanger);
   },
 
   // aSubject is an nsIBrowser (e10s) or an nsIDOMWindow (non-e10s).
-  // aData is an URL string.
+  // aData is an Origin string.
   observe(aSubject, aTopic, aData) {
     if (aTopic != this._permissionsPrompt &&
         aTopic != this._permissionsPromptHideDoorHanger) {
       return;
     }
 
     let browser;
     if (aSubject instanceof Ci.nsIDOMWindow) {
       let contentWindow = aSubject.QueryInterface(Ci.nsIDOMWindow);
       browser = contentWindow.docShell.chromeEventHandler;
     } else {
       browser = aSubject;
     }
 
-    let uri = Services.io.newURI(aData);
     if (gBrowser.selectedBrowser !== browser) {
       // Must belong to some other window.
       return;
     }
 
     let message = gNavigatorBundle.getFormattedString("canvas.siteprompt", ["<>"], 1);
 
-    function setCanvasPermission(aURI, aPerm, aPersistent) {
-      Services.perms.add(aURI, "canvas", aPerm,
-                          aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
-                                      : Ci.nsIPermissionManager.EXPIRE_SESSION);
+    let principal = Services.scriptSecurityManager
+                            .createCodebasePrincipalFromOrigin(aData);
+
+    function setCanvasPermission(aPerm, aPersistent) {
+      Services.perms.addFromPrincipal(
+        principal, "canvas", aPerm,
+        aPersistent ? Ci.nsIPermissionManager.EXPIRE_NEVER
+                    : Ci.nsIPermissionManager.EXPIRE_SESSION);
     }
 
     let mainAction = {
       label: gNavigatorBundle.getString("canvas.allow"),
       accessKey: gNavigatorBundle.getString("canvas.allow.accesskey"),
       callback(state) {
-        setCanvasPermission(uri, Ci.nsIPermissionManager.ALLOW_ACTION,
+        setCanvasPermission(Ci.nsIPermissionManager.ALLOW_ACTION,
                             state && state.checkboxChecked);
       },
     };
 
     let secondaryActions = [{
       label: gNavigatorBundle.getString("canvas.notAllow"),
       accessKey: gNavigatorBundle.getString("canvas.notAllow.accesskey"),
       callback(state) {
-        setCanvasPermission(uri, Ci.nsIPermissionManager.DENY_ACTION,
+        setCanvasPermission(Ci.nsIPermissionManager.DENY_ACTION,
                             state && state.checkboxChecked);
       },
     }];
 
     let checkbox = {
       // In PB mode, we don't want the "always remember" checkbox
       show: !PrivateBrowsingUtils.isWindowPrivate(window),
     };
     if (checkbox.show) {
       checkbox.checked = true;
       checkbox.label = gBrowserBundle.GetStringFromName("canvas.remember");
     }
 
     let options = {
       checkbox,
-      name: uri.asciiHost,
+      name: principal.URI.host,
       learnMoreURL: Services.urlFormatter.formatURLPref("app.support.baseURL") + "fingerprint-permission",
       dismissed: aTopic == this._permissionsPromptHideDoorHanger,
     };
     PopupNotifications.show(browser, this._permissionsPrompt, message,
                             this._notificationIcon, mainAction,
                             secondaryActions, options);
   },
 };
--- a/dom/canvas/CanvasUtils.cpp
+++ b/dom/canvas/CanvasUtils.cpp
@@ -119,18 +119,18 @@ bool IsImageExtractionAllowed(Document* 
   // Load Permission Manager service.
   nsCOMPtr<nsIPermissionManager> permissionManager =
       do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, false);
 
   // Check if the site has permission to extract canvas data.
   // Either permit or block extraction if a stored permission setting exists.
   uint32_t permission;
-  rv = permissionManager->TestPermission(
-      topLevelDocURI, PERMISSION_CANVAS_EXTRACT_DATA, &permission);
+  rv = permissionManager->TestPermissionFromPrincipal(
+      principal, PERMISSION_CANVAS_EXTRACT_DATA, &permission);
   NS_ENSURE_SUCCESS(rv, false);
   switch (permission) {
     case nsIPermissionManager::ALLOW_ACTION:
       return true;
     case nsIPermissionManager::DENY_ACTION:
       return false;
     default:
       break;
@@ -162,30 +162,34 @@ bool IsImageExtractionAllowed(Document* 
         docURISpec.get());
     nsContentUtils::ReportToConsoleNonLocalized(
         message, nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Security"),
         aDocument);
   }
 
   // Prompt the user (asynchronous).
   nsPIDOMWindowOuter* win = aDocument->GetWindow();
+  nsAutoCString origin;
+  rv = principal->GetOrigin(origin);
+  NS_ENSURE_SUCCESS(rv, false);
+
   if (XRE_IsContentProcess()) {
     BrowserChild* browserChild = BrowserChild::GetFrom(win);
     if (browserChild) {
-      browserChild->SendShowCanvasPermissionPrompt(topLevelDocURISpec,
+      browserChild->SendShowCanvasPermissionPrompt(origin,
                                                    isAutoBlockCanvas);
     }
   } else {
     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     if (obs) {
       obs->NotifyObservers(win,
                            isAutoBlockCanvas
                                ? TOPIC_CANVAS_PERMISSIONS_PROMPT_HIDE_DOORHANGER
                                : TOPIC_CANVAS_PERMISSIONS_PROMPT,
-                           NS_ConvertUTF8toUTF16(topLevelDocURISpec).get());
+                           NS_ConvertUTF8toUTF16(origin).get());
     }
   }
 
   // We don't extract the image for now -- user may override at prompt.
   return false;
 }
 
 bool GetCanvasContextType(const nsAString& str,
--- a/dom/ipc/BrowserParent.cpp
+++ b/dom/ipc/BrowserParent.cpp
@@ -3753,33 +3753,33 @@ mozilla::ipc::IPCResult BrowserParent::R
   }
 
   widget->LookUpDictionary(aText, aFontRangeArray, aIsVertical,
                            TransformChildToParent(aPoint));
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserParent::RecvShowCanvasPermissionPrompt(
-    const nsCString& aFirstPartyURI, const bool& aHideDoorHanger) {
+    const nsCString& aOrigin, const bool& aHideDoorHanger) {
   nsCOMPtr<nsIBrowser> browser =
       mFrameElement ? mFrameElement->AsBrowser() : nullptr;
   if (!browser) {
     // If the tab is being closed, the browser may not be available.
     // In this case we can ignore the request.
     return IPC_OK();
   }
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   if (!os) {
     return IPC_FAIL_NO_REASON(this);
   }
   nsresult rv = os->NotifyObservers(
       browser,
       aHideDoorHanger ? "canvas-permissions-prompt-hide-doorhanger"
                       : "canvas-permissions-prompt",
-      NS_ConvertUTF8toUTF16(aFirstPartyURI).get());
+      NS_ConvertUTF8toUTF16(aOrigin).get());
   if (NS_FAILED(rv)) {
     return IPC_FAIL_NO_REASON(this);
   }
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult BrowserParent::RecvVisitURI(
     const URIParams& aURI, const Maybe<URIParams>& aLastVisitedURI,
--- a/dom/ipc/BrowserParent.h
+++ b/dom/ipc/BrowserParent.h
@@ -703,17 +703,17 @@ class BrowserParent final : public PBrow
 
   mozilla::ipc::IPCResult RecvSetDimensions(const uint32_t& aFlags,
                                             const int32_t& aX,
                                             const int32_t& aY,
                                             const int32_t& aCx,
                                             const int32_t& aCy);
 
   mozilla::ipc::IPCResult RecvShowCanvasPermissionPrompt(
-      const nsCString& aFirstPartyURI, const bool& aHideDoorHanger);
+      const nsCString& aOrigin, const bool& aHideDoorHanger);
 
   mozilla::ipc::IPCResult RecvSetSystemFont(const nsCString& aFontName);
   mozilla::ipc::IPCResult RecvGetSystemFont(nsCString* aFontName);
 
   mozilla::ipc::IPCResult RecvVisitURI(const URIParams& aURI,
                                        const Maybe<URIParams>& aLastVisitedURI,
                                        const uint32_t& aFlags);
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -615,19 +615,19 @@ parent:
     // arrive before the BrowserChild attempts to use its cross-process compositor
     // bridge.
     sync EnsureLayersConnected() returns (CompositorOptions compositorOptions);
 
     /**
      * This function is used to notify the parent that it should display a
      * canvas permission prompt.
      *
-     * @param aFirstPartyURI first party of the tab that is requesting access.
+     * @param aOrigin origin string of the document that is requesting access.
      */
-    async ShowCanvasPermissionPrompt(nsCString aFirstPartyURI,
+    async ShowCanvasPermissionPrompt(nsCString aOrigin,
                                      bool aHideDoorHanger);
 
     sync SetSystemFont(nsCString aFontName);
     sync GetSystemFont() returns (nsCString retval);
 
     sync SetPrefersReducedMotionOverrideForTest(bool aValue);
     sync ResetPrefersReducedMotionOverrideForTest();