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:
2023-11-23 23:41:21 +08:00
parent dc9aad1c85
commit 3128ff3820
103 changed files with 2753 additions and 1152 deletions
+5
View File
@@ -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
View File
@@ -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/. */
+6 -5
View File
@@ -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);
+44 -45
View File
@@ -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>
<!--
+3 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
}
+5
View File
@@ -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>">
-67
View File
@@ -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;
}
};
-73
View File
@@ -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");
}
-1
View File
@@ -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
-73
View File
@@ -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");
}
-1
View File
@@ -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
+2 -2
View File
@@ -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,
+120
View File
@@ -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;
}
-1
View File
@@ -114,7 +114,6 @@ button:disabled {
}
#certificateErrorReporting,
#reportCertificateError,
#reportSentMessage {
display: none;
}
+1
View File
@@ -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)
-73
View File
@@ -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");
}
-1
View File
@@ -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
View File
@@ -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;
}
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+4 -2
View File
@@ -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;
+2 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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);
+3 -26
View File
@@ -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,
+1 -4
View File
@@ -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
View File
@@ -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;
+4 -39
View File
@@ -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
+54 -59
View File
@@ -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>
+3 -10
View File
@@ -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,
+2
View File
@@ -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
View File
@@ -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()
{
+1 -1
View File
@@ -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;
+1 -3
View File
@@ -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)
+6 -9
View File
@@ -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();
-8
View File
@@ -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.
*
+1 -1
View File
@@ -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);
+2 -15
View File
@@ -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
+8 -2
View File
@@ -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;
}
+47 -11
View File
@@ -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);
+3 -1
View File
@@ -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
-8
View File
@@ -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;
+3 -8
View File
@@ -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>
+5 -6
View File
@@ -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
+3
View File
@@ -29,4 +29,7 @@ interface Storage {
[Throws]
void clear();
[ChromeOnly]
readonly attribute boolean isSessionOnly;
};
+29 -4
View File
@@ -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;
-2
View File
@@ -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(),
+6
View File
@@ -1162,6 +1162,12 @@ ObjectBox::asFunctionBox()
return static_cast<FunctionBox*>(this);
}
bool
ObjectBox::isModuleBox()
{
return object->is<ModuleObject>();
}
ModuleBox*
ObjectBox::asModuleBox()
{
+1 -1
View File
@@ -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);
-3
View File
@@ -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
View File
@@ -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");
+63
View File
@@ -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");
+4 -4
View File
@@ -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
View File
@@ -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_;
+2 -2
View File
@@ -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++;
+6
View File
@@ -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
{
+7
View File
@@ -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();
}
-3
View File
@@ -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);
+7 -13
View File
@@ -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)
{
-2
View File
@@ -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;
+1 -6
View File
@@ -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
+1 -6
View File
@@ -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);
-1
View File
@@ -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;
+59
View File
@@ -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();
}
+5
View File
@@ -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
+2 -14
View File
@@ -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)) {
+1 -2
View File
@@ -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]
+1 -1
View File
@@ -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>
+1
View File
@@ -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