Bug 1284878 - display a scary warning when the user is about to share Firefox or the whole screen, r=Gijs.
authorFlorian Quèze <florian@queze.net>
Mon, 07 Nov 2016 12:15:37 +0100
changeset 366493 e8669d6d4b436de48a73bb913ce0d9e23e33b92d
parent 366492 f5c8208b0139c97d9470ea64251884acfcc6ac82
child 366494 dbc272fdb23832d038eed46de9227c6e192a07a5
push id1369
push userjlorenzo@mozilla.com
push dateMon, 27 Feb 2017 14:59:41 +0000
treeherdermozilla-release@d75a1dba431f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1284878
milestone52.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 1284878 - display a scary warning when the user is about to share Firefox or the whole screen, r=Gijs.
browser/base/content/popup-notifications.inc
browser/locales/en-US/chrome/browser/browser.properties
browser/modules/ContentWebRTC.jsm
browser/modules/webrtcUI.jsm
browser/themes/shared/jar.inc.mn
browser/themes/shared/notification-icons.inc.css
browser/themes/shared/warning-white.svg
--- a/browser/base/content/popup-notifications.inc
+++ b/browser/base/content/popup-notifications.inc
@@ -25,16 +25,20 @@
                   oncommand="webrtcUI.updateMainActionLabel(this);">
           <menupopup id="webRTC-selectWindow-menupopup"/>
         </menulist>
         <description id="webRTC-all-windows-shared" hidden="true">&getUserMedia.allWindowsShared.message;</description>
       </popupnotificationcontent>
 
       <popupnotificationcontent id="webRTC-preview" hidden="true">
         <html:video id="webRTC-previewVideo"/>
+        <vbox id="webRTC-previewWarningBox">
+          <spacer flex="1"/>
+          <description id="webRTC-previewWarning"/>
+        </vbox>
       </popupnotificationcontent>
 
       <popupnotificationcontent id="webRTC-selectMicrophone" orient="vertical">
         <label value="&getUserMedia.selectMicrophone.label;"
                accesskey="&getUserMedia.selectMicrophone.accesskey;"
                control="webRTC-selectMicrophone-menulist"/>
         <menulist id="webRTC-selectMicrophone-menulist">
           <menupopup id="webRTC-selectMicrophone-menupopup"/>
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -481,16 +481,25 @@ social.aria.toolbarButtonBadgeText=%1$S 
 getUserMedia.shareCamera.message = Would you like to share your camera with %S?
 getUserMedia.shareMicrophone.message = Would you like to share your microphone with %S?
 getUserMedia.shareScreen.message = Would you like to share your screen with %S?
 getUserMedia.shareCameraAndMicrophone.message = Would you like to share your camera and microphone with %S?
 getUserMedia.shareCameraAndAudioCapture.message = Would you like to share your camera and this tab’s audio with %S?
 getUserMedia.shareScreenAndMicrophone.message = Would you like to share your microphone and screen with %S?
 getUserMedia.shareScreenAndAudioCapture.message = Would you like to share this tab’s audio and your screen with %S?
 getUserMedia.shareAudioCapture.message = Would you like to share this tab’s audio with %S?
+# LOCALIZATION NOTE (getUserMedia.shareScreenWarning.message): NB: inserted via innerHTML, so please don't use <, > or & in this string.
+# %S will be the 'learn more' link
+getUserMedia.shareScreenWarning.message = Only share screens with sites you trust. Sharing can allow deceptive sites to browse as you and steal your private data. %S
+# LOCALIZATION NOTE (getUserMedia.shareFirefoxWarning.message): NB: inserted via innerHTML, so please don't use <, > or & in this string.
+# %1$S is brandShortName (eg. Firefox)
+# %2$S will be the 'learn more' link
+getUserMedia.shareFirefoxWarning.message = Only share %1$S with sites you trust. Sharing can allow deceptive sites to browse as you and steal your private data. %2$S
+# LOCALIZATION NOTE(getUserMedia.shareScreen.learnMoreLabel): NB: inserted via innerHTML, so please don't use <, > or & in this string.
+getUserMedia.shareScreen.learnMoreLabel = Learn More
 getUserMedia.selectWindow.label=Window to share:
 getUserMedia.selectWindow.accesskey=W
 getUserMedia.selectScreen.label=Screen to share:
 getUserMedia.selectScreen.accesskey=S
 getUserMedia.selectApplication.label=Application to share:
 getUserMedia.selectApplication.accesskey=A
 getUserMedia.noApplication.label = No Application
 getUserMedia.noScreen.label = No Screen
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -173,18 +173,21 @@ function prompt(aContentWindow, aWindowI
                              id: device.rawId, mediaSource: device.mediaSource});
           devices.push(device);
         }
         break;
       case "video":
         // Verify that if we got a camera, we haven't requested a screen share,
         // or that if we requested a screen share we aren't getting a camera.
         if (video && (device.mediaSource == "camera") != sharingScreen) {
-          videoDevices.push({name: device.name, deviceIndex: devices.length,
-                             id: device.rawId, mediaSource: device.mediaSource});
+          let deviceObject = {name: device.name, deviceIndex: devices.length,
+                              id: device.rawId, mediaSource: device.mediaSource};
+          if (device.scary)
+            deviceObject.scary = true;
+          videoDevices.push(deviceObject);
           devices.push(device);
         }
         break;
     }
   }
 
   let requestTypes = [];
   if (videoDevices.length)
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -480,42 +480,46 @@ function prompt(aBrowser, aRequest) {
         addDeviceToList(menupopup,
                         stringBundle.getString("getUserMedia.no" + typeName + ".label"),
                         "-1");
         menupopup.appendChild(chromeDoc.createElement("menuseparator"));
 
         // Build the list of 'devices'.
         let monitorIndex = 1;
         for (let i = 0; i < devices.length; ++i) {
+          let device = devices[i];
+
           let name;
           // Building screen list from available screens.
           if (type == "screen") {
-            if (devices[i].name == "Primary Monitor") {
+            if (device.name == "Primary Monitor") {
               name = stringBundle.getString("getUserMedia.shareEntireScreen.label");
             } else {
               name = stringBundle.getFormattedString("getUserMedia.shareMonitor.label",
                                                      [monitorIndex]);
               ++monitorIndex;
             }
           }
           else {
-            name = devices[i].name;
+            name = device.name;
             if (type == "application") {
               // The application names returned by the platform are of the form:
               // <window count>\x1e<application name>
               let sepIndex = name.indexOf("\x1e");
               let count = name.slice(0, sepIndex);
               let stringId = "getUserMedia.shareApplicationWindowCount.label";
               name = PluralForm.get(parseInt(count), stringBundle.getString(stringId))
                                .replace("#1", name.slice(sepIndex + 1))
                                .replace("#2", count);
             }
           }
           let item = addDeviceToList(menupopup, name, i, typeName);
-          item.deviceId = devices[i].id;
+          item.deviceId = device.id;
+          if (device.scary)
+            item.scary = true;
         }
 
         // Always re-select the "No <type>" item.
         chromeDoc.getElementById("webRTC-selectWindow-menulist").removeAttribute("value");
         chromeDoc.getElementById("webRTC-all-windows-shared").hidden = true;
         menupopup._commandEventListener = event => {
           let video = chromeDoc.getElementById("webRTC-previewVideo");
           if (video.stream) {
@@ -525,24 +529,53 @@ function prompt(aBrowser, aRequest) {
 
           let deviceId = event.target.deviceId;
           if (deviceId == undefined) {
             chromeDoc.getElementById("webRTC-preview").hidden = true;
             video.src = null;
             return;
           }
 
+          let scary = event.target.scary;
+          let warning = chromeDoc.getElementById("webRTC-previewWarning");
+          warning.hidden = !scary;
+          let chromeWin = chromeDoc.defaultView;
+          if (scary) {
+            warning.hidden = false;
+            let string;
+            let bundle = chromeWin.gNavigatorBundle;
+
+            let learnMoreText =
+              bundle.getString("getUserMedia.shareScreen.learnMoreLabel");
+            let baseURL =
+              Services.urlFormatter.formatURLPref("app.support.baseURL");
+            let learnMore =
+              "<label class='text-link' href='" + baseURL + "screenshare-safety'>" +
+              learnMoreText + "</label>";
+
+            if (type == "screen") {
+              string = bundle.getFormattedString("getUserMedia.shareScreenWarning.message",
+                                                 [learnMore]);
+            }
+            else {
+              let brand =
+                chromeDoc.getElementById("bundle_brand").getString("brandShortName");
+              string = bundle.getFormattedString("getUserMedia.shareFirefoxWarning.message",
+                                                 [brand, learnMore]);
+            }
+            warning.innerHTML = string;
+          }
+
           let perms = Services.perms;
           let chromeUri = Services.io.newURI(chromeDoc.documentURI, null, null);
           perms.add(chromeUri, "MediaManagerVideo", perms.ALLOW_ACTION,
                     perms.EXPIRE_SESSION);
 
           video.deviceId = deviceId;
           let constraints = { video: { mediaSource: type, deviceId: {exact: deviceId } } };
-          let chromeWin = chromeDoc.defaultView;
           chromeWin.navigator.mediaDevices.getUserMedia(constraints).then(stream => {
             if (video.deviceId != deviceId) {
               // The user has selected a different device or closed the panel
               // before getUserMedia finished.
               stream.getTracks().forEach(t => t.stop());
               return;
             }
             video.src = chromeWin.URL.createObjectURL(stream);
--- a/browser/themes/shared/jar.inc.mn
+++ b/browser/themes/shared/jar.inc.mn
@@ -118,16 +118,17 @@
   skin/classic/browser/translating-16@2x.png                   (../shared/translation/translating-16@2x.png)
   skin/classic/browser/translation-16.png                      (../shared/translation/translation-16.png)
   skin/classic/browser/translation-16@2x.png                   (../shared/translation/translation-16@2x.png)
   skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
   skin/classic/browser/undoCloseTab@2x.png                     (../shared/undoCloseTab@2x.png)
   skin/classic/browser/update-badge.svg                        (../shared/update-badge.svg)
   skin/classic/browser/update-badge-failed.svg                 (../shared/update-badge-failed.svg)
   skin/classic/browser/warning.svg                             (../shared/warning.svg)
+  skin/classic/browser/warning-white.svg                       (../shared/warning-white.svg)
   skin/classic/browser/cert-error.svg                          (../shared/incontent-icons/cert-error.svg)
   skin/classic/browser/session-restore.svg                     (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                         (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/favicon-search-16.svg                   (../shared/favicon-search-16.svg)
   skin/classic/browser/icon-search-64.svg                      (../shared/incontent-icons/icon-search-64.svg)
   skin/classic/browser/welcome-back.svg                        (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-tour.png                         (../shared/reader/reader-tour.png)
   skin/classic/browser/reader-tour@2x.png                      (../shared/reader/reader-tour@2x.png)
--- a/browser/themes/shared/notification-icons.inc.css
+++ b/browser/themes/shared/notification-icons.inc.css
@@ -150,23 +150,44 @@
 .screen-icon.in-use {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-sharing);
 }
 
 .screen-icon.blocked-permission-icon {
   list-style-image: url(chrome://browser/skin/notification-icons.svg#screen-blocked);
 }
 
+#webRTC-preview:not([hidden]) {
+  display: -moz-stack;
+  border-radius: 4px;
+  border: 1px solid GrayText;
+  overflow: hidden;
+  min-width: 300px;
+  min-height: 10em;
+}
+
 html|*#webRTC-previewVideo {
   width: 300px;
   /* If we don't set the min-width, width is ignored. */
   min-width: 300px;
   max-height: 200px;
 }
 
+#webRTC-previewWarning {
+  background: rgba(255, 217, 99, .8) url("chrome://browser/skin/warning-white.svg") no-repeat .75em .75em;
+  margin: 0;
+  padding: .5em;
+  padding-inline-start: calc(1.5em + 16px);
+  border-top: 1px solid GrayText;
+}
+
+#webRTC-previewWarning > .text-link {
+  margin-inline-start: 0;
+}
+
 /* This icon has a block sign in it, so we don't need a blocked version. */
 .popup-icon {
   list-style-image: url("chrome://browser/skin/notification-icons.svg#popup");
 }
 
 /* EME */
 
 .popup-notification-icon[popupid="drmContentPlaying"],
new file mode 100644
--- /dev/null
+++ b/browser/themes/shared/warning-white.svg
@@ -0,0 +1,6 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+  <path fill="#fff" stroke="#000" stroke-opacity="0.3" d="M15.4,12.9 9.46,1.41 C9.12,0.756 8.59,0.381 8,0.381 7.41,0.381 6.88,0.756 6.54,1.41 L0.642,12.9 c-0.331,0.6 -0.348,1.3 -0.05,1.9 0.299,0.5 0.854,0.8 1.534,0.8 H13.9 c0.6,0 1.2,-0.3 1.5,-0.8 0.3,-0.6 0.3,-1.3 0,-1.9z M8.83,5.07 8.65,10.5 H7.34 L7.15,5.07 H8.83z M8,13.7 c-0.55,0 -0.99,-0.5 -0.99,-1 0,-0.6 0.44,-1 0.99,-1 0.56,0 0.99,0.4 0.99,1 0,0.5 -0.43,1 -0.99,1z"/>
+</svg>