browser_aboutNetError.js (10398B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const SSL3_PAGE = "https://ssl3.example.com/"; 7 const TLS10_PAGE = "https://tls1.example.com/"; 8 const TLS12_PAGE = "https://tls12.example.com/"; 9 const TRIPLEDES_PAGE = "https://3des.example.com/"; 10 11 const lazy = {}; 12 13 XPCOMUtils.defineLazyServiceGetter( 14 lazy, 15 "gDNSOverride", 16 "@mozilla.org/network/native-dns-override;1", 17 Ci.nsINativeDNSResolverOverride 18 ); 19 20 // This includes all the cipher suite prefs we have. 21 function resetPrefs() { 22 Services.prefs.clearUserPref("security.tls.version.min"); 23 Services.prefs.clearUserPref("security.tls.version.max"); 24 Services.prefs.clearUserPref("security.tls.version.enable-deprecated"); 25 Services.prefs.clearUserPref("browser.fixup.alternate.enabled"); 26 } 27 28 const SSL_ERROR_BASE = -0x3000; 29 const SSL_ERROR_NO_CYPHER_OVERLAP = SSL_ERROR_BASE + 2; 30 const SSL_ERROR_PROTOCOL_VERSION_ALERT = SSL_ERROR_BASE + 98; 31 32 function nssErrorToNSErrorAsString(nssError) { 33 let nssErrorsService = Cc["@mozilla.org/nss_errors_service;1"].getService( 34 Ci.nsINSSErrorsService 35 ); 36 return nssErrorsService.getXPCOMFromNSSError(nssError).toString(); 37 } 38 39 async function resetTelemetry() { 40 Services.telemetry.clearEvents(); 41 await TestUtils.waitForCondition(() => { 42 let events = Services.telemetry.snapshotEvents( 43 Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, 44 true 45 ).content; 46 return !events || !events.length; 47 }); 48 } 49 50 async function checkTelemetry(errorString, nssError) { 51 let loadEvent = await TestUtils.waitForCondition(() => { 52 let events = Services.telemetry.snapshotEvents( 53 Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS, 54 true 55 ).content; 56 return events?.find(e => e[1] == "security.ui.tlserror" && e[2] == "load"); 57 }, "recorded telemetry for the load"); 58 loadEvent.shift(); 59 Assert.deepEqual(loadEvent, [ 60 "security.ui.tlserror", 61 "load", 62 "abouttlserror", 63 errorString, 64 { 65 is_frame: "false", 66 channel_status: nssErrorToNSErrorAsString(nssError), 67 }, 68 ]); 69 } 70 71 add_task(async function resetToDefaultConfig() { 72 info( 73 "Change TLS config to cause page load to fail, check that reset button is shown and that it works" 74 ); 75 76 // Set ourselves up for a TLS error. 77 Services.prefs.setIntPref("security.tls.version.min", 1); // TLS 1.0 78 Services.prefs.setIntPref("security.tls.version.max", 1); 79 80 await resetTelemetry(); 81 82 let browser; 83 let pageLoaded; 84 await BrowserTestUtils.openNewForegroundTab( 85 gBrowser, 86 () => { 87 gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TLS12_PAGE); 88 browser = gBrowser.selectedBrowser; 89 pageLoaded = BrowserTestUtils.waitForErrorPage(browser); 90 }, 91 false 92 ); 93 94 info("Loading and waiting for the net error"); 95 await pageLoaded; 96 97 await checkTelemetry( 98 "SSL_ERROR_PROTOCOL_VERSION_ALERT", 99 SSL_ERROR_PROTOCOL_VERSION_ALERT 100 ); 101 102 // Setup an observer for the target page. 103 const finalLoadComplete = BrowserTestUtils.browserLoaded( 104 browser, 105 false, 106 TLS12_PAGE 107 ); 108 109 await SpecialPowers.spawn(browser, [], async function () { 110 const doc = content.document; 111 ok( 112 doc.documentURI.startsWith("about:neterror"), 113 "Should be showing error page" 114 ); 115 116 const prefResetButton = doc.getElementById("prefResetButton"); 117 await ContentTaskUtils.waitForCondition( 118 () => ContentTaskUtils.isVisible(prefResetButton), 119 "prefResetButton is visible" 120 ); 121 122 if (!Services.focus.focusedElement == prefResetButton) { 123 await ContentTaskUtils.waitForEvent(prefResetButton, "focus"); 124 } 125 126 Assert.ok(true, "prefResetButton has focus"); 127 128 prefResetButton.click(); 129 }); 130 131 info("Waiting for the page to load after the click"); 132 await finalLoadComplete; 133 134 resetPrefs(); 135 BrowserTestUtils.removeTab(gBrowser.selectedTab); 136 }); 137 138 add_task(async function checkLearnMoreLink() { 139 info("Load an unsupported TLS page and check for a learn more link"); 140 141 // Set ourselves up for TLS error 142 Services.prefs.setIntPref("security.tls.version.min", 3); 143 Services.prefs.setIntPref("security.tls.version.max", 4); 144 145 await resetTelemetry(); 146 147 let browser; 148 let pageLoaded; 149 await BrowserTestUtils.openNewForegroundTab( 150 gBrowser, 151 () => { 152 gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TLS10_PAGE); 153 browser = gBrowser.selectedBrowser; 154 pageLoaded = BrowserTestUtils.waitForErrorPage(browser); 155 }, 156 false 157 ); 158 159 info("Loading and waiting for the net error"); 160 await pageLoaded; 161 162 await checkTelemetry( 163 "SSL_ERROR_PROTOCOL_VERSION_ALERT", 164 SSL_ERROR_PROTOCOL_VERSION_ALERT 165 ); 166 167 const baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); 168 169 await SpecialPowers.spawn(browser, [baseURL], function (_baseURL) { 170 const doc = content.document; 171 ok( 172 doc.documentURI.startsWith("about:neterror"), 173 "Should be showing error page" 174 ); 175 176 const tlsVersionNotice = doc.getElementById("tlsVersionNotice"); 177 ok( 178 ContentTaskUtils.isVisible(tlsVersionNotice), 179 "TLS version notice is visible" 180 ); 181 182 const learnMoreLink = doc.getElementById("learnMoreLink"); 183 ok(ContentTaskUtils.isVisible(learnMoreLink), "Learn More link is visible"); 184 is(learnMoreLink.getAttribute("href"), _baseURL + "connection-not-secure"); 185 186 const titleEl = doc.querySelector(".title-text"); 187 const actualDataL10nID = titleEl.getAttribute("data-l10n-id"); 188 is( 189 actualDataL10nID, 190 "nssFailure2-title", 191 "Correct error page title is set" 192 ); 193 194 const errorCodeEl = doc.querySelector("#errorShortDesc2"); 195 const actualDataL10Args = errorCodeEl.getAttribute("data-l10n-args"); 196 ok( 197 actualDataL10Args.includes("SSL_ERROR_PROTOCOL_VERSION_ALERT"), 198 "Correct error code is set" 199 ); 200 }); 201 202 resetPrefs(); 203 BrowserTestUtils.removeTab(gBrowser.selectedTab); 204 }); 205 206 // When a user tries going to a host without a suffix 207 // and the term doesn't match a host and we are able to suggest a 208 // valid correction, the page should show the correction. 209 // e.g. http://example/example2 -> https://www.example.com/example2 210 add_task(async function checkDomainCorrection() { 211 await SpecialPowers.pushPrefEnv({ 212 set: [["browser.fixup.alternate.enabled", false]], 213 }); 214 lazy.gDNSOverride.addIPOverride("www.example.com", "::1"); 215 216 info("Try loading a URI that should result in an error page"); 217 BrowserTestUtils.openNewForegroundTab( 218 gBrowser, 219 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 220 "http://example/example2/", 221 false 222 ); 223 224 info("Loading and waiting for the net error"); 225 let browser = gBrowser.selectedBrowser; 226 let pageLoaded = BrowserTestUtils.waitForErrorPage(browser); 227 await pageLoaded; 228 229 const baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); 230 231 await SpecialPowers.spawn(browser, [baseURL], async function (_baseURL) { 232 const doc = content.document; 233 ok( 234 doc.documentURI.startsWith("about:neterror"), 235 "Should be showing error page" 236 ); 237 238 const errorNotice = doc.getElementById("errorShortDesc"); 239 ok(ContentTaskUtils.isVisible(errorNotice), "Error text is visible"); 240 241 // Wait for the domain suggestion to be resolved and for the text to update 242 let link; 243 await ContentTaskUtils.waitForCondition(() => { 244 link = errorNotice.querySelector("a"); 245 return link && link.textContent != ""; 246 }, "Helper link has been set"); 247 248 is( 249 link.getAttribute("href"), 250 "https://www.example.com/example2/", 251 "Link was corrected" 252 ); 253 254 const actualDataL10nID = link.getAttribute("data-l10n-name"); 255 is(actualDataL10nID, "website", "Correct name is set"); 256 }); 257 258 lazy.gDNSOverride.clearHostOverride("www.example.com"); 259 resetPrefs(); 260 BrowserTestUtils.removeTab(gBrowser.selectedTab); 261 }); 262 263 // Test that ciphersuites that use 3DES (namely, TLS_RSA_WITH_3DES_EDE_CBC_SHA) 264 // can only be enabled when deprecated TLS is enabled. 265 add_task(async function onlyAllow3DESWithDeprecatedTLS() { 266 await resetTelemetry(); 267 268 // By default, connecting to a server that only uses 3DES should fail. 269 await BrowserTestUtils.withNewTab( 270 { gBrowser, url: "about:blank" }, 271 async browser => { 272 BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE); 273 await BrowserTestUtils.waitForErrorPage(browser); 274 } 275 ); 276 277 await checkTelemetry( 278 "SSL_ERROR_NO_CYPHER_OVERLAP", 279 SSL_ERROR_NO_CYPHER_OVERLAP 280 ); 281 282 // Enabling deprecated TLS should also enable 3DES. 283 Services.prefs.setBoolPref("security.tls.version.enable-deprecated", true); 284 await BrowserTestUtils.withNewTab( 285 { gBrowser, url: "about:blank" }, 286 async browser => { 287 BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE); 288 await BrowserTestUtils.browserLoaded(browser, false, TRIPLEDES_PAGE); 289 } 290 ); 291 292 // 3DES can be disabled separately. 293 Services.prefs.setBoolPref( 294 "security.ssl3.deprecated.rsa_des_ede3_sha", 295 false 296 ); 297 await BrowserTestUtils.withNewTab( 298 { gBrowser, url: "about:blank" }, 299 async browser => { 300 BrowserTestUtils.startLoadingURIString(browser, TRIPLEDES_PAGE); 301 await BrowserTestUtils.waitForErrorPage(browser); 302 await SpecialPowers.spawn(browser, [], async function () { 303 const doc = content.document; 304 const netErrorCard = 305 doc.querySelector("net-error-card")?.wrappedJSObject; 306 Assert.ok(netErrorCard, "netErrorCard is rendered."); 307 308 netErrorCard.advancedButton.scrollIntoView(); 309 EventUtils.synthesizeMouseAtCenter( 310 netErrorCard.advancedButton, 311 {}, 312 content 313 ); 314 await ContentTaskUtils.waitForCondition( 315 () => ContentTaskUtils.isVisible(netErrorCard.advancedContainer), 316 "Advanced container is visible" 317 ); 318 319 const prefResetButton = netErrorCard.prefResetButton; 320 Assert.ok(prefResetButton, "prefResetButton exists in the DOM."); 321 netErrorCard.prefResetButton.scrollIntoView(); 322 await ContentTaskUtils.waitForCondition( 323 () => ContentTaskUtils.isVisible(netErrorCard.prefResetButton), 324 "Pref reset button is visible" 325 ); 326 ok( 327 ContentTaskUtils.isVisible(prefResetButton), 328 "prefResetButton is visible" 329 ); 330 }); 331 } 332 ); 333 334 resetPrefs(); 335 });