Bug 1459613 - Show extension name in PermissionUI / webrtcUI doorhangers and menus items. r=johannh
authorLuca Greco <lgreco@mozilla.com>
Wed, 16 May 2018 19:32:42 +0200
changeset 423967 d37a23757d2750251dea1920c8e78c2df3e8e872
parent 423966 2cc73c7d2c75fa46261ab18d8992181eb60d8fa1
child 423968 6a6418171ceef49a79d6952c0d71d082054fc6eb
push id34197
push usercsabou@mozilla.com
push dateThu, 28 Jun 2018 09:44:02 +0000
treeherdermozilla-central@db455160668d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh
bugs1459613
milestone63.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 1459613 - Show extension name in PermissionUI / webrtcUI doorhangers and menus items. r=johannh MozReview-Commit-ID: 2NbbsWkxDHm
browser/base/content/test/popupNotifications/browser_displayURI.js
browser/modules/PermissionUI.jsm
browser/modules/webrtcUI.jsm
--- a/browser/base/content/test/popupNotifications/browser_displayURI.js
+++ b/browser/base/content/test/popupNotifications/browser_displayURI.js
@@ -1,13 +1,13 @@
 /*
  * Make sure that the correct origin is shown for permission prompts.
  */
 
-async function check(contentTask) {
+async function check(contentTask, options = {}) {
   await BrowserTestUtils.withNewTab("https://test1.example.com/", async function(browser) {
     let popupShownPromise = waitForNotificationPanel();
     await ContentTask.spawn(browser, null, contentTask);
     let panel = await popupShownPromise;
     let notification = panel.children[0];
     let body = document.getAnonymousElementByAttribute(notification,
                                                        "class",
                                                        "popup-notification-body");
@@ -15,30 +15,65 @@ async function check(contentTask) {
   });
 
   let channel = NetUtil.newChannel({
     uri: getRootDirectory(gTestPath),
     loadUsingSystemPrincipal: true,
   });
   channel = channel.QueryInterface(Ci.nsIFileChannel);
 
-  return BrowserTestUtils.withNewTab(channel.file.path, async function(browser) {
+  await BrowserTestUtils.withNewTab(channel.file.path, async function(browser) {
     let popupShownPromise = waitForNotificationPanel();
     await ContentTask.spawn(browser, null, contentTask);
     let panel = await popupShownPromise;
     let notification = panel.children[0];
     let body = document.getAnonymousElementByAttribute(notification,
                                                        "class",
                                                        "popup-notification-body");
     if (notification.id == "geolocation-notification") {
       ok(body.innerHTML.includes("local file"), `file:// URIs should be displayed as local file.`);
     } else {
       ok(body.innerHTML.includes("Unknown origin"), "file:// URIs should be displayed as unknown origin.");
     }
   });
+
+  if (!options.skipOnExtension) {
+    // Test the scenario also on the extension page if not explicitly unsupported
+    // (e.g. an extension page can't be navigated on a blob URL).
+    let extension = ExtensionTestUtils.loadExtension({
+      manifest: {
+        name: "Test Extension Name",
+      },
+      background() {
+        let {browser} = this;
+        browser.test.sendMessage("extension-tab-url",
+                                 browser.extension.getURL("extension-tab-page.html"));
+      },
+      files: {
+        "extension-tab-page.html": `<!DOCTYPE html><html><body></body></html>`,
+      },
+    });
+
+    await extension.startup();
+    let extensionURI = await extension.awaitMessage("extension-tab-url");
+
+    await BrowserTestUtils.withNewTab(extensionURI, async function(browser) {
+      let popupShownPromise = waitForNotificationPanel();
+      await ContentTask.spawn(browser, null, contentTask);
+      let panel = await popupShownPromise;
+      let notification = panel.children[0];
+      let body = document.getAnonymousElementByAttribute(notification,
+                                                         "class",
+                                                         "popup-notification-body");
+      ok(body.innerHTML.includes("Test Extension Name"),
+         "Check the the extension name is present in the markup");
+    });
+
+    await extension.unload();
+  }
 }
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({set: [
     ["media.navigator.permission.fake", true],
     ["media.navigator.permission.force", true],
   ]});
 });
@@ -56,20 +91,20 @@ add_task(async function test_displayURI_
 });
 
 add_task(async function test_displayURI_geo_blob() {
   await check(async function() {
     let text = "<script>navigator.geolocation.getCurrentPosition(() => {})</script>";
     let blob = new Blob([text], {type: "text/html"});
     let url = content.URL.createObjectURL(blob);
     content.location.href = url;
-  });
+  }, {skipOnExtension: true});
 });
 
 add_task(async function test_displayURI_camera_blob() {
   await check(async function() {
     let text = "<script>navigator.mediaDevices.getUserMedia({video: true, fake: true})</script>";
     let blob = new Blob([text], {type: "text/html"});
     let url = content.URL.createObjectURL(blob);
     content.location.href = url;
-  });
+  }, {skipOnExtension: true});
 });
 
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -104,16 +104,30 @@ var PermissionPromptPrototype = {
    *
    * @return {nsIPrincipal}
    */
   get principal() {
     throw new Error("Not implemented.");
   },
 
   /**
+   * Provides the preferred name to use in the permission popups,
+   * based on the principal URI (the URI.hostPort for any URI scheme
+   * besides the moz-extension one which should default to the
+   * extension name).
+   */
+  get principalName() {
+    if (this.principal.addonPolicy) {
+      return this.principal.addonPolicy.name;
+    }
+
+    return this.principal.URI.hostPort;
+  },
+
+  /**
    * If the nsIPermissionManager is being queried and written
    * to for this permission request, set this to the key to be
    * used. If this is undefined, user permissions will not be
    * read from or written to.
    *
    * Note that if a permission is set, in any follow-up
    * prompting within the expiry window of that permission,
    * the prompt will be skipped and the allow or deny choice
@@ -422,17 +436,17 @@ GeolocationPermissionPrompt.prototype = 
     return "geo";
   },
 
   get popupOptions() {
     let pref = "browser.geolocation.warning.infoURL";
     let options = {
       learnMoreURL: Services.urlFormatter.formatURLPref(pref),
       displayURI: false,
-      name: this.principal.URI.hostPort,
+      name: this.principalName,
     };
 
     if (this.principal.URI.schemeIs("file")) {
       options.checkbox = { show: false };
     } else {
       // Don't offer "always remember" action in PB mode
       options.checkbox = {
         show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
@@ -455,17 +469,17 @@ GeolocationPermissionPrompt.prototype = 
   },
 
   get message() {
     if (this.principal.URI.schemeIs("file")) {
       return gBrowserBundle.GetStringFromName("geolocation.shareWithFile3");
     }
 
     return gBrowserBundle.formatStringFromName("geolocation.shareWithSite3",
-                                                  ["<>"], 1);
+                                               ["<>"], 1);
   },
 
   get promptActions() {
     // We collect Telemetry data on Geolocation prompts and how users
     // respond to them. The probe keys are a bit verbose, so let's alias them.
     const SHARE_LOCATION =
       Ci.nsISecurityUITelemetry.WARNING_GEOLOCATION_REQUEST_SHARE_LOCATION;
     const ALWAYS_SHARE =
@@ -530,17 +544,17 @@ DesktopNotificationPermissionPrompt.prot
 
   get popupOptions() {
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "push";
 
     return {
       learnMoreURL,
       displayURI: false,
-      name: this.principal.URI.hostPort,
+      name: this.principalName,
     };
   },
 
   get notificationID() {
     return "web-notifications";
   },
 
   get anchorID() {
@@ -612,17 +626,17 @@ PersistentStoragePermissionPrompt.protot
       checkbox.label = gBrowserBundle.GetStringFromName("persistentStorage.remember");
     }
     let learnMoreURL =
       Services.urlFormatter.formatURLPref("app.support.baseURL") + "storage-permissions";
     return {
       checkbox,
       learnMoreURL,
       displayURI: false,
-      name: this.principal.URI.hostPort,
+      name: this.principalName,
     };
   },
 
   get notificationID() {
     return "persistent-storage";
   },
 
   get anchorID() {
@@ -679,17 +693,17 @@ MIDIPermissionPrompt.prototype = {
   get permissionKey() {
     return this.permName;
   },
 
   get popupOptions() {
     // TODO (bug 1433235) We need a security/permissions explanation URL for this
     let options = {
       displayURI: false,
-      name: this.principal.URI.hostPort,
+      name: this.principalName,
     };
 
     if (this.principal.URI.schemeIs("file")) {
       options.checkbox = { show: false };
     } else {
       // Don't offer "always remember" action in PB mode
       options.checkbox = {
         show: !PrivateBrowsingUtils.isWindowPrivate(this.browser.ownerGlobal)
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -295,24 +295,27 @@ var webrtcUI = {
 };
 
 function denyRequest(aBrowser, aRequest) {
   aBrowser.messageManager.sendAsyncMessage("webrtc:Deny",
                                            {callID: aRequest.callID,
                                             windowID: aRequest.windowID});
 }
 
-function getHost(uri, href) {
+function getHostOrExtensionName(uri, href) {
   let host;
   try {
     if (!uri) {
       uri = Services.io.newURI(href);
     }
-    host = uri.host;
+
+    let addonPolicy = WebExtensionPolicy.getByURI(uri);
+    host = addonPolicy ? addonPolicy.name : uri.host;
   } catch (ex) {}
+
   if (!host) {
     if (uri && uri.scheme.toLowerCase() == "about") {
       // For about URIs, just use the full spec, without any #hash parts.
       host = uri.specIgnoringRef;
     } else {
       // This is unfortunate, but we should display *something*...
       const kBundleURI = "chrome://browser/locale/browser.properties";
       let bundle = Services.strings.createBundle(kBundleURI);
@@ -414,17 +417,17 @@ function prompt(aBrowser, aRequest) {
                               SitePermissions.BLOCK, scope, notification.browser);
       }
     }
   ];
 
   let productName = gBrandBundle.GetStringFromName("brandShortName");
 
   let options = {
-    name: getHost(uri),
+    name: getHostOrExtensionName(uri),
     persistent: true,
     hideClose: !Services.prefs.getBoolPref("privacy.permissionPrompts.showCloseButton"),
     eventCallback(aTopic, aNewBrowser) {
       if (aTopic == "swapping")
         return true;
 
       let doc = this.browser.ownerDocument;
 
@@ -1002,17 +1005,17 @@ function onTabSharingMenuPopupShowing(e)
     if (types.microphone)
       stringName += "Microphone";
     if (types.screen)
       stringName += types.screen;
 
     let doc = e.target.ownerDocument;
     let bundle = doc.defaultView.gNavigatorBundle;
 
-    let origin = getHost(null, streamInfo.uri);
+    let origin = getHostOrExtensionName(null, streamInfo.uri);
     let menuitem = doc.createElement("menuitem");
     menuitem.setAttribute("label", bundle.getFormattedString(stringName, [origin]));
     menuitem.stream = streamInfo;
     menuitem.addEventListener("command", onTabSharingMenuPopupCommand);
     e.target.appendChild(menuitem);
   }
 }