mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-29 18:40:41 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1203058 - Set the paint sync id on the top-level window rather than the tab's window, because then it won't get lost during page unload. r=rbarker (977f8909e2)
- Bug 1199283 - nsContentUtils::sIsFrameTimingPrefEnabled should default to false. r=smaug (510c4c4ed1)
- Bug 1237714. Make nsContentUtils::IsCustomElementName faster in the common case of a non-custom-element name. r=smaug (397409f308)
- Bug 1237831 - Use a non-format argument in LogMessageToConsole. r=jst (cc9d2cd390)
- Bug 1208517 - Use the legacy opt-out in CanAccessNativeAnon for now to avoid crashes. r=me (79bd55b387)
- Bug 1230353: P1. Ensure type and subtype of MIME are lowercase. r=bz (09f9a067a6)
- Bug 1230353: P2. Update webref test expected results. r=karlt (4c10a9604c)
- Bug 1227906 - Use unicode flag in pattern attribute. r=jst (d5b4fbae46)
- Bug 1223041 - Emit console warning when document.execCommand('copy'/'cut') is triggered outside of a short-lived user-initiated event, r=bz (b590f3eb86)
- Bug 1235159 - Report pattern compliation failure to web console. r=jst,jorendorff (f4b1ddd863)
- Bug 1000004 - Part a: Remove the unused nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument*) function; r=jst (d873b1a93e)
- Bug 1000004 - Part b: Inline CheckForWindowedPlugins in its only caller; r=jst (f9a2e5cf64)
- Bug 583170 - Handling IPv6 literal address differently to other browsers r=bz (92abdd56ac)
- Bug 1225829 - Use a temporary string to avoid string type confusion via references. r=jimm (47ae4a8b37)
- Bug 1209841 - Support mouse long tap in SendMouseEvent(). r=smaug (23f308d336)
- Bug 1230563 - Part 1: Cookie permissions should override the CookiesL ifetimePolicy, r=ehsan (d7ecd5e7e0)
- Bug 1230563 - Part 2: Test for corrected cookie permission behavior, r=ehsan (f22ef46565)
- Bug 1241078 - Only treat items as backface hidden if they are 3D-transformed. r=tlee (c52f6804cc)
- Bug 1233098 - Refactor CSP upgrade insecure requests flag within loadInfo (r=sicking) (816d36e5d8)
- remove specific PM hack (a0ed71f7f4)
- Bug 1239397: Send Internal ContentPolicyType to CSP and MixedContent (r=sicking) (7c8da2f1df)
- Bug 1236258 part 1. Remove the unused nsDOMAttributeMap::RemoveAttribute. r=smaug (968d788197)
- Bug 1236258 part 3. Remove the unused aNsAware argument of nsDOMAttributeMap::GetAttribute. r=smaug (224d2e1e91)
- Bug 1236258 part 4. Change nsDOMAttributeMap::SetNamedItemNS to not remove the existing attribute when there is one. r=smaug (f1176918a6)
- Bug 1222079. Fix the behavior of Object.getOwnPropertyNames for nsDOMAttributeMap. r=bzbarsky (3b649bf948)
- Bug 1237580. NamedNodeMap should only claim to support a name if that name has no uppercase ASCII chars, for HTML elements in HTML documents. r=bkelly (216aa3ead6)
- just enable visibilityAPI (3df2d50b5d)
- bits of Bug 1153322 (85ba6268b4)
- Bug 1220160 - part 1: add chromeonly getter for documenturi that returns the original document when on an error page, r=bz (d0c256c29f)
- Bug 1212456 - Merge platform-specific aboutCertError.css files into asingle shared file;r=paolo (3289de4887)
- shuffle (185356c978)
- Mac v2 signing - Bug 1070863 - The preprocessed channel-prefs.js file needs to be the same for each build. r=ted (6991214cd4)
- Bug 1207107 - Design update for aboutCertError;r=dao (3d7f314060)
- Bug 1219861 - Remove not-allowed cursor on disabled buttons on in-content pages. r=dao (fa9b2ef2d0)
- Bug 1207146 - Add a link to expert technical information in the cert error page. r=Gijs,keeler (c3292b3fc7)
- Bug 1207130 - Add a checkbox for automatic error reporting to about:certerror r=Gijs,past (f8996f8f33)
- Bug 1241455 Send TLS Error Reports for subresources r=past, Gijs, mcmanus (de66157849)
- Bug 1241821 - Create a SecurityReporter component for TLS Error Reports r=mossop, keeler (50f196bbd2)
- Bug 1220160 - part 2: use mozDocumentURIIfNotForErrorPages for context menu's docLocation, r=MattN (834f200aa6)
- Bug 1220160 - part 3: use mozDocumentURIIfNotForErrorPages for ssl error reporting, r=past (3e32602dbc)
- Bug 1220160 - followup: fix oversight that docLocation should be a string, not a URI object, rs=bustage,me (8061326c97)
- Bug 1224433 - Part 3: Compute the invalidation area for preserve-3d layers by accumulating the leaves. r=roc (fffc5a7dfb)
- Bug 1245306: Devirtualize RefreshCompartmentPrincipal. r=smaug (4fa906b7fe)
- Bug 1205298 - Date.parse() should accept a wider range of potential formats; r=jandem (11a0377372)
- Bug 1247807 - Fix Mixed Content UI when using upgrade-insecure-requests (r=bz) (10a0aba8d4)
- Bug 1224694 - Unify and clean up initialization of CSP (r=sicking) (45b6f0a865)
- Bug 1190093 - Stop throttling frame requests for loading pages by checking Hidden(), not isShowing. r=tnikkel (343d2b39fd)
- Bug 1234554 - verify pointer validity and if valid dereference it otherwise use default value. r=jst (8c3265ef33)
- Bug 1240283 - Slim down JSDate instances by not caching cheaply-computed values. r=Waldo (0148f646a2)
- Bug 1217049 - Make Date.prototype.toString.call(<primitive value>) throw a TypeError. r=arai (e8ec69b296)
- Bug 1187233 part 1 - Date constructor should create a copy when called with a Date object. Original patch by Giovanni Sferro. r=jwalden (6a3125c081)
- Bug 1187233 part 2 - Fix test_networkstats_service_proxy.js to not rely on the old behavior. r=jwalden (86461c8aa0)
- Bug 1208023 - Avoid using a bad initial-scale when computing the CSS viewport. r=botond (42e370ce6a)
- make menu standard, fixes transparency on Mac (637bbe62b4)
- fix library toolbar icons on Mac (a393216a76)
- Bug 1234025 - Part 1: Move ObjectBox::isModuleBox definition to ParseNode.cpp. (ac4454c20a)
- Bug 1234025 - Part 2: Remove unused functions from ScriptedDirectProxyHandler.cpp. (0ea17c2395)
- Bug 1234025 - Part 3: Remove unused constant from Statistics.cpp (8986c23751)
This commit is contained in:
@@ -330,6 +330,7 @@
|
||||
@RESPATH@/components/toolkit_finalizationwitness.xpt
|
||||
@RESPATH@/components/toolkit_formautofill.xpt
|
||||
@RESPATH@/components/toolkit_osfile.xpt
|
||||
@RESPATH@/components/toolkit_securityreporter.xpt
|
||||
#ifdef NIGHTLY_BUILD
|
||||
@RESPATH@/components/toolkit_perfmonitoring.xpt
|
||||
#endif
|
||||
@@ -714,6 +715,10 @@
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
@RESPATH@/components/url-classifier.xpt
|
||||
|
||||
; Security Reports
|
||||
@RESPATH@/components/SecurityReporter.manifest
|
||||
@RESPATH@/components/SecurityReporter.js
|
||||
|
||||
; Signed Packaged Content
|
||||
@RESPATH@/components/InstallPackagedWebapp.manifest
|
||||
@RESPATH@/components/InstallPackagedWebapp.js
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#filter substitution
|
||||
/* 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/. */
|
||||
|
||||
@@ -671,17 +671,18 @@ pref("plugins.update.notifyUser", false);
|
||||
//Enable tri-state option (Always/Never/Ask)
|
||||
pref("plugins.click_to_play", true);
|
||||
|
||||
#ifdef XP_WIN
|
||||
pref("browser.preferences.instantApply", false);
|
||||
#else
|
||||
pref("browser.preferences.instantApply", true);
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
pref("browser.preferences.animateFadeIn", true);
|
||||
#else
|
||||
pref("browser.preferences.animateFadeIn", false);
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
pref("browser.preferences.instantApply", false);
|
||||
#else
|
||||
pref("browser.preferences.instantApply", true);
|
||||
#endif
|
||||
|
||||
pref("browser.download.show_plugins_in_list", true);
|
||||
pref("browser.download.hide_plugins_without_extensions", true);
|
||||
|
||||
|
||||
@@ -144,12 +144,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function sendErrorReport() {
|
||||
var event = new CustomEvent("AboutNetErrorSendReport", {bubbles:true});
|
||||
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function initPage()
|
||||
{
|
||||
var err = getErrorCode();
|
||||
@@ -260,16 +254,7 @@
|
||||
var event = new CustomEvent("AboutNetErrorSetAutomatic",
|
||||
{bubbles:true, detail:evt.target.checked});
|
||||
document.dispatchEvent(event);
|
||||
if (evt.target.checked && reportBtn.style.display != "none") {
|
||||
sendErrorReport();
|
||||
}
|
||||
}, false);
|
||||
|
||||
var reportBtn = document.getElementById('reportCertificateError');
|
||||
var retryBtn = document.getElementById('reportCertificateErrorRetry');
|
||||
|
||||
reportBtn.addEventListener('click', sendErrorReport, false);
|
||||
retryBtn.addEventListener('click', sendErrorReport, false);
|
||||
}
|
||||
}
|
||||
if (getErrorCode() == "weakCryptoUsed") {
|
||||
@@ -285,7 +270,6 @@
|
||||
// almost certainly useless.
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
document.getElementById("errorPageContainer").setAttribute("class", "certerror");
|
||||
addDomainErrorLink();
|
||||
}
|
||||
else {
|
||||
// Remove the override block for non-certificate errors. CSS-hiding
|
||||
@@ -293,6 +277,7 @@
|
||||
var secOverride = document.getElementById("securityOverrideDiv");
|
||||
secOverride.parentNode.removeChild(secOverride);
|
||||
}
|
||||
addDomainErrorLinks();
|
||||
}
|
||||
|
||||
function showSecuritySection() {
|
||||
@@ -301,13 +286,16 @@
|
||||
document.getElementById('securityOverrideLink').style.display = 'none';
|
||||
}
|
||||
|
||||
/* In the case of SSL error pages about domain mismatch, see if
|
||||
/* Try to preserve the links contained in the error description, like
|
||||
the error code.
|
||||
|
||||
Also, in the case of SSL error pages about domain mismatch, see if
|
||||
we can hyperlink the user to the correct site. We don't want
|
||||
to do this generically since it allows MitM attacks to redirect
|
||||
users to a site under attacker control, but in certain cases
|
||||
it is safe (and helpful!) to do so. Bug 402210
|
||||
*/
|
||||
function addDomainErrorLink() {
|
||||
function addDomainErrorLinks() {
|
||||
// Rather than textContent, we need to treat description as HTML
|
||||
var sd = document.getElementById("errorShortDescText");
|
||||
if (sd) {
|
||||
@@ -315,30 +303,39 @@
|
||||
|
||||
// sanitize description text - see bug 441169
|
||||
|
||||
// First, find the index of the <a> tag we care about, being careful not to
|
||||
// use an over-greedy regex
|
||||
var re = /<a id="cert_domain_link" title="([^"]+)">/;
|
||||
var result = re.exec(desc);
|
||||
if(!result)
|
||||
return;
|
||||
// First, find the index of the <a> tags we care about, being
|
||||
// careful not to use an over-greedy regex.
|
||||
var codeRe = /<a id="errorCode" title="([^"]+)">/;
|
||||
var codeResult = codeRe.exec(desc);
|
||||
var domainRe = /<a id="cert_domain_link" title="([^"]+)">/;
|
||||
var domainResult = domainRe.exec(desc);
|
||||
|
||||
// The order of these links in the description is fixed in
|
||||
// TransportSecurityInfo.cpp:formatOverridableCertErrorMessage.
|
||||
var firstResult = domainResult;
|
||||
if(!domainResult)
|
||||
firstResult = codeResult;
|
||||
if (!firstResult)
|
||||
return;
|
||||
// Remove sd's existing children
|
||||
sd.textContent = "";
|
||||
|
||||
// Everything up to the link should be text content
|
||||
sd.appendChild(document.createTextNode(desc.slice(0, result.index)));
|
||||
// Everything up to the first link should be text content.
|
||||
sd.appendChild(document.createTextNode(desc.slice(0, firstResult.index)));
|
||||
|
||||
// Now create the link itself
|
||||
var anchorEl = document.createElement("a");
|
||||
anchorEl.setAttribute("id", "cert_domain_link");
|
||||
anchorEl.setAttribute("title", result[1]);
|
||||
anchorEl.appendChild(document.createTextNode(result[1]));
|
||||
sd.appendChild(anchorEl);
|
||||
// Now create the actual links.
|
||||
if (domainResult) {
|
||||
createLink(sd, "cert_domain_link", domainResult[1])
|
||||
// Append text for anything between the two links.
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length, codeResult.index)));
|
||||
}
|
||||
createLink(sd, "errorCode", codeResult[1])
|
||||
|
||||
// Finally, append text for anything after the closing </a>
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length)));
|
||||
// Finally, append text for anything after the last closing </a>.
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.lastIndexOf("</a>") + "</a>".length)));
|
||||
}
|
||||
|
||||
// Initialize the cert domain link.
|
||||
var link = document.getElementById('cert_domain_link');
|
||||
if (!link)
|
||||
return;
|
||||
@@ -365,7 +362,7 @@
|
||||
* domain names are famous for having '.' characters in them,
|
||||
* which would allow spurious and possibly hostile matches.
|
||||
*/
|
||||
if (endsWith(okHost, "." + thisHost))
|
||||
if (okHost.endsWith("." + thisHost))
|
||||
link.href = proto + okHost;
|
||||
|
||||
/* case #2:
|
||||
@@ -373,12 +370,21 @@
|
||||
*
|
||||
* The certificate is only valid for garage.maemo.org
|
||||
*/
|
||||
if (endsWith(thisHost, "." + okHost))
|
||||
if (thisHost.endsWith("." + okHost))
|
||||
link.href = proto + okHost;
|
||||
|
||||
// If we set a link, meaning there's something helpful for
|
||||
// the user here, expand the section by default
|
||||
if (link.href && getCSSClass() != "expertBadCert")
|
||||
toggleVisibility("advancedPanel");
|
||||
}
|
||||
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) == needle;
|
||||
function createLink(el, id, text) {
|
||||
var anchorEl = document.createElement("a");
|
||||
anchorEl.setAttribute("id", id);
|
||||
anchorEl.setAttribute("title", text);
|
||||
anchorEl.appendChild(document.createTextNode(text));
|
||||
el.appendChild(anchorEl);
|
||||
}
|
||||
|
||||
]]></script>
|
||||
@@ -508,13 +514,6 @@
|
||||
<p>
|
||||
<input type="checkbox" id="automaticallyReportInFuture" />
|
||||
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
|
||||
|
||||
<span id="reportingState">
|
||||
<button id="reportCertificateError">&errorReporting.report;</button>
|
||||
<button id="reportCertificateErrorRetry">&errorReporting.tryAgain;</button>
|
||||
<span id="reportSendingMessage">&errorReporting.sending;</span>
|
||||
<span id="reportSentMessage">&errorReporting.sent;</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -55,6 +55,13 @@
|
||||
{
|
||||
var node = document.getElementById(id);
|
||||
node.style.visibility = node.style.visibility == "" ? "hidden" : "";
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
if (id == "advancedPanel") {
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function getDescription()
|
||||
@@ -81,6 +88,25 @@
|
||||
toggleVisibility('advancedPanel');
|
||||
}
|
||||
|
||||
var checkbox = document.getElementById("automaticallyReportInFuture");
|
||||
checkbox.addEventListener("change", function ({target: {checked}}) {
|
||||
document.dispatchEvent(new CustomEvent("AboutCertErrorSetAutomatic", {
|
||||
detail: checked,
|
||||
bubbles: true
|
||||
}));
|
||||
});
|
||||
|
||||
addEventListener("AboutCertErrorOptions", function (event) {
|
||||
var options = JSON.parse(event.detail);
|
||||
if (options && options.enabled) {
|
||||
// Display error reporting UI
|
||||
document.getElementById("certificateErrorReporting").style.display = "block";
|
||||
|
||||
// set the checkbox
|
||||
checkbox.checked = !!options.automatic;
|
||||
}
|
||||
}, true, true);
|
||||
|
||||
// Disallow overrides if this is a Strict-Transport-Security
|
||||
// host and the cert is bad (STS Spec section 7.3) or if the
|
||||
// certerror is in a frame (bug 633691).
|
||||
@@ -95,16 +121,22 @@
|
||||
if (tech)
|
||||
tech.textContent = getDescription();
|
||||
|
||||
addDomainErrorLink();
|
||||
var event = new CustomEvent("AboutCertErrorLoad", {bubbles:true});
|
||||
document.getElementById("advancedButton").dispatchEvent(event);
|
||||
|
||||
addDomainErrorLinks();
|
||||
}
|
||||
|
||||
/* In the case of SSL error pages about domain mismatch, see if
|
||||
/* Try to preserve the links contained in the error description, like
|
||||
the error code.
|
||||
|
||||
Also, in the case of SSL error pages about domain mismatch, see if
|
||||
we can hyperlink the user to the correct site. We don't want
|
||||
to do this generically since it allows MitM attacks to redirect
|
||||
users to a site under attacker control, but in certain cases
|
||||
it is safe (and helpful!) to do so. Bug 402210
|
||||
*/
|
||||
function addDomainErrorLink() {
|
||||
function addDomainErrorLinks() {
|
||||
// Rather than textContent, we need to treat description as HTML
|
||||
var sd = document.getElementById("technicalContentText");
|
||||
if (sd) {
|
||||
@@ -112,30 +144,56 @@
|
||||
|
||||
// sanitize description text - see bug 441169
|
||||
|
||||
// First, find the index of the <a> tag we care about, being careful not to
|
||||
// use an over-greedy regex
|
||||
var re = /<a id="cert_domain_link" title="([^"]+)">/;
|
||||
var result = re.exec(desc);
|
||||
if(!result)
|
||||
// First, find the index of the <a> tags we care about, being
|
||||
// careful not to use an over-greedy regex.
|
||||
var codeRe = /<a id="errorCode" title="([^"]+)">/;
|
||||
var codeResult = codeRe.exec(desc);
|
||||
var domainRe = /<a id="cert_domain_link" title="([^"]+)">/;
|
||||
var domainResult = domainRe.exec(desc);
|
||||
|
||||
// The order of these links in the description is fixed in
|
||||
// TransportSecurityInfo.cpp:formatOverridableCertErrorMessage.
|
||||
var firstResult = domainResult;
|
||||
if(!domainResult)
|
||||
firstResult = codeResult;
|
||||
if (!firstResult)
|
||||
return;
|
||||
|
||||
// Remove sd's existing children
|
||||
sd.textContent = "";
|
||||
|
||||
// Everything up to the link should be text content
|
||||
sd.appendChild(document.createTextNode(desc.slice(0, result.index)));
|
||||
// Everything up to the first link should be text content.
|
||||
sd.appendChild(document.createTextNode(desc.slice(0, firstResult.index)));
|
||||
|
||||
// Now create the link itself
|
||||
var anchorEl = document.createElement("a");
|
||||
anchorEl.setAttribute("id", "cert_domain_link");
|
||||
anchorEl.setAttribute("title", result[1]);
|
||||
anchorEl.appendChild(document.createTextNode(result[1]));
|
||||
sd.appendChild(anchorEl);
|
||||
// Now create the actual links.
|
||||
if (domainResult) {
|
||||
createLink(sd, "cert_domain_link", domainResult[1])
|
||||
// Append text for anything between the two links.
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length, codeResult.index)));
|
||||
}
|
||||
createLink(sd, "errorCode", codeResult[1])
|
||||
|
||||
// Finally, append text for anything after the closing </a>
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length)));
|
||||
// Finally, append text for anything after the last closing </a>.
|
||||
sd.appendChild(document.createTextNode(desc.slice(desc.lastIndexOf("</a>") + "</a>".length)));
|
||||
}
|
||||
|
||||
// Initialize the error code link embedded in the error message to
|
||||
// display debug information about the cert error.
|
||||
var errorCode = document.getElementById("errorCode");
|
||||
if (errorCode) {
|
||||
errorCode.href = "#technicalInformation";
|
||||
errorCode.addEventListener("click", () => {
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
if (div.style.display == "block") {
|
||||
div.style.display = "none";
|
||||
} else {
|
||||
div.style.display = "block";
|
||||
div.scrollIntoView(true);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
// Then initialize the cert domain link.
|
||||
var link = document.getElementById('cert_domain_link');
|
||||
if (!link)
|
||||
return;
|
||||
@@ -178,6 +236,14 @@
|
||||
if (link.href && getCSSClass() != "expertBadCert")
|
||||
toggleVisibility("advancedPanel");
|
||||
}
|
||||
|
||||
function createLink(el, id, text) {
|
||||
var anchorEl = document.createElement("a");
|
||||
anchorEl.setAttribute("id", id);
|
||||
anchorEl.setAttribute("title", text);
|
||||
anchorEl.appendChild(document.createTextNode(text));
|
||||
el.appendChild(anchorEl);
|
||||
}
|
||||
]]></script>
|
||||
</head>
|
||||
|
||||
@@ -207,12 +273,28 @@
|
||||
<div id="buttonSpacer"></div>
|
||||
<button id="advancedButton" autocomplete="off" onclick="toggleVisibility('advancedPanel');" autofocus="true">&certerror.advanced.label;</button>
|
||||
</div>
|
||||
<!-- Advanced panel, which is hidden by default -->
|
||||
<div id="advancedPanel" style="visibility: hidden;">
|
||||
<p id="technicalContentText"/>
|
||||
<button id='exceptionDialogButton'>&certerror.addException.label;</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- UI for option to report certificate errors to Mozilla. -->
|
||||
<div id="certificateErrorReporting">
|
||||
<p>
|
||||
<input type="checkbox" id="automaticallyReportInFuture" />
|
||||
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic;</label>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Advanced panel, which is hidden by default -->
|
||||
<div id="advancedPanel" style="visibility: hidden;">
|
||||
<p id="technicalContentText"/>
|
||||
<button id="exceptionDialogButton">&certerror.addException.label;</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="certificateErrorDebugInformation">
|
||||
<a name="technicalInformation"></a>
|
||||
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
|
||||
<div id="certificateErrorText"/>
|
||||
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
|
||||
@@ -774,12 +774,13 @@ toolbarbutton[pmkit-button="true"] > .toolbarbutton-badge-container > .toolbarbu
|
||||
}
|
||||
|
||||
/* Give this menupopup an arrow panel styling */
|
||||
/* disable because Mac has transparency issues otherwise
|
||||
menuitems are really transparent against white background.
|
||||
#BMB_bookmarksPopup {
|
||||
-moz-appearance: none;
|
||||
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-arrow");
|
||||
background: transparent;
|
||||
border: none;
|
||||
transition: opacity 300ms;
|
||||
/* The popup inherits -moz-image-region from the button, must reset it */
|
||||
-moz-image-region: auto;
|
||||
}
|
||||
} */
|
||||
|
||||
+96
-104
@@ -2702,7 +2702,7 @@ var BrowserOnClick = {
|
||||
case "Browser:CertExceptionError":
|
||||
this.onAboutCertError(msg.target, msg.data.elementId,
|
||||
msg.data.isTopFrame, msg.data.location,
|
||||
msg.data.sslStatusAsString);
|
||||
msg.data.securityInfoAsString);
|
||||
break;
|
||||
case "Browser:SiteBlockedError":
|
||||
this.onAboutBlocked(msg.data.elementId, msg.data.reason,
|
||||
@@ -2716,9 +2716,8 @@ var BrowserOnClick = {
|
||||
}
|
||||
break;
|
||||
case "Browser:SendSSLErrorReport":
|
||||
this.onSSLErrorReport(msg.target, msg.data.elementId,
|
||||
msg.data.documentURI,
|
||||
msg.data.location,
|
||||
this.onSSLErrorReport(msg.target,
|
||||
msg.data.uri,
|
||||
msg.data.securityInfo);
|
||||
break;
|
||||
case "Browser:SetSSLErrorReportAuto":
|
||||
@@ -2738,7 +2737,7 @@ var BrowserOnClick = {
|
||||
let weakCryptoOverride = Cc["@mozilla.org/security/weakcryptooverride;1"]
|
||||
.getService(Ci.nsIWeakCryptoOverride);
|
||||
weakCryptoOverride.addWeakCryptoOverride(
|
||||
msg.data.location.hostname,
|
||||
msg.data.uri.host,
|
||||
PrivateBrowsingUtils.isBrowserPrivate(gBrowser.selectedBrowser));
|
||||
break;
|
||||
case "Browser:SSLErrorGoBack":
|
||||
@@ -2747,29 +2746,12 @@ var BrowserOnClick = {
|
||||
}
|
||||
},
|
||||
|
||||
onSSLErrorReport: function(browser, elementId, documentURI, location, securityInfo) {
|
||||
function showReportStatus(reportStatus) {
|
||||
gBrowser.selectedBrowser
|
||||
.messageManager
|
||||
.sendAsyncMessage("Browser:SSLErrorReportStatus",
|
||||
{
|
||||
reportStatus: reportStatus,
|
||||
documentURI: documentURI
|
||||
});
|
||||
}
|
||||
|
||||
onSSLErrorReport: function(browser, uri, securityInfo) {
|
||||
if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
|
||||
showReportStatus("error");
|
||||
Cu.reportError("User requested certificate error report sending, but certificate error reporting is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
let bin = TLS_ERROR_REPORT_TELEMETRY_MANUAL_SEND;
|
||||
if (Services.prefs.getBoolPref("security.ssl.errorReporting.automatic")) {
|
||||
bin = TLS_ERROR_REPORT_TELEMETRY_AUTO_SEND;
|
||||
}
|
||||
Services.telemetry.getHistogramById("TLS_ERROR_REPORT_UI").add(bin);
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let transportSecurityInfo = serhelper.deserializeObject(securityInfo);
|
||||
@@ -2779,87 +2761,13 @@ var BrowserOnClick = {
|
||||
Cu.reportError("transportSecurityInfo didn't have a failedCertChain for a failedChannel");
|
||||
return;
|
||||
}
|
||||
|
||||
showReportStatus("activity");
|
||||
|
||||
/*
|
||||
* Requested info for the report:
|
||||
* - Domain of bad connection
|
||||
* - Error type (e.g. Pinning, domain mismatch, etc)
|
||||
* - Cert chain (at minimum, same data to distrust each cert in the
|
||||
* chain)
|
||||
* - Request data (e.g. User Agent, IP, Timestamp)
|
||||
*
|
||||
* The request data should be added to the report by the receiving server.
|
||||
*/
|
||||
|
||||
// TODO: can we pull this in from pippki.js isntead of duplicating it
|
||||
// here?
|
||||
function getDERString(cert)
|
||||
{
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = '';
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
// Convert the nsIX509CertList into a format that can be parsed into
|
||||
// JSON
|
||||
let asciiCertChain = [];
|
||||
let certs = transportSecurityInfo.failedCertChain.getEnumerator();
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
asciiCertChain.push(btoa(getDERString(cert)));
|
||||
}
|
||||
|
||||
let report = {
|
||||
hostname: location.hostname,
|
||||
port: location.port,
|
||||
timestamp: Math.round(Date.now() / 1000),
|
||||
errorCode: transportSecurityInfo.errorCode,
|
||||
failedCertChain: asciiCertChain,
|
||||
userAgent: window.navigator.userAgent,
|
||||
version: 1,
|
||||
build: gAppInfo.appBuildID,
|
||||
product: gAppInfo.name,
|
||||
channel: UpdateUtils.UpdateChannel
|
||||
}
|
||||
|
||||
let reportURL = Services.prefs.getCharPref("security.ssl.errorReporting.url");
|
||||
|
||||
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
|
||||
.createInstance(Ci.nsIXMLHttpRequest);
|
||||
try {
|
||||
xhr.open("POST", reportURL);
|
||||
} catch (e) {
|
||||
Cu.reportError("xhr.open exception", e);
|
||||
showReportStatus("error");
|
||||
}
|
||||
|
||||
xhr.onerror = function (e) {
|
||||
// error making request to reportURL
|
||||
Cu.reportError("xhr onerror", e);
|
||||
showReportStatus("error");
|
||||
};
|
||||
|
||||
xhr.onload = function (event) {
|
||||
if (xhr.status !== 201 && xhr.status !== 0) {
|
||||
// request returned non-success status
|
||||
Cu.reportError("xhr returned failure code", xhr.status);
|
||||
showReportStatus("error");
|
||||
} else {
|
||||
showReportStatus("complete");
|
||||
}
|
||||
};
|
||||
|
||||
xhr.send(JSON.stringify(report));
|
||||
let errorReporter = Cc["@mozilla.org/securityreporter;1"]
|
||||
.getService(Ci.nsISecurityReporter);
|
||||
errorReporter.reportTLSError(transportSecurityInfo,
|
||||
uri.host, uri.port);
|
||||
},
|
||||
|
||||
onAboutCertError: function (browser, elementId, isTopFrame, location, sslStatusAsString) {
|
||||
onAboutCertError: function (browser, elementId, isTopFrame, location, securityInfoAsString) {
|
||||
|
||||
switch (elementId) {
|
||||
case "exceptionDialogButton":
|
||||
@@ -2869,8 +2777,9 @@ var BrowserOnClick = {
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let sslStatus = serhelper.deserializeObject(sslStatusAsString);
|
||||
sslStatus.QueryInterface(Components.interfaces.nsISSLStatus);
|
||||
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
|
||||
let sslStatus = securityInfo.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus;
|
||||
let params = { exceptionAdded : false,
|
||||
sslStatus : sslStatus };
|
||||
|
||||
@@ -2892,6 +2801,19 @@ var BrowserOnClick = {
|
||||
if (params.exceptionAdded) {
|
||||
browser.reload();
|
||||
}
|
||||
|
||||
let errorInfo = getDetailedCertErrorInfo(location,
|
||||
securityInfoAsString);
|
||||
browser.messageManager.sendAsyncMessage("AboutCertErrorDetails",
|
||||
{ info: errorInfo });
|
||||
break;
|
||||
|
||||
case "copyToClipboard":
|
||||
const gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Ci.nsIClipboardHelper);
|
||||
let detailedInfo = getDetailedCertErrorInfo(location,
|
||||
securityInfoAsString);
|
||||
gClipboardHelper.copyString(detailedInfo);
|
||||
break;
|
||||
|
||||
case "getMeOutOfHereButton":
|
||||
@@ -3122,6 +3044,76 @@ function BrowserReloadWithFlags(reloadFlags) {
|
||||
handlingUserInput: windowUtils.isHandlingUserInput });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with detailed information about the certificate validation
|
||||
* failure from the specified URI that can be used to send a report.
|
||||
*/
|
||||
function getDetailedCertErrorInfo(location, securityInfoAsString) {
|
||||
if (!securityInfoAsString)
|
||||
return "";
|
||||
|
||||
let details = [];
|
||||
details.push(location);
|
||||
|
||||
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
|
||||
let errors = Cc["@mozilla.org/nss_errors_service;1"]
|
||||
.getService(Ci.nsINSSErrorsService);
|
||||
let code = securityInfo.errorCode;
|
||||
details.push(errors.getErrorMessage(errors.getXPCOMFromNSSError(code)));
|
||||
|
||||
const sss = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
// SiteSecurityService uses different storage if the channel is
|
||||
// private. Thus we must give isSecureHost correct flags or we
|
||||
// might get incorrect results.
|
||||
let flags = PrivateBrowsingUtils.isWindowPrivate(window) ?
|
||||
Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
|
||||
|
||||
let uri = Services.io.newURI(location, null, null);
|
||||
details.push(sss.isSecureHost(sss.HEADER_HSTS, uri.host, flags));
|
||||
details.push(sss.isSecureHost(sss.HEADER_HPKP, uri.host, flags));
|
||||
|
||||
let certChain = "";
|
||||
if (securityInfo.failedCertChain) {
|
||||
let certs = securityInfo.failedCertChain.getEnumerator();
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
certChain += getPEMString(cert);
|
||||
}
|
||||
}
|
||||
details.push(certChain);
|
||||
return gNavigatorBundle.getFormattedString("certErrorDetails.label", details, 5);
|
||||
}
|
||||
|
||||
// TODO: can we pull getDERString and getPEMString in from pippki.js instead of
|
||||
// duplicating them here?
|
||||
function getDERString(cert)
|
||||
{
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = '';
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
function getPEMString(cert)
|
||||
{
|
||||
var derb64 = btoa(getDERString(cert));
|
||||
// Wrap the Base64 string into lines of 64 characters,
|
||||
// with CRLF line breaks (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
return "-----BEGIN CERTIFICATE-----\r\n"
|
||||
+ wrapped
|
||||
+ "\r\n-----END CERTIFICATE-----\r\n";
|
||||
}
|
||||
|
||||
var PrintPreviewListener = {
|
||||
_printPreviewTab: null,
|
||||
_tabBeforePrintPreview: null,
|
||||
|
||||
+120
-91
@@ -129,7 +129,8 @@ var handleContentContextMenu = function (event) {
|
||||
Services.obs.notifyObservers(subject, "content-contextmenu", null);
|
||||
|
||||
let doc = event.target.ownerDocument;
|
||||
let docLocation = doc.location ? doc.location.href : undefined;
|
||||
let docLocation = doc.mozDocumentURIIfNotForErrorPages;
|
||||
docLocation = docLocation && docLocation.spec;
|
||||
let charSet = doc.characterSet;
|
||||
let baseURI = doc.baseURI;
|
||||
let referrer = doc.referrer;
|
||||
@@ -237,12 +238,100 @@ const TLS_ERROR_REPORT_TELEMETRY_EXPANDED = 1;
|
||||
const TLS_ERROR_REPORT_TELEMETRY_SUCCESS = 6;
|
||||
const TLS_ERROR_REPORT_TELEMETRY_FAILURE = 7;
|
||||
|
||||
var AboutCertErrorListener = {
|
||||
init(chromeGlobal) {
|
||||
addMessageListener("AboutCertErrorDetails", this);
|
||||
chromeGlobal.addEventListener("AboutCertErrorLoad", this, false, true);
|
||||
chromeGlobal.addEventListener("AboutCertErrorSetAutomatic", this, false, true);
|
||||
},
|
||||
|
||||
get isAboutCertError() {
|
||||
return content.document.documentURI.startsWith("about:certerror");
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
if (!this.isAboutCertError) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case "AboutCertErrorLoad":
|
||||
this.onLoad(event);
|
||||
break;
|
||||
case "AboutCertErrorSetAutomatic":
|
||||
this.onSetAutomatic(event);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage(msg) {
|
||||
if (!this.isAboutCertError) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (msg.name) {
|
||||
case "AboutCertErrorDetails":
|
||||
this.onDetails(msg);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(event) {
|
||||
let originalTarget = event.originalTarget;
|
||||
let ownerDoc = originalTarget.ownerDocument;
|
||||
ClickEventHandler.onAboutCertError(originalTarget, ownerDoc);
|
||||
|
||||
// Set up the TLS Error Reporting UI - reports are sent automatically
|
||||
// (from nsHttpChannel::OnStopRequest) if the user has previously enabled
|
||||
// automatic sending of reports. The UI ensures that a report is sent
|
||||
// for the certificate error currently displayed if the user enables it
|
||||
// here.
|
||||
let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
|
||||
content.dispatchEvent(new content.CustomEvent("AboutCertErrorOptions", {
|
||||
detail: JSON.stringify({
|
||||
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
|
||||
automatic,
|
||||
})
|
||||
}));
|
||||
},
|
||||
|
||||
onDetails(msg) {
|
||||
let div = content.document.getElementById("certificateErrorText");
|
||||
div.textContent = msg.data.info;
|
||||
},
|
||||
|
||||
onSetAutomatic(event) {
|
||||
sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
|
||||
automatic: event.detail
|
||||
});
|
||||
|
||||
// if we're enabling reports, send a report for this failure
|
||||
if (event.detail) {
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:SendSSLErrorReport", {
|
||||
uri: { host, port },
|
||||
securityInfo: serializedSecurityInfo
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
AboutCertErrorListener.init(this);
|
||||
|
||||
|
||||
var AboutNetErrorListener = {
|
||||
init: function(chromeGlobal) {
|
||||
chromeGlobal.addEventListener('AboutNetErrorLoad', this, false, true);
|
||||
chromeGlobal.addEventListener('AboutNetErrorSetAutomatic', this, false, true);
|
||||
chromeGlobal.addEventListener('AboutNetErrorSendReport', this, false, true);
|
||||
chromeGlobal.addEventListener('AboutNetErrorUIExpanded', this, false, true);
|
||||
chromeGlobal.addEventListener('AboutNetErrorOverride', this, false, true);
|
||||
},
|
||||
|
||||
@@ -262,13 +351,6 @@ var AboutNetErrorListener = {
|
||||
case "AboutNetErrorSetAutomatic":
|
||||
this.onSetAutomatic(aEvent);
|
||||
break;
|
||||
case "AboutNetErrorSendReport":
|
||||
this.onSendReport(aEvent);
|
||||
break;
|
||||
case "AboutNetErrorUIExpanded":
|
||||
sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_EXPANDED});
|
||||
break;
|
||||
case "AboutNetErrorOverride":
|
||||
this.onOverride(aEvent);
|
||||
break;
|
||||
@@ -278,97 +360,44 @@ var AboutNetErrorListener = {
|
||||
onPageLoad: function(evt) {
|
||||
let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
|
||||
content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
|
||||
detail: JSON.stringify({
|
||||
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
|
||||
automatic: automatic
|
||||
})
|
||||
}
|
||||
));
|
||||
if (automatic) {
|
||||
this.onSendReport(evt);
|
||||
}
|
||||
// hide parts of the UI we don't need yet
|
||||
let contentDoc = content.document;
|
||||
detail: JSON.stringify({
|
||||
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
|
||||
automatic: automatic
|
||||
})
|
||||
}));
|
||||
|
||||
let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
|
||||
let reportSentMsg = contentDoc.getElementById("reportSentMessage");
|
||||
let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
|
||||
reportSendingMsg.style.display = "none";
|
||||
reportSentMsg.style.display = "none";
|
||||
retryBtn.style.display = "none";
|
||||
sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN});
|
||||
},
|
||||
|
||||
onSetAutomatic: function(evt) {
|
||||
sendAsyncMessage("Browser:SetSSLErrorReportAuto", {
|
||||
automatic: evt.detail
|
||||
});
|
||||
},
|
||||
|
||||
onSendReport: function(evt) {
|
||||
let contentDoc = content.document;
|
||||
|
||||
let reportSendingMsg = contentDoc.getElementById("reportSendingMessage");
|
||||
let reportSentMsg = contentDoc.getElementById("reportSentMessage");
|
||||
let reportBtn = contentDoc.getElementById("reportCertificateError");
|
||||
let retryBtn = contentDoc.getElementById("reportCertificateErrorRetry");
|
||||
|
||||
addMessageListener("Browser:SSLErrorReportStatus", function(message) {
|
||||
// show and hide bits - but only if this is a message for the right
|
||||
// document - we'll compare on document URI
|
||||
if (contentDoc.documentURI === message.data.documentURI) {
|
||||
switch(message.data.reportStatus) {
|
||||
case "activity":
|
||||
// Hide the button that was just clicked
|
||||
reportBtn.style.display = "none";
|
||||
retryBtn.style.display = "none";
|
||||
reportSentMsg.style.display = "none";
|
||||
reportSendingMsg.style.removeProperty("display");
|
||||
break;
|
||||
case "error":
|
||||
// show the retry button
|
||||
retryBtn.style.removeProperty("display");
|
||||
reportSendingMsg.style.display = "none";
|
||||
sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_FAILURE});
|
||||
break;
|
||||
case "complete":
|
||||
// Show a success indicator
|
||||
reportSentMsg.style.removeProperty("display");
|
||||
reportSendingMsg.style.display = "none";
|
||||
sendAsyncMessage("Browser:SSLErrorReportTelemetry",
|
||||
{reportStatus: TLS_ERROR_REPORT_TELEMETRY_SUCCESS});
|
||||
break;
|
||||
}
|
||||
}
|
||||
automatic: evt.detail
|
||||
});
|
||||
|
||||
let location = contentDoc.location.href;
|
||||
// if we're enabling reports, send a report for this failure
|
||||
if (evt.detail) {
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
|
||||
sendAsyncMessage("Browser:SendSSLErrorReport", {
|
||||
elementId: evt.target.id,
|
||||
documentURI: contentDoc.documentURI,
|
||||
location: {hostname: contentDoc.location.hostname, port: contentDoc.location.port},
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:SendSSLErrorReport", {
|
||||
uri: { host, port },
|
||||
securityInfo: serializedSecurityInfo
|
||||
});
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
onOverride: function(evt) {
|
||||
let contentDoc = content.document;
|
||||
let location = contentDoc.location;
|
||||
|
||||
sendAsyncMessage("Browser:OverrideWeakCrypto", {
|
||||
documentURI: contentDoc.documentURI,
|
||||
location: {hostname: location.hostname, port: location.port}
|
||||
});
|
||||
let {host, port} = content.document.mozDocumentURIIfNotForErrorPages;
|
||||
sendAsyncMessage("Browser:OverrideWeakCrypto", { uri: {host, port} });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,21 +490,21 @@ var ClickEventHandler = {
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serializedSSLStatus = "";
|
||||
let serializedSecurityInfo = "";
|
||||
|
||||
try {
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsISSLStatusProvider)
|
||||
.SSLStatus
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
serializedSSLStatus = serhelper.serializeToString(serializable);
|
||||
|
||||
serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
} catch (e) { }
|
||||
|
||||
sendAsyncMessage("Browser:CertExceptionError", {
|
||||
location: ownerDoc.location.href,
|
||||
elementId: targetElement.getAttribute("id"),
|
||||
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
|
||||
sslStatusAsString: serializedSSLStatus
|
||||
securityInfoAsString: serializedSecurityInfo
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ support-files =
|
||||
offlineQuotaNotification.cacheManifest
|
||||
offlineQuotaNotification.html
|
||||
page_style_sample.html
|
||||
ssl_error_reports.sjs
|
||||
print_postdata.sjs
|
||||
redirect_bug623155.sjs
|
||||
searchSuggestionEngine.sjs
|
||||
@@ -112,6 +113,7 @@ support-files =
|
||||
readerModeArticle.html
|
||||
[browser_domFullscreen_fullscreenMode.js]
|
||||
tags = fullscreen
|
||||
[browser_aboutCertError.js]
|
||||
[browser_aboutSupport_newtab_security_state.js]
|
||||
[browser_aboutHealthReport.js]
|
||||
skip-if = os == "linux" # Bug 924307
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// This is testing the aboutCertError page (Bug 1207107).
|
||||
|
||||
const GOOD_PAGE = "https://example.com/";
|
||||
const BAD_CERT = "https://expired.example.com/";
|
||||
const BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443";
|
||||
const {TabStateFlusher} = Cu.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
|
||||
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
|
||||
|
||||
add_task(function* checkReturnToAboutHome() {
|
||||
info("Loading a bad cert page directly and making sure 'return to previous page' goes to about:home");
|
||||
let browser;
|
||||
let certErrorLoaded;
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
|
||||
browser = gBrowser.selectedBrowser;
|
||||
certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
}, false);
|
||||
|
||||
info("Loading and waiting for the cert error");
|
||||
yield certErrorLoaded;
|
||||
|
||||
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
|
||||
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
|
||||
|
||||
// Populate the shistory entries manually, since it happens asynchronously
|
||||
// and the following tests will be too soon otherwise.
|
||||
yield TabStateFlusher.flush(browser);
|
||||
let {entries} = JSON.parse(ss.getTabState(tab));
|
||||
is(entries.length, 1, "there is one shistory entry");
|
||||
|
||||
info("Clicking the go back button on about:certerror");
|
||||
let pageshowPromise = promiseWaitForEvent(browser, "pageshow");
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let returnButton = doc.getElementById("returnButton");
|
||||
returnButton.click();
|
||||
});
|
||||
yield pageshowPromise;
|
||||
|
||||
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
|
||||
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
|
||||
is(gBrowser.currentURI.spec, "about:home", "Went back");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* checkReturnToPreviousPage() {
|
||||
info("Loading a bad cert page and making sure 'return to previous page' goes back");
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
info("Loading and waiting for the cert error");
|
||||
let certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
BrowserTestUtils.loadURI(browser, BAD_CERT);
|
||||
yield certErrorLoaded;
|
||||
|
||||
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
|
||||
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
|
||||
|
||||
// Populate the shistory entries manually, since it happens asynchronously
|
||||
// and the following tests will be too soon otherwise.
|
||||
yield TabStateFlusher.flush(browser);
|
||||
let {entries} = JSON.parse(ss.getTabState(tab));
|
||||
is(entries.length, 2, "there are two shistory entries");
|
||||
|
||||
info("Clicking the go back button on about:certerror");
|
||||
let pageshowPromise = promiseWaitForEvent(browser, "pageshow");
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let returnButton = doc.getElementById("returnButton");
|
||||
returnButton.click();
|
||||
});
|
||||
yield pageshowPromise;
|
||||
|
||||
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
|
||||
is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
|
||||
is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* checkBadStsCert() {
|
||||
info("Loading a badStsCert and making sure exception button doesn't show up");
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
|
||||
info("Loading and waiting for the cert error");
|
||||
let certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
BrowserTestUtils.loadURI(browser, BAD_STS_CERT);
|
||||
yield certErrorLoaded;
|
||||
|
||||
let exceptionButtonHidden = yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let exceptionButton = doc.getElementById("exceptionDialogButton");
|
||||
return exceptionButton.hidden;
|
||||
});
|
||||
ok(exceptionButtonHidden, "Exception button is hidden");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* checkAdvancedDetails() {
|
||||
info("Loading a bad cert page and verifying the advanced details section");
|
||||
let browser;
|
||||
let certErrorLoaded;
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
gBrowser.selectedTab = gBrowser.addTab(BAD_CERT);
|
||||
browser = gBrowser.selectedBrowser;
|
||||
certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
}, false);
|
||||
|
||||
info("Loading and waiting for the cert error");
|
||||
yield certErrorLoaded;
|
||||
|
||||
let message = yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let advancedButton = doc.getElementById("advancedButton");
|
||||
advancedButton.click();
|
||||
let el = doc.getElementById("errorCode");
|
||||
return { textContent: el.textContent, tagName: el.tagName };
|
||||
});
|
||||
is(message.textContent, "SEC_ERROR_EXPIRED_CERTIFICATE",
|
||||
"Correct error message found");
|
||||
is(message.tagName, "a", "Error message is a link");
|
||||
|
||||
message = yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let errorCode = doc.getElementById("errorCode");
|
||||
errorCode.click();
|
||||
let div = doc.getElementById("certificateErrorDebugInformation");
|
||||
let text = doc.getElementById("certificateErrorText");
|
||||
|
||||
let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
return {
|
||||
divDisplay: div.style.display,
|
||||
text: text.textContent,
|
||||
securityInfoAsString: serializedSecurityInfo
|
||||
};
|
||||
});
|
||||
is(message.divDisplay, "block", "Debug information is visible");
|
||||
ok(message.text.contains(BAD_CERT), "Correct URL found");
|
||||
ok(message.text.contains("Certificate has expired"),
|
||||
"Correct error message found");
|
||||
ok(message.text.contains("HTTP Strict Transport Security: false"),
|
||||
"Correct HSTS value found");
|
||||
ok(message.text.contains("HTTP Public Key Pinning: false"),
|
||||
"Correct HPKP value found");
|
||||
let certChain = getCertChain(message.securityInfoAsString);
|
||||
ok(message.text.contains(certChain), "Found certificate chain");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
add_task(function* checkAdvancedDetailsForHSTS() {
|
||||
info("Loading a bad STS cert page and verifying the advanced details section");
|
||||
let browser;
|
||||
let certErrorLoaded;
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
|
||||
gBrowser.selectedTab = gBrowser.addTab(BAD_STS_CERT);
|
||||
browser = gBrowser.selectedBrowser;
|
||||
certErrorLoaded = waitForCertErrorLoad(browser);
|
||||
}, false);
|
||||
|
||||
info("Loading and waiting for the cert error");
|
||||
yield certErrorLoaded;
|
||||
|
||||
let message = yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let advancedButton = doc.getElementById("advancedButton");
|
||||
advancedButton.click();
|
||||
let ec = doc.getElementById("errorCode");
|
||||
let cdl = doc.getElementById("cert_domain_link");
|
||||
return {
|
||||
ecTextContent: ec.textContent,
|
||||
ecTagName: ec.tagName,
|
||||
cdlTextContent: cdl.textContent,
|
||||
cdlTagName: cdl.tagName
|
||||
};
|
||||
});
|
||||
|
||||
const badStsUri = Services.io.newURI(BAD_STS_CERT, null, null);
|
||||
is(message.ecTextContent, "SSL_ERROR_BAD_CERT_DOMAIN",
|
||||
"Correct error message found");
|
||||
is(message.ecTagName, "a", "Error message is a link");
|
||||
const url = badStsUri.prePath.slice(badStsUri.prePath.indexOf(".") + 1);
|
||||
is(message.cdlTextContent, url,
|
||||
"Correct cert_domain_link contents found");
|
||||
is(message.cdlTagName, "a", "cert_domain_link is a link");
|
||||
|
||||
message = yield ContentTask.spawn(browser, null, function* () {
|
||||
let doc = content.document;
|
||||
let errorCode = doc.getElementById("errorCode");
|
||||
errorCode.click();
|
||||
let div = doc.getElementById("certificateErrorDebugInformation");
|
||||
let text = doc.getElementById("certificateErrorText");
|
||||
|
||||
let docshell = content.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell);
|
||||
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let serializable = docShell.failedChannel.securityInfo
|
||||
.QueryInterface(Ci.nsITransportSecurityInfo)
|
||||
.QueryInterface(Ci.nsISerializable);
|
||||
let serializedSecurityInfo = serhelper.serializeToString(serializable);
|
||||
return {
|
||||
divDisplay: div.style.display,
|
||||
text: text.textContent,
|
||||
securityInfoAsString: serializedSecurityInfo
|
||||
};
|
||||
});
|
||||
is(message.divDisplay, "block", "Debug information is visible");
|
||||
ok(message.text.contains(badStsUri.spec), "Correct URL found");
|
||||
ok(message.text.contains("requested domain name does not match the server's certificate"),
|
||||
"Correct error message found");
|
||||
ok(message.text.contains("HTTP Strict Transport Security: false"),
|
||||
"Correct HSTS value found");
|
||||
ok(message.text.contains("HTTP Public Key Pinning: true"),
|
||||
"Correct HPKP value found");
|
||||
let certChain = getCertChain(message.securityInfoAsString);
|
||||
ok(message.text.contains(certChain), "Found certificate chain");
|
||||
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
function waitForCertErrorLoad(browser) {
|
||||
return new Promise(resolve => {
|
||||
info("Waiting for DOMContentLoaded event");
|
||||
browser.addEventListener("DOMContentLoaded", function load() {
|
||||
browser.removeEventListener("DOMContentLoaded", load, false, true);
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
function getCertChain(securityInfoAsString) {
|
||||
let certChain = "";
|
||||
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
|
||||
.getService(Ci.nsISerializationHelper);
|
||||
let securityInfo = serhelper.deserializeObject(securityInfoAsString);
|
||||
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
|
||||
let certs = securityInfo.failedCertChain.getEnumerator();
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
certChain += getPEMString(cert);
|
||||
}
|
||||
return certChain;
|
||||
}
|
||||
|
||||
function getDERString(cert)
|
||||
{
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = '';
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
function getPEMString(cert)
|
||||
{
|
||||
var derb64 = btoa(getDERString(cert));
|
||||
// Wrap the Base64 string into lines of 64 characters,
|
||||
// with CRLF line breaks (as specified in RFC 1421).
|
||||
var wrapped = derb64.replace(/(\S{64}(?!$))/g, "$1\r\n");
|
||||
return "-----BEGIN CERTIFICATE-----\r\n"
|
||||
+ wrapped
|
||||
+ "\r\n-----END CERTIFICATE-----\r\n";
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
// Test that visiting a site pinned with HPKP headers does not succeed when it
|
||||
// uses a certificate with a key not in the pinset. This should result in an
|
||||
// about:neterror page
|
||||
// Also verify that removal of the HPKP headers succeeds (via HPKP headers)
|
||||
// and that after removal the visit to the site with the previously
|
||||
// unauthorized pins succeeds.
|
||||
//
|
||||
// This test required three certs to be created in build/pgo/certs:
|
||||
// 1. A new trusted root:
|
||||
// a. certutil -S -s "Alternate trusted authority" -s "CN=Alternate Trusted Authority" -t "C,," -x -m 1 -v 120 -n "alternateTrustedAuthority" -Z SHA256 -g 2048 -2 -d .
|
||||
// b. (export) certutil -L -d . -n "alternateTrustedAuthority" -a -o alternateroot.ca
|
||||
// (files ended in .ca are added as trusted roots by the mochitest harness)
|
||||
// 2. A good pinning server cert (signed by the pgo root):
|
||||
// certutil -S -n "dynamicPinningGood" -s "CN=dynamic-pinning.example.com" -c "pgo temporary ca" -t "P,," -k rsa -g 2048 -Z SHA256 -m 8939454 -v 120 -8 "*.include-subdomains.pinning-dynamic.example.com,*.pinning-dynamic.example.com" -d .
|
||||
// 3. A certificate with a different issuer, so as to cause a key pinning violation."
|
||||
// certutil -S -n "dynamicPinningBad" -s "CN=bad.include-subdomains.pinning-dynamic.example.com" -c "alternateTrustedAuthority" -t "P,," -k rsa -g 2048 -Z SHA256 -m 893945439 -v 120 -8 "bad.include-subdomains.pinning-dynamic.example.com" -d .
|
||||
|
||||
const gSSService = Cc["@mozilla.org/ssservice;1"]
|
||||
.getService(Ci.nsISiteSecurityService);
|
||||
const gIOService = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
const kPinningDomain = "include-subdomains.pinning-dynamic.example.com";
|
||||
const khpkpPinninEnablePref = "security.cert_pinning.process_headers_from_non_builtin_roots";
|
||||
const kpkpEnforcementPref = "security.cert_pinning.enforcement_level";
|
||||
const kBadPinningDomain = "bad.include-subdomains.pinning-dynamic.example.com";
|
||||
const kURLPath = "/browser/browser/base/content/test/general/pinning_headers.sjs?";
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
// Enable enforcing strict pinning and processing headers from
|
||||
// non-builtin roots.
|
||||
Services.prefs.setIntPref(kpkpEnforcementPref, 2);
|
||||
Services.prefs.setBoolPref(khpkpPinninEnablePref, true);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref(kpkpEnforcementPref);
|
||||
Services.prefs.clearUserPref(khpkpPinninEnablePref);
|
||||
let uri = gIOService.newURI("https://" + kPinningDomain, null, null);
|
||||
gSSService.removeState(Ci.nsISiteSecurityService.HEADER_HPKP, uri, 0);
|
||||
});
|
||||
whenNewTabLoaded(window, loadPinningPage);
|
||||
}
|
||||
|
||||
// Start by making a successful connection to a domain that will pin a site
|
||||
function loadPinningPage() {
|
||||
gBrowser.selectedBrowser.addEventListener("load",
|
||||
successfulPinningPageListener,
|
||||
true);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "valid");
|
||||
}
|
||||
|
||||
// After the site is pinned try to load with a subdomain site that should
|
||||
// fail to validate
|
||||
var successfulPinningPageListener = {
|
||||
handleEvent: function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", this, true);
|
||||
gBrowser.addProgressListener(certErrorProgressListener);
|
||||
gBrowser.selectedBrowser.loadURI("https://" + kBadPinningDomain);
|
||||
}
|
||||
};
|
||||
|
||||
// The browser should load about:neterror, when this happens, proceed
|
||||
// to load the pinning domain again, this time removing the pinning information
|
||||
var certErrorProgressListener = {
|
||||
onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
|
||||
let textElement = content.document.getElementById("errorShortDescText");
|
||||
let text = textElement.innerHTML;
|
||||
ok(text.indexOf("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE") > 0,
|
||||
"Got a pinning error page");
|
||||
gBrowser.removeProgressListener(this);
|
||||
gBrowser.selectedBrowser.addEventListener("load",
|
||||
successfulPinningRemovalPageListener,
|
||||
true);
|
||||
gBrowser.selectedBrowser.loadURI("https://" + kPinningDomain + kURLPath + "zeromaxagevalid");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// After the pinning information has been removed (successful load) proceed
|
||||
// to load again with the invalid pin domain.
|
||||
var successfulPinningRemovalPageListener = {
|
||||
handleEvent: function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", this, true);
|
||||
gBrowser.selectedBrowser.addEventListener("load",
|
||||
successfulLoadListener,
|
||||
true);
|
||||
|
||||
gBrowser.selectedBrowser.loadURI("https://" + kBadPinningDomain);
|
||||
}
|
||||
};
|
||||
|
||||
// Finally, we should successfully load
|
||||
// https://bad.include-subdomains.pinning-dynamic.example.com.
|
||||
var successfulLoadListener = {
|
||||
handleEvent: function() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", this, true);
|
||||
gBrowser.removeTab(gBrowser.selectedTab);
|
||||
ok(true, "load complete");
|
||||
finish();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
function remote(task) {
|
||||
return ContentTask.spawn(gBrowser.selectedBrowser, null, task);
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
let promise = remote(function () {
|
||||
return ContentTaskUtils.waitForEvent(this, "DOMContentLoaded", true, event => {
|
||||
return content.document.documentURI != "about:blank";
|
||||
}).then(() => 0); // don't want to send the event to the chrome process
|
||||
});
|
||||
gBrowser.loadURI("https://nocert.example.com/");
|
||||
yield promise;
|
||||
|
||||
let uri = yield remote(() => {
|
||||
return content.document.documentURI;
|
||||
});
|
||||
|
||||
// Confirm that we are displaying the contributed error page, not the default
|
||||
ok(uri.startsWith("about:certerror"), "Broken page should go to about:certerror, not about:neterror");
|
||||
|
||||
let advancedDiv, advancedDivVisibility, technicalDivCollapsed;
|
||||
|
||||
[advancedDiv, advancedDivVisibility] = yield remote(() => {
|
||||
let div = content.document.getElementById("advancedPanel");
|
||||
if (div) {
|
||||
return [true, div.ownerDocument.defaultView.getComputedStyle(div, "").visibility];
|
||||
} else {
|
||||
return [null, null];
|
||||
}
|
||||
});
|
||||
|
||||
// Confirm that the expert section is collapsed
|
||||
ok(advancedDiv, "Advanced content div should exist");
|
||||
is(advancedDivVisibility, "hidden", "Advanced content should not be visible by default");
|
||||
|
||||
// Tweak the expert mode pref
|
||||
gPrefService.setBoolPref("browser.xul.error_pages.expert_bad_cert", true);
|
||||
|
||||
promise = remote(function () {
|
||||
return ContentTaskUtils.waitForEvent(this, "DOMContentLoaded", true);
|
||||
});
|
||||
gBrowser.reload();
|
||||
yield promise;
|
||||
|
||||
[advancedDiv, advancedDivVisibility] = yield remote(() => {
|
||||
let div = content.document.getElementById("advancedPanel");
|
||||
if (div) {
|
||||
return [true, div.ownerDocument.defaultView.getComputedStyle(div, "").visibility];
|
||||
} else {
|
||||
return [null, null];
|
||||
}
|
||||
});
|
||||
|
||||
ok(advancedDiv, "Advanced content div should exist");
|
||||
is(advancedDivVisibility, "visible", "Advanced content should be visible by default");
|
||||
|
||||
// Clean up
|
||||
gBrowser.removeCurrentTab();
|
||||
if (gPrefService.prefHasUserValue("browser.xul.error_pages.expert_bad_cert"))
|
||||
gPrefService.clearUserPref("browser.xul.error_pages.expert_bad_cert");
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab("data:text/html,<iframe width='700' height='700' src='about:certerror'></iframe>");
|
||||
// Open a html page with about:certerror in an iframe
|
||||
BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser).then(testIframeCert);
|
||||
}
|
||||
|
||||
function testIframeCert(e) {
|
||||
// Confirm that the expert section is hidden
|
||||
var doc = gBrowser.contentDocument.getElementsByTagName('iframe')[0].contentDocument;
|
||||
var aP = doc.getElementById("advancedPanel");
|
||||
ok(aP, "Advanced content should exist");
|
||||
is_element_hidden(aP, "Advanced content should not be visible by default")
|
||||
|
||||
// Clean up
|
||||
gBrowser.removeCurrentTab();
|
||||
|
||||
finish();
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
"use strict";
|
||||
|
||||
const URL_REPORTS = "https://example.com/browser/browser/base/content/test/general/ssl_error_reports.sjs?";
|
||||
const URL_BAD_CHAIN = "https://badchain.include-subdomains.pinning.example.com/";
|
||||
const URL_NO_CERT = "https://fail-handshake.example.com/";
|
||||
const URL_BAD_CERT = "https://expired.example.com/";
|
||||
const URL_BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443/";
|
||||
const ROOT = getRootDirectory(gTestPath);
|
||||
const PREF_REPORT_ENABLED = "security.ssl.errorReporting.enabled";
|
||||
const PREF_REPORT_AUTOMATIC = "security.ssl.errorReporting.automatic";
|
||||
const PREF_REPORT_URL = "security.ssl.errorReporting.url";
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
|
||||
function cleanup() {
|
||||
Services.prefs.clearUserPref(PREF_REPORT_ENABLED);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_AUTOMATIC);
|
||||
Services.prefs.clearUserPref(PREF_REPORT_URL);
|
||||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
|
||||
cleanup();
|
||||
});
|
||||
|
||||
add_task(function* test_send_report_neterror() {
|
||||
yield testSendReportAutomatically(URL_BAD_CHAIN, "succeed", "neterror");
|
||||
yield testSendReportAutomatically(URL_NO_CERT, "nocert", "neterror");
|
||||
yield testSetAutomatic(URL_NO_CERT, "nocert", "neterror");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_send_report_certerror() {
|
||||
yield testSendReportAutomatically(URL_BAD_CERT, "badcert", "certerror");
|
||||
yield testSetAutomatic(URL_BAD_CERT, "badcert", "certerror");
|
||||
});
|
||||
|
||||
add_task(function* test_send_disabled() {
|
||||
Services.prefs.setBoolPref(PREF_REPORT_ENABLED, false);
|
||||
Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
|
||||
Services.prefs.setCharPref(PREF_REPORT_URL, "https://example.com/invalid");
|
||||
|
||||
// Check with enabled=false but automatic=true.
|
||||
yield testSendReportDisabled(URL_NO_CERT, "neterror");
|
||||
yield testSendReportDisabled(URL_BAD_CERT, "certerror");
|
||||
|
||||
Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, false);
|
||||
|
||||
// Check again with both prefs false.
|
||||
yield testSendReportDisabled(URL_NO_CERT, "neterror");
|
||||
yield testSendReportDisabled(URL_BAD_CERT, "certerror");
|
||||
cleanup();
|
||||
});
|
||||
|
||||
function* testSendReportAutomatically(testURL, suffix, errorURISuffix) {
|
||||
Services.prefs.setBoolPref(PREF_REPORT_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
|
||||
Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);
|
||||
|
||||
// Add a tab and wait until it's loaded.
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Load the page and wait for the error report submission.
|
||||
let promiseStatus = createReportResponseStatusPromise(URL_REPORTS + suffix);
|
||||
browser.loadURI(testURL);
|
||||
|
||||
ok(!isErrorStatus(yield promiseStatus),
|
||||
"SSL error report submitted successfully");
|
||||
|
||||
// Check that we loaded the right error page.
|
||||
yield checkErrorPage(browser, errorURISuffix);
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
cleanup();
|
||||
};
|
||||
|
||||
function* testSetAutomatic(testURL, suffix, errorURISuffix) {
|
||||
Services.prefs.setBoolPref(PREF_REPORT_ENABLED, true);
|
||||
Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, false);
|
||||
Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);
|
||||
|
||||
// Add a tab and wait until it's loaded.
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Load the page.
|
||||
browser.loadURI(testURL);
|
||||
yield promiseErrorPageLoaded(browser);
|
||||
|
||||
// Check that we loaded the right error page.
|
||||
yield checkErrorPage(browser, errorURISuffix);
|
||||
|
||||
let statusPromise = createReportResponseStatusPromise(URL_REPORTS + suffix);
|
||||
|
||||
// Click the checkbox, enable automatic error reports.
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.document.getElementById("automaticallyReportInFuture").click();
|
||||
});
|
||||
|
||||
// Wait for the error report submission.
|
||||
yield statusPromise;
|
||||
|
||||
let isAutomaticReportingEnabled = () =>
|
||||
Services.prefs.getBoolPref(PREF_REPORT_AUTOMATIC);
|
||||
|
||||
// Check that the pref was flipped.
|
||||
ok(isAutomaticReportingEnabled(), "automatic SSL report submission enabled");
|
||||
|
||||
// Disable automatic error reports.
|
||||
yield ContentTask.spawn(browser, null, function* () {
|
||||
content.document.getElementById("automaticallyReportInFuture").click();
|
||||
});
|
||||
|
||||
// Check that the pref was flipped.
|
||||
ok(!isAutomaticReportingEnabled(), "automatic SSL report submission disabled");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
cleanup();
|
||||
}
|
||||
|
||||
function* testSendReportDisabled(testURL, errorURISuffix) {
|
||||
// Add a tab and wait until it's loaded.
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
// Load the page.
|
||||
browser.loadURI(testURL);
|
||||
yield promiseErrorPageLoaded(browser);
|
||||
|
||||
// Check that we loaded the right error page.
|
||||
yield checkErrorPage(browser, errorURISuffix);
|
||||
|
||||
// Check that the error reporting section is hidden.
|
||||
let hidden = yield ContentTask.spawn(browser, null, function* () {
|
||||
let section = content.document.getElementById("certificateErrorReporting");
|
||||
return content.getComputedStyle(section).display == "none";
|
||||
});
|
||||
ok(hidden, "error reporting section should be hidden");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
}
|
||||
|
||||
function isErrorStatus(status) {
|
||||
return status < 200 || status >= 300;
|
||||
}
|
||||
|
||||
// use the observer service to see when a report is sent
|
||||
function createReportResponseStatusPromise(expectedURI) {
|
||||
return new Promise(resolve => {
|
||||
let observer = (subject, topic, data) => {
|
||||
subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let requestURI = subject.URI.spec;
|
||||
if (requestURI == expectedURI) {
|
||||
Services.obs.removeObserver(observer, "http-on-examine-response");
|
||||
resolve(subject.responseStatus);
|
||||
}
|
||||
};
|
||||
Services.obs.addObserver(observer, "http-on-examine-response", false);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseErrorPageLoaded(browser) {
|
||||
return new Promise(resolve => {
|
||||
browser.addEventListener("DOMContentLoaded", function onLoad() {
|
||||
browser.removeEventListener("DOMContentLoaded", onLoad, false, true);
|
||||
resolve();
|
||||
}, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
function checkErrorPage(browser, suffix) {
|
||||
return ContentTask.spawn(browser, null, function* () {
|
||||
return content.document.documentURI;
|
||||
}).then(uri => {
|
||||
ok(uri.startsWith(`about:${suffix}`), "correct error page loaded");
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
const EXPECTED_CHAIN = [
|
||||
"MIIDCjCCAfKgAwIBAgIENUiGYDANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDExtBbHRlcm5hdGUgVHJ1c3RlZCBBdXRob3JpdHkwHhcNMTQxMDAxMjExNDE5WhcNMjQxMDAxMjExNDE5WjAxMS8wLQYDVQQDEyZpbmNsdWRlLXN1YmRvbWFpbnMucGlubmluZy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxYrge8C4eVfTb6/lJ4k/+/4J6wlnWpp5Szxy1MHhsLB+LJh/HRHqkO/tsigT204kTeU3dxuAfQHz0g+Td8dr6KICLLNVFUPw+XjhBV4AtxV8wcprs6EmdBhJgAjkFB4M76BL7/Ow0NfH012WNESn8TTbsp3isgkmrXjTZhWR33vIL1eDNimykp/Os/+JO+x9KVfdCtDCrPwO9Yusial5JiaW7qemRtVuUDL87NSJ7xokPEOSc9luv/fBamZ3rgqf3K6epqg+0o3nNCCcNFnfLW52G0t69+dIjr39WISHnqqZj3Sb7JPU6OmxTd13ByoLkoM3ZUQ2Lpas+RJvQyGXkCAwEAAaM1MDMwMQYDVR0RBCowKIImaW5jbHVkZS1zdWJkb21haW5zLnBpbm5pbmcuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAAmzXfeoOS59FkNABRonFPRyFl7BoGpVJENUteFfTa2pdAhGYdo19Y4uILTTj+vtDAa5yryb5Uvd+YuJnExosbMMkzCrmZ9+VJCJdqUTb+idwk9/sgPl2gtGeRmefB0hXSUFHc/p1CDufSpYOmj9NCUZD2JEsybgJQNulkfAsVnS3lzDcxAwcO+RC/1uJDSiUtcBpWS4FW58liuDYE7PD67kLJHZPVUV2WCMuIl4VM2tKPtvShz1JkZ5UytOLs6jPfviNAk/ftXczaE2/RJgM2MnDX9nGzOxG6ONcVNCljL8avhFBCosutE6i5LYSZR6V14YY/xOn15WDSuWdnIsJCo=",
|
||||
"MIIC2jCCAcKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDExtBbHRlcm5hdGUgVHJ1c3RlZCBBdXRob3JpdHkwHhcNMTQwOTI1MjEyMTU0WhcNMjQwOTI1MjEyMTU0WjAmMSQwIgYDVQQDExtBbHRlcm5hdGUgVHJ1c3RlZCBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBT+BwAhO52IWgSIdZZifU9LHOs3IR/+8DCC0WP5d/OuyKlZ6Rqd0tsd3i7durhQyjHSbLf2lJStcnFjcVEbEnNI76RuvlN8xLLn5eV+2Ayr4cZYKztudwRmw+DV/iYAiMSy0hs7m3ssfX7qpoi1aNRjUanwU0VTCPQhF1bEKAC2du+C5Z8e92zN5t87w7bYr7lt+m8197XliXEu+0s9RgnGwGaZ296BIRz6NOoJYTa43n06LU1I1+Z4d6lPdzUFrSR0GBaMhUSurUBtOin3yWiMhg1VHX/KwqGc4als5GyCVXy8HGrA/0zQPOhetxrlhEVAdK/xBt7CZvByj1Rcc7AgMBAAGjEzARMA8GA1UdEwQIMAYBAf8CAQAwDQYJKoZIhvcNAQELBQADggEBAJq/hogSRqzPWTwX4wTn/DVSNdWwFLv53qep9YrSMJ8ZsfbfK9Es4VP4dBLRQAVMJ0Z5mW1I6d/n0KayTanuUBvemYdxPi/qQNSs8UJcllqdhqWzmzAg6a0LxrMnEeKzPBPD6q8PwQ7tYP+B4sBN9tnnsnyPgti9ZiNZn5FwXZliHXseQ7FE9/SqHlLw5LXW3YtKjuti6RmuV6fq3j+D4oeC5vb1mKgIyoTqGN6ze57v8RHi+pQ8Q+kmoUn/L3Z2YmFe4SKN/4WoyXr8TdejpThGOCGCAd3565s5gOx5QfSQX11P8NZKO8hcN0tme3VzmGpHK0Z/6MTmdpNaTwQ6odk="
|
||||
];
|
||||
|
||||
const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = -16384;
|
||||
|
||||
function parseReport(request) {
|
||||
// read the report from the request
|
||||
let inputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
inputStream.init(request.bodyInputStream, 0x01, 0004, 0);
|
||||
|
||||
let body = "";
|
||||
if (inputStream) {
|
||||
while (inputStream.available()) {
|
||||
body = body + inputStream.read(inputStream.available());
|
||||
}
|
||||
}
|
||||
// parse the report
|
||||
return JSON.parse(body);
|
||||
}
|
||||
|
||||
function handleRequest(request, response) {
|
||||
let report = {};
|
||||
let certChain = [];
|
||||
|
||||
switch (request.queryString) {
|
||||
case "succeed":
|
||||
report = parseReport(request);
|
||||
certChain = report.failedCertChain;
|
||||
|
||||
// ensure the cert chain is what we expect
|
||||
for (idx in certChain) {
|
||||
if (certChain[idx] !== EXPECTED_CHAIN[idx]) {
|
||||
// if the chain differs, send an error response to cause test
|
||||
// failure
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>The report contained an unexpected chain</html>");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (report.errorCode !== MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) {
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>The report contained an unexpected error code</html>");
|
||||
return;
|
||||
}
|
||||
|
||||
// if all is as expected, send the 201 the client expects
|
||||
response.setStatusLine("1.1", 201, "Created");
|
||||
response.write("<html>OK</html>");
|
||||
break;
|
||||
case "nocert":
|
||||
report = parseReport(request);
|
||||
certChain = report.failedCertChain;
|
||||
|
||||
if (certChain && certChain.length > 0) {
|
||||
// We're not expecting a chain; if there is one, send an error
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>The report contained an unexpected chain</html>");
|
||||
return;
|
||||
}
|
||||
|
||||
// if all is as expected, send the 201 the client expects
|
||||
response.setStatusLine("1.1", 201, "Created");
|
||||
response.write("<html>OK</html>");
|
||||
break;
|
||||
case "badcert":
|
||||
report = parseReport(request);
|
||||
certChain = report.failedCertChain;
|
||||
|
||||
if (!certChain || certChain.length != 2) {
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>The report contained an unexpected chain</html>");
|
||||
return;
|
||||
}
|
||||
|
||||
// if all is as expected, send the 201 the client expects
|
||||
response.setStatusLine("1.1", 201, "Created");
|
||||
response.write("<html>OK</html>");
|
||||
break;
|
||||
case "error":
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>server error</html>");
|
||||
break;
|
||||
default:
|
||||
response.setStatusLine("1.1", 500, "Server error");
|
||||
response.write("<html>succeed, nocert or error expected (got " + request.queryString + ")</html>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -344,6 +344,7 @@
|
||||
@RESPATH@/components/toolkit_finalizationwitness.xpt
|
||||
@RESPATH@/components/toolkit_formautofill.xpt
|
||||
@RESPATH@/components/toolkit_osfile.xpt
|
||||
@RESPATH@/components/toolkit_securityreporter.xpt
|
||||
#ifdef NIGHTLY_BUILD
|
||||
@RESPATH@/components/toolkit_perfmonitoring.xpt
|
||||
#endif
|
||||
@@ -653,6 +654,10 @@
|
||||
@RESPATH@/components/PrivateBrowsing.manifest
|
||||
@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js
|
||||
|
||||
; Security Reports
|
||||
@RESPATH@/components/SecurityReporter.manifest
|
||||
@RESPATH@/components/SecurityReporter.js
|
||||
|
||||
; Signed Packaged Content
|
||||
@RESPATH@/components/InstallPackagedWebapp.manifest
|
||||
@RESPATH@/components/InstallPackagedWebapp.js
|
||||
|
||||
@@ -36,5 +36,8 @@ tampering with your connection.</b>">
|
||||
<!ENTITY certerror.expert.contentPara2 "Don't add an exception unless
|
||||
you know there's a good reason why this site doesn't use trusted identification.">
|
||||
<!ENTITY certerror.addException.label "Add Exception…">
|
||||
<!ENTITY certerror.copyToClipboard.label "Copy text to clipboard">
|
||||
|
||||
<!ENTITY certerror.technical.heading "Technical Details">
|
||||
|
||||
<!ENTITY errorReporting.automatic "Report errors like this to help Mozilla identify misconfigured sites">
|
||||
|
||||
@@ -657,3 +657,20 @@ muteTab.label = Mute Tab
|
||||
muteTab.accesskey = M
|
||||
unmuteTab.label = Unmute Tab
|
||||
unmuteTab.accesskey = M
|
||||
|
||||
# LOCALIZATION NOTE (weakCryptoOverriding.message): %S is brandShortName
|
||||
weakCryptoOverriding.message = %S recommends that you don't enter your password, credit card and other personal information on this website.
|
||||
revokeOverride.label = Don't Trust This Website
|
||||
revokeOverride.accesskey = D
|
||||
# LOCALIZATION NOTE (certErrorDetails.label): This is a text string that
|
||||
# appears in the about:certerror page, so that the user can copy and send it to
|
||||
# the server administrators for troubleshooting. %1$S is the visited URL, %2$S
|
||||
# is the error message, %3$S is true or false, depending on whether the server
|
||||
# supports HSTS, %4$S is true or false, depending on whether the server
|
||||
# supports HPKP, %5$S is the certificate chain in PEM format.
|
||||
certErrorDetails.label = %1$S\r\n\r\n%2$S\r\n\r\nHTTP Strict Transport Security: %3$S\r\nHTTP Public Key Pinning: %4$S\r\n\r\nCertificate chain:\r\n\r\n%5$S
|
||||
|
||||
# LOCALIZATION NOTE (tabgroups.migration.anonGroup):
|
||||
# %S is the group number/ID
|
||||
tabgroups.migration.anonGroup = Group %S
|
||||
tabgroups.migration.tabGroupBookmarkFolderName = Bookmarked Tab Groups
|
||||
|
||||
@@ -217,10 +217,6 @@ functionality specific to firefox. -->
|
||||
|
||||
<!ENTITY errorReporting.automatic2 "Report errors like this to help Mozilla identify and block malicious sites">
|
||||
<!ENTITY errorReporting.learnMore "Learn more…">
|
||||
<!ENTITY errorReporting.sending "Sending report">
|
||||
<!ENTITY errorReporting.sent "Report sent">
|
||||
<!ENTITY errorReporting.report "Report">
|
||||
<!ENTITY errorReporting.tryAgain "Try again">
|
||||
|
||||
<!ENTITY remoteXUL.title "Remote XUL">
|
||||
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "AboutHomeUtils" ];
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.AboutHomeUtils = {
|
||||
/**
|
||||
* Returns an object containing the name and searchURL of the original default
|
||||
* search engine.
|
||||
*/
|
||||
get defaultSearchEngine() {
|
||||
let defaultEngine = Services.search.defaultEngine;
|
||||
let submission = defaultEngine.getSubmission("_searchTerms_", null, "homepage");
|
||||
|
||||
return Object.freeze({
|
||||
name: defaultEngine.name,
|
||||
searchURL: submission.uri.spec,
|
||||
postDataString: submission.postDataString
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* showKnowYourRights - Determines if the user should be shown the
|
||||
* about:rights notification. The notification should *not* be shown if
|
||||
* we've already shown the current version, or if the override pref says to
|
||||
* never show it. The notification *should* be shown if it's never been seen
|
||||
* before, if a newer version is available, or if the override pref says to
|
||||
* always show it.
|
||||
*/
|
||||
get showKnowYourRights() {
|
||||
// Look for an unconditional override pref. If set, do what it says.
|
||||
// (true --> never show, false --> always show)
|
||||
try {
|
||||
return !Services.prefs.getBoolPref("browser.rights.override");
|
||||
} catch (e) { }
|
||||
// Ditto, for the legacy EULA pref.
|
||||
try {
|
||||
return !Services.prefs.getBoolPref("browser.EULA.override");
|
||||
} catch (e) { }
|
||||
|
||||
#ifndef MOZILLA_OFFICIAL
|
||||
// Non-official builds shouldn't show the notification.
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// Look to see if the user has seen the current version or not.
|
||||
var currentVersion = Services.prefs.getIntPref("browser.rights.version");
|
||||
try {
|
||||
return !Services.prefs.getBoolPref("browser.rights." + currentVersion + ".shown");
|
||||
} catch (e) { }
|
||||
|
||||
// Legacy: If the user accepted a EULA, we won't annoy them with the
|
||||
// equivalent about:rights page until the version changes.
|
||||
try {
|
||||
return !Services.prefs.getBoolPref("browser.EULA." + currentVersion + ".accepted");
|
||||
} catch (e) { }
|
||||
|
||||
// We haven't shown the notification before, so do so now.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
html {
|
||||
background: #833;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 1em;
|
||||
color: -moz-FieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 .6em 0;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
font-size: 160%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#errorPageContainer {
|
||||
position: relative;
|
||||
min-width: 13em;
|
||||
max-width: 52em;
|
||||
margin: 4em auto;
|
||||
border: 2px solid #DD0D09;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 8px red;
|
||||
padding: 3em;
|
||||
-moz-padding-start: 30px;
|
||||
background: url("chrome://global/skin/icons/sslWarning.png") left 0 no-repeat -moz-Field;
|
||||
background-origin: content-box;
|
||||
}
|
||||
|
||||
#errorPageContainer:-moz-dir(rtl) {
|
||||
background-position: right 0;
|
||||
}
|
||||
|
||||
#errorTitle {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#errorLongContent {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expander > button:-moz-dir(rtl) {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
.expander[collapsed] > button:-moz-dir(rtl) {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
@@ -9,7 +9,6 @@ browser.jar:
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
html {
|
||||
background: #833;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 1em;
|
||||
color: -moz-FieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 .6em 0;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
font-size: 160%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#errorPageContainer {
|
||||
position: relative;
|
||||
min-width: 13em;
|
||||
max-width: 52em;
|
||||
margin: 4em auto;
|
||||
border: 2px solid #DD0D09;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 8px red;
|
||||
padding: 3em;
|
||||
-moz-padding-start: 30px;
|
||||
background: url("chrome://global/skin/icons/sslWarning.png") left 0 no-repeat -moz-Field;
|
||||
background-origin: content-box;
|
||||
}
|
||||
|
||||
#errorPageContainer:-moz-dir(rtl) {
|
||||
background-position: right 0;
|
||||
}
|
||||
|
||||
#errorTitle {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#errorLongContent {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expander > button:-moz-dir(rtl) {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
.expander[collapsed] > button:-moz-dir(rtl) {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
@@ -8,7 +8,6 @@ browser.jar:
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png (preferences/application.png)
|
||||
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
}
|
||||
|
||||
#back-button {
|
||||
-moz-image-region: rect(0, 18px, 18px, 0);
|
||||
-moz-image-region: rect(0, 54px, 18px, 36px);
|
||||
}
|
||||
|
||||
#forward-button {
|
||||
-moz-image-region: rect(0, 36px, 18px, 18px);
|
||||
-moz-image-region: rect(0, 72px, 18px, 54px);
|
||||
}
|
||||
|
||||
#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/* 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/. */
|
||||
|
||||
@import url("chrome://global/skin/in-content/common.css");
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
min-height: 100vh;
|
||||
padding: 0 48px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#errorPageContainer {
|
||||
position: relative;
|
||||
min-width: 320px;
|
||||
max-width: 512px;
|
||||
}
|
||||
|
||||
#errorTitle {
|
||||
background: url("chrome://browser/skin/cert-error.svg") left 0 no-repeat;
|
||||
background-size: 3em;
|
||||
margin-inline-start: -5em;
|
||||
padding-inline-start: 5em;
|
||||
}
|
||||
|
||||
#errorTitle:-moz-dir(rtl) {
|
||||
background-position: right 0;
|
||||
}
|
||||
|
||||
#errorTitleText {
|
||||
border-bottom: 1px solid #C1C1C1;
|
||||
padding-bottom: 0.4em;
|
||||
}
|
||||
|
||||
@media (max-width: 675px) {
|
||||
#errorTitle {
|
||||
padding-top: 0;
|
||||
background-image: none;
|
||||
margin-inline-start: 0;
|
||||
padding-inline-start: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#buttonContainer {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
#buttonSpacer {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#certificateErrorDebugInformation {
|
||||
display: none;
|
||||
background-color: var(--in-content-box-background-hover) !important;
|
||||
border-top: 1px solid var(--in-content-border-color);
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
top: 100%;
|
||||
width: 65%;
|
||||
padding: 1em 17.5%;
|
||||
}
|
||||
|
||||
#certificateErrorText {
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
#errorCode {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#returnButton {
|
||||
background-color: var(--in-content-primary-button-background);
|
||||
border: none;
|
||||
color: var(--in-content-selected-text);
|
||||
min-width: 250px;
|
||||
margin-inline-start: 0;
|
||||
}
|
||||
|
||||
#returnButton:hover {
|
||||
background-color: var(--in-content-primary-button-background-hover) !important;
|
||||
}
|
||||
|
||||
#returnButton:hover:active {
|
||||
background-color: var(--in-content-primary-button-background-active) !important;
|
||||
}
|
||||
|
||||
#advancedButton {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
/* Advanced section is hidden via inline styles until the link is clicked */
|
||||
#advancedPanel {
|
||||
position: absolute;
|
||||
background-color: white;
|
||||
color: var(--in-content-text-color);
|
||||
border: 1px lightgray solid;
|
||||
/* Don't use top padding because the default p style has top padding, and it
|
||||
* makes the overall div look uneven */
|
||||
padding: 0 12px 10px;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0 0 4px #ddd;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.hostname {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#reportCertificateErrorRetry,
|
||||
#certificateErrorReporting,
|
||||
#reportSendingMessage,
|
||||
#reportSentMessage {
|
||||
display: none;
|
||||
}
|
||||
@@ -114,7 +114,6 @@ button:disabled {
|
||||
}
|
||||
|
||||
#certificateErrorReporting,
|
||||
#reportCertificateError,
|
||||
#reportSentMessage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# be specified once. As a result, the source file paths are relative
|
||||
# to the location of the actual manifest.
|
||||
|
||||
skin/classic/browser/aboutCertError.css (../shared/aboutCertError.css)
|
||||
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
|
||||
skin/classic/browser/aboutNetError_info.svg (../shared/aboutNetError_info.svg)
|
||||
* skin/classic/browser/aboutSessionRestore.css (../shared/aboutSessionRestore.css)
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/* 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/. */
|
||||
|
||||
|
||||
html {
|
||||
background: #833;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0 1em;
|
||||
color: -moz-FieldText;
|
||||
font: message-box;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0 0 .6em 0;
|
||||
border-bottom: 1px solid ThreeDLightShadow;
|
||||
font-size: 160%;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
#errorPageContainer {
|
||||
position: relative;
|
||||
min-width: 13em;
|
||||
max-width: 52em;
|
||||
margin: 4em auto;
|
||||
border: 2px solid #DD0D09;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 0px 8px red;
|
||||
padding: 3em;
|
||||
-moz-padding-start: 30px;
|
||||
background: url("chrome://global/skin/icons/sslWarning.png") left 0 no-repeat -moz-Field;
|
||||
background-origin: content-box;
|
||||
}
|
||||
|
||||
#errorPageContainer:-moz-dir(rtl) {
|
||||
background-position: right 0;
|
||||
}
|
||||
|
||||
#errorTitle {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
#errorLongContent {
|
||||
-moz-margin-start: 80px;
|
||||
}
|
||||
|
||||
.expander > button {
|
||||
-moz-padding-start: 20px;
|
||||
-moz-margin-start: -20px;
|
||||
background: url("chrome://browser/skin/aboutCertError_sectionExpanded.png") left center no-repeat;
|
||||
border: none;
|
||||
font: inherit;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.expander > button:-moz-dir(rtl) {
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
.expander[collapsed] > button {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed.png");
|
||||
}
|
||||
|
||||
.expander[collapsed] > button:-moz-dir(rtl) {
|
||||
background-image: url("chrome://browser/skin/aboutCertError_sectionCollapsed-rtl.png");
|
||||
}
|
||||
@@ -8,7 +8,6 @@ browser.jar:
|
||||
skin/classic/browser/sanitizeDialog.css
|
||||
skin/classic/browser/aboutSessionRestore-window-icon.png
|
||||
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
|
||||
skin/classic/browser/aboutCertError.css
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed.png
|
||||
skin/classic/browser/aboutCertError_sectionCollapsed-rtl.png
|
||||
skin/classic/browser/aboutCertError_sectionExpanded.png
|
||||
|
||||
+31
-6
@@ -364,13 +364,25 @@ BasePrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
BasePrincipal::EnsureCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aCSP)
|
||||
{
|
||||
if (mCSP) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
// if there is a CSP already associated with this principal
|
||||
// then just return that - do not overwrite it!!!
|
||||
NS_IF_ADDREF(*aCSP = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mCSP = aCsp;
|
||||
nsresult rv = NS_OK;
|
||||
mCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context for violation reports
|
||||
rv = aDocument ? mCSP->SetRequestContext(aDocument, nullptr)
|
||||
: mCSP->SetRequestContext(nullptr, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_IF_ADDREF(*aCSP = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -382,12 +394,25 @@ BasePrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BasePrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP)
|
||||
BasePrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aPreloadCSP)
|
||||
{
|
||||
if (mPreloadCSP) {
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
// if there is a speculative CSP already associated with this principal
|
||||
// then just return that - do not overwrite it!!!
|
||||
NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
mPreloadCSP = aPreloadCSP;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
mPreloadCSP = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context for violation reports
|
||||
rv = aDocument ? mPreloadCSP->SetRequestContext(aDocument, nullptr)
|
||||
: mPreloadCSP->SetRequestContext(nullptr, this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_IF_ADDREF(*aPreloadCSP = mPreloadCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -202,9 +202,9 @@ public:
|
||||
NS_IMETHOD SubsumesConsideringDomain(nsIPrincipal* other, bool* _retval) final;
|
||||
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report, bool allowIfInheritsPrincipal) final;
|
||||
NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
|
||||
NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
|
||||
NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
|
||||
NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override;
|
||||
NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetCspJSON(nsAString& outCSPinJSON) override;
|
||||
NS_IMETHOD GetIsNullPrincipal(bool* aResult) override;
|
||||
NS_IMETHOD GetIsCodebasePrincipal(bool* aResult) override;
|
||||
|
||||
+26
-12
@@ -15,12 +15,13 @@ struct JSPrincipals;
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIContentSecurityPolicy;
|
||||
interface nsIDOMDocument;
|
||||
|
||||
[ptr] native JSContext(JSContext);
|
||||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
|
||||
|
||||
[scriptable, builtinclass, uuid(188fc4a2-3157-4956-a7a2-d674991770da)]
|
||||
[scriptable, builtinclass, uuid(d0391e86-1ad7-4ab0-bb7c-14d6d9967369)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
@@ -133,12 +134,19 @@ interface nsIPrincipal : nsISerializable
|
||||
/**
|
||||
* A Content Security Policy associated with this principal.
|
||||
*
|
||||
* Please note that if a csp was already set on the
|
||||
* principal, then it should not be destroyed! Instead, the
|
||||
* current csp should be quried and extended by
|
||||
* calling AppendPolicy() on it.
|
||||
* Use this function to query the associated CSP with this principal.
|
||||
*/
|
||||
[noscript] attribute nsIContentSecurityPolicy csp;
|
||||
[noscript] readonly attribute nsIContentSecurityPolicy csp;
|
||||
|
||||
/*
|
||||
* Use this function to query a CSP associated with this principal.
|
||||
* If no CSP is associated with this principal then one is created
|
||||
* internally and setRequestContext is called on the CSP using aDocument.
|
||||
*
|
||||
* Please note if aDocument is null, then setRequestContext on the
|
||||
* CSP object is called using the current principal.
|
||||
*/
|
||||
[noscript] nsIContentSecurityPolicy ensureCSP(in nsIDOMDocument aDocument);
|
||||
|
||||
/**
|
||||
* A speculative Content Security Policy associated with this
|
||||
@@ -147,13 +155,19 @@ interface nsIPrincipal : nsISerializable
|
||||
*
|
||||
* If you want to query the CSP associated with that principal,
|
||||
* then this is *not* what you want. Instead query 'csp'.
|
||||
*
|
||||
* Please note that if a preloadCSP was already set on the
|
||||
* principal, then it should not be destroyed! Instead, the
|
||||
* current preloadCSP should be quried and extended by
|
||||
* calling AppendPolicy() on it.
|
||||
*/
|
||||
[noscript] attribute nsIContentSecurityPolicy preloadCsp;
|
||||
[noscript] readonly attribute nsIContentSecurityPolicy preloadCsp;
|
||||
|
||||
/*
|
||||
* Use this function to query a speculative CSP associated with this
|
||||
* principal. If no speculative CSP is associated with this principal
|
||||
* then one is created internally and setRequestContext is called on
|
||||
* the CSP using aDocument.
|
||||
*
|
||||
* Please note if aDocument is null, then setRequestContext on the
|
||||
* speculative CSP object is called using the current principal.
|
||||
*/
|
||||
[noscript] nsIContentSecurityPolicy ensurePreloadCSP(in nsIDOMDocument aDocument);
|
||||
|
||||
/**
|
||||
* The CSP of the principal in JSON notation.
|
||||
|
||||
+5
-10
@@ -398,19 +398,14 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
|
||||
rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(supports));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// This may be null.
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp = do_QueryInterface(supports, &rv);
|
||||
|
||||
rv = Init(codebase, attrs);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// need to link in the CSP context here (link in the URI of the protected
|
||||
// resource).
|
||||
if (csp) {
|
||||
csp->SetRequestContext(nullptr, this);
|
||||
mCSP = do_QueryInterface(supports, &rv);
|
||||
// make sure setRequestContext is called after Init(),
|
||||
// to make sure the principals URI been initalized.
|
||||
if (mCSP) {
|
||||
mCSP->SetRequestContext(nullptr, this);
|
||||
}
|
||||
|
||||
SetDomain(domain);
|
||||
|
||||
@@ -70,7 +70,8 @@ nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aCSP)
|
||||
{
|
||||
// CSP on a system principal makes no sense
|
||||
return NS_OK;
|
||||
@@ -84,7 +85,8 @@ nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP)
|
||||
nsSystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument,
|
||||
nsIContentSecurityPolicy** aPreloadCSP)
|
||||
{
|
||||
// CSP on a system principal makes no sense
|
||||
return NS_OK;
|
||||
|
||||
@@ -30,9 +30,9 @@ public:
|
||||
NS_IMETHOD GetDomain(nsIURI** aDomain) override;
|
||||
NS_IMETHOD SetDomain(nsIURI* aDomain) override;
|
||||
NS_IMETHOD GetCsp(nsIContentSecurityPolicy** aCsp) override;
|
||||
NS_IMETHOD SetCsp(nsIContentSecurityPolicy* aCsp) override;
|
||||
NS_IMETHOD EnsureCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) override;
|
||||
NS_IMETHOD SetPreloadCsp(nsIContentSecurityPolicy* aPreloadCSP) override;
|
||||
NS_IMETHOD EnsurePreloadCSP(nsIDOMDocument* aDocument, nsIContentSecurityPolicy** aCSP) override;
|
||||
NS_IMETHOD GetBaseDomain(nsACString& aBaseDomain) override;
|
||||
nsresult GetOriginInternal(nsACString& aOrigin) override;
|
||||
|
||||
|
||||
+5
-6
@@ -28,9 +28,8 @@
|
||||
#include "nsWrapperCacheInlines.h"
|
||||
|
||||
nsIAttribute::nsIAttribute(nsDOMAttributeMap* aAttrMap,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
bool aNsAware)
|
||||
: nsINode(aNodeInfo), mAttrMap(aAttrMap), mNsAware(aNsAware)
|
||||
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
|
||||
: nsINode(aNodeInfo), mAttrMap(aAttrMap)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,8 +45,8 @@ bool Attr::sInitialized;
|
||||
|
||||
Attr::Attr(nsDOMAttributeMap *aAttrMap,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
const nsAString &aValue, bool aNsAware)
|
||||
: nsIAttribute(aAttrMap, aNodeInfo, aNsAware), mValue(aValue)
|
||||
const nsAString &aValue)
|
||||
: nsIAttribute(aAttrMap, aNodeInfo), mValue(aValue)
|
||||
{
|
||||
MOZ_ASSERT(mNodeInfo, "We must get a nodeinfo here!");
|
||||
MOZ_ASSERT(mNodeInfo->NodeType() == nsIDOMNode::ATTRIBUTE_NODE,
|
||||
@@ -262,7 +261,7 @@ Attr::Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
const_cast<Attr*>(this)->GetValue(value);
|
||||
|
||||
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
||||
*aResult = new Attr(nullptr, ni.forget(), value, mNsAware);
|
||||
*aResult = new Attr(nullptr, ni.forget(), value);
|
||||
if (!*aResult) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
+1
-2
@@ -37,8 +37,7 @@ class Attr final : public nsIAttribute,
|
||||
public:
|
||||
Attr(nsDOMAttributeMap* aAttrMap,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
|
||||
const nsAString& aValue,
|
||||
bool aNsAware);
|
||||
const nsAString& aValue);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
|
||||
@@ -1560,7 +1560,7 @@ WebSocketImpl::Init(JSContext* aCx,
|
||||
// to reflect that upgrade. Please note that we can not upgrade from ws:
|
||||
// to wss: before performing content policy checks because CSP needs to
|
||||
// send reports in case the scheme is about to be upgraded.
|
||||
if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests()) {
|
||||
if (!mSecure && originDoc && originDoc->GetUpgradeInsecureRequests(false)) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
NS_ConvertUTF8toUTF16 reportSpec(mURI);
|
||||
|
||||
|
||||
@@ -116,12 +116,6 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
nsContentPolicyType externalType =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternal(contentType);
|
||||
|
||||
nsContentPolicyType externalTypeOrMCBInternal =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentType);
|
||||
|
||||
nsContentPolicyType externalTypeOrCSPInternal =
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(contentType);
|
||||
|
||||
nsCOMPtr<nsIContentPolicy> mixedContentBlocker =
|
||||
do_GetService(NS_MIXEDCONTENTBLOCKER_CONTRACTID);
|
||||
|
||||
@@ -138,27 +132,10 @@ nsContentPolicy::CheckPolicy(CPMethod policyMethod,
|
||||
int32_t count = entries.Count();
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
/* check the appropriate policy */
|
||||
// Send the internal content policy type to the mixed content blocker
|
||||
// which needs to know about TYPE_INTERNAL_WORKER,
|
||||
// TYPE_INTERNAL_SHARED_WORKER and TYPE_INTERNAL_SERVICE_WORKER
|
||||
// and also preloads: TYPE_INTERNAL_SCRIPT_PRELOAD,
|
||||
// TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
bool isMixedContentBlocker = mixedContentBlocker == entries[i];
|
||||
// Send internal content policy type to CSP and mixed content blocker
|
||||
nsContentPolicyType type = externalType;
|
||||
if (isMixedContentBlocker) {
|
||||
type = externalTypeOrMCBInternal;
|
||||
}
|
||||
// Send the internal content policy type for CSP which needs to
|
||||
// know about preloads and workers, in particular:
|
||||
// * TYPE_INTERNAL_SCRIPT_PRELOAD
|
||||
// * TYPE_INTERNAL_IMAGE_PRELOAD
|
||||
// * TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
// * TYPE_INTERNAL_WORKER
|
||||
// * TYPE_INTERNAL_SHARED_WORKER
|
||||
// * TYPE_INTERNAL_SERVICE_WORKER
|
||||
bool isCSP = cspService == entries[i];
|
||||
if (isCSP) {
|
||||
type = externalTypeOrCSPInternal;
|
||||
if (mixedContentBlocker == entries[i] || cspService == entries[i]) {
|
||||
type = contentType;
|
||||
}
|
||||
rv = (entries[i]->*policyMethod)(type, contentLocation,
|
||||
requestingLocation, requestingContext,
|
||||
|
||||
@@ -17,10 +17,7 @@ public:
|
||||
~nsContentTypeParser();
|
||||
|
||||
nsresult GetParameter(const char* aParameterName, nsAString& aResult);
|
||||
nsresult GetType(nsAString& aResult)
|
||||
{
|
||||
return GetParameter(nullptr, aResult);
|
||||
}
|
||||
nsresult GetType(nsAString& aResult);
|
||||
|
||||
private:
|
||||
NS_ConvertUTF16toUTF8 mString;
|
||||
|
||||
+131
-153
@@ -11,7 +11,6 @@
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
|
||||
#include "prprf.h"
|
||||
#include "DecoderTraits.h"
|
||||
#include "harfbuzz/hb.h"
|
||||
#include "imgICache.h"
|
||||
@@ -553,7 +552,7 @@ nsContentUtils::Init()
|
||||
"dom.performance.enable_user_timing_logging", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sIsFrameTimingPrefEnabled,
|
||||
"dom.enable_frame_timing", true);
|
||||
"dom.enable_frame_timing", false);
|
||||
|
||||
Preferences::AddBoolVarCache(&sIsExperimentalAutocompleteEnabled,
|
||||
"dom.forms.autocomplete.experimental", false);
|
||||
@@ -2779,11 +2778,14 @@ nsContentUtils::IsCustomElementName(nsIAtom* aName)
|
||||
{
|
||||
// The custom element name identifies a custom element and is a sequence of
|
||||
// alphanumeric ASCII characters that must match the NCName production and
|
||||
// contain a U+002D HYPHEN-MINUS character.
|
||||
// contain a U+002D HYPHEN-MINUS character. We check for the HYPHEN-MINUS
|
||||
// first, since that will typically not be present, which will allow us to
|
||||
// return before doing the more expensive (and generally passing) CheckQName
|
||||
// check.
|
||||
nsDependentAtomString str(aName);
|
||||
const char16_t* colon;
|
||||
if (NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon ||
|
||||
str.FindChar('-') == -1) {
|
||||
if (str.FindChar('-') == -1 ||
|
||||
NS_FAILED(nsContentUtils::CheckQName(str, false, &colon)) || colon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3528,7 +3530,7 @@ nsContentUtils::ReportToConsoleNonLocalized(const nsAString& aErrorText,
|
||||
}
|
||||
|
||||
void
|
||||
nsContentUtils::LogMessageToConsole(const char* aMsg, ...)
|
||||
nsContentUtils::LogMessageToConsole(const char* aMsg)
|
||||
{
|
||||
if (!sConsoleService) { // only need to bother null-checking here
|
||||
CallGetService(NS_CONSOLESERVICE_CONTRACTID, &sConsoleService);
|
||||
@@ -3536,17 +3538,7 @@ nsContentUtils::LogMessageToConsole(const char* aMsg, ...)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, aMsg);
|
||||
char* formatted = PR_vsmprintf(aMsg, args);
|
||||
va_end(args);
|
||||
if (!formatted) {
|
||||
return;
|
||||
}
|
||||
|
||||
sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(formatted).get());
|
||||
PR_smprintf_free(formatted);
|
||||
sConsoleService->LogStringMessage(NS_ConvertUTF8toUTF16(aMsg).get());
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -6109,12 +6101,21 @@ nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult
|
||||
aResult);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentTypeParser::GetType(nsAString& aResult)
|
||||
{
|
||||
nsresult rv = GetParameter(nullptr, aResult);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsContentUtils::ASCIIToLower(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
||||
bool
|
||||
nsContentUtils::CanAccessNativeAnon()
|
||||
{
|
||||
return IsCallerChrome() || IsCallerContentXBL();
|
||||
return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL();
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
@@ -6640,6 +6641,48 @@ nsContentUtils::FindInternalContentViewer(const nsACString& aType,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void
|
||||
ReportPatternCompileFailure(nsAString& aPattern, nsIDocument* aDocument,
|
||||
JSContext* cx)
|
||||
{
|
||||
MOZ_ASSERT(JS_IsExceptionPending(cx));
|
||||
|
||||
JS::RootedValue exn(cx);
|
||||
if (!JS_GetPendingException(cx, &exn)) {
|
||||
return;
|
||||
}
|
||||
if (!exn.isObject()) {
|
||||
// If pending exception is not an object, it should be OOM.
|
||||
return;
|
||||
}
|
||||
|
||||
JS::AutoSaveExceptionState savedExc(cx);
|
||||
JS::RootedObject exnObj(cx, &exn.toObject());
|
||||
JS::RootedValue messageVal(cx);
|
||||
if (!JS_GetProperty(cx, exnObj, "message", &messageVal)) {
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(messageVal.isString());
|
||||
|
||||
JS::RootedString messageStr(cx, messageVal.toString());
|
||||
MOZ_ASSERT(messageStr);
|
||||
|
||||
nsAutoString wideMessage;
|
||||
if (!AssignJSString(cx, wideMessage, messageStr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsString& pattern = PromiseFlatString(aPattern);
|
||||
const char16_t *strings[] = { pattern.get(), wideMessage.get() };
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
|
||||
NS_LITERAL_CSTRING("DOM"),
|
||||
aDocument,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"PatternAttributeCompileFailure",
|
||||
strings, ArrayLength(strings));
|
||||
savedExc.drop();
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
||||
@@ -6666,8 +6709,12 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
|
||||
JS::Rooted<JSObject*> re(cx,
|
||||
JS_NewUCRegExpObjectNoStatics(cx,
|
||||
static_cast<char16_t*>(aPattern.BeginWriting()),
|
||||
aPattern.Length(), 0));
|
||||
aPattern.Length(), JSREG_UNICODE));
|
||||
if (!re) {
|
||||
// Remove extra patterns added above to report with the original pattern.
|
||||
aPattern.Cut(0, 4);
|
||||
aPattern.Cut(aPattern.Length() - 2, 2);
|
||||
ReportPatternCompileFailure(aPattern, aDocument, cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6784,66 +6831,6 @@ nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
|
||||
return principalsEqual;
|
||||
}
|
||||
|
||||
static void
|
||||
CheckForWindowedPlugins(nsISupports* aSupports, void* aResult)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(aSupports));
|
||||
if (!content || !content->IsInDoc()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(content));
|
||||
if (!olc) {
|
||||
return;
|
||||
}
|
||||
RefPtr<nsNPAPIPluginInstance> plugin;
|
||||
olc->GetPluginInstance(getter_AddRefs(plugin));
|
||||
if (!plugin) {
|
||||
return;
|
||||
}
|
||||
bool isWindowless = false;
|
||||
nsresult res = plugin->IsWindowless(&isWindowless);
|
||||
if (NS_SUCCEEDED(res) && !isWindowless) {
|
||||
*static_cast<bool*>(aResult) = true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
DocTreeContainsWindowedPlugins(nsIDocument* aDoc, void* aResult)
|
||||
{
|
||||
if (!nsContentUtils::IsChromeDoc(aDoc)) {
|
||||
aDoc->EnumerateActivityObservers(CheckForWindowedPlugins, aResult);
|
||||
}
|
||||
if (*static_cast<bool*>(aResult)) {
|
||||
// Return false to stop iteration, we found a windowed plugin.
|
||||
return false;
|
||||
}
|
||||
aDoc->EnumerateSubDocuments(DocTreeContainsWindowedPlugins, aResult);
|
||||
// Return false to stop iteration if we found a windowed plugin in
|
||||
// the sub documents.
|
||||
return !*static_cast<bool*>(aResult);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc)
|
||||
{
|
||||
#ifdef XP_MACOSX
|
||||
// We control dispatch to all mac plugins.
|
||||
return false;
|
||||
#endif
|
||||
bool result = false;
|
||||
|
||||
// Find the top of the document's branch, the child of the chrome document.
|
||||
nsIDocument* doc = aDoc;
|
||||
nsIDocument* parent = nullptr;
|
||||
while (doc && (parent = doc->GetParentDocument()) && !IsChromeDoc(parent)) {
|
||||
doc = parent;
|
||||
}
|
||||
|
||||
DocTreeContainsWindowedPlugins(doc, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
|
||||
@@ -6851,10 +6838,30 @@ nsContentUtils::HasPluginWithUncontrolledEventDispatch(nsIContent* aContent)
|
||||
#ifdef XP_MACOSX
|
||||
// We control dispatch to all mac plugins.
|
||||
return false;
|
||||
#else
|
||||
if (!aContent || !aContent->IsInDoc()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObjectLoadingContent> olc = do_QueryInterface(aContent);
|
||||
if (!olc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<nsNPAPIPluginInstance> plugin;
|
||||
olc->GetPluginInstance(getter_AddRefs(plugin));
|
||||
if (!plugin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isWindowless = false;
|
||||
nsresult res = plugin->IsWindowless(&isWindowless);
|
||||
if (NS_FAILED(res)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isWindowless;
|
||||
#endif
|
||||
bool result = false;
|
||||
CheckForWindowedPlugins(aContent, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* static */
|
||||
@@ -7300,13 +7307,13 @@ nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
|
||||
return inner ? inner->WindowID() : 0;
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
|
||||
{
|
||||
aHost.Truncate();
|
||||
nsresult rv = aURI->GetHost(aHost);
|
||||
if (NS_FAILED(rv)) { // Some URIs do not have a host
|
||||
return;
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aHost.FindChar(':') != -1) { // Escape IPv6 address
|
||||
@@ -7315,14 +7322,20 @@ nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost)
|
||||
aHost.Insert('[', 0);
|
||||
aHost.Append(']');
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsresult
|
||||
nsContentUtils::GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost)
|
||||
{
|
||||
nsAutoCString hostname;
|
||||
GetHostOrIPv6WithBrackets(aURI, hostname);
|
||||
nsresult rv = GetHostOrIPv6WithBrackets(aURI, hostname);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
CopyUTF8toUTF16(hostname, aHost);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -7558,7 +7571,9 @@ nsContentUtils::TransferableToIPCTransferable(nsITransferable* aTransferable,
|
||||
if (IsFileImage(file, type)) {
|
||||
IPCDataTransferItem* item = aIPCDataTransfer->items().AppendElement();
|
||||
item->flavor() = type;
|
||||
SlurpFileToString(file, item->data());
|
||||
nsAutoCString data;
|
||||
SlurpFileToString(file, data);
|
||||
item->data() = data;
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -7870,23 +7885,26 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<nsIPresShell> aPresShell,
|
||||
|
||||
EventMessage msg;
|
||||
bool contextMenuKey = false;
|
||||
if (aType.EqualsLiteral("mousedown"))
|
||||
if (aType.EqualsLiteral("mousedown")) {
|
||||
msg = eMouseDown;
|
||||
else if (aType.EqualsLiteral("mouseup"))
|
||||
} else if (aType.EqualsLiteral("mouseup")) {
|
||||
msg = eMouseUp;
|
||||
else if (aType.EqualsLiteral("mousemove"))
|
||||
} else if (aType.EqualsLiteral("mousemove")) {
|
||||
msg = eMouseMove;
|
||||
else if (aType.EqualsLiteral("mouseover"))
|
||||
} else if (aType.EqualsLiteral("mouseover")) {
|
||||
msg = eMouseEnterIntoWidget;
|
||||
else if (aType.EqualsLiteral("mouseout"))
|
||||
} else if (aType.EqualsLiteral("mouseout")) {
|
||||
msg = eMouseExitFromWidget;
|
||||
else if (aType.EqualsLiteral("contextmenu")) {
|
||||
} else if (aType.EqualsLiteral("mouselongtap")) {
|
||||
msg = eMouseLongTap;
|
||||
} else if (aType.EqualsLiteral("contextmenu")) {
|
||||
msg = eContextMenu;
|
||||
contextMenuKey = (aButton == 0);
|
||||
} else if (aType.EqualsLiteral("MozMouseHittest"))
|
||||
} else if (aType.EqualsLiteral("MozMouseHittest")) {
|
||||
msg = eMouseHitTest;
|
||||
else
|
||||
} else {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aInputSourceArg == nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN) {
|
||||
aInputSourceArg = nsIDOMMouseEvent::MOZ_SOURCE_MOUSE;
|
||||
@@ -8042,35 +8060,6 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SCRIPT:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER:
|
||||
return aType;
|
||||
|
||||
default:
|
||||
return InternalContentPolicyTypeToExternalOrPreload(aType);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrPreload(nsContentPolicyType aType)
|
||||
{
|
||||
if (aType == nsIContentPolicy::TYPE_INTERNAL_SCRIPT_PRELOAD ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD ||
|
||||
aType == nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD) {
|
||||
return aType;
|
||||
}
|
||||
return InternalContentPolicyTypeToExternal(aType);
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(nsContentPolicyType aType)
|
||||
@@ -8098,17 +8087,6 @@ nsContentUtils::IsPreloadType(nsContentPolicyType aType)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsContentPolicyType
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(nsContentPolicyType aType)
|
||||
{
|
||||
if (aType == InternalContentPolicyTypeToExternalOrWorker(aType) ||
|
||||
aType == InternalContentPolicyTypeToExternalOrPreload(aType)) {
|
||||
return aType;
|
||||
}
|
||||
return InternalContentPolicyTypeToExternal(aType);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentUtils::SetFetchReferrerURIWithPolicy(nsIPrincipal* aPrincipal,
|
||||
nsIDocument* aDoc,
|
||||
@@ -8249,6 +8227,24 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
services::GetPermissionManager();
|
||||
if (!permissionManager) {
|
||||
return StorageAccess::eDeny;
|
||||
}
|
||||
|
||||
// check the permission manager for any allow or deny permissions
|
||||
// for cookies for the window.
|
||||
uint32_t perm;
|
||||
permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm);
|
||||
if (perm == nsIPermissionManager::DENY_ACTION) {
|
||||
return StorageAccess::eDeny;
|
||||
} else if (perm == nsICookiePermission::ACCESS_SESSION) {
|
||||
return std::min(access, StorageAccess::eSessionScoped);
|
||||
} else if (perm == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return access;
|
||||
}
|
||||
|
||||
// Check if we should only allow storage for the session, and record that fact
|
||||
if (sCookiesLifetimePolicy == nsICookieService::ACCEPT_SESSION) {
|
||||
// Storage could be StorageAccess::ePrivateBrowsing or StorageAccess::eAllow
|
||||
@@ -8270,24 +8266,6 @@ nsContentUtils::InternalStorageAllowedForPrincipal(nsIPrincipal* aPrincipal,
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPermissionManager> permissionManager =
|
||||
services::GetPermissionManager();
|
||||
if (!permissionManager) {
|
||||
return StorageAccess::eDeny;
|
||||
}
|
||||
|
||||
// check the permission manager for any allow or deny permissions
|
||||
// for cookies for the window.
|
||||
uint32_t perm;
|
||||
permissionManager->TestPermissionFromPrincipal(aPrincipal, "cookie", &perm);
|
||||
if (perm == nsIPermissionManager::DENY_ACTION) {
|
||||
return StorageAccess::eDeny;
|
||||
} else if (perm == nsICookiePermission::ACCESS_SESSION) {
|
||||
return std::min(access, StorageAccess::eSessionScoped);
|
||||
} else if (perm == nsIPermissionManager::ALLOW_ACTION) {
|
||||
return access;
|
||||
}
|
||||
|
||||
// We don't want to prompt for every attempt to access permissions.
|
||||
if (sCookiesBehavior == nsICookieService::BEHAVIOR_REJECT) {
|
||||
return StorageAccess::eDeny;
|
||||
|
||||
@@ -893,8 +893,8 @@ public:
|
||||
uint32_t aLineNumber = 0,
|
||||
uint32_t aColumnNumber = 0);
|
||||
|
||||
static void LogMessageToConsole(const char* aMsg, ...);
|
||||
|
||||
static void LogMessageToConsole(const char* aMsg);
|
||||
|
||||
/**
|
||||
* Get the localized string named |aKey| in properties file |aFile|.
|
||||
*/
|
||||
@@ -984,20 +984,6 @@ public:
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones or script types or preload types:
|
||||
* * TYPE_INTERNAL_SCRIPT
|
||||
* * TYPE_INTERNAL_WORKER
|
||||
* * TYPE_INTERNAL_SHARED_WORKER
|
||||
* * TYPE_INTERNAL_SERVICE_WORKER
|
||||
* * TYPE_INTERNAL_SCRIPT_PRELOAD
|
||||
* * TYPE_INTERNAL_IMAGE_PRELOAD
|
||||
* * TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
*
|
||||
* Note: DO NOT call this function unless you know what you're doing!
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternalOrMCBInternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones or preload types:
|
||||
* * TYPE_INTERNAL_SCRIPT_PRELOAD
|
||||
@@ -1008,19 +994,6 @@ public:
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternalOrPreload(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones, worker, or preload types:
|
||||
* * TYPE_INTERNAL_WORKER
|
||||
* * TYPE_INTERNAL_SHARED_WORKER
|
||||
* * TYPE_INTERNAL_SERVICE_WORKER
|
||||
* * TYPE_INTERNAL_SCRIPT_PRELOAD
|
||||
* * TYPE_INTERNAL_IMAGE_PRELOAD
|
||||
* * TYPE_INTERNAL_STYLESHEET_PRELOAD
|
||||
*
|
||||
* Note: DO NOT call this function unless you know what you're doing!
|
||||
*/
|
||||
static nsContentPolicyType InternalContentPolicyTypeToExternalOrCSPInternal(nsContentPolicyType aType);
|
||||
|
||||
/**
|
||||
* Map internal content policy types to external ones, worker, or preload types:
|
||||
* * TYPE_INTERNAL_WORKER
|
||||
@@ -2061,14 +2034,6 @@ public:
|
||||
return sPrivacyResistFingerprinting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the doc tree branch which contains aDoc contains any
|
||||
* plugins which we don't control event dispatch for, i.e. do any plugins
|
||||
* in the same tab as this document receive key events outside of our
|
||||
* control? This always returns false on MacOSX.
|
||||
*/
|
||||
static bool HasPluginWithUncontrolledEventDispatch(nsIDocument* aDoc);
|
||||
|
||||
/**
|
||||
* Return true if this doc is controlled by a ServiceWorker.
|
||||
*/
|
||||
@@ -2432,8 +2397,8 @@ public:
|
||||
* If the hostname for aURI is an IPv6 it encloses it in brackets,
|
||||
* otherwise it just outputs the hostname in aHost.
|
||||
*/
|
||||
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
|
||||
static void GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
|
||||
static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsAString& aHost);
|
||||
static nsresult GetHostOrIPv6WithBrackets(nsIURI* aURI, nsCString& aHost);
|
||||
|
||||
/*
|
||||
* Call the given callback on all remote children of the given top-level
|
||||
|
||||
@@ -129,35 +129,8 @@ nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName)
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Attr>
|
||||
nsDOMAttributeMap::RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo)
|
||||
{
|
||||
NS_ASSERTION(aNodeInfo, "RemoveAttribute() called with aNodeInfo == nullptr!");
|
||||
|
||||
nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom());
|
||||
|
||||
RefPtr<Attr> node;
|
||||
if (!mAttributeCache.Get(attr, getter_AddRefs(node))) {
|
||||
nsAutoString value;
|
||||
// As we are removing the attribute we need to set the current value in
|
||||
// the attribute node.
|
||||
mContent->GetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), value);
|
||||
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
||||
node = new Attr(nullptr, ni.forget(), value, true);
|
||||
}
|
||||
else {
|
||||
// Break link to map
|
||||
node->SetMap(nullptr);
|
||||
|
||||
// Remove from cache
|
||||
mAttributeCache.Remove(attr);
|
||||
}
|
||||
|
||||
return node.forget();
|
||||
}
|
||||
|
||||
Attr*
|
||||
nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware)
|
||||
nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo)
|
||||
{
|
||||
NS_ASSERTION(aNodeInfo, "GetAttribute() called with aNodeInfo == nullptr!");
|
||||
|
||||
@@ -167,7 +140,7 @@ nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware
|
||||
if (!node) {
|
||||
RefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
|
||||
RefPtr<Attr> newAttr =
|
||||
new Attr(this, ni.forget(), EmptyString(), aNsAware);
|
||||
new Attr(this, ni.forget(), EmptyString());
|
||||
mAttributeCache.Put(attr, newAttr);
|
||||
node = newAttr;
|
||||
}
|
||||
@@ -187,13 +160,51 @@ nsDOMAttributeMap::NamedGetter(const nsAString& aAttrName, bool& aFound)
|
||||
}
|
||||
|
||||
aFound = true;
|
||||
return GetAttribute(ni, false);
|
||||
return GetAttribute(ni);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDOMAttributeMap::NameIsEnumerable(const nsAString& aName)
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMAttributeMap::GetSupportedNames(unsigned aFlags,
|
||||
nsTArray<nsString>& aNames)
|
||||
{
|
||||
if (!(aFlags & JSITER_HIDDEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For HTML elements in HTML documents, only include names that are still the
|
||||
// same after ASCII-lowercasing, since our named getter will end up
|
||||
// ASCII-lowercasing the given string.
|
||||
bool lowercaseNamesOnly =
|
||||
mContent->IsHTMLElement() && mContent->IsInHTMLDocument();
|
||||
|
||||
const uint32_t count = mContent->GetAttrCount();
|
||||
bool seenNonAtomName = false;
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
const nsAttrName* name = mContent->GetAttrNameAt(i);
|
||||
seenNonAtomName = seenNonAtomName || !name->IsAtom();
|
||||
nsString qualifiedName;
|
||||
name->GetQualifiedName(qualifiedName);
|
||||
|
||||
if (lowercaseNamesOnly &&
|
||||
nsContentUtils::StringContainsASCIIUpper(qualifiedName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Omit duplicates. We only need to do this check if we've seen a non-atom
|
||||
// name, because that's the only way we can have two identical qualified
|
||||
// names.
|
||||
if (seenNonAtomName && aNames.Contains(qualifiedName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aNames.AppendElement(qualifiedName);
|
||||
}
|
||||
}
|
||||
|
||||
Attr*
|
||||
@@ -287,38 +298,22 @@ nsDOMAttributeMap::SetNamedItemNS(Attr& aAttr, ErrorResult& aError)
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<Attr> attr;
|
||||
RefPtr<Attr> oldAttr;
|
||||
|
||||
if (oldNi) {
|
||||
RefPtr<Attr> oldAttr = GetAttribute(oldNi, true);
|
||||
oldAttr = GetAttribute(oldNi);
|
||||
|
||||
if (oldAttr == &aAttr) {
|
||||
return oldAttr.forget();
|
||||
}
|
||||
|
||||
if (oldAttr) {
|
||||
attr = RemoveNamedItem(oldNi, aError);
|
||||
NS_ASSERTION(attr->NodeInfo()->NameAndNamespaceEquals(oldNi),
|
||||
"RemoveNamedItem() called, attr->NodeInfo() should be equal to oldNi!");
|
||||
|
||||
// That might have run mutation event listeners, so re-verify
|
||||
// our assumptions.
|
||||
nsDOMAttributeMap* newOwner = aAttr.GetMap();
|
||||
if (newOwner) {
|
||||
if (newOwner == this) {
|
||||
// OK, we're just done here.
|
||||
return attr.forget();
|
||||
}
|
||||
|
||||
// The attr we're trying to set got stuck on some other
|
||||
// element. Just throw, for lack of anything better to do.
|
||||
aError.Throw(NS_ERROR_DOM_INUSE_ATTRIBUTE_ERR);
|
||||
return nullptr;
|
||||
} else if (mContent->OwnerDoc() != aAttr.OwnerDoc()) {
|
||||
// Got moved into a different document, boo.
|
||||
aError.Throw(NS_ERROR_DOM_HIERARCHY_REQUEST_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
// Just remove it from our hashtable. This has no side-effects, so we
|
||||
// don't have to recheck anything after we do it. Then we'll add our new
|
||||
// Attr to the hashtable and do the actual attr set on the element. This
|
||||
// will make the whole thing look like a single attribute mutation (with
|
||||
// the new attr node in place) as opposed to a removal and addition.
|
||||
DropAttribute(oldNi->NamespaceID(), oldNi->NameAtom());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -340,13 +335,13 @@ nsDOMAttributeMap::SetNamedItemNS(Attr& aAttr, ErrorResult& aError)
|
||||
DropAttribute(ni->NamespaceID(), ni->NameAtom());
|
||||
}
|
||||
|
||||
return attr.forget();
|
||||
return oldAttr.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Attr>
|
||||
nsDOMAttributeMap::RemoveNamedItem(NodeInfo* aNodeInfo, ErrorResult& aError)
|
||||
{
|
||||
RefPtr<Attr> attribute = GetAttribute(aNodeInfo, true);
|
||||
RefPtr<Attr> attribute = GetAttribute(aNodeInfo);
|
||||
// This removes the attribute node from the attribute map.
|
||||
aError = mContent->UnsetAttr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom(), true);
|
||||
return attribute.forget();
|
||||
@@ -396,7 +391,7 @@ nsDOMAttributeMap::IndexedGetter(uint32_t aIndex, bool& aFound)
|
||||
RefPtr<mozilla::dom::NodeInfo> ni = mContent->NodeInfo()->NodeInfoManager()->
|
||||
GetNodeInfo(name->LocalName(), name->GetPrefix(), name->NamespaceID(),
|
||||
nsIDOMNode::ATTRIBUTE_NODE);
|
||||
return GetAttribute(ni, true);
|
||||
return GetAttribute(ni);
|
||||
}
|
||||
|
||||
Attr*
|
||||
@@ -447,7 +442,7 @@ nsDOMAttributeMap::GetNamedItemNS(const nsAString& aNamespaceURI,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GetAttribute(ni, true);
|
||||
return GetAttribute(ni);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::NodeInfo>
|
||||
|
||||
@@ -158,10 +158,8 @@ public:
|
||||
RemoveNamedItemNS(const nsAString& aNamespaceURI, const nsAString& aLocalName,
|
||||
ErrorResult& aError);
|
||||
|
||||
void GetSupportedNames(unsigned, nsTArray<nsString>& aNames)
|
||||
{
|
||||
// No supported names we want to show up in iteration.
|
||||
}
|
||||
void
|
||||
GetSupportedNames(unsigned aFlags, nsTArray<nsString>& aNames);
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
@@ -180,12 +178,7 @@ private:
|
||||
GetAttrNodeInfo(const nsAString& aNamespaceURI,
|
||||
const nsAString& aLocalName);
|
||||
|
||||
Attr* GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware);
|
||||
|
||||
/**
|
||||
* Remove an attribute, returns the removed node.
|
||||
*/
|
||||
already_AddRefed<Attr> RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo);
|
||||
Attr* GetAttribute(mozilla::dom::NodeInfo* aNodeInfo);
|
||||
};
|
||||
|
||||
// XXX khuey yes this is crazy. The bindings code needs to see this include,
|
||||
|
||||
@@ -3857,9 +3857,11 @@ nsDOMWindowUtils::SetNextPaintSyncId(int32_t aSyncId)
|
||||
if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
|
||||
ClientLayerManager* clm = static_cast<ClientLayerManager*>(lm.get());
|
||||
clm->SetNextPaintSyncId(aSyncId);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_WARNING("Paint sync id could not be set on the ClientLayerManager");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
+32
-29
@@ -2272,7 +2272,7 @@ nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
||||
|
||||
// Refresh the principal on the compartment.
|
||||
if (nsPIDOMWindowInner* win = GetInnerWindow()) {
|
||||
win->RefreshCompartmentPrincipal();
|
||||
nsGlobalWindow::Cast(win)->RefreshCompartmentPrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2549,12 +2549,12 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
|
||||
if (sameTypeParent) {
|
||||
mUpgradeInsecureRequests =
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests();
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(false);
|
||||
// if the parent document makes use of upgrade-insecure-requests
|
||||
// then subdocument preloads should always be upgraded.
|
||||
mUpgradeInsecurePreloads =
|
||||
mUpgradeInsecureRequests ||
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecurePreloads();
|
||||
sameTypeParent->GetDocument()->GetUpgradeInsecureRequests(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2660,6 +2660,9 @@ nsDocument::ApplySettingsFromCSP(bool aSpeculative)
|
||||
rv = csp->GetUpgradeInsecureRequests(&mUpgradeInsecureRequests);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
if (!mUpgradeInsecurePreloads) {
|
||||
mUpgradeInsecurePreloads = mUpgradeInsecureRequests;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -2784,19 +2787,8 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
}
|
||||
}
|
||||
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug, ("Failed to create CSP object: %x", rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
// used as a "self" identifier for the CSP.
|
||||
nsCOMPtr<nsIURI> selfURI;
|
||||
aChannel->GetURI(getter_AddRefs(selfURI));
|
||||
|
||||
// Store the request context for violation reports
|
||||
csp->SetRequestContext(this, nullptr);
|
||||
rv = principal->EnsureCSP(this, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// ----- if the doc is an app and we want a default CSP, apply it.
|
||||
if (applyAppDefaultCSP) {
|
||||
@@ -2846,14 +2838,7 @@ nsDocument::InitCSP(nsIChannel* aChannel)
|
||||
aChannel->Cancel(NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
MOZ_LOG(gCspPRLog, LogLevel::Debug,
|
||||
("Inserted CSP into principal %p", principal));
|
||||
|
||||
ApplySettingsFromCSP(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -3802,8 +3787,8 @@ nsIDocument::ShouldThrottleFrameRequests()
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mIsShowing) {
|
||||
// We're not showing (probably in a background tab or the bf cache).
|
||||
if (Hidden()) {
|
||||
// We're not visible (probably in a background tab or the bf cache).
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5711,7 +5696,7 @@ nsIDocument::CreateAttribute(const nsAString& aName, ErrorResult& rv)
|
||||
}
|
||||
|
||||
RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
|
||||
EmptyString(), false);
|
||||
EmptyString());
|
||||
return attribute.forget();
|
||||
}
|
||||
|
||||
@@ -5744,7 +5729,7 @@ nsIDocument::CreateAttributeNS(const nsAString& aNamespaceURI,
|
||||
}
|
||||
|
||||
RefPtr<Attr> attribute = new Attr(nullptr, nodeInfo.forget(),
|
||||
EmptyString(), true);
|
||||
EmptyString());
|
||||
return attribute.forget();
|
||||
}
|
||||
|
||||
@@ -7818,7 +7803,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
// pixel an integer, and we want the adjusted value.
|
||||
float fullZoom = context ? context->DeviceContext()->GetFullZoom() : 1.0;
|
||||
fullZoom = (fullZoom == 0.0) ? 1.0 : fullZoom;
|
||||
CSSToLayoutDeviceScale layoutDeviceScale = context->CSSToDevPixelScale();
|
||||
CSSToLayoutDeviceScale layoutDeviceScale = context ? context->CSSToDevPixelScale() : CSSToLayoutDeviceScale(1);
|
||||
|
||||
CSSToScreenScale defaultScale = layoutDeviceScale
|
||||
* LayoutDeviceToScreenScale(1.0);
|
||||
@@ -8031,7 +8016,7 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
|
||||
// We need to perform a conversion, but only if the initial or maximum
|
||||
// scale were set explicitly by the user.
|
||||
if (mValidScaleFloat) {
|
||||
if (mValidScaleFloat && scaleFloat >= scaleMinFloat && scaleFloat <= scaleMaxFloat) {
|
||||
CSSSize displaySize = ScreenSize(aDisplaySize) / scaleFloat;
|
||||
size.width = std::max(size.width, displaySize.width);
|
||||
size.height = std::max(size.height, displaySize.height);
|
||||
@@ -10837,6 +10822,24 @@ nsIDocument::ObsoleteSheet(const nsAString& aSheetURI, ErrorResult& rv)
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<nsIURI>
|
||||
nsIDocument::GetMozDocumentURIIfNotForErrorPages()
|
||||
{
|
||||
if (mFailedChannel) {
|
||||
nsCOMPtr<nsIURI> failedURI;
|
||||
if (NS_SUCCEEDED(mFailedChannel->GetURI(getter_AddRefs(failedURI)))) {
|
||||
return failedURI.forget();
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri = GetDocumentURIObject();
|
||||
if (!uri) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return uri.forget();
|
||||
}
|
||||
|
||||
nsIHTMLCollection*
|
||||
nsIDocument::Children()
|
||||
{
|
||||
|
||||
@@ -478,7 +478,7 @@ public:
|
||||
bool DispatchResizeEvent(const mozilla::CSSIntSize& aSize);
|
||||
|
||||
// Inner windows only.
|
||||
virtual void RefreshCompartmentPrincipal() override;
|
||||
void RefreshCompartmentPrincipal();
|
||||
|
||||
// For accessing protected field mFullScreen
|
||||
friend class FullscreenTransitionTask;
|
||||
|
||||
@@ -41,13 +41,11 @@ public:
|
||||
protected:
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
nsIAttribute(nsDOMAttributeMap *aAttrMap,
|
||||
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
|
||||
bool aNsAware);
|
||||
already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
|
||||
#endif //MOZILLA_INTERNAL_API
|
||||
virtual ~nsIAttribute();
|
||||
|
||||
RefPtr<nsDOMAttributeMap> mAttrMap;
|
||||
bool mNsAware;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIAttribute, NS_IATTRIBUTE_IID)
|
||||
|
||||
@@ -329,19 +329,14 @@ public:
|
||||
* of the document's ancestors up to the toplevel document makes use
|
||||
* of the CSP directive 'upgrade-insecure-requests'.
|
||||
*/
|
||||
bool GetUpgradeInsecureRequests() const
|
||||
bool GetUpgradeInsecureRequests(bool aPreload) const
|
||||
{
|
||||
if (aPreload) {
|
||||
return mUpgradeInsecurePreloads;
|
||||
}
|
||||
return mUpgradeInsecureRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as GetUpgradeInsecureRequests() but *only* for preloads.
|
||||
*/
|
||||
bool GetUpgradeInsecurePreloads() const
|
||||
{
|
||||
return mUpgradeInsecurePreloads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the principal responsible for this document.
|
||||
*/
|
||||
@@ -2627,6 +2622,8 @@ public:
|
||||
|
||||
void ObsoleteSheet(const nsAString& aSheetURI, mozilla::ErrorResult& rv);
|
||||
|
||||
already_AddRefed<nsIURI> GetMozDocumentURIIfNotForErrorPages();
|
||||
|
||||
// ParentNode
|
||||
nsIHTMLCollection* Children();
|
||||
uint32_t ChildElementCount();
|
||||
|
||||
@@ -516,14 +516,6 @@ public:
|
||||
*/
|
||||
virtual bool DispatchCustomEvent(const nsAString& aEventName) = 0;
|
||||
|
||||
/**
|
||||
* Call when the document principal may have changed and the compartment
|
||||
* principal needs to be updated.
|
||||
*
|
||||
* Inner windows only.
|
||||
*/
|
||||
virtual void RefreshCompartmentPrincipal() = 0;
|
||||
|
||||
/**
|
||||
* Like nsIDOMWindow::Open, except that we don't navigate to the given URL.
|
||||
*
|
||||
|
||||
@@ -1744,7 +1744,7 @@ HTMLFormElement::GetActionURL(nsIURI** aActionURL,
|
||||
bool isHttpScheme = false;
|
||||
rv = actionURL->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests()) {
|
||||
if (isHttpScheme && document->GetUpgradeInsecureRequests(false)) {
|
||||
// let's use the old specification before the upgrade for logging
|
||||
nsAutoCString spec;
|
||||
rv = actionURL->GetSpec(spec);
|
||||
|
||||
@@ -129,26 +129,13 @@ HTMLMetaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
|
||||
nsIPrincipal* principal = aDocument->NodePrincipal();
|
||||
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
||||
rv = principal->GetCsp(getter_AddRefs(csp));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
|
||||
rv = principal->EnsureCSP(domDoc, getter_AddRefs(csp));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Multiple CSPs (delivered through either header of meta tag) need to be
|
||||
// joined together, see:
|
||||
// https://w3c.github.io/webappsec/specs/content-security-policy/#delivery-html-meta-element
|
||||
if (!csp) {
|
||||
csp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Store the request context so CSP can resolve 'self'
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(aDocument);
|
||||
rv = csp->SetRequestContext(domDoc, nullptr);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// set the new CSP
|
||||
rv = principal->SetCsp(csp);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
rv = csp->AppendPolicy(content,
|
||||
false, // csp via meta tag can not be report only
|
||||
true); // delivered through the meta tag
|
||||
|
||||
@@ -891,8 +891,8 @@ nsHTMLDocument::GetDomain(nsAString& aDomain)
|
||||
}
|
||||
|
||||
nsAutoCString hostName;
|
||||
|
||||
if (NS_SUCCEEDED(uri->GetHost(hostName))) {
|
||||
nsresult rv = nsContentUtils::GetHostOrIPv6WithBrackets(uri, hostName);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
CopyUTF8toUTF16(hostName, aDomain);
|
||||
} else {
|
||||
// If we can't get the host from the URI (e.g. about:, javascript:,
|
||||
@@ -3262,6 +3262,12 @@ nsHTMLDocument::ExecCommand(const nsAString& commandID,
|
||||
}
|
||||
|
||||
if (!nsContentUtils::IsCutCopyAllowed()) {
|
||||
// We have rejected the event due to it not being performed in an
|
||||
// input-driven context therefore, we report the error to the console.
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), this,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
"ExecCommandCutCopyDeniedNotInputDriven");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,12 @@ function checkInvalidPattern(element, completeCheck)
|
||||
}
|
||||
}
|
||||
|
||||
function checkSyntaxError(element)
|
||||
{
|
||||
ok(!element.validity.patternMismatch,
|
||||
"On SyntaxError, element should not suffer");
|
||||
}
|
||||
|
||||
function checkPatternValidity(element)
|
||||
{
|
||||
element.pattern = "foo";
|
||||
@@ -165,17 +171,6 @@ function checkPatternValidity(element)
|
||||
element.value = "foo";
|
||||
checkInvalidPattern(element);
|
||||
|
||||
// We need '\\\\' because '\\' will produce '\\' and we want to escape the '\'
|
||||
// for the regexp.
|
||||
element.pattern = "foo\\\\bar";
|
||||
element.value = "foo\\bar";
|
||||
checkValidPattern(element);
|
||||
|
||||
// The same way, we want to escape the ' in the pattern.
|
||||
element.pattern = "foo\\'bar";
|
||||
element.value = "foo'bar";
|
||||
checkValidPattern(element);
|
||||
|
||||
// Check for 'i' flag disabled. Should be case sensitive.
|
||||
element.value = "Foo";
|
||||
checkInvalidPattern(element);
|
||||
@@ -183,6 +178,20 @@ function checkPatternValidity(element)
|
||||
// We can't check for the 'g' flag because we only test, we don't execute.
|
||||
// We can't check for the 'm' flag because .value shouldn't contain line breaks.
|
||||
|
||||
// We need '\\\\' because '\\' will produce '\\' and we want to escape the '\'
|
||||
// for the regexp.
|
||||
element.pattern = "foo\\\\bar";
|
||||
element.value = "foo\\bar";
|
||||
checkValidPattern(element);
|
||||
|
||||
// We may want to escape the ' in the pattern, but this is a SyntaxError
|
||||
// when unicode flag is set.
|
||||
element.pattern = "foo\\'bar";
|
||||
element.value = "foo'bar";
|
||||
checkSyntaxError(element);
|
||||
element.value = "baz";
|
||||
checkSyntaxError(element);
|
||||
|
||||
// We should check the pattern attribute do not pollute |RegExp.lastParen|.
|
||||
is(RegExp.lastParen, "", "RegExp.lastParen should be the empty string");
|
||||
|
||||
@@ -254,6 +263,33 @@ function checkPatternValidity(element)
|
||||
|
||||
element.removeAttribute('pattern');
|
||||
checkValidPattern(element, true);
|
||||
|
||||
// Unicode pattern
|
||||
for (var pattern of ["\\u{1F438}{2}", "\u{1F438}{2}",
|
||||
"\\uD83D\\uDC38{2}", "\uD83D\uDC38{2}",
|
||||
"\u{D83D}\u{DC38}{2}"]) {
|
||||
element.pattern = pattern;
|
||||
|
||||
element.value = "\u{1F438}\u{1F438}";
|
||||
checkValidPattern(element);
|
||||
|
||||
element.value = "\uD83D\uDC38\uD83D\uDC38";
|
||||
checkValidPattern(element);
|
||||
|
||||
element.value = "\uD83D\uDC38\uDC38";
|
||||
checkInvalidPattern(element);
|
||||
}
|
||||
|
||||
element.pattern = "\\u{D83D}\\u{DC38}{2}";
|
||||
|
||||
element.value = "\u{1F438}\u{1F438}";
|
||||
checkInvalidPattern(element);
|
||||
|
||||
element.value = "\uD83D\uDC38\uD83D\uDC38";
|
||||
checkInvalidPattern(element);
|
||||
|
||||
element.value = "\uD83D\uDC38\uDC38";
|
||||
checkInvalidPattern(element);
|
||||
}
|
||||
|
||||
var input = document.getElementById('i');
|
||||
|
||||
@@ -189,6 +189,8 @@ InterceptionCanceledWithURL=Failed to load '%S'. A ServiceWorker canceled the lo
|
||||
InterceptionRejectedResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that rejected with '%2$S'.
|
||||
# LOCALIZATION NOTE: Do not translate "ServiceWorker", "promise", "FetchEvent.respondWith()", or "Response". %1$S is a URL. %2$S is an error string.
|
||||
InterceptedNonResponseWithURL=Failed to load '%1$S'. A ServiceWorker passed a promise to FetchEvent.respondWith() that resolved with non-Response value '%2$S'.
|
||||
ExecCommandCutCopyDeniedNotInputDriven=document.execCommand('cut'/'copy') was denied because it was not called from inside a short running user-generated event handler.
|
||||
PatternAttributeCompileFailure=Unable to check <input pattern='%S'> because the pattern is not a valid regexp: %S
|
||||
# LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port
|
||||
RewriteYoutubeEmbed=Rewriting old-style Youtube Flash embed (%S) to iframe embed (%S). Please update page to use iframe instead of embed/object, if possible.
|
||||
# LOCALIZATION NOTE: Do not translate 'youtube'. %S values are origins, like https://domain.com:port
|
||||
|
||||
@@ -61,16 +61,14 @@ add_test(function test_saveAppStats() {
|
||||
do_check_eq(cachedStats[key1].serviceType.length, 0);
|
||||
do_check_eq(cachedStats[key1].networkId, wifi.id);
|
||||
do_check_eq(cachedStats[key1].networkType, wifi.type);
|
||||
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedStats[key1].date.getTime(), timestamp);
|
||||
do_check_eq(cachedStats[key1].rxBytes, 10);
|
||||
do_check_eq(cachedStats[key1].txBytes, 20);
|
||||
do_check_eq(cachedStats[key2].appId, 1);
|
||||
do_check_eq(cachedStats[key1].serviceType.length, 0);
|
||||
do_check_eq(cachedStats[key2].networkId, mobile.id);
|
||||
do_check_eq(cachedStats[key2].networkType, mobile.type);
|
||||
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedStats[key2].date.getTime(), timestamp);
|
||||
do_check_eq(cachedStats[key2].rxBytes, 10);
|
||||
do_check_eq(cachedStats[key2].txBytes, 20);
|
||||
|
||||
@@ -113,16 +111,14 @@ add_test(function test_saveServiceStats() {
|
||||
do_check_eq(cachedStats[key1].serviceType, serviceType);
|
||||
do_check_eq(cachedStats[key1].networkId, wifi.id);
|
||||
do_check_eq(cachedStats[key1].networkType, wifi.type);
|
||||
do_check_eq(new Date(cachedStats[key1].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedStats[key1].date.getTime(), timestamp);
|
||||
do_check_eq(cachedStats[key1].rxBytes, 10);
|
||||
do_check_eq(cachedStats[key1].txBytes, 20);
|
||||
do_check_eq(cachedStats[key2].appId, 0);
|
||||
do_check_eq(cachedStats[key1].serviceType, serviceType);
|
||||
do_check_eq(cachedStats[key2].networkId, mobile.id);
|
||||
do_check_eq(cachedStats[key2].networkType, mobile.type);
|
||||
do_check_eq(new Date(cachedStats[key2].date).getTime() / 1000,
|
||||
Math.floor(timestamp / 1000));
|
||||
do_check_eq(cachedStats[key2].date.getTime(), timestamp);
|
||||
do_check_eq(cachedStats[key2].rxBytes, 10);
|
||||
do_check_eq(cachedStats[key2].txBytes, 20);
|
||||
|
||||
@@ -157,8 +153,7 @@ add_test(function test_saveStatsWithDifferentDates() {
|
||||
do_check_eq(cachedStats[key].isInBrowser, false);
|
||||
do_check_eq(cachedStats[key].networkId, mobile.id);
|
||||
do_check_eq(cachedStats[key].networkType, mobile.type);
|
||||
do_check_eq(new Date(cachedStats[key].date).getTime() / 1000,
|
||||
Math.floor(tomorrow.getTime() / 1000));
|
||||
do_check_eq(cachedStats[key].date.getTime(), tomorrow.getTime());
|
||||
do_check_eq(cachedStats[key].rxBytes, 30);
|
||||
do_check_eq(cachedStats[key].txBytes, 40);
|
||||
|
||||
|
||||
@@ -424,7 +424,9 @@ nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
|
||||
|
||||
// use selfURI as the sourceFile
|
||||
nsAutoCString sourceFile;
|
||||
mSelfURI->GetSpec(sourceFile);
|
||||
if (mSelfURI) {
|
||||
mSelfURI->GetSpec(sourceFile);
|
||||
}
|
||||
|
||||
nsAutoString codeSample(aContent);
|
||||
// cap the length of the script sample at 40 chars
|
||||
|
||||
@@ -102,10 +102,6 @@ CSPService::ShouldLoad(uint32_t aContentType,
|
||||
nsIPrincipal *aRequestPrincipal,
|
||||
int16_t *aDecision)
|
||||
{
|
||||
MOZ_ASSERT(aContentType ==
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(aContentType),
|
||||
"We should only see external content policy types or CSP special types (preloads or workers) here.");
|
||||
|
||||
if (!aContentLocation) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -250,10 +246,6 @@ CSPService::ShouldProcess(uint32_t aContentType,
|
||||
nsIPrincipal *aRequestPrincipal,
|
||||
int16_t *aDecision)
|
||||
{
|
||||
MOZ_ASSERT(aContentType ==
|
||||
nsContentUtils::InternalContentPolicyTypeToExternalOrCSPInternal(aContentType),
|
||||
"We should only see external content policy types or preloads here.");
|
||||
|
||||
if (!aContentLocation)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
|
||||
@@ -310,7 +310,7 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
}
|
||||
|
||||
int16_t decision = REJECT_REQUEST;
|
||||
rv = ShouldLoad(nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(contentPolicyType),
|
||||
rv = ShouldLoad(contentPolicyType,
|
||||
newUri,
|
||||
requestingLocation,
|
||||
loadInfo->LoadingNode(),
|
||||
@@ -323,7 +323,6 @@ nsMixedContentBlocker::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
|
||||
// If the channel is about to load mixed content, abort the channel
|
||||
if (!NS_CP_ACCEPTED(decision)) {
|
||||
autoCallback.DontCallback();
|
||||
aOldChannel->Cancel(NS_ERROR_DOM_BAD_URI);
|
||||
return NS_BINDING_FAILED;
|
||||
}
|
||||
|
||||
@@ -379,9 +378,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
// to them.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternalOrMCBInternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
|
||||
bool isPreload = nsContentUtils::IsPreloadType(aContentType);
|
||||
|
||||
// The content policy type that we receive may be an internal type for
|
||||
@@ -671,7 +667,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
|
||||
bool isHttpScheme = false;
|
||||
rv = aContentLocation->SchemeIs("http", &isHttpScheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests()) {
|
||||
if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests(isPreload)) {
|
||||
*aDecision = ACCEPT;
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -898,8 +894,7 @@ nsMixedContentBlocker::ShouldProcess(uint32_t aContentType,
|
||||
nsIPrincipal* aRequestPrincipal,
|
||||
int16_t* aDecision)
|
||||
{
|
||||
MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
|
||||
"We should only see external content policy types here.");
|
||||
aContentType = nsContentUtils::InternalContentPolicyTypeToExternal(aContentType);
|
||||
|
||||
if (!aContentLocation) {
|
||||
// aContentLocation may be null when a plugin is loading without an associated URI resource
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<body>
|
||||
<script>
|
||||
parent.postMessage(SpecialPowers.wrap(localStorage).isSessionOnly, "*");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,6 +16,7 @@ support-files =
|
||||
interOriginTest.js
|
||||
interOriginTest2.js
|
||||
localStorageCommon.js
|
||||
frameLocalStorageSessionOnly.html
|
||||
|
||||
[test_appIsolation.html]
|
||||
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 793211 # b2g(needs https to work) b2g-debug(needs https to work) b2g-desktop(needs https to work)
|
||||
@@ -56,3 +57,4 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(needs https
|
||||
skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'android'
|
||||
[test_lowDeviceStorage.html]
|
||||
[test_storageConstructor.html]
|
||||
[test_localStorageSessionPrefOverride.html]
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Local Storage Session Pref Override</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<script>
|
||||
const ACCEPT_SESSION = 2;
|
||||
|
||||
add_task(function*() {
|
||||
yield new Promise((resolve, reject) => {
|
||||
SpecialPowers.pushPrefEnv({"set": [["network.cookie.lifetimePolicy",
|
||||
ACCEPT_SESSION]]},
|
||||
resolve);
|
||||
});
|
||||
|
||||
// Before setting permission
|
||||
yield new Promise((resolve) => {
|
||||
var frame = document.createElement('iframe');
|
||||
frame.src = "frameLocalStorageSessionOnly.html";
|
||||
|
||||
var listener = (e) => {
|
||||
is(e.data, true, "Before adding permission should be session only");
|
||||
window.removeEventListener('message', listener);
|
||||
resolve();
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
document.body.appendChild(frame);
|
||||
});
|
||||
|
||||
// After setting permission
|
||||
yield new Promise((resolve) => {
|
||||
SpecialPowers.pushPermissions([{"type": "cookie", "allow": 1, "context": document}],
|
||||
resolve);
|
||||
});
|
||||
|
||||
yield new Promise((resolve) => {
|
||||
var frame = document.createElement('iframe');
|
||||
frame.src = "frameLocalStorageSessionOnly.html";
|
||||
|
||||
var listener = (e) => {
|
||||
is(e.data, false, "After adding permission should not be session only");
|
||||
window.removeEventListener('message', listener);
|
||||
resolve();
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
document.body.appendChild(frame);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -259,17 +259,12 @@ partial interface Document {
|
||||
Element createElementNS(DOMString? namespace, DOMString qualifiedName, DOMString typeExtension);
|
||||
};
|
||||
|
||||
// https://w3c.github.io/page-visibility/#extensions-to-the-document-interface
|
||||
// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html#sec-document-interface
|
||||
partial interface Document {
|
||||
[Pref="dom.visibilityAPI.enabled"]
|
||||
readonly attribute boolean hidden;
|
||||
[Pref="dom.visibilityAPI.enabled"]
|
||||
readonly attribute boolean mozHidden;
|
||||
[Pref="dom.visibilityAPI.enabled"]
|
||||
readonly attribute VisibilityState visibilityState;
|
||||
[Pref="dom.visibilityAPI.enabled"]
|
||||
readonly attribute VisibilityState mozVisibilityState;
|
||||
[Pref="dom.visibilityAPI.enabled"]
|
||||
attribute EventHandler onvisibilitychange;
|
||||
};
|
||||
|
||||
@@ -377,6 +372,10 @@ partial interface Document {
|
||||
[ChromeOnly] readonly attribute DOMString contentLanguage;
|
||||
|
||||
[ChromeOnly] readonly attribute nsILoadGroup? documentLoadGroup;
|
||||
|
||||
// like documentURI, except that for error pages, it returns the URI we were
|
||||
// trying to load when we hit an error, rather than the error page's own URI.
|
||||
[ChromeOnly] readonly attribute URI? mozDocumentURIIfNotForErrorPages;
|
||||
};
|
||||
|
||||
// Extension to give chrome JS the ability to determine when a document was
|
||||
|
||||
@@ -29,4 +29,7 @@ interface Storage {
|
||||
|
||||
[Throws]
|
||||
void clear();
|
||||
|
||||
[ChromeOnly]
|
||||
readonly attribute boolean isSessionOnly;
|
||||
};
|
||||
|
||||
@@ -231,13 +231,13 @@ struct LayerPropertiesBase : public LayerProperties
|
||||
return result;
|
||||
}
|
||||
|
||||
IntRect NewTransformedBounds()
|
||||
virtual IntRect NewTransformedBounds()
|
||||
{
|
||||
return TransformRect(mLayer->GetVisibleRegion().ToUnknownRegion().GetBounds(),
|
||||
GetTransformForInvalidation(mLayer));
|
||||
}
|
||||
|
||||
IntRect OldTransformedBounds()
|
||||
virtual IntRect OldTransformedBounds()
|
||||
{
|
||||
return TransformRect(mVisibleRegion.ToUnknownRegion().GetBounds(), mTransform);
|
||||
}
|
||||
@@ -273,8 +273,8 @@ struct ContainerLayerProperties : public LayerPropertiesBase
|
||||
}
|
||||
}
|
||||
|
||||
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
|
||||
bool& aGeometryChanged)
|
||||
nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
|
||||
bool& aGeometryChanged) override
|
||||
{
|
||||
ContainerLayer* container = mLayer->AsContainerLayer();
|
||||
nsIntRegion invalidOfLayer; // Invalid regions of this layer.
|
||||
@@ -382,6 +382,31 @@ struct ContainerLayerProperties : public LayerPropertiesBase
|
||||
return result;
|
||||
}
|
||||
|
||||
IntRect NewTransformedBounds() override
|
||||
{
|
||||
if (mLayer->Extend3DContext()) {
|
||||
IntRect result;
|
||||
for (UniquePtr<LayerPropertiesBase>& child : mChildren) {
|
||||
result = result.Union(child->NewTransformedBounds());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return LayerPropertiesBase::NewTransformedBounds();
|
||||
}
|
||||
|
||||
IntRect OldTransformedBounds() override
|
||||
{
|
||||
if (mLayer->Extend3DContext()) {
|
||||
IntRect result;
|
||||
for (UniquePtr<LayerPropertiesBase>& child : mChildren) {
|
||||
result = result.Union(child->OldTransformedBounds());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return LayerPropertiesBase::OldTransformedBounds();
|
||||
}
|
||||
|
||||
// The old list of children:
|
||||
AutoTArray<UniquePtr<LayerPropertiesBase>,1> mChildren;
|
||||
float mPreXScale;
|
||||
|
||||
@@ -244,7 +244,6 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
|
||||
aLoadInfo->InternalContentPolicyType(),
|
||||
static_cast<uint32_t>(aLoadInfo->GetTainting()),
|
||||
aLoadInfo->GetUpgradeInsecureRequests(),
|
||||
aLoadInfo->GetUpgradeInsecurePreloads(),
|
||||
aLoadInfo->GetInnerWindowID(),
|
||||
aLoadInfo->GetOuterWindowID(),
|
||||
aLoadInfo->GetParentOuterWindowID(),
|
||||
@@ -304,7 +303,6 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
|
||||
loadInfoArgs.contentPolicyType(),
|
||||
static_cast<LoadTainting>(loadInfoArgs.tainting()),
|
||||
loadInfoArgs.upgradeInsecureRequests(),
|
||||
loadInfoArgs.upgradeInsecurePreloads(),
|
||||
loadInfoArgs.innerWindowID(),
|
||||
loadInfoArgs.outerWindowID(),
|
||||
loadInfoArgs.parentOuterWindowID(),
|
||||
|
||||
@@ -1162,6 +1162,12 @@ ObjectBox::asFunctionBox()
|
||||
return static_cast<FunctionBox*>(this);
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectBox::isModuleBox()
|
||||
{
|
||||
return object->is<ModuleObject>();
|
||||
}
|
||||
|
||||
ModuleBox*
|
||||
ObjectBox::asModuleBox()
|
||||
{
|
||||
|
||||
@@ -1719,7 +1719,7 @@ class ObjectBox
|
||||
ObjectBox(JSObject* object, ObjectBox* traceLink);
|
||||
bool isFunctionBox() { return object->is<JSFunction>(); }
|
||||
FunctionBox* asFunctionBox();
|
||||
bool isModuleBox() { return object->is<ModuleObject>(); }
|
||||
bool isModuleBox();
|
||||
ModuleBox* asModuleBox();
|
||||
virtual void trace(JSTracer* trc);
|
||||
|
||||
|
||||
@@ -31,9 +31,6 @@ using mozilla::MakeRange;
|
||||
using mozilla::PodArrayZero;
|
||||
using mozilla::PodZero;
|
||||
|
||||
/* Except for the first and last, slices of less than 10ms are not reported. */
|
||||
static const int64_t SLICE_MIN_REPORT_TIME = 10 * PRMJ_USEC_PER_MSEC;
|
||||
|
||||
const char*
|
||||
js::gcstats::ExplainInvocationKind(JSGCInvocationKind gckind)
|
||||
{
|
||||
|
||||
+141
-51
@@ -700,6 +700,26 @@ ParseDigitsN(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read and convert n or less decimal digits from s[*i]
|
||||
* to s[min(*i+n,limit)] into *result.
|
||||
*
|
||||
* Succeed only if greater than zero but less than or equal to n digits are
|
||||
* converted. Advance *i only on success.
|
||||
*/
|
||||
template <typename CharT>
|
||||
static bool
|
||||
ParseDigitsNOrLess(size_t n, size_t* result, const CharT* s, size_t* i, size_t limit)
|
||||
{
|
||||
size_t init = *i;
|
||||
|
||||
if (ParseDigits(result, s, i, Min(limit, init + n)))
|
||||
return ((*i - init) > 0) && ((*i - init) <= n);
|
||||
|
||||
*i = init;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
DaysInMonth(int year, int month)
|
||||
{
|
||||
@@ -713,11 +733,6 @@ DaysInMonth(int year, int month)
|
||||
* "NOTE-datetime" specification. These formats make up a restricted
|
||||
* profile of the ISO 8601 format. Quoted here:
|
||||
*
|
||||
* The formats are as follows. Exactly the components shown here
|
||||
* must be present, with exactly this punctuation. Note that the "T"
|
||||
* appears literally in the string, to indicate the beginning of the
|
||||
* time element, as specified in ISO 8601.
|
||||
*
|
||||
* Any combination of the date formats with the time formats is
|
||||
* allowed, and also either the date or the time can be missing.
|
||||
*
|
||||
@@ -730,6 +745,12 @@ DaysInMonth(int year, int month)
|
||||
* 00:00 UTC. If the time is present but the time zone field is
|
||||
* missing then we use local time.
|
||||
*
|
||||
* For the sake of cross compatibility with other implementations we
|
||||
* make a few exceptions to the standard: months, days, hours, minutes
|
||||
* and seconds may be either one or two digits long, and the 'T' from
|
||||
* the time part may be replaced with a space. Given that, a date time
|
||||
* like "1999-1-1 1:1:1" will parse successfully.
|
||||
*
|
||||
* Date part:
|
||||
*
|
||||
* Year:
|
||||
@@ -755,17 +776,17 @@ DaysInMonth(int year, int month)
|
||||
* where:
|
||||
*
|
||||
* YYYY = four-digit year or six digit year as +YYYYYY or -YYYYYY
|
||||
* MM = two-digit month (01=January, etc.)
|
||||
* DD = two-digit day of month (01 through 31)
|
||||
* hh = two digits of hour (00 through 23) (am/pm NOT allowed)
|
||||
* mm = two digits of minute (00 through 59)
|
||||
* ss = two digits of second (00 through 59)
|
||||
* MM = one or two-digit month (01=January, etc.)
|
||||
* DD = one or two-digit day of month (01 through 31)
|
||||
* hh = one or two digits of hour (00 through 23) (am/pm NOT allowed)
|
||||
* mm = one or two digits of minute (00 through 59)
|
||||
* ss = one or two digits of second (00 through 59)
|
||||
* s = one or more digits representing a decimal fraction of a second
|
||||
* TZD = time zone designator (Z or +hh:mm or -hh:mm or missing for local)
|
||||
*/
|
||||
template <typename CharT>
|
||||
static bool
|
||||
ParseISODate(const CharT* s, size_t length, ClippedTime* result)
|
||||
ParseISOStyleDate(const CharT* s, size_t length, ClippedTime* result)
|
||||
{
|
||||
size_t i = 0;
|
||||
int tzMul = 1;
|
||||
@@ -795,6 +816,9 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result)
|
||||
#define NEED_NDIGITS(n, field) \
|
||||
if (!ParseDigitsN(n, &field, s, &i, length)) { return false; }
|
||||
|
||||
#define NEED_NDIGITS_OR_LESS(n, field) \
|
||||
if (!ParseDigitsNOrLess(n, &field, s, &i, length)) { return false; }
|
||||
|
||||
if (PEEK('+') || PEEK('-')) {
|
||||
if (PEEK('-'))
|
||||
dateMul = -1;
|
||||
@@ -804,19 +828,23 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result)
|
||||
NEED_NDIGITS(4, year);
|
||||
}
|
||||
DONE_DATE_UNLESS('-');
|
||||
NEED_NDIGITS(2, month);
|
||||
NEED_NDIGITS_OR_LESS(2, month);
|
||||
DONE_DATE_UNLESS('-');
|
||||
NEED_NDIGITS(2, day);
|
||||
NEED_NDIGITS_OR_LESS(2, day);
|
||||
|
||||
done_date:
|
||||
DONE_UNLESS('T');
|
||||
NEED_NDIGITS(2, hour);
|
||||
if (PEEK('T') || PEEK(' '))
|
||||
i++;
|
||||
else
|
||||
goto done;
|
||||
|
||||
NEED_NDIGITS_OR_LESS(2, hour);
|
||||
NEED(':');
|
||||
NEED_NDIGITS(2, min);
|
||||
NEED_NDIGITS_OR_LESS(2, min);
|
||||
|
||||
if (PEEK(':')) {
|
||||
++i;
|
||||
NEED_NDIGITS(2, sec);
|
||||
NEED_NDIGITS_OR_LESS(2, sec);
|
||||
if (PEEK('.')) {
|
||||
++i;
|
||||
if (!ParseFractional(&frac, s, &i, length))
|
||||
@@ -882,7 +910,7 @@ template <typename CharT>
|
||||
static bool
|
||||
ParseDate(const CharT* s, size_t length, ClippedTime* result)
|
||||
{
|
||||
if (ParseISODate(s, length, result))
|
||||
if (ParseISOStyleDate(s, length, result))
|
||||
return true;
|
||||
|
||||
if (length == 0)
|
||||
@@ -1338,14 +1366,7 @@ DateObject::fillLocalTimeSlots()
|
||||
int weekday = WeekDay(localTime);
|
||||
setReservedSlot(LOCAL_DAY_SLOT, Int32Value(weekday));
|
||||
|
||||
int seconds = yearSeconds % 60;
|
||||
setReservedSlot(LOCAL_SECONDS_SLOT, Int32Value(seconds));
|
||||
|
||||
int minutes = (yearSeconds / 60) % 60;
|
||||
setReservedSlot(LOCAL_MINUTES_SLOT, Int32Value(minutes));
|
||||
|
||||
int hours = (yearSeconds / (60 * 60)) % 24;
|
||||
setReservedSlot(LOCAL_HOURS_SLOT, Int32Value(hours));
|
||||
setReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT, Int32Value(yearSeconds));
|
||||
}
|
||||
|
||||
inline double
|
||||
@@ -1546,7 +1567,15 @@ DateObject::getHours_impl(JSContext* cx, const CallArgs& args)
|
||||
DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
|
||||
dateObj->fillLocalTimeSlots();
|
||||
|
||||
args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT));
|
||||
// Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
|
||||
// int32 or NaN after the call to fillLocalTimeSlots.
|
||||
Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
|
||||
if (yearSeconds.isDouble()) {
|
||||
MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
|
||||
args.rval().set(yearSeconds);
|
||||
} else {
|
||||
args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerHour)) % int(HoursPerDay));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1581,7 +1610,15 @@ DateObject::getMinutes_impl(JSContext* cx, const CallArgs& args)
|
||||
DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
|
||||
dateObj->fillLocalTimeSlots();
|
||||
|
||||
args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT));
|
||||
// Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
|
||||
// int32 or NaN after the call to fillLocalTimeSlots.
|
||||
Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
|
||||
if (yearSeconds.isDouble()) {
|
||||
MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
|
||||
args.rval().set(yearSeconds);
|
||||
} else {
|
||||
args.rval().setInt32((yearSeconds.toInt32() / int(SecondsPerMinute)) % int(MinutesPerHour));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1610,7 +1647,17 @@ date_getUTCMinutes(JSContext* cx, unsigned argc, Value* vp)
|
||||
return CallNonGenericMethod<IsDate, DateObject::getUTCMinutes_impl>(cx, args);
|
||||
}
|
||||
|
||||
/* Date.getSeconds is mapped to getUTCSeconds */
|
||||
/*
|
||||
* Date.getSeconds is mapped to getUTCSeconds. As long as no supported time
|
||||
* zone has a fractional-minute component, the differences in their
|
||||
* specifications aren't observable.
|
||||
*
|
||||
* We'll have to split the implementations if a new time zone with a
|
||||
* fractional-minute component is introduced or once we implement ES6's
|
||||
* 20.3.1.7 Local Time Zone Adjustment: time zones with adjustments like that
|
||||
* did historically exist, e.g.
|
||||
* https://en.wikipedia.org/wiki/UTC%E2%88%9200:25:21
|
||||
*/
|
||||
|
||||
/* static */ MOZ_ALWAYS_INLINE bool
|
||||
DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args)
|
||||
@@ -1618,7 +1665,15 @@ DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args)
|
||||
DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
|
||||
dateObj->fillLocalTimeSlots();
|
||||
|
||||
args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT));
|
||||
// Note: LOCAL_SECONDS_INTO_YEAR_SLOT is guaranteed to contain an
|
||||
// int32 or NaN after the call to fillLocalTimeSlots.
|
||||
Value yearSeconds = dateObj->getReservedSlot(LOCAL_SECONDS_INTO_YEAR_SLOT);
|
||||
if (yearSeconds.isDouble()) {
|
||||
MOZ_ASSERT(IsNaN(yearSeconds.toDouble()));
|
||||
args.rval().set(yearSeconds);
|
||||
} else {
|
||||
args.rval().setInt32(yearSeconds.toInt32() % int(SecondsPerMinute));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1628,8 +1683,13 @@ date_getUTCSeconds(JSContext* cx, unsigned argc, Value* vp)
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsDate, DateObject::getUTCSeconds_impl>(cx, args);
|
||||
}
|
||||
|
||||
/* Date.getMilliseconds is mapped to getUTCMilliseconds */
|
||||
/*
|
||||
* Date.getMilliseconds is mapped to getUTCMilliseconds for the same reasons
|
||||
* that getSeconds is mapped to getUTCSeconds (see above). No known LocalTZA
|
||||
* has *ever* included a fractional-second component, however, so we can keep
|
||||
* this simplification even if we stop implementing ES5 local-time computation
|
||||
* semantics.
|
||||
*/
|
||||
|
||||
/* static */ MOZ_ALWAYS_INLINE bool
|
||||
DateObject::getUTCMilliseconds_impl(JSContext* cx, const CallArgs& args)
|
||||
@@ -2863,34 +2923,49 @@ date_toSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
#endif
|
||||
|
||||
// ES6 final draft 20.3.4.41.
|
||||
static bool
|
||||
date_toString(JSContext* cx, unsigned argc, Value* vp)
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
IsObject(HandleValue v)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
// Step 2.a. (reordered)
|
||||
double tv = GenericNaN();
|
||||
if (args.thisv().isObject()) {
|
||||
// Step 1.
|
||||
RootedObject obj(cx, &args.thisv().toObject());
|
||||
return v.isObject();
|
||||
}
|
||||
|
||||
// ES6 20.3.4.41.
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
date_toString_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
// Step 1.
|
||||
RootedObject obj(cx, &args.thisv().toObject());
|
||||
|
||||
// Step 2.
|
||||
ESClassValue cls;
|
||||
if (!GetBuiltinClass(cx, obj, &cls))
|
||||
return false;
|
||||
|
||||
double tv;
|
||||
if (cls != ESClass_Date) {
|
||||
// Step 2.
|
||||
ESClassValue cls;
|
||||
if (!GetBuiltinClass(cx, obj, &cls))
|
||||
tv = GenericNaN();
|
||||
} else {
|
||||
// Step 3.
|
||||
RootedValue unboxed(cx);
|
||||
if (!Unbox(cx, obj, &unboxed))
|
||||
return false;
|
||||
|
||||
if (cls == ESClass_Date) {
|
||||
// Step 3.a.
|
||||
RootedValue unboxed(cx);
|
||||
if (!Unbox(cx, obj, &unboxed))
|
||||
return false;
|
||||
tv = unboxed.toNumber();
|
||||
}
|
||||
tv = unboxed.toNumber();
|
||||
}
|
||||
|
||||
// Step 4.
|
||||
return date_format(cx, tv, FORMATSPEC_FULL, args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
date_toString(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
// Step 1.
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return CallNonGenericMethod<IsObject, date_toString_impl>(cx, args);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
date_valueOf_impl(JSContext* cx, const CallArgs& args)
|
||||
{
|
||||
@@ -3040,11 +3115,26 @@ DateOneArgument(JSContext* cx, const CallArgs& args)
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
|
||||
if (args.isConstructing()) {
|
||||
ClippedTime t;
|
||||
if (args[0].isObject()) {
|
||||
RootedObject obj(cx, &args[0].toObject());
|
||||
|
||||
ESClassValue cls;
|
||||
if (!GetBuiltinClass(cx, obj, &cls))
|
||||
return false;
|
||||
|
||||
if (cls == ESClass_Date) {
|
||||
RootedValue unboxed(cx);
|
||||
if (!Unbox(cx, obj, &unboxed))
|
||||
return false;
|
||||
|
||||
return NewDateObject(cx, args, TimeClip(unboxed.toNumber()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!ToPrimitive(cx, args[0]))
|
||||
return false;
|
||||
|
||||
ClippedTime t;
|
||||
if (args[0].isString()) {
|
||||
JSLinearString* linearStr = args[0].toString()->ensureLinear(cx);
|
||||
if (!linearStr)
|
||||
|
||||
@@ -18,18 +18,6 @@ using namespace js;
|
||||
using JS::IsArrayAnswer;
|
||||
using mozilla::ArrayLength;
|
||||
|
||||
static inline bool
|
||||
IsDataDescriptor(const PropertyDescriptor& desc)
|
||||
{
|
||||
return desc.obj && !(desc.attrs & (JSPROP_GETTER | JSPROP_SETTER));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsAccessorDescriptor(const PropertyDescriptor& desc)
|
||||
{
|
||||
return desc.obj && desc.attrs & (JSPROP_GETTER | JSPROP_SETTER);
|
||||
}
|
||||
|
||||
// ES6 (5 April 2014) ValidateAndApplyPropertyDescriptor(O, P, Extensible, Desc, Current)
|
||||
// Since we are actually performing 9.1.6.2 IsCompatiblePropertyDescriptor(Extensible, Desc,
|
||||
// Current), some parameters are omitted.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommonn.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var BUGNUMBER = 1187233;
|
||||
var summary =
|
||||
"Passing a Date object to |new Date()| should copy it, not convert it to " +
|
||||
"a primitive and create it from that.";
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
Date.prototype.toString = Date.prototype.valueOf = null;
|
||||
var d = new Date(new Date(8675309));
|
||||
assertEq(d.getTime(), 8675309);
|
||||
|
||||
Date.prototype.valueOf = () => 42;
|
||||
d = new Date(new Date(8675309));
|
||||
assertEq(d.getTime(), 8675309);
|
||||
|
||||
var D = newGlobal().Date;
|
||||
|
||||
D.prototype.toString = D.prototype.valueOf = null;
|
||||
var d = new Date(new D(3141592654));
|
||||
assertEq(d.getTime(), 3141592654);
|
||||
|
||||
D.prototype.valueOf = () => 525600;
|
||||
d = new Date(new D(3141592654));
|
||||
assertEq(d.getTime(), 3141592654);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommonn.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
/*
|
||||
* For the sake of cross compatibility with other implementations we
|
||||
* follow the W3C "NOTE-datetime" specification when parsing dates of
|
||||
* the form YYYY-MM-DDTHH:MM:SS save for a few exceptions: months, days, hours
|
||||
* minutes, and seconds may be either one _or_ two digits long, and the 'T'
|
||||
* preceding the time part may be replaced with a space. So, a string like
|
||||
* "1997-3-8 1:1:1" will parse successfully. See bug: 1203298
|
||||
*/
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
assertEq(new Date("1997-03-08 1:1:1.01").getTime(),
|
||||
new Date("1997-03-08T01:01:01.01").getTime());
|
||||
assertEq(new Date("1997-03-08 11:19:20").getTime(),
|
||||
new Date("1997-03-08T11:19:20").getTime());
|
||||
assertEq(new Date("1997-3-08 11:19:20").getTime(),
|
||||
new Date("1997-03-08T11:19:20").getTime());
|
||||
assertEq(new Date("1997-3-8 11:19:20").getTime(),
|
||||
new Date("1997-03-08T11:19:20").getTime());
|
||||
assertEq(new Date("1997-3-8T11:19:20").getTime(),
|
||||
new Date("1997-03-08T11:19:20").getTime());
|
||||
assertEq(new Date("1997-03-8T11:19:20").getTime(),
|
||||
new Date("1997-03-08T11:19:20").getTime());
|
||||
assertEq(new Date("1997-03-08 11:19").getTime(),
|
||||
new Date("1997-03-08T11:19").getTime());
|
||||
assertEq(new Date("1997-03-08 1:19").getTime(),
|
||||
new Date("1997-03-08T1:19").getTime());
|
||||
assertEq(new Date("1997-03-08 1:1").getTime(),
|
||||
new Date("1997-03-08T1:1").getTime());
|
||||
assertEq(new Date("1997-03-08 1:1:01").getTime(),
|
||||
new Date("1997-03-08T1:1:01").getTime());
|
||||
assertEq(new Date("1997-03-08 1:1:1").getTime(),
|
||||
new Date("1997-03-08T1:1:1").getTime());
|
||||
assertEq(new Date("1997-03-08 11").getTime(),
|
||||
new Date("1997-03-08T11").getTime());
|
||||
assertEq(new Date("1997-03-08").getTime(),
|
||||
new Date("1997-03-08").getTime());
|
||||
assertEq(new Date("1997-03-8").getTime(),
|
||||
new Date("1997-03-08").getTime());
|
||||
assertEq(new Date("1997-3-8").getTime(),
|
||||
new Date("1997-03-08").getTime());
|
||||
assertEq(new Date("1997-3-8 ").getTime(),
|
||||
new Date("1997-03-08T").getTime()); // Date(NaN)
|
||||
assertEq(new Date("1997-3-8 :00:01").getTime(),
|
||||
new Date(NaN).getTime());
|
||||
assertEq(new Date("1997-3-8 :00:01").getTime(),
|
||||
new Date(NaN).getTime());
|
||||
assertEq(new Date("1997-3-8 01::01").getTime(),
|
||||
new Date(NaN).getTime());
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
print("Tests complete");
|
||||
@@ -3,11 +3,11 @@ var summary = 'Date.prototype.toString is a generic function';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
for (var thisValue of [null, undefined, 0, 1.2, true, false, "foo", Symbol.iterator,
|
||||
{}, [], /foo/, Date.prototype, new Proxy(new Date(), {})])
|
||||
{
|
||||
for (var thisValue of [{}, [], /foo/, Date.prototype, new Proxy(new Date(), {})])
|
||||
assertEq(Date.prototype.toString.call(thisValue), "Invalid Date");
|
||||
}
|
||||
|
||||
for (var prim of [null, undefined, 0, 1.2, true, false, "foo", Symbol.iterator])
|
||||
assertThrowsInstanceOf(() => Date.prototype.toString.call(prim), TypeError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
+12
-4
@@ -31,11 +31,19 @@ class DateObject : public NativeObject
|
||||
static const uint32_t LOCAL_MONTH_SLOT = COMPONENTS_START_SLOT + 2;
|
||||
static const uint32_t LOCAL_DATE_SLOT = COMPONENTS_START_SLOT + 3;
|
||||
static const uint32_t LOCAL_DAY_SLOT = COMPONENTS_START_SLOT + 4;
|
||||
static const uint32_t LOCAL_HOURS_SLOT = COMPONENTS_START_SLOT + 5;
|
||||
static const uint32_t LOCAL_MINUTES_SLOT = COMPONENTS_START_SLOT + 6;
|
||||
static const uint32_t LOCAL_SECONDS_SLOT = COMPONENTS_START_SLOT + 7;
|
||||
|
||||
static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_SLOT + 1;
|
||||
/*
|
||||
* Unlike the above slots that hold LocalTZA-adjusted component values,
|
||||
* LOCAL_SECONDS_INTO_YEAR_SLOT holds a composite value that can be used
|
||||
* to compute LocalTZA-adjusted hours, minutes, and seconds values.
|
||||
* Specifically, LOCAL_SECONDS_INTO_YEAR_SLOT holds the number of
|
||||
* LocalTZA-adjusted seconds into the year. Unix timestamps ignore leap
|
||||
* seconds, so recovering hours/minutes/seconds requires only trivial
|
||||
* division/modulus operations.
|
||||
*/
|
||||
static const uint32_t LOCAL_SECONDS_INTO_YEAR_SLOT = COMPONENTS_START_SLOT + 5;
|
||||
|
||||
static const uint32_t RESERVED_SLOTS = LOCAL_SECONDS_INTO_YEAR_SLOT + 1;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
@@ -3507,7 +3507,7 @@ ContainerState::NewPaintedLayerData(nsDisplayItem* aItem,
|
||||
data.mAnimatedGeometryRootOffset = aTopLeft;
|
||||
data.mReferenceFrame = aItem->ReferenceFrame();
|
||||
data.mSingleItemFixedToViewport = aShouldFixToViewport;
|
||||
data.mBackfaceHidden = aItem->Frame()->BackfaceIsHidden();
|
||||
data.mBackfaceHidden = aItem->Frame()->In3DContextAndBackfaceIsHidden();
|
||||
data.mIsCaret = aItem->GetType() == nsDisplayItem::TYPE_CARET;
|
||||
|
||||
data.mNewChildLayersIndex = mNewChildLayers.Length();
|
||||
@@ -4126,7 +4126,7 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList)
|
||||
PaintedLayerData* paintedLayerData =
|
||||
mPaintedLayerDataTree.FindPaintedLayerFor(animatedGeometryRoot, agrScrollClip,
|
||||
itemVisibleRect, false,
|
||||
item->Frame()->BackfaceIsHidden(),
|
||||
item->Frame()->In3DContextAndBackfaceIsHidden(),
|
||||
avoidCreatingLayer,
|
||||
[&]() {
|
||||
layerCount++;
|
||||
|
||||
@@ -1170,6 +1170,12 @@ nsIFrame::Combines3DTransformWithAncestors() const
|
||||
return StyleDisplay()->HasTransform(this) || StyleDisplay()->BackfaceIsHidden();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::In3DContextAndBackfaceIsHidden() const
|
||||
{
|
||||
return Combines3DTransformWithAncestors() && StyleDisplay()->BackfaceIsHidden();
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::HasPerspective() const
|
||||
{
|
||||
|
||||
@@ -1281,6 +1281,13 @@ public:
|
||||
*/
|
||||
bool Combines3DTransformWithAncestors() const;
|
||||
|
||||
/**
|
||||
* Returns whether this frame has a hidden backface and has a parent that
|
||||
* Extend3DContext(). This is useful because in some cases the hidden
|
||||
* backface can safely be ignored if it could not be visible anyway.
|
||||
*/
|
||||
bool In3DContextAndBackfaceIsHidden() const;
|
||||
|
||||
bool IsPreserve3DLeaf() const {
|
||||
return Combines3DTransformWithAncestors() && !Extend3DContext();
|
||||
}
|
||||
|
||||
@@ -133,9 +133,6 @@ pref("dom.select_events.enabled", true);
|
||||
// Whether or not selection events on text controls are enabled
|
||||
pref("dom.select_events.textcontrols.enabled", true);
|
||||
|
||||
// Whether or not the document visbility API is enabled
|
||||
pref("dom.visibilityAPI.enabled", true);
|
||||
|
||||
// Whether or not File Handle is enabled.
|
||||
pref("dom.fileHandle.enabled", true);
|
||||
|
||||
|
||||
@@ -38,7 +38,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mTainting(LoadTainting::Basic)
|
||||
, mUpgradeInsecureRequests(false)
|
||||
, mUpgradeInsecurePreloads(false)
|
||||
, mInnerWindowID(0)
|
||||
, mOuterWindowID(0)
|
||||
, mParentOuterWindowID(0)
|
||||
@@ -90,8 +89,13 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
ComputeIsThirdPartyContext(outerWindow);
|
||||
}
|
||||
|
||||
mUpgradeInsecureRequests = aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests();
|
||||
mUpgradeInsecurePreloads = aLoadingContext->OwnerDoc()->GetUpgradeInsecurePreloads();
|
||||
// if the document forces all requests to be upgraded from http to https, then
|
||||
// we should do that for all requests. If it only forces preloads to be upgraded
|
||||
// then we should enforce upgrade insecure requests only for preloads.
|
||||
mUpgradeInsecureRequests =
|
||||
aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(false) ||
|
||||
(nsContentUtils::IsPreloadType(mInternalContentPolicyType) &&
|
||||
aLoadingContext->OwnerDoc()->GetUpgradeInsecureRequests(true));
|
||||
}
|
||||
|
||||
const PrincipalOriginAttributes attrs = BasePrincipal::Cast(mLoadingPrincipal)->OriginAttributesRef();
|
||||
@@ -106,7 +110,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
|
||||
, mInternalContentPolicyType(rhs.mInternalContentPolicyType)
|
||||
, mTainting(rhs.mTainting)
|
||||
, mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests)
|
||||
, mUpgradeInsecurePreloads(rhs.mUpgradeInsecurePreloads)
|
||||
, mInnerWindowID(rhs.mInnerWindowID)
|
||||
, mOuterWindowID(rhs.mOuterWindowID)
|
||||
, mParentOuterWindowID(rhs.mParentOuterWindowID)
|
||||
@@ -130,7 +133,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
LoadTainting aTainting,
|
||||
bool aUpgradeInsecureRequests,
|
||||
bool aUpgradeInsecurePreloads,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID,
|
||||
@@ -149,7 +151,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
|
||||
, mInternalContentPolicyType(aContentPolicyType)
|
||||
, mTainting(aTainting)
|
||||
, mUpgradeInsecureRequests(aUpgradeInsecureRequests)
|
||||
, mUpgradeInsecurePreloads(aUpgradeInsecurePreloads)
|
||||
, mInnerWindowID(aInnerWindowID)
|
||||
, mOuterWindowID(aOuterWindowID)
|
||||
, mParentOuterWindowID(aParentOuterWindowID)
|
||||
@@ -391,13 +392,6 @@ LoadInfo::GetUpgradeInsecureRequests(bool* aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetUpgradeInsecurePreloads(bool* aResult)
|
||||
{
|
||||
*aResult = mUpgradeInsecurePreloads;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LoadInfo::GetInnerWindowID(uint64_t* aResult)
|
||||
{
|
||||
|
||||
@@ -81,7 +81,6 @@ private:
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
LoadTainting aTainting,
|
||||
bool aUpgradeInsecureRequests,
|
||||
bool aUpgradeInsecurePreloads,
|
||||
uint64_t aInnerWindowID,
|
||||
uint64_t aOuterWindowID,
|
||||
uint64_t aParentOuterWindowID,
|
||||
@@ -119,7 +118,6 @@ private:
|
||||
nsContentPolicyType mInternalContentPolicyType;
|
||||
LoadTainting mTainting;
|
||||
bool mUpgradeInsecureRequests;
|
||||
bool mUpgradeInsecurePreloads;
|
||||
uint64_t mInnerWindowID;
|
||||
uint64_t mOuterWindowID;
|
||||
uint64_t mParentOuterWindowID;
|
||||
|
||||
@@ -29,7 +29,7 @@ typedef unsigned long nsSecurityFlags;
|
||||
/**
|
||||
* An nsILoadOwner represents per-load information about who started the load.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(41e311d0-5894-4aaa-80b5-5b7099dfc404)]
|
||||
[scriptable, builtinclass, uuid(ddc65bf9-2f60-41ab-b22a-4f1ae9efcd36)]
|
||||
interface nsILoadInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
@@ -336,11 +336,6 @@ interface nsILoadInfo : nsISupports
|
||||
*/
|
||||
[infallible] readonly attribute boolean upgradeInsecureRequests;
|
||||
|
||||
/**
|
||||
* Same as upgradeInsecureRequests but for preloads.
|
||||
*/
|
||||
[infallible] readonly attribute boolean upgradeInsecurePreloads;
|
||||
|
||||
/**
|
||||
* Typically these are the window IDs of the window in which the element being
|
||||
* loaded lives. However, if the element being loaded is <frame
|
||||
|
||||
@@ -2258,11 +2258,6 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
|
||||
// the promise to CSP and mixed content blocking to upgrade the channel
|
||||
// from http to https.
|
||||
if (aLoadInfo) {
|
||||
bool isPreload = nsContentUtils::IsPreloadType(aLoadInfo->InternalContentPolicyType());
|
||||
bool upgradeRequests =
|
||||
((isPreload && aLoadInfo->GetUpgradeInsecurePreloads()) ||
|
||||
(aLoadInfo->GetUpgradeInsecureRequests()));
|
||||
|
||||
// Please note that cross origin top level navigations are not subject
|
||||
// to upgrade-insecure-requests, see:
|
||||
// http://www.w3.org/TR/upgrade-insecure-requests/#examples
|
||||
@@ -2270,7 +2265,7 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
|
||||
(aLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT) &&
|
||||
(!aChannelResultPrincipal->Equals(aLoadInfo->LoadingPrincipal()));
|
||||
|
||||
if (upgradeRequests && !crossOriginNavigation) {
|
||||
if (aLoadInfo->GetUpgradeInsecureRequests() && !crossOriginNavigation) {
|
||||
// let's log a message to the console that we are upgrading a request
|
||||
nsAutoCString spec, scheme;
|
||||
aURI->GetSpec(spec);
|
||||
|
||||
@@ -33,7 +33,6 @@ struct LoadInfoArgs
|
||||
uint32_t contentPolicyType;
|
||||
uint32_t tainting;
|
||||
bool upgradeInsecureRequests;
|
||||
bool upgradeInsecurePreloads;
|
||||
uint64_t innerWindowID;
|
||||
uint64_t outerWindowID;
|
||||
uint64_t parentOuterWindowID;
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "nsICaptivePortalService.h"
|
||||
#include "nsICryptoHash.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsINSSErrorsService.h"
|
||||
#include "nsISecurityReporter.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsIStreamListenerTee.h"
|
||||
#include "nsISeekableStream.h"
|
||||
@@ -1308,6 +1310,56 @@ nsHttpChannel::ProcessSecurityHeaders()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide whether or not to send a security report and, if so, give the
|
||||
* SecurityReporter the information required to send such a report.
|
||||
*/
|
||||
void
|
||||
nsHttpChannel::ProcessSecurityReport(nsresult status) {
|
||||
uint32_t errorClass;
|
||||
nsCOMPtr<nsINSSErrorsService> errSvc =
|
||||
do_GetService("@mozilla.org/nss_errors_service;1");
|
||||
// getErrorClass will throw a generic NS_ERROR_FAILURE if the error code is
|
||||
// not in the set of errors covered by the NSS errors service.
|
||||
nsresult rv = errSvc->GetErrorClass(status, &errorClass);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the content was not loaded succesfully and we have security info,
|
||||
// send a TLS error report - we must do this early as other parts of
|
||||
// OnStopRequest can return early
|
||||
bool reportingEnabled =
|
||||
Preferences::GetBool("security.ssl.errorReporting.enabled");
|
||||
bool reportingAutomatic =
|
||||
Preferences::GetBool("security.ssl.errorReporting.automatic");
|
||||
if (!mSecurityInfo || !reportingEnabled || !reportingAutomatic) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransportSecurityInfo> secInfo =
|
||||
do_QueryInterface(mSecurityInfo);
|
||||
nsCOMPtr<nsISecurityReporter> errorReporter =
|
||||
do_GetService("@mozilla.org/securityreporter;1");
|
||||
|
||||
if (!secInfo || !mURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoCString hostStr;
|
||||
int32_t port;
|
||||
rv = mURI->GetHost(hostStr);
|
||||
if (!NS_SUCCEEDED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = mURI->GetPort(&port);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
errorReporter->ReportTLSError(secInfo, hostStr, port);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHttpChannel::IsHTTPS()
|
||||
{
|
||||
@@ -5795,6 +5847,13 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st
|
||||
LOG(("nsHttpChannel::OnStopRequest [this=%p request=%p status=%x]\n",
|
||||
this, request, status));
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(),
|
||||
"OnStopRequest should only be called from the main thread");
|
||||
|
||||
if (NS_FAILED(status)) {
|
||||
ProcessSecurityReport(status);
|
||||
}
|
||||
|
||||
if (mTimingEnabled && request == mCachePump) {
|
||||
mCacheReadEnd = TimeStamp::Now();
|
||||
}
|
||||
|
||||
@@ -365,6 +365,11 @@ private:
|
||||
*/
|
||||
nsresult ProcessSecurityHeaders();
|
||||
|
||||
/**
|
||||
* A function that will, if the feature is enabled, send security reports.
|
||||
*/
|
||||
void ProcessSecurityReport(nsresult status);
|
||||
|
||||
/**
|
||||
* A function to process a single security header (STS or PKP), assumes
|
||||
* some basic sanity checks have been applied to the channel. Called
|
||||
|
||||
@@ -1028,21 +1028,9 @@ nsHtml5TreeOpExecutor::AddSpeculationCSP(const nsAString& aCSP)
|
||||
|
||||
nsIPrincipal* principal = mDocument->NodePrincipal();
|
||||
nsCOMPtr<nsIContentSecurityPolicy> preloadCsp;
|
||||
nsresult rv = principal->GetPreloadCsp(getter_AddRefs(preloadCsp));
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
|
||||
nsresult rv = principal->EnsurePreloadCSP(domDoc, getter_AddRefs(preloadCsp));
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if (!preloadCsp) {
|
||||
preloadCsp = do_CreateInstance("@mozilla.org/cspcontext;1", &rv);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// Store the request context for violation reports
|
||||
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mDocument);
|
||||
rv = preloadCsp->SetRequestContext(domDoc, nullptr);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
// set the new csp
|
||||
rv = principal->SetPreloadCsp(preloadCsp);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
||||
// please note that meta CSPs and CSPs delivered through a header need
|
||||
// to be joined together.
|
||||
|
||||
@@ -292,7 +292,8 @@ certErrorExpiredNow=The certificate expired on %1$S. The current time is %2$S.
|
||||
# LOCALIZATION NOTE (certErrorNotYetValidNow): Do not translate %1$S (date+time certificate will become valid) or %2$S (current date+time)
|
||||
certErrorNotYetValidNow=The certificate will not be valid until %1$S. The current time is %2$S.
|
||||
|
||||
certErrorCodePrefix=(Error code: %S)
|
||||
# LOCALIZATION NOTE (certErrorCodePrefix2): Do not translate <a id="errorCode" title="%1$S">%1$S</a>
|
||||
certErrorCodePrefix2=Error code: <a id="errorCode" title="%1$S">%1$S</a>
|
||||
|
||||
CertInfoIssuedFor=Issued to:
|
||||
CertInfoIssuedBy=Issued by:
|
||||
|
||||
@@ -885,7 +885,6 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport,
|
||||
if (codeName)
|
||||
{
|
||||
nsCString error_id(codeName);
|
||||
ToLowerCase(error_id);
|
||||
NS_ConvertASCIItoUTF16 idU(error_id);
|
||||
|
||||
const char16_t *params[1];
|
||||
@@ -893,7 +892,7 @@ AppendErrorTextCode(PRErrorCode errorCodeToReport,
|
||||
|
||||
nsString formattedString;
|
||||
nsresult rv;
|
||||
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
|
||||
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2",
|
||||
params, 1,
|
||||
formattedString);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
@@ -78,14 +78,13 @@ nsNSSErrors::getErrorMessageFromCode(PRErrorCode err,
|
||||
{
|
||||
nsresult rv;
|
||||
nsCString error_id(nss_error_id_str);
|
||||
ToLowerCase(error_id);
|
||||
NS_ConvertASCIItoUTF16 idU(error_id);
|
||||
|
||||
const char16_t *params[1];
|
||||
params[0] = idU.get();
|
||||
|
||||
nsString formattedString;
|
||||
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
|
||||
rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix2",
|
||||
params, 1,
|
||||
formattedString);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
/* This test is for the TLS error reporting functionality exposed by
|
||||
* SecurityReporter.js in /toolkit/components/securityreporter. The test is
|
||||
* here because we make use of the tlsserver functionality that lives with the
|
||||
* PSM ssl tests.
|
||||
*
|
||||
* The testing here will be augmented by the existing mochitests for the
|
||||
* error reporting functionality in aboutNetError.xhtml and
|
||||
* aboutCertError.xhtml once these make use of this component.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
const CC = Components.Constructor;
|
||||
const Cm = Components.manager;
|
||||
|
||||
Cu.import("resource://testing-common/AppInfo.jsm");
|
||||
updateAppInfo();
|
||||
|
||||
// We must get the profile before performing operations on the cert db.
|
||||
do_get_profile();
|
||||
|
||||
const certdb = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
const reporter = Cc["@mozilla.org/securityreporter;1"]
|
||||
.getService(Ci.nsISecurityReporter);
|
||||
|
||||
|
||||
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
|
||||
"nsIBinaryInputStream", "setInputStream");
|
||||
|
||||
var server;
|
||||
|
||||
// this allows us to create a callback which checks that a report is as
|
||||
// expected.
|
||||
function getReportCheck(expectReport, expectedError) {
|
||||
return function sendReportWithInfo(transportSecurityInfo) {
|
||||
// register a path handler on the server
|
||||
server.registerPathHandler("/submit/sslreports",
|
||||
function(request, response) {
|
||||
if (expectReport) {
|
||||
let report = JSON.parse(readDataFromRequest(request));
|
||||
do_check_eq(report.errorCode, expectedError);
|
||||
response.setStatusLine(null, 201, "Created");
|
||||
response.write("Created");
|
||||
} else {
|
||||
do_throw("No report should have been received");
|
||||
}
|
||||
});
|
||||
|
||||
reporter.reportTLSError(transportSecurityInfo, "example.com", -1);
|
||||
}
|
||||
}
|
||||
|
||||
// read the request body from a request
|
||||
function readDataFromRequest(aRequest) {
|
||||
if (aRequest.method == "POST" || aRequest.method == "PUT") {
|
||||
if (aRequest.bodyInputStream) {
|
||||
let inputStream = new BinaryInputStream(aRequest.bodyInputStream);
|
||||
let bytes = [];
|
||||
let available;
|
||||
|
||||
while ((available = inputStream.available()) > 0) {
|
||||
Array.prototype.push.apply(bytes, inputStream.readByteArray(available));
|
||||
}
|
||||
|
||||
return String.fromCharCode.apply(null, bytes);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
// start a report server
|
||||
server = new HttpServer();
|
||||
server.start(-1);
|
||||
|
||||
let port = server.identity.primaryPort;
|
||||
|
||||
// Set the reporting URL to ensure any reports are sent to the test server
|
||||
Services.prefs.setCharPref("security.ssl.errorReporting.url",
|
||||
`http://localhost:${port}/submit/sslreports`);
|
||||
// set strict-mode pinning enforcement so we can cause connection failures.
|
||||
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
|
||||
|
||||
// start a TLS server
|
||||
add_tls_server_setup("BadCertServer", "bad_certs");
|
||||
|
||||
// Add a user-specified trust anchor.
|
||||
addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
|
||||
|
||||
|
||||
// Cause a reportable condition with error reporting disabled. No report
|
||||
// should be sent.
|
||||
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", false);
|
||||
add_connection_test("expired.example.com",
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE, null,
|
||||
getReportCheck(false));
|
||||
|
||||
// Now enable reporting
|
||||
add_test(function () {
|
||||
Services.prefs.setBoolPref("security.ssl.errorReporting.enabled", true);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// test calling the component with no transportSecurityInfo. No report should
|
||||
// be sent even though reporting is enabled.
|
||||
add_test(function() {
|
||||
server.registerPathHandler("/submit/sslreports",
|
||||
function(request, response) {
|
||||
do_throw("No report should be sent");
|
||||
});
|
||||
reporter.reportTLSError(null, "example.com", -1);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Test sending a report with no error. This allows us to check the case
|
||||
// where there is no failed cert chain
|
||||
add_connection_test("good.include-subdomains.pinning.example.com",
|
||||
PRErrorCodeSuccess, null,
|
||||
getReportCheck(true, PRErrorCodeSuccess));
|
||||
|
||||
// Test sending a report where there is an error and a failed cert chain.
|
||||
add_connection_test("expired.example.com",
|
||||
SEC_ERROR_EXPIRED_CERTIFICATE, null,
|
||||
getReportCheck(true, SEC_ERROR_EXPIRED_CERTIFICATE));
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
@@ -158,3 +158,6 @@ skip-if = toolkit == 'android' || buildapp == 'b2g'
|
||||
|
||||
[test_weak_crypto.js]
|
||||
firefox-appdir = browser
|
||||
|
||||
# The TLS error reporting functionality lives in /toolkit but needs tlsserver
|
||||
[test_toolkit_securityreporter.js]
|
||||
|
||||
@@ -243,7 +243,7 @@ user_pref("identity.fxaccounts.settings.uri", "https://%(server)s/fxa-settings")
|
||||
user_pref('identity.fxaccounts.remote.webchannel.uri', 'https://%(server)s/');
|
||||
|
||||
// Make sure SSL Error reports don't hit the network
|
||||
user_pref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/pinning_reports.sjs?succeed");
|
||||
user_pref("security.ssl.errorReporting.url", "https://example.com/browser/browser/base/content/test/general/ssl_error_reports.sjs?succeed");
|
||||
|
||||
// Make sure Translation won't hit the network.
|
||||
user_pref("browser.translation.bing.authURL", "http://%(server)s/browser/browser/components/translation/test/bing.sjs");
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
|
||||
expected: FAIL
|
||||
|
||||
[Test valid WebM type "AUDIO/WEBM;CODECS="vorbis""]
|
||||
bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1191833
|
||||
expected: FAIL
|
||||
|
||||
[Test valid MP4 type "video/mp4;codecs="avc1.4d001e""]
|
||||
expected:
|
||||
if (os == "win") and (version == "5.1.2600"): FAIL
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>cssom-view - scrollingElement</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<iframe id="quirksframe"></iframe>
|
||||
<iframe id="nonquirksframe"></iframe>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
|
||||
var quirksFrame;
|
||||
var nonQuirksFrame;
|
||||
|
||||
function loadTestFrames(callback) {
|
||||
quirksFrame = document.getElementById("quirksframe");
|
||||
quirksFrame.onload = function() {
|
||||
nonQuirksFrame = document.getElementById("nonquirksframe");
|
||||
nonQuirksFrame.onload = callback;
|
||||
nonQuirksFrame.src =
|
||||
URL.createObjectURL(new Blob(["<!doctype html>"], { type: "text/html" }));
|
||||
}
|
||||
quirksFrame.src =
|
||||
URL.createObjectURL(new Blob([""], { type: "text/html" }));
|
||||
}
|
||||
|
||||
var test = async_test("Tests for scrollingElement");
|
||||
loadTestFrames(function() {
|
||||
test.step(function() {
|
||||
var quirksDoc = quirksFrame.contentDocument;
|
||||
var nonQuirksDoc = nonQuirksFrame.contentDocument;
|
||||
|
||||
// Initial checks that we have the expected kinds of documents.
|
||||
assert_equals(quirksDoc.compatMode, "BackCompat", "Should be in quirks mode.");
|
||||
assert_equals(nonQuirksDoc.compatMode, "CSS1Compat", "Should be in standards mode.");
|
||||
|
||||
assert_not_equals(quirksDoc.body, null, "Should have a body element");
|
||||
assert_not_equals(nonQuirksDoc.body, null, "Should have a body element");
|
||||
|
||||
// Tests for quirks mode document.
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body,
|
||||
"scrollingElement in quirks mode should default to body element.");
|
||||
|
||||
quirksDoc.documentElement.style.overflow = "scroll";
|
||||
quirksDoc.body.style.overflow = "scroll";
|
||||
assert_equals(quirksDoc.scrollingElement, null,
|
||||
"scrollingElement in quirks mode should be null if overflow of body and root element isn't visible.");
|
||||
quirksDoc.documentElement.style.overflow = "visible";
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
quirksDoc.documentElement.style.overflow = "scroll";
|
||||
quirksDoc.body.style.overflow = "visible";
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
quirksDoc.documentElement.style.overflow = "visible";
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
|
||||
quirksDoc.body.style.display = "none";
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body)
|
||||
quirksDoc.body.style.display = "block";
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
|
||||
quirksDoc.documentElement.appendChild(quirksDoc.createElement("body"));
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.getElementsByTagName("body")[0]);
|
||||
quirksDoc.documentElement.removeChild(quirksDoc.documentElement.lastChild);
|
||||
assert_equals(quirksDoc.scrollingElement, quirksDoc.body);
|
||||
|
||||
quirksDoc.documentElement.removeChild(quirksDoc.body);
|
||||
assert_equals(quirksDoc.scrollingElement, null);
|
||||
quirksDoc.documentElement.appendChild(quirksDoc.createElementNS("foobarNS", "body"));
|
||||
assert_equals(quirksDoc.scrollingElement, null);
|
||||
|
||||
quirksDoc.removeChild(quirksDoc.documentElement);
|
||||
assert_equals(quirksDoc.scrollingElement, null);
|
||||
|
||||
quirksDoc.appendChild(quirksDoc.createElementNS("foobarNS", "html"));
|
||||
quirksDoc.documentElement.appendChild(quirksDoc.createElement("body"));
|
||||
assert_equals(quirksDoc.scrollingElement, null);
|
||||
|
||||
quirksDoc.removeChild(quirksDoc.documentElement);
|
||||
quirksDoc.appendChild(quirksDoc.createElement("body"));
|
||||
assert_equals(quirksDoc.scrollingElement, null);
|
||||
|
||||
// Tests for standards mode document.
|
||||
assert_equals(nonQuirksDoc.scrollingElement, nonQuirksDoc.documentElement,
|
||||
"scrollingElement in standards mode should be the document element.");
|
||||
nonQuirksDoc.documentElement.style.overflow = "scroll";
|
||||
nonQuirksDoc.body.style.overflow = "scroll";
|
||||
assert_equals(nonQuirksDoc.scrollingElement, nonQuirksDoc.documentElement);
|
||||
|
||||
nonQuirksDoc.removeChild(nonQuirksDoc.documentElement);
|
||||
assert_equals(nonQuirksDoc.scrollingElement, null);
|
||||
nonQuirksDoc.appendChild(nonQuirksDoc.createElement("foobar"));
|
||||
assert_equals(nonQuirksDoc.scrollingElement.localName, "foobar");
|
||||
|
||||
});
|
||||
test.done();
|
||||
});
|
||||
</script>
|
||||
@@ -395,6 +395,125 @@ test(function() {
|
||||
assert_equals(attr.ownerElement, null)
|
||||
}, "Attribute loses its owner when removed")
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div")
|
||||
el.setAttribute("foo", "bar")
|
||||
var attr = el.attributes[0]
|
||||
var attrNode = el.getAttributeNode("foo");
|
||||
var attrNodeNS = el.getAttributeNodeNS("", "foo");
|
||||
assert_equals(attr, attrNode);
|
||||
assert_equals(attr, attrNodeNS);
|
||||
el.setAttributeNS("x", "foo2", "bar2");
|
||||
var attr2 = el.attributes[1];
|
||||
var attrNodeNS2 = el.getAttributeNodeNS("x", "foo2");
|
||||
assert_equals(attr2, attrNodeNS2);
|
||||
}, "Basic functionality of getAttributeNode/getAttributeNodeNS")
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div")
|
||||
el.setAttribute("foo", "bar")
|
||||
var attrNode = el.getAttributeNode("foo");
|
||||
var attrNodeNS = el.getAttributeNodeNS("", "foo");
|
||||
assert_equals(attrNode, attrNodeNS);
|
||||
el.removeAttribute("foo");
|
||||
var el2 = document.createElement("div");
|
||||
el2.setAttributeNode(attrNode);
|
||||
assert_equals(attrNode, el2.getAttributeNode("foo"));
|
||||
assert_equals(attrNode, el2.attributes[0]);
|
||||
assert_equals(attrNode.ownerElement, el2);
|
||||
assert_equals(attrNode.value, "bar");
|
||||
|
||||
var el3 = document.createElement("div");
|
||||
el2.removeAttribute("foo");
|
||||
el3.setAttribute("foo", "baz");
|
||||
el3.setAttributeNode(attrNode);
|
||||
assert_equals(el3.getAttribute("foo"), "bar");
|
||||
}, "Basic functionality of setAttributeNode")
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div")
|
||||
el.setAttributeNS("x", "foo", "bar")
|
||||
var attrNode = el.getAttributeNodeNS("x", "foo");
|
||||
el.removeAttribute("foo");
|
||||
var el2 = document.createElement("div");
|
||||
el2.setAttributeNS("x", "foo", "baz");
|
||||
el2.setAttributeNodeNS(attrNode);
|
||||
assert_equals(el2.getAttributeNS("x", "foo"), "bar");
|
||||
}, "Basic functionality of setAttributeNodeNS")
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div")
|
||||
el.setAttribute("foo", "bar")
|
||||
var attrNode = el.getAttributeNode("foo");
|
||||
el.removeAttributeNode(attrNode);
|
||||
var el2 = document.createElement("div");
|
||||
el2.setAttributeNode(attrNode);
|
||||
assert_equals(el2.attributes[0], attrNode);
|
||||
assert_equals(el.attributes.length, 0);
|
||||
}, "Basic functionality of removeAttributeNode")
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div")
|
||||
el.setAttribute("foo", "bar")
|
||||
var attrNode = el.getAttributeNode("foo");
|
||||
var el2 = document.createElement("div");
|
||||
assert_throws("INUSE_ATTRIBUTE_ERR", function(){el2.setAttributeNode(attrNode)});
|
||||
}, "setAttributeNode on bound attribute should throw InUseAttributeError")
|
||||
|
||||
// Have to use an async_test to see what a DOMAttrModified listener sees,
|
||||
// because otherwise the event dispatch code will swallow our exceptions. And
|
||||
// we want to make sure this test always happens, even when no mutation events
|
||||
// run.
|
||||
var setAttributeNode_mutation_test = async_test("setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute");
|
||||
|
||||
test(function(){
|
||||
var el = document.createElement("div")
|
||||
var attrNode1 = document.createAttribute("foo");
|
||||
attrNode1.value = "bar";
|
||||
el.setAttributeNode(attrNode1);
|
||||
var attrNode2 = document.createAttribute("foo");
|
||||
attrNode2.value = "baz";
|
||||
|
||||
el.addEventListener("DOMAttrModified", function(e) {
|
||||
// If this never gets called, that's OK, I guess. But if it gets called, it
|
||||
// better represent a single modification with attrNode2 as the relatedNode.
|
||||
// We have to do an inner test() call here, because otherwise the exceptions
|
||||
// our asserts trigger will get swallowed by the event dispatch code.
|
||||
setAttributeNode_mutation_test.step(function() {
|
||||
assert_equals(e.attrName, "foo");
|
||||
assert_equals(e.attrChange, MutationEvent.MODIFICATION);
|
||||
assert_equals(e.prevValue, "bar");
|
||||
assert_equals(e.newValue, "baz");
|
||||
assert_equals(e.relatedNode, attrNode2);
|
||||
});
|
||||
});
|
||||
|
||||
var oldNode = el.setAttributeNode(attrNode2);
|
||||
assert_equals(oldNode, attrNode1,
|
||||
"Must return the old attr node from a setAttributeNode call");
|
||||
}, "setAttributeNode, if it fires mutation events, should fire one with the new node when resetting an existing attribute (outer shell)");
|
||||
setAttributeNode_mutation_test.done();
|
||||
|
||||
test(function(){
|
||||
var el = document.createElement("div")
|
||||
el.setAttribute("a", "b");
|
||||
el.setAttribute("c", "d");
|
||||
|
||||
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
|
||||
["a", "c"]);
|
||||
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
|
||||
["b", "d"]);
|
||||
|
||||
var attrNode = document.createAttribute("a");
|
||||
attrNode.value = "e";
|
||||
el.setAttributeNode(attrNode);
|
||||
|
||||
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.name }),
|
||||
["a", "c"]);
|
||||
assert_array_equals(Array.prototype.map.call(el.attributes, function(a) { return a.value }),
|
||||
["e", "d"]);
|
||||
}, "setAttributeNode called with an Attr that has the same name as an existing one should not change attribute order");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttribute("foo", "bar");
|
||||
@@ -428,4 +547,132 @@ test(function() {
|
||||
assert_equals(el.getAttributeNames()[1], el.attributes[1].name);
|
||||
assert_equals(el.getAttributeNames()[2], el.attributes[2].name);
|
||||
}, "getAttributeNames tests");
|
||||
|
||||
function getEnumerableOwnProps1(obj) {
|
||||
var arr = [];
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
arr.push(prop);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function getEnumerableOwnProps2(obj) {
|
||||
return Object.getOwnPropertyNames(obj).filter(
|
||||
(name) => Object.getOwnPropertyDescriptor(obj, name).enumerable)
|
||||
}
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttribute("a", "");
|
||||
el.setAttribute("b", "");
|
||||
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||
["0", "1"])
|
||||
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||
["0", "1"])
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "a", "b"])
|
||||
}, "Own property correctness with basic attributes");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttributeNS("", "a", "");
|
||||
el.setAttribute("b", "");
|
||||
el.setAttributeNS("foo", "a", "");
|
||||
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "a", "b"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property correctness with non-namespaced attribute before same-name namespaced one");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttributeNS("foo", "a", "");
|
||||
el.setAttribute("b", "");
|
||||
el.setAttributeNS("", "a", "");
|
||||
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "a", "b"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property correctness with namespaced attribute before same-name non-namespaced one");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttributeNS("foo", "a:b", "");
|
||||
el.setAttributeNS("foo", "c:d", "");
|
||||
el.setAttributeNS("bar", "a:b", "");
|
||||
assert_array_equals(getEnumerableOwnProps1(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(getEnumerableOwnProps2(el.attributes),
|
||||
["0", "1", "2"])
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "a:b", "c:d"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property correctness with two namespaced attributes with the same name-with-prefix");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElement("div");
|
||||
el.setAttributeNS("foo", "A:B", "");
|
||||
el.setAttributeNS("bar", "c:D", "");
|
||||
el.setAttributeNS("baz", "e:F", "");
|
||||
el.setAttributeNS("qux", "g:h", "");
|
||||
el.setAttributeNS("", "I", "");
|
||||
el.setAttributeNS("", "j", "");
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "3", "4", "5", "g:h", "j"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property names should only include all-lowercase qualified names for an HTML element in an HTML document");
|
||||
|
||||
test(function() {
|
||||
var el = document.createElementNS("", "div");
|
||||
el.setAttributeNS("foo", "A:B", "");
|
||||
el.setAttributeNS("bar", "c:D", "");
|
||||
el.setAttributeNS("baz", "e:F", "");
|
||||
el.setAttributeNS("qux", "g:h", "");
|
||||
el.setAttributeNS("", "I", "");
|
||||
el.setAttributeNS("", "j", "");
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property names should include all qualified names for a non-HTML element in an HTML document");
|
||||
|
||||
test(function() {
|
||||
var doc = document.implementation.createDocument(null, "");
|
||||
assert_equals(doc.contentType, "application/xml");
|
||||
var el = doc.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
el.setAttributeNS("foo", "A:B", "");
|
||||
el.setAttributeNS("bar", "c:D", "");
|
||||
el.setAttributeNS("baz", "e:F", "");
|
||||
el.setAttributeNS("qux", "g:h", "");
|
||||
el.setAttributeNS("", "I", "");
|
||||
el.setAttributeNS("", "j", "");
|
||||
assert_array_equals(Object.getOwnPropertyNames(el.attributes),
|
||||
["0", "1", "2", "3", "4", "5", "A:B", "c:D", "e:F", "g:h", "I", "j"])
|
||||
for (var propName of Object.getOwnPropertyNames(el.attributes)) {
|
||||
assert_true(el.attributes[propName] instanceof Attr,
|
||||
"el.attributes has an Attr for property name " + propName);
|
||||
}
|
||||
}, "Own property names should include all qualified names for an HTML element in a non-HTML document");
|
||||
</script>
|
||||
|
||||
@@ -47,6 +47,7 @@ DIRS += [
|
||||
'protobuf',
|
||||
'reader',
|
||||
'reflect',
|
||||
'securityreporter',
|
||||
'sqlite',
|
||||
'startup',
|
||||
'statusfilter',
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
Cu.importGlobalProperties(['fetch']);
|
||||
|
||||
const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
|
||||
const protocolHandler = Cc["@mozilla.org/network/protocol;1?name=http"]
|
||||
.getService(Ci.nsIHttpProtocolHandler);
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
const TLS_ERROR_REPORT_TELEMETRY_SUCCESS = 6;
|
||||
const TLS_ERROR_REPORT_TELEMETRY_FAILURE = 7;
|
||||
const HISTOGRAM_ID = "TLS_ERROR_REPORT_UI";
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
|
||||
"resource://gre/modules/UpdateUtils.jsm");
|
||||
|
||||
function getDERString(cert)
|
||||
{
|
||||
var length = {};
|
||||
var derArray = cert.getRawDER(length);
|
||||
var derString = '';
|
||||
for (var i = 0; i < derArray.length; i++) {
|
||||
derString += String.fromCharCode(derArray[i]);
|
||||
}
|
||||
return derString;
|
||||
}
|
||||
|
||||
function SecurityReporter() { }
|
||||
|
||||
SecurityReporter.prototype = {
|
||||
classDescription: "Security reporter component",
|
||||
classID: Components.ID("{8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b}"),
|
||||
contractID: "@mozilla.org/securityreporter;1",
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISecurityReporter]),
|
||||
reportTLSError: function(transportSecurityInfo, hostname, port) {
|
||||
// don't send if there's no transportSecurityInfo (since the report cannot
|
||||
// contain anything of interest)
|
||||
if (!transportSecurityInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
// don't send a report if the pref is not enabled
|
||||
if (!Services.prefs.getBoolPref("security.ssl.errorReporting.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't send a report if the host we're connecting to is the report
|
||||
// server (otherwise we'll get loops when this fails)
|
||||
let endpoint =
|
||||
Services.prefs.getCharPref("security.ssl.errorReporting.url");
|
||||
let reportURI = Services.io.newURI(endpoint, null, null);
|
||||
|
||||
if (reportURI.host == hostname) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert the nsIX509CertList into a format that can be parsed into
|
||||
// JSON
|
||||
let asciiCertChain = [];
|
||||
|
||||
if (transportSecurityInfo.failedCertChain) {
|
||||
let certs = transportSecurityInfo.failedCertChain.getEnumerator();
|
||||
while (certs.hasMoreElements()) {
|
||||
let cert = certs.getNext();
|
||||
cert.QueryInterface(Ci.nsIX509Cert);
|
||||
asciiCertChain.push(btoa(getDERString(cert)));
|
||||
}
|
||||
}
|
||||
|
||||
let report = {
|
||||
hostname: hostname,
|
||||
port: port,
|
||||
timestamp: Math.round(Date.now() / 1000),
|
||||
errorCode: transportSecurityInfo.errorCode,
|
||||
failedCertChain: asciiCertChain,
|
||||
userAgent: protocolHandler.userAgent,
|
||||
version: 1,
|
||||
build: Services.appinfo.appBuildID,
|
||||
product: Services.appinfo.name,
|
||||
channel: UpdateUtils.UpdateChannel
|
||||
}
|
||||
|
||||
fetch(endpoint, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(report),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}).then(function (aResponse) {
|
||||
if (!aResponse.ok) {
|
||||
// request returned non-success status
|
||||
Services.telemetry.getHistogramById(HISTOGRAM_ID)
|
||||
.add(TLS_ERROR_REPORT_TELEMETRY_FAILURE);
|
||||
} else {
|
||||
Services.telemetry.getHistogramById(HISTOGRAM_ID)
|
||||
.add(TLS_ERROR_REPORT_TELEMETRY_SUCCESS);
|
||||
}
|
||||
}).catch(function (e) {
|
||||
// error making request to reportURL
|
||||
Services.telemetry.getHistogramById(HISTOGRAM_ID)
|
||||
.add(TLS_ERROR_REPORT_TELEMETRY_FAILURE);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecurityReporter]);
|
||||
@@ -0,0 +1,2 @@
|
||||
component {8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b} SecurityReporter.js
|
||||
contract @mozilla.org/securityreporter;1 {8a997c9a-bea1-11e5-a1fa-be6aBc8e7f8b}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user