head.js (13272B)
1 function openIdentityPopup() { 2 gIdentityHandler._initializePopup(); 3 let mainView = document.getElementById("identity-popup-mainView"); 4 let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown"); 5 gIdentityHandler._identityIconBox.click(); 6 return viewShown; 7 } 8 9 function openPermissionPopup() { 10 gPermissionPanel._initializePopup(); 11 let mainView = document.getElementById("permission-popup-mainView"); 12 let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown"); 13 gPermissionPanel.openPopup(); 14 return viewShown; 15 } 16 17 function getIdentityMode(aWindow = window) { 18 return aWindow.document.getElementById("identity-box").className; 19 } 20 21 // Compares the security state of the page with what is expected 22 function isSecurityState(browser, expectedState) { 23 let ui = browser.securityUI; 24 if (!ui) { 25 ok(false, "No security UI to get the security state"); 26 return; 27 } 28 29 const wpl = Ci.nsIWebProgressListener; 30 31 // determine the security state 32 let isSecure = ui.state & wpl.STATE_IS_SECURE; 33 let isBroken = ui.state & wpl.STATE_IS_BROKEN; 34 let isInsecure = ui.state & wpl.STATE_IS_INSECURE; 35 36 let actualState; 37 if (isSecure && !(isBroken || isInsecure)) { 38 actualState = "secure"; 39 } else if (isBroken && !(isSecure || isInsecure)) { 40 actualState = "broken"; 41 } else if (isInsecure && !(isSecure || isBroken)) { 42 actualState = "insecure"; 43 } else { 44 actualState = "unknown"; 45 } 46 47 is( 48 expectedState, 49 actualState, 50 "Expected state " + 51 expectedState + 52 " and the actual state is " + 53 actualState + 54 "." 55 ); 56 } 57 58 /** 59 * Test the state of the identity box and control center to make 60 * sure they are correctly showing the expected mixed content states. 61 * 62 * Note: The checks are done synchronously, but new code should wait on the 63 * returned Promise object to ensure the identity panel has closed. 64 * Bug 1221114 is filed to fix the existing code. 65 * 66 * @param tabbrowser 67 * @param Object states 68 * MUST include the following properties: 69 * { 70 * activeLoaded: true|false, 71 * activeBlocked: true|false, 72 * passiveLoaded: true|false, 73 * } 74 * 75 * @returns {Promise<void>} 76 * Resolves when the operation has finished and the identity panel has closed. 77 */ 78 async function assertMixedContentBlockingState(tabbrowser, states = {}) { 79 if ( 80 !tabbrowser || 81 !("activeLoaded" in states) || 82 !("activeBlocked" in states) || 83 !("passiveLoaded" in states) 84 ) { 85 throw new Error( 86 "assertMixedContentBlockingState requires a browser and a states object" 87 ); 88 } 89 90 let { passiveLoaded, activeLoaded, activeBlocked } = states; 91 let { gIdentityHandler } = tabbrowser.ownerGlobal; 92 let doc = tabbrowser.ownerDocument; 93 let identityBox = gIdentityHandler._identityBox; 94 let classList = identityBox.classList; 95 let identityIcon = doc.getElementById("identity-icon"); 96 let identityIconImage = tabbrowser.ownerGlobal 97 .getComputedStyle(identityIcon) 98 .getPropertyValue("list-style-image"); 99 100 let stateSecure = 101 gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_SECURE; 102 let stateBroken = 103 gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_BROKEN; 104 let stateInsecure = 105 gIdentityHandler._state & Ci.nsIWebProgressListener.STATE_IS_INSECURE; 106 let stateActiveBlocked = 107 gIdentityHandler._state & 108 Ci.nsIWebProgressListener.STATE_BLOCKED_MIXED_ACTIVE_CONTENT; 109 let stateActiveLoaded = 110 gIdentityHandler._state & 111 Ci.nsIWebProgressListener.STATE_LOADED_MIXED_ACTIVE_CONTENT; 112 let statePassiveLoaded = 113 gIdentityHandler._state & 114 Ci.nsIWebProgressListener.STATE_LOADED_MIXED_DISPLAY_CONTENT; 115 116 is( 117 activeBlocked, 118 !!stateActiveBlocked, 119 "Expected state for activeBlocked matches UI state" 120 ); 121 is( 122 activeLoaded, 123 !!stateActiveLoaded, 124 "Expected state for activeLoaded matches UI state" 125 ); 126 is( 127 passiveLoaded, 128 !!statePassiveLoaded, 129 "Expected state for passiveLoaded matches UI state" 130 ); 131 132 if (stateInsecure) { 133 // HTTP request, there should be a broken padlock shown always. 134 ok(classList.contains("notSecure"), "notSecure on HTTP page"); 135 ok( 136 !BrowserTestUtils.isHidden(identityIcon), 137 "information icon should be visible" 138 ); 139 140 ok(!classList.contains("mixedActiveContent"), "No MCB icon on HTTP page"); 141 ok(!classList.contains("mixedActiveBlocked"), "No MCB icon on HTTP page"); 142 ok(!classList.contains("mixedDisplayContent"), "No MCB icon on HTTP page"); 143 ok( 144 !classList.contains("mixedDisplayContentLoadedActiveBlocked"), 145 "No MCB icon on HTTP page" 146 ); 147 } else { 148 // Make sure the identity box UI has the correct mixedcontent states and icons 149 is( 150 classList.contains("mixedActiveContent"), 151 activeLoaded, 152 "identityBox has expected class for activeLoaded" 153 ); 154 is( 155 classList.contains("mixedActiveBlocked"), 156 activeBlocked && !passiveLoaded, 157 "identityBox has expected class for activeBlocked && !passiveLoaded" 158 ); 159 is( 160 classList.contains("mixedDisplayContent"), 161 passiveLoaded && !(activeLoaded || activeBlocked), 162 "identityBox has expected class for passiveLoaded && !(activeLoaded || activeBlocked)" 163 ); 164 is( 165 classList.contains("mixedDisplayContentLoadedActiveBlocked"), 166 passiveLoaded && activeBlocked, 167 "identityBox has expected class for passiveLoaded && activeBlocked" 168 ); 169 170 ok( 171 !BrowserTestUtils.isHidden(identityIcon), 172 "information icon should be visible" 173 ); 174 if (activeLoaded) { 175 is( 176 identityIconImage, 177 'url("chrome://global/skin/icons/security-broken.svg")', 178 "Using active loaded icon" 179 ); 180 } 181 if (activeBlocked && !passiveLoaded) { 182 is( 183 identityIconImage, 184 'url("chrome://global/skin/icons/security.svg")', 185 "Using active blocked icon" 186 ); 187 } 188 if (passiveLoaded && !(activeLoaded || activeBlocked)) { 189 is( 190 identityIconImage, 191 'url("chrome://global/skin/icons/security-warning.svg")', 192 "Using passive loaded icon" 193 ); 194 } 195 if (passiveLoaded && activeBlocked) { 196 is( 197 identityIconImage, 198 'url("chrome://global/skin/icons/security-warning.svg")', 199 "Using active blocked and passive loaded icon" 200 ); 201 } 202 } 203 204 // Make sure the identity popup has the correct mixedcontent states 205 let promisePanelOpen = BrowserTestUtils.waitForEvent( 206 tabbrowser.ownerGlobal, 207 "popupshown", 208 true, 209 event => event.target == gIdentityHandler._identityPopup 210 ); 211 gIdentityHandler._identityIconBox.click(); 212 await promisePanelOpen; 213 let popupAttr = 214 doc.getElementById("identity-popup").getAttribute("mixedcontent") || ""; 215 let bodyAttr = 216 doc 217 .getElementById("identity-popup-securityView-extended-info") 218 .getAttribute("mixedcontent") || ""; 219 220 is( 221 popupAttr.includes("active-loaded"), 222 activeLoaded, 223 "identity-popup has expected attr for activeLoaded" 224 ); 225 is( 226 bodyAttr.includes("active-loaded"), 227 activeLoaded, 228 "securityView-body has expected attr for activeLoaded" 229 ); 230 231 is( 232 popupAttr.includes("active-blocked"), 233 activeBlocked, 234 "identity-popup has expected attr for activeBlocked" 235 ); 236 is( 237 bodyAttr.includes("active-blocked"), 238 activeBlocked, 239 "securityView-body has expected attr for activeBlocked" 240 ); 241 242 is( 243 popupAttr.includes("passive-loaded"), 244 passiveLoaded, 245 "identity-popup has expected attr for passiveLoaded" 246 ); 247 is( 248 bodyAttr.includes("passive-loaded"), 249 passiveLoaded, 250 "securityView-body has expected attr for passiveLoaded" 251 ); 252 253 // Make sure the correct icon is visible in the Control Center. 254 // This logic is controlled with CSS, so this helps prevent regressions there. 255 let securityViewBG = tabbrowser.ownerGlobal 256 .getComputedStyle( 257 document 258 .getElementById("identity-popup-securityView") 259 .getElementsByClassName("identity-popup-security-connection")[0] 260 ) 261 .getPropertyValue("list-style-image"); 262 let securityContentBG = tabbrowser.ownerGlobal 263 .getComputedStyle( 264 document 265 .getElementById("identity-popup-mainView") 266 .getElementsByClassName("identity-popup-security-connection")[0] 267 ) 268 .getPropertyValue("list-style-image"); 269 270 if (stateInsecure) { 271 is( 272 securityViewBG, 273 'url("chrome://global/skin/icons/security-broken.svg")', 274 "CC using 'not secure' icon" 275 ); 276 is( 277 securityContentBG, 278 'url("chrome://global/skin/icons/security-broken.svg")', 279 "CC using 'not secure' icon" 280 ); 281 } 282 283 if (stateSecure) { 284 is( 285 securityViewBG, 286 'url("chrome://global/skin/icons/security.svg")', 287 "CC using secure icon" 288 ); 289 is( 290 securityContentBG, 291 'url("chrome://global/skin/icons/security.svg")', 292 "CC using secure icon" 293 ); 294 } 295 296 if (stateBroken) { 297 if (activeLoaded) { 298 is( 299 securityViewBG, 300 'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")', 301 "CC using active loaded icon" 302 ); 303 is( 304 securityContentBG, 305 'url("chrome://browser/skin/controlcenter/mcb-disabled.svg")', 306 "CC using active loaded icon" 307 ); 308 } else if (activeBlocked || passiveLoaded) { 309 is( 310 securityViewBG, 311 'url("chrome://global/skin/icons/security-warning.svg")', 312 "CC using degraded icon" 313 ); 314 is( 315 securityContentBG, 316 'url("chrome://global/skin/icons/security-warning.svg")', 317 "CC using degraded icon" 318 ); 319 } else { 320 // There is a case here with weak ciphers, but no bc tests are handling this yet. 321 is( 322 securityViewBG, 323 'url("chrome://global/skin/icons/security.svg")', 324 "CC using degraded icon" 325 ); 326 is( 327 securityContentBG, 328 'url("chrome://global/skin/icons/security.svg")', 329 "CC using degraded icon" 330 ); 331 } 332 } 333 334 if (activeLoaded || activeBlocked || passiveLoaded) { 335 let promiseViewShown = BrowserTestUtils.waitForEvent( 336 gIdentityHandler._identityPopup, 337 "ViewShown" 338 ); 339 doc.getElementById("identity-popup-security-button").click(); 340 await promiseViewShown; 341 is( 342 Array.prototype.filter.call( 343 doc 344 .getElementById("identity-popup-securityView") 345 .querySelectorAll(".identity-popup-mcb-learn-more"), 346 element => !BrowserTestUtils.isHidden(element) 347 ).length, 348 1, 349 "The 'Learn more' link should be visible once." 350 ); 351 } 352 353 if (gIdentityHandler._identityPopup.state != "closed") { 354 let hideEvent = BrowserTestUtils.waitForEvent( 355 gIdentityHandler._identityPopup, 356 "popuphidden" 357 ); 358 info("Hiding identity popup"); 359 gIdentityHandler._identityPopup.hidePopup(); 360 await hideEvent; 361 } 362 } 363 364 async function loadBadCertPage(url, feltPrivacyV1) { 365 const loaded = BrowserTestUtils.waitForErrorPage(gBrowser.selectedBrowser); 366 const loadFlagsSkipCache = 367 Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY | 368 Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE; 369 BrowserTestUtils.startLoadingURIString( 370 gBrowser.selectedBrowser, 371 url, 372 loadFlagsSkipCache 373 ); 374 await loaded; 375 await SpecialPowers.spawn( 376 gBrowser.selectedBrowser, 377 [feltPrivacyV1], 378 async prefFeltPrivacyV1 => { 379 if (prefFeltPrivacyV1) { 380 const netErrorCard = 381 content.document.querySelector("net-error-card").wrappedJSObject; 382 await netErrorCard.getUpdateComplete(); 383 EventUtils.synthesizeMouseAtCenter( 384 netErrorCard.advancedButton, 385 {}, 386 content 387 ); 388 await ContentTaskUtils.waitForCondition(() => { 389 return ( 390 netErrorCard.exceptionButton && 391 !netErrorCard.exceptionButton.disabled 392 ); 393 }, "Waiting for exception button"); 394 netErrorCard.exceptionButton.scrollIntoView(true); 395 EventUtils.synthesizeMouseAtCenter( 396 netErrorCard.exceptionButton, 397 {}, 398 content 399 ); 400 } else { 401 const advancedButton = 402 content.document.getElementById("advancedButton"); 403 advancedButton.scrollIntoView(true); 404 EventUtils.synthesizeMouseAtCenter(advancedButton, {}, content); 405 const exceptionButton = content.document.getElementById( 406 "exceptionDialogButton" 407 ); 408 await ContentTaskUtils.waitForCondition(() => { 409 return exceptionButton && !exceptionButton.disabled; 410 }, "Waiting for exception button"); 411 exceptionButton.scrollIntoView(true); 412 EventUtils.synthesizeMouseAtCenter(exceptionButton, {}, content); 413 } 414 } 415 ); 416 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 417 } 418 419 // nsITLSServerSocket needs a certificate with a corresponding private key 420 // available. In mochitests, the certificate with the common name "Mochitest 421 // client" has such a key. 422 function getTestServerCertificate() { 423 const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService( 424 Ci.nsIX509CertDB 425 ); 426 for (const cert of certDB.getCerts()) { 427 if (cert.commonName == "Mochitest client") { 428 return cert; 429 } 430 } 431 return null; 432 }