summaryrefslogtreecommitdiffstats
path: root/dom/security
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /dom/security
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz
firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/security')
-rw-r--r--dom/security/ReferrerInfo.cpp36
-rw-r--r--dom/security/ReferrerInfo.h7
-rw-r--r--dom/security/featurepolicy/test/mochitest/mochitest.toml2
-rw-r--r--dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html26
-rw-r--r--dom/security/metrics.yaml153
-rw-r--r--dom/security/moz.build2
-rw-r--r--dom/security/nsCSPContext.cpp225
-rw-r--r--dom/security/nsCSPContext.h13
-rw-r--r--dom/security/nsCSPUtils.cpp51
-rw-r--r--dom/security/nsCSPUtils.h12
-rw-r--r--dom/security/nsContentSecurityUtils.cpp53
-rw-r--r--dom/security/nsHTTPSOnlyUtils.cpp63
-rw-r--r--dom/security/nsHTTPSOnlyUtils.h9
-rw-r--r--dom/security/test/csp/file_csp_error_messages.html33
-rw-r--r--dom/security/test/csp/mochitest.toml3
-rw-r--r--dom/security/test/csp/test_csp_error_messages.html75
-rw-r--r--dom/security/test/general/browser.toml10
-rw-r--r--dom/security/test/general/browser_restrict_privileged_about_script.js2
-rw-r--r--dom/security/test/general/browser_test_data_download.js4
-rw-r--r--dom/security/test/general/browser_test_data_text_csv.js4
-rw-r--r--dom/security/test/general/browser_test_http_download.js275
-rw-r--r--dom/security/test/general/browser_test_report_blocking.js2
-rw-r--r--dom/security/test/general/browser_test_toplevel_data_navigations.js2
-rw-r--r--dom/security/test/general/browser_test_view_image_data_navigation.js4
-rw-r--r--dom/security/test/general/http_download_page.html23
-rw-r--r--dom/security/test/general/http_download_server.sjs20
-rw-r--r--dom/security/test/general/test_block_script_wrong_mime.html6
-rw-r--r--dom/security/test/general/test_block_toplevel_data_navigation.html2
-rw-r--r--dom/security/test/general/test_bug1277803.xhtml2
-rw-r--r--dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html2
-rw-r--r--dom/security/test/general/test_meta_referrer.html2
-rw-r--r--dom/security/test/general/test_same_site_cookies_subrequest.html2
-rw-r--r--dom/security/test/general/test_same_site_cookies_toplevel_nav.html2
-rw-r--r--dom/security/test/https-first/browser_download_attribute.js2
-rw-r--r--dom/security/test/https-first/browser_httpsfirst.js35
-rw-r--r--dom/security/test/https-first/browser_mixed_content_download.js2
-rw-r--r--dom/security/test/https-first/browser_schemeless.js28
-rw-r--r--dom/security/test/https-first/file_data_uri.html2
-rw-r--r--dom/security/test/https-first/test_resource_upgrade.html2
-rw-r--r--dom/security/test/https-only/browser_hsts_host.js2
-rw-r--r--dom/security/test/https-only/browser_save_as.js14
-rw-r--r--dom/security/test/https-only/browser_user_gesture.js2
-rw-r--r--dom/security/test/https-only/file_upgrade_insecure.html2
-rw-r--r--dom/security/test/https-only/file_websocket_exceptions_iframe.html6
-rw-r--r--dom/security/test/https-only/test_redirect_upgrade.html4
-rw-r--r--dom/security/test/https-only/test_resource_upgrade.html2
-rw-r--r--dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js2
-rw-r--r--dom/security/test/referrer-policy/browser.toml4
-rw-r--r--dom/security/test/referrer-policy/browser_session_history.js (renamed from dom/security/test/referrer-policy/browser_fragment_navigation.js)17
-rw-r--r--dom/security/test/referrer-policy/file_session_history.sjs (renamed from dom/security/test/referrer-policy/file_fragment_navigation.sjs)14
-rw-r--r--dom/security/test/referrer-policy/referrer_helper.js4
-rw-r--r--dom/security/test/referrer-policy/test_img_referrer.html4
-rw-r--r--dom/security/test/sec-fetch/browser_external_loads.js4
-rw-r--r--dom/security/test/sec-fetch/browser_navigation.js2
-rw-r--r--dom/security/test/sec-fetch/test_iframe_history_manipulation.html2
-rw-r--r--dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html2
-rw-r--r--dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html2
-rw-r--r--dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html2
-rw-r--r--dom/security/test/sec-fetch/test_trustworthy_loopback.html2
-rw-r--r--dom/security/test/sec-fetch/test_websocket.html6
-rw-r--r--dom/security/test/unit/test_csp_reports.js2
-rw-r--r--dom/security/test/unit/test_csp_upgrade_insecure_request_header.js8
-rw-r--r--dom/security/test/unit/test_https_only_https_first_default_port.js8
-rw-r--r--dom/security/test/unit/test_https_only_https_first_prefs.js6
-rw-r--r--dom/security/trusted-types/TrustedHTML.cpp13
-rw-r--r--dom/security/trusted-types/TrustedHTML.h19
-rw-r--r--dom/security/trusted-types/TrustedScript.cpp13
-rw-r--r--dom/security/trusted-types/TrustedScript.h19
-rw-r--r--dom/security/trusted-types/TrustedScriptURL.cpp14
-rw-r--r--dom/security/trusted-types/TrustedScriptURL.h18
-rw-r--r--dom/security/trusted-types/TrustedTypePolicy.cpp43
-rw-r--r--dom/security/trusted-types/TrustedTypePolicy.h72
-rw-r--r--dom/security/trusted-types/TrustedTypePolicyFactory.cpp50
-rw-r--r--dom/security/trusted-types/TrustedTypePolicyFactory.h105
-rw-r--r--dom/security/trusted-types/TrustedTypeUtils.h35
-rw-r--r--dom/security/trusted-types/moz.build27
76 files changed, 1483 insertions, 266 deletions
diff --git a/dom/security/ReferrerInfo.cpp b/dom/security/ReferrerInfo.cpp
index 70cdddb8ab..565d4d3284 100644
--- a/dom/security/ReferrerInfo.cpp
+++ b/dom/security/ReferrerInfo.cpp
@@ -131,16 +131,9 @@ ReferrerPolicy ReferrerPolicyFromToken(const nsAString& aContent,
}
}
- // Supported tokes - ReferrerPolicyValues, are generated from
- // ReferrerPolicy.webidl
- for (uint8_t i = 0; ReferrerPolicyValues::strings[i].value; i++) {
- if (lowerContent.EqualsASCII(ReferrerPolicyValues::strings[i].value)) {
- return static_cast<enum ReferrerPolicy>(i);
- }
- }
-
- // Return no referrer policy (empty string) if none of the previous match
- return ReferrerPolicy::_empty;
+ // Return no referrer policy (empty string) if it's not a valid enum value.
+ return StringToEnum<ReferrerPolicy>(lowerContent)
+ .valueOr(ReferrerPolicy::_empty);
}
// static
@@ -187,18 +180,6 @@ ReferrerPolicy ReferrerInfo::ReferrerPolicyFromHeaderString(
return referrerPolicy;
}
-// static
-const char* ReferrerInfo::ReferrerPolicyToString(ReferrerPolicyEnum aPolicy) {
- uint8_t index = static_cast<uint8_t>(aPolicy);
- uint8_t referrerPolicyCount = ArrayLength(ReferrerPolicyValues::strings);
- MOZ_ASSERT(index < referrerPolicyCount);
- if (index >= referrerPolicyCount) {
- return "";
- }
-
- return ReferrerPolicyValues::strings[index].value;
-}
-
/* static */
uint32_t ReferrerInfo::GetUserReferrerSendingPolicy() {
return clamped<uint32_t>(
@@ -831,11 +812,8 @@ bool ReferrerInfo::ShouldIgnoreLessRestrictedPolicies(
nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, true);
- uint32_t idx = static_cast<uint32_t>(aPolicy);
-
AutoTArray<nsString, 2> params = {
- NS_ConvertUTF8toUTF16(
- nsDependentCString(ReferrerPolicyValues::strings[idx].value)),
+ NS_ConvertUTF8toUTF16(GetEnumString(aPolicy)),
NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault())};
LogMessageToConsole(aChannel, "ReferrerPolicyDisallowRelaxingMessage",
params);
@@ -1051,7 +1029,7 @@ ReferrerInfo::GetReferrerPolicy(
NS_IMETHODIMP
ReferrerInfo::GetReferrerPolicyString(nsACString& aResult) {
- aResult.AssignASCII(ReferrerPolicyToString(mPolicy));
+ aResult.AssignASCII(GetEnumString(mPolicy));
return NS_OK;
}
@@ -1719,7 +1697,9 @@ void ReferrerInfo::RecordTelemetry(nsIHttpChannel* aChannel) {
// requests and the rest 9 buckets are for cross-site requests.
uint32_t telemetryOffset =
IsCrossSiteRequest(aChannel)
- ? static_cast<uint32_t>(ReferrerPolicy::EndGuard_)
+ ? UnderlyingValue(
+ MaxContiguousEnumValue<dom::ReferrerPolicy>::value) +
+ 1
: 0;
Telemetry::Accumulate(Telemetry::REFERRER_POLICY_COUNT,
diff --git a/dom/security/ReferrerInfo.h b/dom/security/ReferrerInfo.h
index 78440a5a70..b62afbb934 100644
--- a/dom/security/ReferrerInfo.h
+++ b/dom/security/ReferrerInfo.h
@@ -258,13 +258,6 @@ class ReferrerInfo : public nsIReferrerInfo {
static ReferrerPolicyEnum ReferrerPolicyFromHeaderString(
const nsAString& aContent);
- /*
- * Helper function to convert ReferrerPolicy enum to string
- *
- * @param aPolicy referrer policy to convert.
- */
- static const char* ReferrerPolicyToString(ReferrerPolicyEnum aPolicy);
-
/**
* Hash function for this object
*/
diff --git a/dom/security/featurepolicy/test/mochitest/mochitest.toml b/dom/security/featurepolicy/test/mochitest/mochitest.toml
index c621331596..b61b067b97 100644
--- a/dom/security/featurepolicy/test/mochitest/mochitest.toml
+++ b/dom/security/featurepolicy/test/mochitest/mochitest.toml
@@ -10,5 +10,7 @@ support-files = [
["test_featureList.html"]
+["test_initial_aboutblank.html"]
+
["test_parser.html"]
fail-if = ["xorigin"]
diff --git a/dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html b/dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html
new file mode 100644
index 0000000000..79d1bfd4c4
--- /dev/null
+++ b/dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test feature policy - Initial about:blank</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<iframe name="parentIframe" allow="fullscreen 'none'" srcdoc="
+ <iframe name='regular'></iframe>
+ <iframe name='transient'></iframe>
+ <script>transient.stop()</script>
+"></iframe>
+
+<script type="text/javascript">
+add_task(function testAboutBlank() {
+ isDeeply(frames[0].transient.document.featurePolicy.allowedFeatures(),
+ frames[0].document.featurePolicy.allowedFeatures(),
+ "check allowed feature list for initial about:blank");
+ isDeeply(frames[0].regular.document.featurePolicy.allowedFeatures(),
+ frames[0].document.featurePolicy.allowedFeatures(),
+ "check allowed feature list for real load about:blank");
+});
+</script>
+</body>
+</html>
diff --git a/dom/security/metrics.yaml b/dom/security/metrics.yaml
new file mode 100644
index 0000000000..02084407b1
--- /dev/null
+++ b/dom/security/metrics.yaml
@@ -0,0 +1,153 @@
+# 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/.
+
+# Adding a new metric? We have docs for that!
+# https://firefox-source-docs.mozilla.org/toolkit/components/glean/user/new_definitions_file.html
+
+---
+$schema: moz://mozilla.org/schemas/glean/metrics/2-0-0
+$tags:
+ - 'Core :: DOM: Security'
+
+httpsfirst:
+ upgraded:
+ type: counter
+ description: >
+ Counts how often a load is marked to be upgraded to HTTPS because of
+ HTTPS-First (`dom.security.https_first` enabled).
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ upgraded_schemeless:
+ type: counter
+ description: >
+ Counts how often a load is marked to be upgraded to HTTPS because of
+ schemeless HTTPS-First (`dom.security.https_first` disabled, but load
+ marked as schemeless).
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgraded:
+ type: counter
+ description: >
+ How many regular HTTPS-First (`dom.security.https_first` enabled)
+ upgrades get downgraded again.
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgraded_schemeless:
+ type: counter
+ description: >
+ How many schemeless HTTPS-First (`dom.security.https_first` disabled, but
+ load marked as schemeless) upgrades get downgraded again.
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgraded_on_timer:
+ type: rate
+ description: >
+ How many HTTPS-First (`dom.security.https_first` enabled) upgrades get
+ downgraded again because the HTTP request fired after 3s received a answer
+ faster than the HTTPS request.
+ denominator_metric: httpsfirst.downgraded
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgraded_on_timer_schemeless:
+ type: rate
+ description: >
+ How many of schemeless HTTPS-First (`dom.security.https_first` disabled,
+ but load marked as schemeless) upgrades get downgraded again because the
+ HTTP request fired after 3s received a answer faster than the HTTPS
+ request
+ denominator_metric: httpsfirst.downgraded_schemeless
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgrade_time:
+ type: timing_distribution
+ description: >
+ If a HTTPS-First (`dom.security.https_first` enabled) upgrade isn't
+ successful, measures the timespan between the navigation start and the
+ downgrade. This is essentially the overhead caused by HTTPS-First if a
+ site does not support HTTPS.
+ time_unit: millisecond
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
+
+ downgrade_time_schemeless:
+ type: timing_distribution
+ description: >
+ If a schemeless HTTPS-First (`dom.security.https_first` disabled, but
+ load marked as schemeless) upgrade isn't successful, measures the
+ timespan between the navigation start and the downgrade. This is
+ essentially the overhead caused by HTTPS-First if a site does not support
+ HTTPS.
+ time_unit: millisecond
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1868380#c10
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - mjurgens@mozilla.com
+ - seceng-telemetry@mozilla.com
+ expires: never
diff --git a/dom/security/moz.build b/dom/security/moz.build
index 0f2aed6a1f..f63fa22db6 100644
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -9,7 +9,7 @@ with Files("*"):
TEST_DIRS += ["test"]
-DIRS += ["featurepolicy", "sanitizer"]
+DIRS += ["featurepolicy", "sanitizer", "trusted-types"]
EXPORTS.mozilla.dom += [
"CSPEvalChecker.h",
diff --git a/dom/security/nsCSPContext.cpp b/dom/security/nsCSPContext.cpp
index aafd2b64f2..ed44304484 100644
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -189,10 +189,11 @@ bool nsCSPContext::permitsInternal(
bool permits = true;
nsAutoString violatedDirective;
+ nsAutoString violatedDirectiveString;
for (uint32_t p = 0; p < mPolicies.Length(); p++) {
if (!mPolicies[p]->permits(aDir, aLoadInfo, aContentLocation,
!!aOriginalURIIfRedirect, aSpecific,
- violatedDirective)) {
+ violatedDirective, violatedDirectiveString)) {
// If the policy is violated and not report-only, reject the load and
// report to the console
if (!mPolicies[p]->getReportOnlyFlag()) {
@@ -200,12 +201,6 @@ bool nsCSPContext::permitsInternal(
permits = false;
}
- // In CSP 3.0 the effective directive doesn't become the actually used
- // directive in case of a fallback from e.g. script-src-elem to
- // script-src or default-src.
- nsAutoString effectiveDirective;
- effectiveDirective.AssignASCII(CSP_CSPDirectiveToString(aDir));
-
// Callers should set |aSendViolationReports| to false if this is a
// preload - the decision may be wrong due to the inability to get the
// nonce, and will incorrectly fail the unit tests.
@@ -226,9 +221,11 @@ bool nsCSPContext::permitsInternal(
BlockedContentSource::eUnknown, /* a BlockedContentSource */
aOriginalURIIfRedirect, /* in case of redirect originalURI is not
null */
- violatedDirective, effectiveDirective, p, /* policy index */
- u""_ns, /* no observer subject */
- spec, /* source file */
+ violatedDirective, violatedDirectiveString,
+ aDir, // aViolatedDirective
+ p, // policy index
+ u""_ns, // no observer subject
+ spec, // source file
false, // aReportSample (no sample)
u""_ns, /* no script sample */
lineNumber, /* line number */
@@ -519,7 +516,8 @@ void nsCSPContext::reportInlineViolation(
CSPDirective aDirective, Element* aTriggeringElement,
nsICSPEventListener* aCSPEventListener, const nsAString& aNonce,
bool aReportSample, const nsAString& aSample,
- const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective,
+ const nsAString& aViolatedDirective,
+ const nsAString& aViolatedDirectiveString, CSPDirective aEffectiveDirective,
uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
uint32_t aLineNumber, uint32_t aColumnNumber) {
nsString observerSubject;
@@ -564,14 +562,15 @@ void nsCSPContext::reportInlineViolation(
BlockedContentSource::eInline, // aBlockedSource
mSelfURI, // aOriginalURI
aViolatedDirective, // aViolatedDirective
- aEffectiveDirective, // aEffectiveDirective
- aViolatedPolicyIndex, // aViolatedPolicyIndex
- observerSubject, // aObserverSubject
- sourceFile, // aSourceFile
- aReportSample, // aReportSample
- aSample, // aScriptSample
- lineNumber, // aLineNum
- columnNumber); // aColumnNum
+ aViolatedDirectiveString,
+ aEffectiveDirective, // aEffectiveDirective
+ aViolatedPolicyIndex, // aViolatedPolicyIndex
+ observerSubject, // aObserverSubject
+ sourceFile, // aSourceFile
+ aReportSample, // aReportSample
+ aSample, // aScriptSample
+ lineNumber, // aLineNum
+ columnNumber); // aColumnNum
}
NS_IMETHODIMP
@@ -672,19 +671,16 @@ nsCSPContext::GetAllowsInline(CSPDirective aDirective, bool aHasUnsafeHash,
*outAllowsInline = false;
}
nsAutoString violatedDirective;
+ nsAutoString violatedDirectiveString;
bool reportSample = false;
- mPolicies[i]->getDirectiveStringAndReportSampleForContentType(
- aDirective, violatedDirective, &reportSample);
-
- // In CSP 3.0 the effective directive doesn't become the actually used
- // directive in case of a fallback from e.g. script-src-elem to
- // script-src or default-src.
- nsAutoString effectiveDirective;
- effectiveDirective.AssignASCII(CSP_CSPDirectiveToString(aDirective));
+ mPolicies[i]->getViolatedDirectiveInformation(
+ aDirective, violatedDirective, violatedDirectiveString,
+ &reportSample);
reportInlineViolation(aDirective, aTriggeringElement, aCSPEventListener,
aNonce, reportSample, content, violatedDirective,
- effectiveDirective, i, aLineNumber, aColumnNumber);
+ violatedDirectiveString, aDirective, i, aLineNumber,
+ aColumnNumber);
}
}
@@ -747,15 +743,18 @@ nsCSPContext::LogViolationDetails(
}
nsAutoString violatedDirective;
+ nsAutoString violatedDirectiveString;
bool reportSample = false;
- mPolicies[p]->getDirectiveStringAndReportSampleForContentType(
- SCRIPT_SRC_DIRECTIVE, violatedDirective, &reportSample);
+ mPolicies[p]->getViolatedDirectiveInformation(
+ SCRIPT_SRC_DIRECTIVE, violatedDirective, violatedDirectiveString,
+ &reportSample);
- AsyncReportViolation(aTriggeringElement, aCSPEventListener, nullptr,
- blockedContentSource, nullptr, violatedDirective,
- u"script-src"_ns /* aEffectiveDirective */, p,
- observerSubject, aSourceFile, reportSample,
- aScriptSample, aLineNum, aColumnNum);
+ AsyncReportViolation(
+ aTriggeringElement, aCSPEventListener, nullptr, blockedContentSource,
+ nullptr, violatedDirective, violatedDirectiveString,
+ CSPDirective::SCRIPT_SRC_DIRECTIVE /* aEffectiveDirective */, p,
+ observerSubject, aSourceFile, reportSample, aScriptSample, aLineNum,
+ aColumnNum);
}
return NS_OK;
}
@@ -1375,10 +1374,12 @@ class CSPReportSenderRunnable final : public Runnable {
nsIURI* aBlockedURI,
nsCSPContext::BlockedContentSource aBlockedContentSource,
nsIURI* aOriginalURI, uint32_t aViolatedPolicyIndex, bool aReportOnlyFlag,
- const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective,
- const nsAString& aObserverSubject, const nsAString& aSourceFile,
- bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum,
- uint32_t aColumnNum, nsCSPContext* aCSPContext)
+ const nsAString& aViolatedDirective,
+ const nsAString& aViolatedDirectiveString,
+ const CSPDirective aEffectiveDirective, const nsAString& aObserverSubject,
+ const nsAString& aSourceFile, bool aReportSample,
+ const nsAString& aScriptSample, uint32_t aLineNum, uint32_t aColumnNum,
+ nsCSPContext* aCSPContext)
: mozilla::Runnable("CSPReportSenderRunnable"),
mTriggeringElement(aTriggeringElement),
mCSPEventListener(aCSPEventListener),
@@ -1389,6 +1390,7 @@ class CSPReportSenderRunnable final : public Runnable {
mReportOnlyFlag(aReportOnlyFlag),
mReportSample(aReportSample),
mViolatedDirective(aViolatedDirective),
+ mViolatedDirectiveString(aViolatedDirectiveString),
mEffectiveDirective(aEffectiveDirective),
mSourceFile(aSourceFile),
mScriptSample(aScriptSample),
@@ -1436,16 +1438,18 @@ class CSPReportSenderRunnable final : public Runnable {
NS_IMETHOD Run() override {
MOZ_ASSERT(NS_IsMainThread());
- nsresult rv;
-
// 0) prepare violation data
mozilla::dom::SecurityPolicyViolationEventInit init;
nsAutoCString blockedContentSource;
BlockedContentSourceToString(mBlockedContentSource, blockedContentSource);
- rv = mCSPContext->GatherSecurityPolicyViolationEventData(
- mBlockedURI, blockedContentSource, mOriginalURI, mEffectiveDirective,
+ nsAutoString effectiveDirective;
+ effectiveDirective.AssignASCII(
+ CSP_CSPDirectiveToString(mEffectiveDirective));
+
+ nsresult rv = mCSPContext->GatherSecurityPolicyViolationEventData(
+ mBlockedURI, blockedContentSource, mOriginalURI, effectiveDirective,
mViolatedPolicyIndex, mSourceFile,
mReportSample ? mScriptSample : EmptyString(), mLineNum, mColumnNum,
init);
@@ -1464,32 +1468,7 @@ class CSPReportSenderRunnable final : public Runnable {
mCSPContext->SendReports(init, mViolatedPolicyIndex);
// 3) log to console (one per policy violation)
-
- if (mBlockedURI) {
- mBlockedURI->GetSpec(blockedContentSource);
- if (blockedContentSource.Length() >
- nsCSPContext::ScriptSampleMaxLength()) {
- bool isData = mBlockedURI->SchemeIs("data");
- if (NS_SUCCEEDED(rv) && isData &&
- blockedContentSource.Length() >
- nsCSPContext::ScriptSampleMaxLength()) {
- blockedContentSource.Truncate(nsCSPContext::ScriptSampleMaxLength());
- blockedContentSource.Append(
- NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis()));
- }
- }
- }
-
- if (blockedContentSource.Length() > 0) {
- nsString blockedContentSource16 =
- NS_ConvertUTF8toUTF16(blockedContentSource);
- AutoTArray<nsString, 2> params = {mViolatedDirective,
- blockedContentSource16};
- mCSPContext->logToConsole(
- mReportOnlyFlag ? "CSPROViolationWithURI" : "CSPViolationWithURI",
- params, mSourceFile, mScriptSample, mLineNum, mColumnNum,
- nsIScriptError::errorFlag);
- }
+ ReportToConsole();
// 4) fire violation event
// A frame-ancestors violation has occurred, but we should not dispatch
@@ -1503,6 +1482,104 @@ class CSPReportSenderRunnable final : public Runnable {
}
private:
+ void ReportToConsole() const {
+ NS_ConvertUTF8toUTF16 effectiveDirective(
+ CSP_CSPDirectiveToString(mEffectiveDirective));
+
+ switch (mBlockedContentSource) {
+ case nsCSPContext::BlockedContentSource::eInline: {
+ const char* errorName = nullptr;
+ if (mEffectiveDirective == CSPDirective::STYLE_SRC_ATTR_DIRECTIVE ||
+ mEffectiveDirective == CSPDirective::STYLE_SRC_ELEM_DIRECTIVE) {
+ errorName = mReportOnlyFlag ? "CSPROInlineStyleViolation"
+ : "CSPInlineStyleViolation";
+ } else if (mEffectiveDirective ==
+ CSPDirective::SCRIPT_SRC_ATTR_DIRECTIVE) {
+ errorName = mReportOnlyFlag ? "CSPROEventHandlerScriptViolation"
+ : "CSPEventHandlerScriptViolation";
+ } else {
+ MOZ_ASSERT(mEffectiveDirective ==
+ CSPDirective::SCRIPT_SRC_ELEM_DIRECTIVE);
+ errorName = mReportOnlyFlag ? "CSPROInlineScriptViolation"
+ : "CSPInlineScriptViolation";
+ }
+
+ AutoTArray<nsString, 2> params = {mViolatedDirectiveString,
+ effectiveDirective};
+ mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample,
+ mLineNum, mColumnNum,
+ nsIScriptError::errorFlag);
+ break;
+ }
+
+ case nsCSPContext::BlockedContentSource::eEval: {
+ AutoTArray<nsString, 2> params = {mViolatedDirectiveString,
+ effectiveDirective};
+ mCSPContext->logToConsole(mReportOnlyFlag ? "CSPROEvalScriptViolation"
+ : "CSPEvalScriptViolation",
+ params, mSourceFile, mScriptSample, mLineNum,
+ mColumnNum, nsIScriptError::errorFlag);
+ break;
+ }
+
+ case nsCSPContext::BlockedContentSource::eWasmEval: {
+ AutoTArray<nsString, 2> params = {mViolatedDirectiveString,
+ effectiveDirective};
+ mCSPContext->logToConsole(mReportOnlyFlag
+ ? "CSPROWasmEvalScriptViolation"
+ : "CSPWasmEvalScriptViolation",
+ params, mSourceFile, mScriptSample, mLineNum,
+ mColumnNum, nsIScriptError::errorFlag);
+ break;
+ }
+
+ case nsCSPContext::BlockedContentSource::eSelf:
+ case nsCSPContext::BlockedContentSource::eUnknown: {
+ nsAutoString source(u"<unknown>"_ns);
+ if (mBlockedURI) {
+ nsAutoCString uri;
+ mBlockedURI->GetSpec(uri);
+
+ if (mBlockedURI->SchemeIs("data") &&
+ uri.Length() > nsCSPContext::ScriptSampleMaxLength()) {
+ uri.Truncate(nsCSPContext::ScriptSampleMaxLength());
+ uri.Append(
+ NS_ConvertUTF16toUTF8(nsContentUtils::GetLocalizedEllipsis()));
+ }
+
+ if (!uri.IsEmpty()) {
+ CopyUTF8toUTF16(uri, source);
+ }
+ }
+
+ const char* errorName = nullptr;
+ switch (mEffectiveDirective) {
+ case CSPDirective::STYLE_SRC_ELEM_DIRECTIVE:
+ errorName =
+ mReportOnlyFlag ? "CSPROStyleViolation" : "CSPStyleViolation";
+ break;
+ case CSPDirective::SCRIPT_SRC_ELEM_DIRECTIVE:
+ errorName =
+ mReportOnlyFlag ? "CSPROScriptViolation" : "CSPScriptViolation";
+ break;
+ case CSPDirective::WORKER_SRC_DIRECTIVE:
+ errorName =
+ mReportOnlyFlag ? "CSPROWorkerViolation" : "CSPWorkerViolation";
+ break;
+ default:
+ errorName = mReportOnlyFlag ? "CSPROGenericViolation"
+ : "CSPGenericViolation";
+ }
+
+ AutoTArray<nsString, 3> params = {mViolatedDirectiveString, source,
+ effectiveDirective};
+ mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample,
+ mLineNum, mColumnNum,
+ nsIScriptError::errorFlag);
+ }
+ }
+ }
+
RefPtr<Element> mTriggeringElement;
nsCOMPtr<nsICSPEventListener> mCSPEventListener;
nsCOMPtr<nsIURI> mBlockedURI;
@@ -1512,7 +1589,8 @@ class CSPReportSenderRunnable final : public Runnable {
bool mReportOnlyFlag;
bool mReportSample;
nsString mViolatedDirective;
- nsString mEffectiveDirective;
+ nsString mViolatedDirectiveString;
+ CSPDirective mEffectiveDirective;
nsCOMPtr<nsISupports> mObserverSubject;
nsString mSourceFile;
nsString mScriptSample;
@@ -1554,7 +1632,8 @@ nsresult nsCSPContext::AsyncReportViolation(
Element* aTriggeringElement, nsICSPEventListener* aCSPEventListener,
nsIURI* aBlockedURI, BlockedContentSource aBlockedContentSource,
nsIURI* aOriginalURI, const nsAString& aViolatedDirective,
- const nsAString& aEffectiveDirective, uint32_t aViolatedPolicyIndex,
+ const nsAString& aViolatedDirectiveString,
+ const CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex,
const nsAString& aObserverSubject, const nsAString& aSourceFile,
bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum,
uint32_t aColumnNum) {
@@ -1565,8 +1644,8 @@ nsresult nsCSPContext::AsyncReportViolation(
aTriggeringElement, aCSPEventListener, aBlockedURI, aBlockedContentSource,
aOriginalURI, aViolatedPolicyIndex,
mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(), aViolatedDirective,
- aEffectiveDirective, aObserverSubject, aSourceFile, aReportSample,
- aScriptSample, aLineNum, aColumnNum, this);
+ aViolatedDirectiveString, aEffectiveDirective, aObserverSubject,
+ aSourceFile, aReportSample, aScriptSample, aLineNum, aColumnNum, this);
if (XRE_IsContentProcess()) {
if (mEventTarget) {
diff --git a/dom/security/nsCSPContext.h b/dom/security/nsCSPContext.h
index 0c1438e573..ae47e34cb3 100644
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -126,10 +126,12 @@ class nsCSPContext : public nsIContentSecurityPolicy {
mozilla::dom::Element* aTriggeringElement,
nsICSPEventListener* aCSPEventListener, nsIURI* aBlockedURI,
BlockedContentSource aBlockedContentSource, nsIURI* aOriginalURI,
- const nsAString& aViolatedDirective, const nsAString& aEffectiveDirective,
- uint32_t aViolatedPolicyIndex, const nsAString& aObserverSubject,
- const nsAString& aSourceFile, bool aReportSample,
- const nsAString& aScriptSample, uint32_t aLineNum, uint32_t aColumnNum);
+ const nsAString& aViolatedDirective,
+ const nsAString& aViolatedDirectiveString,
+ const CSPDirective aEffectiveDirective, uint32_t aViolatedPolicyIndex,
+ const nsAString& aObserverSubject, const nsAString& aSourceFile,
+ bool aReportSample, const nsAString& aScriptSample, uint32_t aLineNum,
+ uint32_t aColumnNum);
// Hands off! Don't call this method unless you know what you
// are doing. It's only supposed to be called from within
@@ -168,7 +170,8 @@ class nsCSPContext : public nsIContentSecurityPolicy {
const nsAString& aNonce, bool aReportSample,
const nsAString& aSample,
const nsAString& aViolatedDirective,
- const nsAString& aEffectiveDirective,
+ const nsAString& aViolatedDirectiveString,
+ CSPDirective aEffectiveDirective,
uint32_t aViolatedPolicyIndex,
uint32_t aLineNumber, uint32_t aColumnNumber);
diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp
index 50730b691b..11d09909f7 100644
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -1569,7 +1569,8 @@ nsCSPPolicy::~nsCSPPolicy() {
bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo,
nsIURI* aUri, bool aWasRedirected, bool aSpecific,
- nsAString& outViolatedDirective) const {
+ nsAString& outViolatedDirective,
+ nsAString& outViolatedDirectiveString) const {
if (CSPUTILSLOGENABLED()) {
CSPUTILSLOG(("nsCSPPolicy::permits, aUri: %s, aDir: %s, aSpecific: %s",
aUri->GetSpecOrDefault().get(), CSP_CSPDirectiveToString(aDir),
@@ -1578,6 +1579,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo,
NS_ASSERTION(aUri, "permits needs an uri to perform the check!");
outViolatedDirective.Truncate();
+ outViolatedDirectiveString.Truncate();
nsCSPDirective* defaultDir = nullptr;
@@ -1589,6 +1591,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo,
if (!mDirectives[i]->permits(aDir, aLoadInfo, aUri, aWasRedirected,
mReportOnly, mUpgradeInsecDir)) {
mDirectives[i]->getDirName(outViolatedDirective);
+ mDirectives[i]->toString(outViolatedDirectiveString);
return false;
}
return true;
@@ -1604,6 +1607,7 @@ bool nsCSPPolicy::permits(CSPDirective aDir, nsILoadInfo* aLoadInfo,
if (!defaultDir->permits(aDir, aLoadInfo, aUri, aWasRedirected, mReportOnly,
mUpgradeInsecDir)) {
defaultDir->getDirName(outViolatedDirective);
+ defaultDir->toString(outViolatedDirectiveString);
return false;
}
return true;
@@ -1692,43 +1696,22 @@ bool nsCSPPolicy::allowsAllInlineBehavior(CSPDirective aDir) const {
* The parameter outDirective is the equivalent of 'outViolatedDirective'
* for the ::permits() function family.
*/
-void nsCSPPolicy::getDirectiveStringAndReportSampleForContentType(
- CSPDirective aDirective, nsAString& outDirective,
- bool* aReportSample) const {
- MOZ_ASSERT(aReportSample);
+void nsCSPPolicy::getViolatedDirectiveInformation(CSPDirective aDirective,
+ nsAString& outDirective,
+ nsAString& outDirectiveString,
+ bool* aReportSample) const {
*aReportSample = false;
-
- nsCSPDirective* defaultDir = nullptr;
- for (uint32_t i = 0; i < mDirectives.Length(); i++) {
- if (mDirectives[i]->isDefaultDirective()) {
- defaultDir = mDirectives[i];
- continue;
- }
- if (mDirectives[i]->equals(aDirective)) {
- mDirectives[i]->getDirName(outDirective);
- *aReportSample = mDirectives[i]->hasReportSampleKeyword();
- return;
- }
- }
- // if we haven't found a matching directive yet,
- // the contentType must be restricted by the default directive
- if (defaultDir) {
- defaultDir->getDirName(outDirective);
- *aReportSample = defaultDir->hasReportSampleKeyword();
+ nsCSPDirective* directive = matchingOrDefaultDirective(aDirective);
+ if (!directive) {
+ MOZ_ASSERT_UNREACHABLE("Can not query violated directive");
+ outDirective.AppendLiteral("couldNotQueryViolatedDirective");
+ outDirective.Truncate();
return;
}
- NS_ASSERTION(false, "Can not query directive string for contentType!");
- outDirective.AppendLiteral("couldNotQueryViolatedDirective");
-}
-void nsCSPPolicy::getDirectiveAsString(CSPDirective aDir,
- nsAString& outDirective) const {
- for (uint32_t i = 0; i < mDirectives.Length(); i++) {
- if (mDirectives[i]->equals(aDir)) {
- mDirectives[i]->toString(outDirective);
- return;
- }
- }
+ directive->getDirName(outDirective);
+ directive->toString(outDirectiveString);
+ *aReportSample = directive->hasReportSampleKeyword();
}
/*
diff --git a/dom/security/nsCSPUtils.h b/dom/security/nsCSPUtils.h
index 2692681d03..eeccaf0c4a 100644
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -619,7 +619,8 @@ class nsCSPPolicy {
bool permits(CSPDirective aDirective, nsILoadInfo* aLoadInfo, nsIURI* aUri,
bool aWasRedirected, bool aSpecific,
- nsAString& outViolatedDirective) const;
+ nsAString& outViolatedDirective,
+ nsAString& outViolatedDirectiveString) const;
bool allows(CSPDirective aDirective, enum CSPKeyword aKeyword,
const nsAString& aHashOrNonce) const;
void toString(nsAString& outStr) const;
@@ -650,11 +651,10 @@ class nsCSPPolicy {
void getReportURIs(nsTArray<nsString>& outReportURIs) const;
- void getDirectiveStringAndReportSampleForContentType(
- CSPDirective aDirective, nsAString& outDirective,
- bool* aReportSample) const;
-
- void getDirectiveAsString(CSPDirective aDir, nsAString& outDirective) const;
+ void getViolatedDirectiveInformation(CSPDirective aDirective,
+ nsAString& outDirective,
+ nsAString& outDirectiveString,
+ bool* aReportSample) const;
uint32_t getSandboxFlags() const;
diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp
index a483522499..01e9c6d5db 100644
--- a/dom/security/nsContentSecurityUtils.cpp
+++ b/dom/security/nsContentSecurityUtils.cpp
@@ -1365,6 +1365,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
// preferences and downloads allow legacy inline scripts through hash src.
MOZ_ASSERT(!foundScriptSrc ||
StringBeginsWith(aboutSpec, "about:preferences"_ns) ||
+ StringBeginsWith(aboutSpec, "about:settings"_ns) ||
StringBeginsWith(aboutSpec, "about:downloads"_ns) ||
StringBeginsWith(aboutSpec, "about:asrouter"_ns) ||
StringBeginsWith(aboutSpec, "about:newtab"_ns) ||
@@ -1383,6 +1384,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
// remote web resources
MOZ_ASSERT(!foundWebScheme ||
StringBeginsWith(aboutSpec, "about:preferences"_ns) ||
+ StringBeginsWith(aboutSpec, "about:settings"_ns) ||
StringBeginsWith(aboutSpec, "about:addons"_ns) ||
StringBeginsWith(aboutSpec, "about:newtab"_ns) ||
StringBeginsWith(aboutSpec, "about:debugging"_ns) ||
@@ -1411,6 +1413,7 @@ void nsContentSecurityUtils::AssertAboutPageHasCSP(Document* aDocument) {
// Bug 1579160: Remove 'unsafe-inline' from style-src within
// about:preferences
"about:preferences"_ns,
+ "about:settings"_ns,
// Bug 1571346: Remove 'unsafe-inline' from style-src within about:addons
"about:addons"_ns,
// Bug 1584485: Remove 'unsafe-inline' from style-src within:
@@ -1553,7 +1556,7 @@ bool nsContentSecurityUtils::ValidateScriptFilename(JSContext* cx,
// and this is the most reasonable. See 1727770
u"about:downloads"_ns,
// We think this is the same problem as about:downloads
- u"about:preferences"_ns,
+ u"about:preferences"_ns, u"about:settings"_ns,
// Browser console will give a filename of 'debugger' See 1763943
// Sometimes it's 'debugger eager eval code', other times just 'debugger
// eval code'
@@ -1667,37 +1670,25 @@ long nsContentSecurityUtils::ClassifyDownload(
nsCOMPtr<nsIURI> contentLocation;
aChannel->GetURI(getter_AddRefs(contentLocation));
- nsCOMPtr<nsIPrincipal> loadingPrincipal = loadInfo->GetLoadingPrincipal();
- if (!loadingPrincipal) {
- loadingPrincipal = loadInfo->TriggeringPrincipal();
- }
- // Creating a fake Loadinfo that is just used for the MCB check.
- nsCOMPtr<nsILoadInfo> secCheckLoadInfo = new mozilla::net::LoadInfo(
- loadingPrincipal, loadInfo->TriggeringPrincipal(), nullptr,
- nsILoadInfo::SEC_ONLY_FOR_EXPLICIT_CONTENTSEC_CHECK,
- nsIContentPolicy::TYPE_FETCH);
- // Disable HTTPS-Only checks for that loadinfo. This is required because
- // otherwise nsMixedContentBlocker::ShouldLoad would assume that the request
- // is safe, because HTTPS-Only is handling it.
- secCheckLoadInfo->SetHttpsOnlyStatus(nsILoadInfo::HTTPS_ONLY_EXEMPT);
-
- int16_t decission = nsIContentPolicy::ACCEPT;
- nsMixedContentBlocker::ShouldLoad(false, // aHadInsecureImageRedirect
- contentLocation, // aContentLocation,
- secCheckLoadInfo, // aLoadinfo
- false, // aReportError
- &decission // aDecision
- );
- Telemetry::Accumulate(mozilla::Telemetry::MIXED_CONTENT_DOWNLOADS,
- decission != nsIContentPolicy::ACCEPT);
-
- if (StaticPrefs::dom_block_download_insecure() &&
- decission != nsIContentPolicy::ACCEPT) {
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
- if (httpChannel) {
- LogMessageToConsole(httpChannel, "MixedContentBlockedDownload");
+ if (StaticPrefs::dom_block_download_insecure()) {
+ // If we are not dealing with a potentially trustworthy origin, or a URI
+ // that is safe to be loaded like e.g. data:, then we block the load.
+ bool isInsecureDownload =
+ !nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(
+ contentLocation) &&
+ !nsMixedContentBlocker::URISafeToBeLoadedInSecureContext(
+ contentLocation);
+
+ Telemetry::Accumulate(mozilla::Telemetry::INSECURE_DOWNLOADS,
+ isInsecureDownload);
+
+ if (isInsecureDownload) {
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+ if (httpChannel) {
+ LogMessageToConsole(httpChannel, "BlockedInsecureDownload");
+ }
+ return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE;
}
- return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE;
}
if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
diff --git a/dom/security/nsHTTPSOnlyUtils.cpp b/dom/security/nsHTTPSOnlyUtils.cpp
index 2a3880ba70..535efaba4e 100644
--- a/dom/security/nsHTTPSOnlyUtils.cpp
+++ b/dom/security/nsHTTPSOnlyUtils.cpp
@@ -6,6 +6,8 @@
#include "mozilla/Components.h"
#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/NullPrincipal.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/net/DNS.h"
@@ -438,7 +440,7 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
// We can upgrade the request - let's log to the console and set the status
// so we know that we upgraded the request.
if (aLoadInfo->GetWasSchemelessInput() &&
- mozilla::StaticPrefs::dom_security_https_first_schemeless()) {
+ !IsHttpsFirstModeEnabled(isPrivateWin)) {
nsAutoCString urlCString;
aURI->GetSpec(urlCString);
NS_ConvertUTF8toUTF16 urlString(urlCString);
@@ -447,6 +449,8 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
nsHTTPSOnlyUtils::LogLocalizedString("HTTPSFirstSchemeless", params,
nsIScriptError::warningFlag, aLoadInfo,
aURI, true);
+
+ mozilla::glean::httpsfirst::upgraded_schemeless.Add();
} else {
nsAutoCString scheme;
@@ -461,7 +465,12 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
isSpeculative ? "HTTPSOnlyUpgradeSpeculativeConnection"
: "HTTPSOnlyUpgradeRequest",
params, nsIScriptError::warningFlag, aLoadInfo, aURI, true);
+
+ if (!isSpeculative) {
+ mozilla::glean::httpsfirst::upgraded.Add();
+ }
}
+
// Set flag so we know that we upgraded the request
httpsOnlyStatus |= nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST;
aLoadInfo->SetHttpsOnlyStatus(httpsOnlyStatus);
@@ -470,9 +479,11 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeHttpsFirstRequest(nsIURI* aURI,
/* static */
already_AddRefed<nsIURI>
-nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
- nsresult aStatus) {
- nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
+nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(
+ mozilla::net::DocumentLoadListener* aDocumentLoadListener,
+ nsresult aStatus) {
+ nsCOMPtr<nsIChannel> channel = aDocumentLoadListener->GetChannel();
+ nsCOMPtr<nsILoadInfo> loadInfo = channel->LoadInfo();
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
// Only downgrade if we this request was upgraded using HTTPS-First Mode
if (!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_UPGRADED_HTTPS_FIRST)) {
@@ -488,7 +499,7 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
// to check each NS_OK for those errors.
// Only downgrade an NS_OK status if it is an 4xx or 5xx error.
if (NS_SUCCEEDED(aStatus)) {
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
+ nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
// If no httpChannel exists we have nothing to do here.
if (!httpChannel) {
return nullptr;
@@ -532,7 +543,7 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
}
nsCOMPtr<nsIURI> uri;
- nsresult rv = aChannel->GetURI(getter_AddRefs(uri));
+ nsresult rv = channel->GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, nullptr);
nsAutoCString spec;
@@ -584,6 +595,33 @@ nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel,
nsIScriptError::warningFlag, loadInfo,
uri, true);
+ // Record telemety
+ nsDOMNavigationTiming* timing = aDocumentLoadListener->GetTiming();
+ if (timing) {
+ mozilla::TimeStamp navigationStart = timing->GetNavigationStartTimeStamp();
+ if (navigationStart) {
+ mozilla::TimeDuration duration =
+ mozilla::TimeStamp::Now() - navigationStart;
+ bool isPrivateWin =
+ loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
+
+ if (loadInfo->GetWasSchemelessInput() &&
+ !IsHttpsFirstModeEnabled(isPrivateWin)) {
+ mozilla::glean::httpsfirst::downgraded_schemeless.Add();
+ if (timing) {
+ mozilla::glean::httpsfirst::downgrade_time_schemeless
+ .AccumulateRawDuration(duration);
+ }
+ } else {
+ mozilla::glean::httpsfirst::downgraded.Add();
+ if (timing) {
+ mozilla::glean::httpsfirst::downgrade_time.AccumulateRawDuration(
+ duration);
+ }
+ }
+ }
+ }
+
return newURI.forget();
}
@@ -954,6 +992,19 @@ TestHTTPAnswerRunnable::OnStartRequest(nsIRequest* aRequest) {
nsresult httpsOnlyChannelStatus;
httpsOnlyChannel->GetStatus(&httpsOnlyChannelStatus);
if (httpsOnlyChannelStatus == NS_OK) {
+ bool isPrivateWin =
+ loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
+ if (!nsHTTPSOnlyUtils::IsHttpsOnlyModeEnabled(isPrivateWin)) {
+ // Record HTTPS-First Telemetry
+ if (loadInfo->GetWasSchemelessInput() &&
+ !nsHTTPSOnlyUtils::IsHttpsFirstModeEnabled(isPrivateWin)) {
+ mozilla::glean::httpsfirst::downgraded_on_timer_schemeless
+ .AddToNumerator();
+ } else {
+ mozilla::glean::httpsfirst::downgraded_on_timer.AddToNumerator();
+ }
+ }
+
httpsOnlyChannel->Cancel(NS_ERROR_NET_TIMEOUT_EXTERNAL);
}
}
diff --git a/dom/security/nsHTTPSOnlyUtils.h b/dom/security/nsHTTPSOnlyUtils.h
index 73a5219082..7e36bfadbd 100644
--- a/dom/security/nsHTTPSOnlyUtils.h
+++ b/dom/security/nsHTTPSOnlyUtils.h
@@ -95,12 +95,13 @@ class nsHTTPSOnlyUtils {
/**
* Determines if the request was previously upgraded with HTTPS-First, creates
* a downgraded URI and logs to console.
- * @param aStatus Status code
- * @param aChannel Failed channel
- * @return URI with http-scheme or nullptr
+ * @param aStatus Status code
+ * @param aDocumentLoadListener Failed document load listener
+ * @return URI with http-scheme or nullptr
*/
static already_AddRefed<nsIURI> PotentiallyDowngradeHttpsFirstRequest(
- nsIChannel* aChannel, nsresult aStatus);
+ mozilla::net::DocumentLoadListener* aDocumentLoadListener,
+ nsresult aStatus);
/**
* Checks if the error code is on a block-list of codes that are probably
diff --git a/dom/security/test/csp/file_csp_error_messages.html b/dom/security/test/csp/file_csp_error_messages.html
new file mode 100644
index 0000000000..65d26ac57e
--- /dev/null
+++ b/dom/security/test/csp/file_csp_error_messages.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Security-Policy" content="default-src 'nonce-abc';">
+ <title></title>
+</head>
+
+<!-- event handler -->
+<body onload="alert('onload');">
+
+ <!-- img-src -->
+ <img src="image.png">
+
+ <!-- external script -->
+ <script src=script.js></script>
+
+ <!-- inline script -->
+ <script>
+ alert("failure");
+ </script>
+
+ <script nonce="abc">
+ /* worker-src */
+ new Worker("/worker.js")
+ </script>
+
+ <script nonce="abc">
+ // eslint-disable-next-line no-eval
+ eval("hello world");
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/dom/security/test/csp/mochitest.toml b/dom/security/test/csp/mochitest.toml
index 8d8c6c31f5..5dd9a14222 100644
--- a/dom/security/test/csp/mochitest.toml
+++ b/dom/security/test/csp/mochitest.toml
@@ -433,6 +433,9 @@ skip-if = [
["test_connect-src.html"]
+["test_csp_error_messages.html"]
+support-files = ["file_csp_error_messages.html"]
+
["test_csp_frame_ancestors_about_blank.html"]
support-files = [
"file_csp_frame_ancestors_about_blank.html",
diff --git a/dom/security/test/csp/test_csp_error_messages.html b/dom/security/test/csp/test_csp_error_messages.html
new file mode 100644
index 0000000000..51be37e7c0
--- /dev/null
+++ b/dom/security/test/csp/test_csp_error_messages.html
@@ -0,0 +1,75 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test some specialized CSP errors</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<iframe id="cspframe"></iframe>
+
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+
+function cleanup() {
+ SpecialPowers.postConsoleSentinel();
+ SimpleTest.finish();
+};
+
+let errors = [];
+function add(name) {
+ ok(!errors.includes(name), `duplicate error for ${name}`);
+ errors.push(name);
+}
+
+SpecialPowers.registerConsoleListener(msg => {
+ if (!msg.errorMessage) {
+ return;
+ }
+
+ let {errorMessage} = msg;
+ function contains(str) {
+ ok(errorMessage.includes(str), `error message contains "${str}"`);
+ }
+
+ if (errorMessage.includes("(script-src-attr)")) {
+ contains("blocked an event handler");
+ contains("from being executed");
+ contains("Source: alert('onload');");
+ add("event handler");
+ } else if (errorMessage.includes("(img-src)")) {
+ contains("blocked the loading of a resource");
+ contains("/image.png");
+ add("image");
+ } else if (errorMessage.includes("an inline script")) {
+ contains("(script-src-elem)");
+ contains("from being executed");
+ add("inline script");
+ } else if (errorMessage.includes("a script")) {
+ contains("(script-src-elem)");
+ contains("from being executed");
+ contains("/script.js");
+ add("script");
+ } else if (errorMessage.includes("(worker-src)")) {
+ contains("(worker-src)");
+ contains("from being executed");
+ contains("/worker.js");
+ add("worker");
+ } else if (errorMessage.includes("a JavaScript eval")) {
+ contains("(script-src)");
+ contains("from being executed");
+ contains("Missing 'unsafe-eval'")
+ add("eval");
+ }
+
+ if (errors.length == 6) {
+ SimpleTest.executeSoon(cleanup);
+ }
+});
+
+document.getElementById('cspframe').src = 'file_csp_error_messages.html';
+</script>
+</body>
+</html>
diff --git a/dom/security/test/general/browser.toml b/dom/security/test/general/browser.toml
index 0f4ec5b224..c6d6b4bf79 100644
--- a/dom/security/test/general/browser.toml
+++ b/dom/security/test/general/browser.toml
@@ -48,6 +48,16 @@ support-files = [
"file_gpc_server.sjs",
]
+["browser_test_http_download.js"]
+skip-if = [
+ "win11_2009", # Bug 1784764
+ "os == 'linux' && !debug",
+]
+support-files = [
+ "http_download_page.html",
+ "http_download_server.sjs"
+]
+
["browser_test_referrer_loadInOtherProcess.js"]
["browser_test_report_blocking.js"]
diff --git a/dom/security/test/general/browser_restrict_privileged_about_script.js b/dom/security/test/general/browser_restrict_privileged_about_script.js
index 0baa6e3d4d..7dfb6d691a 100644
--- a/dom/security/test/general/browser_restrict_privileged_about_script.js
+++ b/dom/security/test/general/browser_restrict_privileged_about_script.js
@@ -20,7 +20,7 @@ add_task(async function test_principal_click() {
});
await BrowserTestUtils.withNewTab(
"about:test-about-privileged-with-scripts",
- async function (browser) {
+ async function () {
// Wait for page to fully load
info("Waiting for tab to be loaded..");
// let's look into the fully loaded about page
diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js
index df5a8aeac4..9cebb97b30 100644
--- a/dom/security/test/general/browser_test_data_download.js
+++ b/dom/security/test/general/browser_test_data_download.js
@@ -22,13 +22,13 @@ function addWindowListener(aURL) {
resolve(domwindow);
}, domwindow);
},
- onCloseWindow(aXULWindow) {},
+ onCloseWindow() {},
});
});
}
function waitDelay(delay) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
/* eslint-disable mozilla/no-arbitrary-setTimeout */
window.setTimeout(resolve, delay);
});
diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js
index 9855ddce46..b6c9f46336 100644
--- a/dom/security/test/general/browser_test_data_text_csv.js
+++ b/dom/security/test/general/browser_test_data_text_csv.js
@@ -6,7 +6,7 @@ const kTestPath = getRootDirectory(gTestPath).replace(
);
const kTestURI = kTestPath + "file_data_text_csv.html";
-function addWindowListener(aURL, aCallback) {
+function addWindowListener(aURL) {
return new Promise(resolve => {
Services.wm.addListener({
onOpenWindow(aXULWindow) {
@@ -22,7 +22,7 @@ function addWindowListener(aURL, aCallback) {
resolve(domwindow);
}, domwindow);
},
- onCloseWindow(aXULWindow) {},
+ onCloseWindow() {},
});
});
}
diff --git a/dom/security/test/general/browser_test_http_download.js b/dom/security/test/general/browser_test_http_download.js
new file mode 100644
index 0000000000..35e3fdfc4b
--- /dev/null
+++ b/dom/security/test/general/browser_test_http_download.js
@@ -0,0 +1,275 @@
+/* Any copyright is dedicated to the Public Domain.
+ * https://creativecommons.org/publicdomain/zero/1.0/ */
+
+ChromeUtils.defineESModuleGetters(this, {
+ Downloads: "resource://gre/modules/Downloads.sys.mjs",
+ DownloadsCommon: "resource:///modules/DownloadsCommon.sys.mjs",
+});
+
+const HandlerService = Cc[
+ "@mozilla.org/uriloader/handler-service;1"
+].getService(Ci.nsIHandlerService);
+
+const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+
+// Using insecure HTTP URL for a test cases around HTTP downloads
+let INSECURE_BASE_URL =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content/",
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ "http://example.com/"
+ ) + "http_download_page.html";
+
+function promiseFocus() {
+ return new Promise(resolve => {
+ waitForFocus(resolve);
+ });
+}
+
+async function task_openPanel() {
+ await promiseFocus();
+
+ let promise = BrowserTestUtils.waitForPopupEvent(
+ DownloadsPanel.panel,
+ "shown"
+ );
+ DownloadsPanel.showPanel();
+ await promise;
+}
+
+const downloadMonitoringView = {
+ _listeners: [],
+ onDownloadAdded(download) {
+ for (let listener of this._listeners) {
+ listener(download);
+ }
+ this._listeners = [];
+ },
+ waitForDownload(listener) {
+ this._listeners.push(listener);
+ },
+};
+
+/**
+ * Waits until a download is triggered.
+ * Unless the always_ask_before_handling_new_types pref is true, the download
+ * will simply be saved, so resolve when the view is notified of the new
+ * download. Otherwise, it waits until a prompt is shown, selects the choosen
+ * <action>, then accepts the dialog
+ * @param [action] Which action to select, either:
+ * "handleInternally", "save" or "open".
+ * @returns {Promise} Resolved once done.
+ */
+
+function shouldTriggerDownload(action = "save") {
+ if (
+ Services.prefs.getBoolPref(
+ "browser.download.always_ask_before_handling_new_types"
+ )
+ ) {
+ return new Promise((resolve, reject) => {
+ Services.wm.addListener({
+ onOpenWindow(xulWin) {
+ Services.wm.removeListener(this);
+ let win = xulWin.docShell.domWindow;
+ waitForFocus(() => {
+ if (
+ win.location ==
+ "chrome://mozapps/content/downloads/unknownContentType.xhtml"
+ ) {
+ let dialog = win.document.getElementById("unknownContentType");
+ let button = dialog.getButton("accept");
+ let actionRadio = win.document.getElementById(action);
+ actionRadio.click();
+ button.disabled = false;
+ dialog.acceptDialog();
+ resolve();
+ } else {
+ reject();
+ }
+ }, win);
+ },
+ });
+ });
+ }
+ return new Promise(res => {
+ downloadMonitoringView.waitForDownload(res);
+ });
+}
+
+const CONSOLE_ERROR_MESSAGE = "We blocked a download that’s not secure";
+
+function shouldConsoleError() {
+ // Waits until CONSOLE_ERROR_MESSAGE was logged
+ return new Promise((resolve, reject) => {
+ function listener(msgObj) {
+ let text = msgObj.message;
+ if (text.includes(CONSOLE_ERROR_MESSAGE)) {
+ Services.console.unregisterListener(listener);
+ resolve();
+ }
+ }
+ Services.console.registerListener(listener);
+ });
+}
+
+async function resetDownloads() {
+ // Removes all downloads from the download List
+ const types = new Set();
+ let publicList = await Downloads.getList(Downloads.PUBLIC);
+ let downloads = await publicList.getAll();
+ for (let download of downloads) {
+ if (download.contentType) {
+ types.add(download.contentType);
+ }
+ publicList.remove(download);
+ await download.finalize(true);
+ }
+
+ if (types.size) {
+ // reset handlers for the contentTypes of any files previously downloaded
+ for (let type of types) {
+ const mimeInfo = MIMEService.getFromTypeAndExtension(type, "");
+ info("resetting handler for type: " + type);
+ HandlerService.remove(mimeInfo);
+ }
+ }
+}
+
+function shouldNotifyDownloadUI() {
+ return new Promise(res => {
+ downloadMonitoringView.waitForDownload(async aDownload => {
+ let { error } = aDownload;
+ if (
+ error.becauseBlockedByReputationCheck &&
+ error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE
+ ) {
+ // It's an insecure Download, now Check that it has been cleaned up properly
+ if ((await IOUtils.stat(aDownload.target.path)).size != 0) {
+ throw new Error(`Download target is not empty!`);
+ }
+ if ((await IOUtils.stat(aDownload.target.path)).size != 0) {
+ throw new Error(`Download partFile was not cleaned up properly`);
+ }
+ // Assert that the Referrer is presnt
+ if (!aDownload.source.referrerInfo) {
+ throw new Error("The Blocked download is missing the ReferrerInfo");
+ }
+
+ res(aDownload);
+ } else {
+ ok(false, "No error for download that was expected to error!");
+ }
+ });
+ });
+}
+
+async function runTest(url, link, checkFunction, description) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["dom.block_download_insecure", true]],
+ });
+ await resetDownloads();
+
+ let tab = BrowserTestUtils.addTab(gBrowser, url);
+ gBrowser.selectedTab = tab;
+
+ let browser = gBrowser.getBrowserForTab(tab);
+ await BrowserTestUtils.browserLoaded(browser);
+
+ info("Checking: " + description);
+
+ let checkPromise = checkFunction();
+ // Click the Link to trigger the download
+ SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => {
+ content.document.getElementById(contentLink).click();
+ });
+
+ await checkPromise;
+
+ ok(true, description);
+ BrowserTestUtils.removeTab(tab);
+
+ await SpecialPowers.popPrefEnv();
+}
+
+add_setup(async () => {
+ let list = await Downloads.getList(Downloads.ALL);
+ list.addView(downloadMonitoringView);
+ registerCleanupFunction(() => list.removeView(downloadMonitoringView));
+});
+
+// Test Blocking
+add_task(async function test_blocking() {
+ for (let prefVal of [true, false]) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.download.always_ask_before_handling_new_types", prefVal]],
+ });
+ await runTest(
+ INSECURE_BASE_URL,
+ "http-link",
+ () =>
+ Promise.all([
+ shouldTriggerDownload(),
+ shouldNotifyDownloadUI(),
+ shouldConsoleError(),
+ ]),
+ "Insecure (HTTP) toplevel -> Insecure (HTTP) download should Error"
+ );
+ await SpecialPowers.popPrefEnv();
+ }
+});
+
+// Test Manual Unblocking
+add_task(async function test_manual_unblocking() {
+ for (let prefVal of [true, false]) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.download.always_ask_before_handling_new_types", prefVal]],
+ });
+ await runTest(
+ INSECURE_BASE_URL,
+ "http-link",
+ async () => {
+ let [, download] = await Promise.all([
+ shouldTriggerDownload(),
+ shouldNotifyDownloadUI(),
+ ]);
+ await download.unblock();
+ Assert.equal(
+ download.error,
+ null,
+ "There should be no error after unblocking"
+ );
+ },
+ "A blocked download should succeed to download after a manual unblock"
+ );
+ await SpecialPowers.popPrefEnv();
+ }
+});
+
+// Test Unblock Download Visible
+add_task(async function test_unblock_download_visible() {
+ for (let prefVal of [true, false]) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.download.always_ask_before_handling_new_types", prefVal]],
+ });
+ await promiseFocus();
+ await runTest(
+ INSECURE_BASE_URL,
+ "http-link",
+ async () => {
+ let panelHasOpened = BrowserTestUtils.waitForPopupEvent(
+ DownloadsPanel.panel,
+ "shown"
+ );
+ info("awaiting that the download is triggered and added to the list");
+ await Promise.all([shouldTriggerDownload(), shouldNotifyDownloadUI()]);
+ info("awaiting that the Download list shows itself");
+ await panelHasOpened;
+ DownloadsPanel.hidePanel();
+ ok(true, "The Download Panel should have opened on blocked download");
+ },
+ "A blocked download should open the download panel"
+ );
+ await SpecialPowers.popPrefEnv();
+ }
+});
diff --git a/dom/security/test/general/browser_test_report_blocking.js b/dom/security/test/general/browser_test_report_blocking.js
index ebd7514097..ab66f1d836 100644
--- a/dom/security/test/general/browser_test_report_blocking.js
+++ b/dom/security/test/general/browser_test_report_blocking.js
@@ -108,7 +108,7 @@ async function testReporting(test) {
return iframe.browsingContext;
});
- await SpecialPowers.spawn(frameBC, [type], async obj => {
+ await SpecialPowers.spawn(frameBC, [type], async () => {
// Wait until the reporting UI is visible.
await ContentTaskUtils.waitForCondition(() => {
let reportUI = content.document.getElementById("blockingErrorReporting");
diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js
index 0e006f1fd2..cf7c116eba 100644
--- a/dom/security/test/general/browser_test_toplevel_data_navigations.js
+++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js
@@ -15,7 +15,7 @@ add_task(async function test_nav_data_uri() {
await SpecialPowers.pushPrefEnv({
set: [["security.data_uri.block_toplevel_data_uri_navigations", true]],
});
- await BrowserTestUtils.withNewTab(kDataURI, async function (browser) {
+ await BrowserTestUtils.withNewTab(kDataURI, async function () {
await SpecialPowers.spawn(
gBrowser.selectedBrowser,
[{ kDataBody }],
diff --git a/dom/security/test/general/browser_test_view_image_data_navigation.js b/dom/security/test/general/browser_test_view_image_data_navigation.js
index 90aace1e3e..6e4173e343 100644
--- a/dom/security/test/general/browser_test_view_image_data_navigation.js
+++ b/dom/security/test/general/browser_test_view_image_data_navigation.js
@@ -8,7 +8,7 @@ add_task(async function test_principal_right_click_open_link_in_new_tab() {
const TEST_PAGE =
getRootDirectory(gTestPath) + "file_view_image_data_navigation.html";
- await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) {
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function () {
let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
// simulate right-click->view-image
@@ -43,7 +43,7 @@ add_task(async function test_right_click_open_bg_image() {
const TEST_PAGE =
getRootDirectory(gTestPath) + "file_view_bg_image_data_navigation.html";
- await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) {
+ await BrowserTestUtils.withNewTab(TEST_PAGE, async function () {
let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
// simulate right-click->view-image
diff --git a/dom/security/test/general/http_download_page.html b/dom/security/test/general/http_download_page.html
new file mode 100644
index 0000000000..c5461eaed3
--- /dev/null
+++ b/dom/security/test/general/http_download_page.html
@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+ <head>
+ <title>Test for the download attribute</title>
+ </head>
+ <body>
+ hi
+
+ <script>
+ const host = window.location.host;
+ const path = location.pathname.replace("http_download_page.html","http_download_server.sjs");
+
+ const insecureLink = document.createElement("a");
+ // eslint-disable-next-line @microsoft/sdl/no-insecure-url
+ insecureLink.href=`http://${host}/${path}`;
+ insecureLink.download="true";
+ insecureLink.id="http-link";
+ insecureLink.textContent="Not secure Link";
+
+ document.body.append(insecureLink);
+ </script>
+ </body>
+</html>
diff --git a/dom/security/test/general/http_download_server.sjs b/dom/security/test/general/http_download_server.sjs
new file mode 100644
index 0000000000..e659df2f40
--- /dev/null
+++ b/dom/security/test/general/http_download_server.sjs
@@ -0,0 +1,20 @@
+// force the Browser to Show a Download Prompt
+
+function handleRequest(request, response) {
+ let type = "image/png";
+ let filename = "hello.png";
+ request.queryString.split("&").forEach(val => {
+ var [key, value] = val.split("=");
+ if (key == "type") {
+ type = value;
+ }
+ if (key == "name") {
+ filename = value;
+ }
+ });
+
+ response.setHeader("Cache-Control", "no-cache", false);
+ response.setHeader("Content-Disposition", `attachment; filename=${filename}`);
+ response.setHeader("Content-Type", type);
+ response.write("🙈🙊🐵🙊");
+}
diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html
index 93a4b9d220..7122363dfc 100644
--- a/dom/security/test/general/test_block_script_wrong_mime.html
+++ b/dom/security/test/general/test_block_script_wrong_mime.html
@@ -25,7 +25,7 @@ const MIMETypes = [
// <script src="">
function testScript([mime, shouldLoad]) {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
let script = document.createElement("script");
script.onload = () => {
document.body.removeChild(script);
@@ -44,7 +44,7 @@ function testScript([mime, shouldLoad]) {
// new Worker()
function testWorker([mime, shouldLoad]) {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
let worker = new Worker("file_block_script_wrong_mime_server.sjs?type=worker&mime="+mime);
worker.onmessage = (event) => {
ok(shouldLoad, `worker with mime '${mime}' should load`)
@@ -62,7 +62,7 @@ function testWorker([mime, shouldLoad]) {
// new Worker() with importScripts()
function testWorkerImportScripts([mime, shouldLoad]) {
- return new Promise((resolve, reject) => {
+ return new Promise((resolve) => {
let worker = new Worker("file_block_script_wrong_mime_server.sjs?type=worker-import&mime="+mime);
worker.onmessage = (event) => {
ok(shouldLoad, `worker/importScripts with mime '${mime}' should load`)
diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html
index bbadacb218..1a1e6e8f8a 100644
--- a/dom/security/test/general/test_block_toplevel_data_navigation.html
+++ b/dom/security/test/general/test_block_toplevel_data_navigation.html
@@ -45,7 +45,7 @@ async function expectBlockedToplevelData() {
}
};
- function observer(subject, topic) {
+ function observer(subject) {
if (!bcs.includes(subject.webProgress)) {
bcs.push(subject.webProgress);
subject.webProgress.addProgressListener(progressListener, Ci.nsIWebProgress.NOTIFY_ALL);
diff --git a/dom/security/test/general/test_bug1277803.xhtml b/dom/security/test/general/test_bug1277803.xhtml
index 30cc82310b..8987219ed1 100644
--- a/dom/security/test/general/test_bug1277803.xhtml
+++ b/dom/security/test/general/test_bug1277803.xhtml
@@ -27,7 +27,7 @@
function runTest() {
// Register our observer to intercept favicon requests.
- function observer(aSubject, aTopic, aData) {
+ function observer(aSubject, aTopic) {
// Make sure this is a favicon request.
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
if (FAVICON_URI != httpChannel.URI.spec) {
diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
index 24ec5dbdd9..d0d702d606 100644
--- a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
+++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html
@@ -51,7 +51,7 @@ function createChromeScript() {
return Ci.nsIContentPolicy.ACCEPT;
},
- shouldProcess(contentLocation, loadInfo) {
+ shouldProcess() {
return Ci.nsIContentPolicy.ACCEPT;
}
};
diff --git a/dom/security/test/general/test_meta_referrer.html b/dom/security/test/general/test_meta_referrer.html
index f5e8b649f4..2871028869 100644
--- a/dom/security/test/general/test_meta_referrer.html
+++ b/dom/security/test/general/test_meta_referrer.html
@@ -24,7 +24,7 @@ function checkTestsDone() {
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
let counter = 0;
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com") || counter >= 2) {
return;
diff --git a/dom/security/test/general/test_same_site_cookies_subrequest.html b/dom/security/test/general/test_same_site_cookies_subrequest.html
index 304dbafa9a..0975e49663 100644
--- a/dom/security/test/general/test_same_site_cookies_subrequest.html
+++ b/dom/security/test/general/test_same_site_cookies_subrequest.html
@@ -78,7 +78,7 @@ function checkResult(aCookieVal) {
function setupQueryResultAndRunTest() {
var myXHR = new XMLHttpRequest();
myXHR.open("GET", "file_same_site_cookies_subrequest.sjs?queryresult" + curTest);
- myXHR.onload = function(e) {
+ myXHR.onload = function() {
checkResult(myXHR.responseText);
}
myXHR.onerror = function(e) {
diff --git a/dom/security/test/general/test_same_site_cookies_toplevel_nav.html b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
index aba825916b..9ba625e4a3 100644
--- a/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
+++ b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html
@@ -83,7 +83,7 @@ function checkResult(aCookieVal) {
function setupQueryResultAndRunTest() {
var myXHR = new XMLHttpRequest();
myXHR.open("GET", "file_same_site_cookies_toplevel_nav.sjs?queryresult" + curTest);
- myXHR.onload = function(e) {
+ myXHR.onload = function() {
checkResult( myXHR.responseText);
}
myXHR.onerror = function(e) {
diff --git a/dom/security/test/https-first/browser_download_attribute.js b/dom/security/test/https-first/browser_download_attribute.js
index 8165add998..ea4558cc84 100644
--- a/dom/security/test/https-first/browser_download_attribute.js
+++ b/dom/security/test/https-first/browser_download_attribute.js
@@ -31,7 +31,7 @@ let msgCounter = 0;
function shouldConsoleTryUpgradeAndError() {
// Waits until CONSOLE_ERROR_MESSAGE was logged.
// Checks if download was tried via http://
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
function listener(msgObj) {
let text = msgObj.message;
// Verify upgrade messages
diff --git a/dom/security/test/https-first/browser_httpsfirst.js b/dom/security/test/https-first/browser_httpsfirst.js
index 733474dcc1..c4437f6051 100644
--- a/dom/security/test/https-first/browser_httpsfirst.js
+++ b/dom/security/test/https-first/browser_httpsfirst.js
@@ -31,6 +31,7 @@ add_task(async function () {
await SpecialPowers.pushPrefEnv({
set: [["dom.security.https_first", false]],
});
+ Services.fog.testResetFOG();
await runPrefTest(
"http://example.com",
@@ -42,6 +43,23 @@ add_task(async function () {
set: [["dom.security.https_first", true]],
});
+ for (const key of [
+ "upgraded",
+ "upgradedSchemeless",
+ "downgraded",
+ "downgradedSchemeless",
+ "downgradedOnTimer",
+ "downgradedOnTimerSchemeless",
+ "downgradeTime",
+ "downgradeTimeSchemeless",
+ ]) {
+ is(
+ Glean.httpsfirst[key].testGetValue(),
+ null,
+ `No telemetry should have been recorded yet for ${key}`
+ );
+ }
+
await runPrefTest(
"http://example.com",
"Should upgrade upgradeable website",
@@ -71,4 +89,21 @@ add_task(async function () {
"Should downgrade after timeout.",
"http://"
);
+
+ info("Checking expected telemetry");
+ is(Glean.httpsfirst.upgraded.testGetValue(), 5);
+ is(Glean.httpsfirst.upgradedSchemeless.testGetValue(), null);
+ is(Glean.httpsfirst.downgraded.testGetValue(), 3);
+ is(Glean.httpsfirst.downgradedSchemeless.testGetValue(), null);
+ is(Glean.httpsfirst.downgradedOnTimer.testGetValue().numerator, 1);
+ is(Glean.httpsfirst.downgradedOnTimerSchemeless.testGetValue(), null);
+ const downgradeSeconds =
+ Glean.httpsfirst.downgradeTime.testGetValue().sum / 1_000_000_000;
+ ok(
+ downgradeSeconds > 2 && downgradeSeconds < 30,
+ `Summed downgrade time should be above 2 and below 30 seconds (is ${downgradeSeconds.toFixed(
+ 2
+ )}s)`
+ );
+ is(null, Glean.httpsfirst.downgradeTimeSchemeless.testGetValue());
});
diff --git a/dom/security/test/https-first/browser_mixed_content_download.js b/dom/security/test/https-first/browser_mixed_content_download.js
index 09ea64cea8..919470a78e 100644
--- a/dom/security/test/https-first/browser_mixed_content_download.js
+++ b/dom/security/test/https-first/browser_mixed_content_download.js
@@ -57,7 +57,7 @@ const DOWNLOAD_URL =
// falls back since download is not available via https
let msgCounter = 0;
function shouldConsoleError() {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
function listener(msgObj) {
let text = msgObj.message;
if (text.includes(CONSOLE_UPGRADE_MESSAGE) && msgCounter == 0) {
diff --git a/dom/security/test/https-first/browser_schemeless.js b/dom/security/test/https-first/browser_schemeless.js
index 9687f15072..64b078983d 100644
--- a/dom/security/test/https-first/browser_schemeless.js
+++ b/dom/security/test/https-first/browser_schemeless.js
@@ -153,6 +153,7 @@ async function runTest(aInput, aDesc, aExpectedScheme) {
add_task(async function () {
requestLongerTimeout(10);
+ Services.fog.testResetFOG();
await SpecialPowers.pushPrefEnv({
set: [
@@ -183,9 +184,36 @@ add_task(async function () {
"http"
);
+ for (const key of [
+ "upgraded",
+ "upgradedSchemeless",
+ "downgraded",
+ "downgradedSchemeless",
+ "downgradedOnTimer",
+ "downgradedOnTimerSchemeless",
+ "downgradeTime",
+ "downgradeTimeSchemeless",
+ ]) {
+ is(
+ Glean.httpsfirst[key].testGetValue(),
+ null,
+ `No telemetry should have been recorded yet for ${key}`
+ );
+ }
+
await runTest(
"example.com",
"Should upgrade upgradeable website without explicit scheme",
"https"
);
+
+ info("Checking expected telemetry");
+ is(Glean.httpsfirst.upgraded.testGetValue(), null);
+ is(Glean.httpsfirst.upgradedSchemeless.testGetValue(), 5);
+ is(Glean.httpsfirst.downgraded.testGetValue(), null);
+ is(Glean.httpsfirst.downgradedSchemeless.testGetValue(), null);
+ is(Glean.httpsfirst.downgradedOnTimer.testGetValue(), null);
+ is(Glean.httpsfirst.downgradedOnTimerSchemeless.testGetValue(), null);
+ is(Glean.httpsfirst.downgradeTime.testGetValue(), null);
+ is(Glean.httpsfirst.downgradeTimeSchemeless.testGetValue(), null);
});
diff --git a/dom/security/test/https-first/file_data_uri.html b/dom/security/test/https-first/file_data_uri.html
index 69133e5079..e6d5744802 100644
--- a/dom/security/test/https-first/file_data_uri.html
+++ b/dom/security/test/https-first/file_data_uri.html
@@ -6,7 +6,7 @@
</head>
<body>
<script class="testbody" type="text/javascript">
- window.onload = (event) => {
+ window.onload = () => {
let myLoc = window.location.href;
window.opener.parent.postMessage({location: myLoc}, "*");
window.close();
diff --git a/dom/security/test/https-first/test_resource_upgrade.html b/dom/security/test/https-first/test_resource_upgrade.html
index 66f65d9a04..275a6a23af 100644
--- a/dom/security/test/https-first/test_resource_upgrade.html
+++ b/dom/security/test/https-first/test_resource_upgrade.html
@@ -44,7 +44,7 @@
// returns after the server has received all the expected requests.
var myXHR = new XMLHttpRequest();
myXHR.open("GET", "file_upgrade_insecure_server.sjs?queryresult");
- myXHR.onload = function (e) {
+ myXHR.onload = function () {
var results = myXHR.responseText.split(",");
for (var index in results) {
checkResult(results[index]);
diff --git a/dom/security/test/https-only/browser_hsts_host.js b/dom/security/test/https-only/browser_hsts_host.js
index 858c19865c..c612606f72 100644
--- a/dom/security/test/https-only/browser_hsts_host.js
+++ b/dom/security/test/https-only/browser_hsts_host.js
@@ -146,7 +146,7 @@ add_task(async function () {
Services.obs.removeObserver(observer, "http-on-examine-response");
});
-function observer(subject, topic, state) {
+function observer(subject, topic) {
info("observer called with " + topic);
if (topic == "http-on-examine-response") {
onExamineResponse(subject);
diff --git a/dom/security/test/https-only/browser_save_as.js b/dom/security/test/https-only/browser_save_as.js
index 309dd69c79..fbfdf276a8 100644
--- a/dom/security/test/https-only/browser_save_as.js
+++ b/dom/security/test/https-only/browser_save_as.js
@@ -14,7 +14,7 @@ const TEST_PATH =
"http://example.com/browser/dom/security/test/https-only/file_save_as.html";
let MockFilePicker = SpecialPowers.MockFilePicker;
-MockFilePicker.init(window);
+MockFilePicker.init(window.browsingContext);
const tempDir = createTemporarySaveDirectory();
MockFilePicker.displayDirectory = tempDir;
@@ -78,7 +78,7 @@ function createPromiseForTransferComplete() {
}
function createPromiseForConsoleError(message) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
function listener(msgObj) {
let text = msgObj.message;
if (text.includes(message)) {
@@ -155,7 +155,11 @@ async function setHttpsFirstAndOnlyPrefs(httpsFirst, httpsOnly) {
add_task(async function testBaseline() {
// Run with HTTPS-First and HTTPS-Only disabled
await setHttpsFirstAndOnlyPrefs(false, false);
- await runTest("#insecure-link", HTTP_LINK, undefined);
+ await runTest(
+ "#insecure-link",
+ HTTP_LINK,
+ "We blocked a download that’s not secure: “http://example.org/”."
+ );
await runTest("#secure-link", HTTPS_LINK, undefined);
});
@@ -169,7 +173,7 @@ add_task(async function testHttpsFirst() {
await runTest(
"#insecure-link",
HTTP_LINK,
- "Blocked downloading insecure content “http://example.org/”."
+ "We blocked a download that’s not secure: “http://example.org/”."
);
await runTest("#secure-link", HTTPS_LINK, undefined);
});
@@ -181,7 +185,7 @@ add_task(async function testHttpsOnly() {
await runTest(
"#insecure-link",
HTTP_LINK,
- "Blocked downloading insecure content “http://example.org/”."
+ "We blocked a download that’s not secure: “http://example.org/”."
);
await runTest("#secure-link", HTTPS_LINK, undefined);
});
diff --git a/dom/security/test/https-only/browser_user_gesture.js b/dom/security/test/https-only/browser_user_gesture.js
index e7d6a20318..9eec10bd88 100644
--- a/dom/security/test/https-only/browser_user_gesture.js
+++ b/dom/security/test/https-only/browser_user_gesture.js
@@ -23,7 +23,7 @@ add_task(async function () {
// 1. Upgrade a page to https://
BrowserTestUtils.startLoadingURIString(browser, kTestURI);
await loaded;
- await ContentTask.spawn(browser, {}, async args => {
+ await ContentTask.spawn(browser, {}, async () => {
ok(
content.document.location.href.startsWith("https://"),
"Should be https"
diff --git a/dom/security/test/https-only/file_upgrade_insecure.html b/dom/security/test/https-only/file_upgrade_insecure.html
index 346cfbeb9c..b2d3b89e3d 100644
--- a/dom/security/test/https-only/file_upgrade_insecure.html
+++ b/dom/security/test/https-only/file_upgrade_insecure.html
@@ -55,7 +55,7 @@
);
if (AppConstants.platform !== "android") {
var mySocket = new WebSocket("ws://example.com/tests/dom/security/test/https-only/file_upgrade_insecure");
- mySocket.onopen = function(e) {
+ mySocket.onopen = function() {
if (mySocket.url.includes("wss://")) {
window.parent.postMessage({result: "websocket-ok"}, "*");
}
diff --git a/dom/security/test/https-only/file_websocket_exceptions_iframe.html b/dom/security/test/https-only/file_websocket_exceptions_iframe.html
index 23c6af2d45..d8d0046119 100644
--- a/dom/security/test/https-only/file_websocket_exceptions_iframe.html
+++ b/dom/security/test/https-only/file_websocket_exceptions_iframe.html
@@ -5,17 +5,17 @@
<script>
window.addEventListener("message", receiveMessage);
-function receiveMessage(event) {
+function receiveMessage() {
window.removeEventListener("message", receiveMessage);
var mySocket = new WebSocket("ws://example.com/tests/dom/security/test/https-only/file_upgrade_insecure");
- mySocket.onopen = function(e) {
+ mySocket.onopen = function() {
parent.dispatchEvent(new CustomEvent("WebSocketEnded", {
detail: { url: mySocket.url, state: "onopen" }
}));
mySocket.close();
};
- mySocket.onerror = function(e) {
+ mySocket.onerror = function() {
parent.dispatchEvent(new CustomEvent("WebSocketEnded", {
detail: { url: mySocket.url, state: "onerror" }
}));
diff --git a/dom/security/test/https-only/test_redirect_upgrade.html b/dom/security/test/https-only/test_redirect_upgrade.html
index 59f02f96d0..6cf96bd494 100644
--- a/dom/security/test/https-only/test_redirect_upgrade.html
+++ b/dom/security/test/https-only/test_redirect_upgrade.html
@@ -28,12 +28,12 @@ Test that 302 redirect requests get upgraded to https:// with HTTPS-Only Mode en
// Make a request to a site (eg. https://file_redirect.sjs?301), which will redirect to http://file_redirect.sjs?check.
// The response will either be secure-ok, if the request has been upgraded to https:// or secure-error if it didn't.
myXHR.open("GET", `https://example.com/tests/dom/security/test/https-only/file_redirect.sjs?${currentCode}`);
- myXHR.onload = (e) => {
+ myXHR.onload = () => {
is(myXHR.responseText, "secure-ok", `a ${currentCode} redirect when posting violation report should be blocked`)
testDone();
}
// This should not happen
- myXHR.onerror = (e) => {
+ myXHR.onerror = () => {
ok(false, `Could not query results from server for ${currentCode}-redirect test (" + e.message + ")`);
testDone();
}
diff --git a/dom/security/test/https-only/test_resource_upgrade.html b/dom/security/test/https-only/test_resource_upgrade.html
index 6584bad020..1be7fcc3dd 100644
--- a/dom/security/test/https-only/test_resource_upgrade.html
+++ b/dom/security/test/https-only/test_resource_upgrade.html
@@ -54,7 +54,7 @@
// returns after the server has received all the expected requests.
var myXHR = new XMLHttpRequest();
myXHR.open("GET", "file_upgrade_insecure_server.sjs?queryresult");
- myXHR.onload = function (e) {
+ myXHR.onload = function () {
var results = myXHR.responseText.split(",");
for (var index in results) {
checkResult(results[index]);
diff --git a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js
index ee350008aa..b103d83cd7 100644
--- a/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js
+++ b/dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js
@@ -101,7 +101,7 @@ function shouldTriggerDownload(action = "save") {
});
}
-const CONSOLE_ERROR_MESSAGE = "Blocked downloading insecure content";
+const CONSOLE_ERROR_MESSAGE = "We blocked a download that’s not secure";
function shouldConsoleError() {
// Waits until CONSOLE_ERROR_MESSAGE was logged
diff --git a/dom/security/test/referrer-policy/browser.toml b/dom/security/test/referrer-policy/browser.toml
index 325b6a3f49..a77046c85b 100644
--- a/dom/security/test/referrer-policy/browser.toml
+++ b/dom/security/test/referrer-policy/browser.toml
@@ -1,8 +1,8 @@
[DEFAULT]
support-files = ["referrer_page.sjs"]
-["browser_fragment_navigation.js"]
-support-files = ["file_fragment_navigation.sjs"]
+["browser_session_history.js"]
+support-files = ["file_session_history.sjs"]
["browser_referrer_disallow_cross_site_relaxing.js"]
diff --git a/dom/security/test/referrer-policy/browser_fragment_navigation.js b/dom/security/test/referrer-policy/browser_session_history.js
index c3d5e62854..b480ce4ff0 100644
--- a/dom/security/test/referrer-policy/browser_fragment_navigation.js
+++ b/dom/security/test/referrer-policy/browser_session_history.js
@@ -4,7 +4,7 @@
"use strict";
const TEST_FILE =
- "https://example.com/browser/dom/security/test/referrer-policy/file_fragment_navigation.sjs";
+ "https://example.com/browser/dom/security/test/referrer-policy/file_session_history.sjs";
add_task(async function test_browser_navigation() {
await BrowserTestUtils.withNewTab(TEST_FILE, async browser => {
@@ -37,6 +37,21 @@ add_task(async function test_browser_navigation() {
content.document.getElementById("ok"),
"Page should load when checking referrer after fragment navigation and reload"
);
+
+ info("Clicking on push_state button");
+ content.document.getElementById("push_state").click();
+ });
+
+ info("Reloading tab");
+ loadPromise = BrowserTestUtils.browserLoaded(browser);
+ await BrowserTestUtils.reloadTab(gBrowser.selectedTab);
+ await loadPromise;
+
+ await SpecialPowers.spawn(browser, [], () => {
+ ok(
+ content.document.getElementById("ok"),
+ "Page should load when checking referrer after history.pushState and reload"
+ );
});
});
});
diff --git a/dom/security/test/referrer-policy/file_fragment_navigation.sjs b/dom/security/test/referrer-policy/file_session_history.sjs
index 5fb6f0d826..3d5f06b026 100644
--- a/dom/security/test/referrer-policy/file_fragment_navigation.sjs
+++ b/dom/security/test/referrer-policy/file_session_history.sjs
@@ -6,16 +6,22 @@ function handleRequest(request, response) {
request.queryString === "check_referrer" &&
(!request.hasHeader("referer") ||
request.getHeader("referer") !==
- "https://example.com/browser/dom/security/test/referrer-policy/file_fragment_navigation.sjs")
+ "https://example.com/browser/dom/security/test/referrer-policy/file_session_history.sjs")
) {
response.setStatusLine(request.httpVersion, 400, "Bad Request");
response.write("Did not receive referrer");
} else {
response.setHeader("Content-Type", "text/html");
response.write(
- `<span id="ok">OK</span>
-<a id="check_referrer" href="?check_referrer">check_referrer</a>
-<a id="fragment" href="#fragment">fragment</a>`
+ `<span id="ok">OK</span>
+ <a id="check_referrer" href="?check_referrer">check_referrer</a>
+ <a id="fragment" href="#fragment">fragment</a>
+ <script>
+ function pushState(){
+ history.pushState({}, "", location);
+ }
+ </script>
+ <button id="push_state" onclick="pushState();" >push_state</button>`
);
}
}
diff --git a/dom/security/test/referrer-policy/referrer_helper.js b/dom/security/test/referrer-policy/referrer_helper.js
index b892017eef..92593fa907 100644
--- a/dom/security/test/referrer-policy/referrer_helper.js
+++ b/dom/security/test/referrer-policy/referrer_helper.js
@@ -61,7 +61,7 @@ function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
);
advance();
};
- var onerror = xhr => {
+ var onerror = () => {
ok(false, "Can't get results from the counter server.");
SimpleTest.finish();
};
@@ -69,7 +69,7 @@ function checkIndividualResults(aTestname, aExpectedReferrer, aName) {
}
function resetState() {
- doXHR(RESET_STATE, advance, function (xhr) {
+ doXHR(RESET_STATE, advance, function () {
ok(false, "error in reset state");
SimpleTest.finish();
});
diff --git a/dom/security/test/referrer-policy/test_img_referrer.html b/dom/security/test/referrer-policy/test_img_referrer.html
index fcc80929d2..5e3a2e6ddf 100644
--- a/dom/security/test/referrer-policy/test_img_referrer.html
+++ b/dom/security/test/referrer-policy/test_img_referrer.html
@@ -64,7 +64,7 @@ function checkIndividualResults(aTestname, aExpectedImg, aName) {
advance();
},
- function(xhr) {
+ function() {
ok(false, "Can't get results from the counter server.");
SimpleTest.finish();
});
@@ -73,7 +73,7 @@ function checkIndividualResults(aTestname, aExpectedImg, aName) {
function resetState() {
doXHR('/tests/dom/security/test/referrer-policy/img_referrer_testserver.sjs?action=resetState',
advance,
- function(xhr) {
+ function() {
ok(false, "error in reset state");
SimpleTest.finish();
});
diff --git a/dom/security/test/sec-fetch/browser_external_loads.js b/dom/security/test/sec-fetch/browser_external_loads.js
index 0340b46899..070342e800 100644
--- a/dom/security/test/sec-fetch/browser_external_loads.js
+++ b/dom/security/test/sec-fetch/browser_external_loads.js
@@ -7,7 +7,7 @@ const TEST_PATH = getRootDirectory(gTestPath).replace(
var gExpectedHeader = {};
-function checkSecFetchUser(subject, topic, data) {
+function checkSecFetchUser(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com")) {
return;
@@ -45,7 +45,7 @@ add_task(async function external_load() {
Services.obs.addObserver(checkSecFetchUser, "http-on-stop-request");
let headersChecked = new Promise(resolve => {
- let reqStopped = async (subject, topic, data) => {
+ let reqStopped = async () => {
Services.obs.removeObserver(reqStopped, "http-on-stop-request");
resolve();
};
diff --git a/dom/security/test/sec-fetch/browser_navigation.js b/dom/security/test/sec-fetch/browser_navigation.js
index d203391356..2d51a7d1f5 100644
--- a/dom/security/test/sec-fetch/browser_navigation.js
+++ b/dom/security/test/sec-fetch/browser_navigation.js
@@ -10,7 +10,7 @@ async function setup() {
waitForExplicitFinish();
}
-function checkSecFetchUser(subject, topic, data) {
+function checkSecFetchUser(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com/")) {
return;
diff --git a/dom/security/test/sec-fetch/test_iframe_history_manipulation.html b/dom/security/test/sec-fetch/test_iframe_history_manipulation.html
index 5ec749bf4d..65d79fa530 100644
--- a/dom/security/test/sec-fetch/test_iframe_history_manipulation.html
+++ b/dom/security/test/sec-fetch/test_iframe_history_manipulation.html
@@ -18,7 +18,7 @@ let testFrame;
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
info("request observed: " + channel.URI.spec);
if (!channel.URI.spec.startsWith("https://example.org")) {
diff --git a/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html
index 28eae80226..d05ae4df70 100644
--- a/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html
+++ b/dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html
@@ -25,7 +25,7 @@ let testPassCounter = 0;
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) {
return;
diff --git a/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html
index adee5afe84..1a3fa85603 100644
--- a/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html
+++ b/dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html
@@ -25,7 +25,7 @@ let testPassCounter = 0;
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) {
return;
diff --git a/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html b/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html
index b532baeb5e..1dd7f8864e 100644
--- a/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html
+++ b/dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html
@@ -26,7 +26,7 @@ let testWindow;
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_redirect.sjs")) {
return;
diff --git a/dom/security/test/sec-fetch/test_trustworthy_loopback.html b/dom/security/test/sec-fetch/test_trustworthy_loopback.html
index 95ecac17ed..3b44895e77 100644
--- a/dom/security/test/sec-fetch/test_trustworthy_loopback.html
+++ b/dom/security/test/sec-fetch/test_trustworthy_loopback.html
@@ -23,7 +23,7 @@ function checkTestsDone() {
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.includes("localhost") ||
channel.URI.spec.startsWith("http://localhost:9898/tests/dom/security/test/sec-fetch/file_trustworthy_loopback.html")) {
diff --git a/dom/security/test/sec-fetch/test_websocket.html b/dom/security/test/sec-fetch/test_websocket.html
index 5df0553a4f..4613419040 100644
--- a/dom/security/test/sec-fetch/test_websocket.html
+++ b/dom/security/test/sec-fetch/test_websocket.html
@@ -21,7 +21,7 @@ function checkTestsDone() {
var script = SpecialPowers.loadChromeScript(() => {
/* eslint-env mozilla/chrome-script */
- Services.obs.addObserver(function onExamResp(subject, topic, data) {
+ Services.obs.addObserver(function onExamResp(subject) {
let channel = subject.QueryInterface(Ci.nsIHttpChannel);
if (!channel.URI.spec.startsWith("https://example.com/tests/dom/security/test/sec-fetch/file_websocket")) {
return;
@@ -61,11 +61,11 @@ script.addMessageListener("test-end", () => {
});
var wssSocket = new WebSocket("wss://example.com/tests/dom/security/test/sec-fetch/file_websocket");
-wssSocket.onopen = function(e) {
+wssSocket.onopen = function() {
ok(true, "sanity: wssSocket onopen");
checkTestsDone();
};
-wssSocket.onerror = function(e) {
+wssSocket.onerror = function() {
ok(false, "sanity: wssSocket onerror");
};
diff --git a/dom/security/test/unit/test_csp_reports.js b/dom/security/test/unit/test_csp_reports.js
index 36da1a13e5..3d5a00b0f6 100644
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -23,7 +23,7 @@ const REPORT_SERVER_URI = "http://localhost";
* or fails a test based on what it gets.
*/
function makeReportHandler(testpath, message, expectedJSON) {
- return function (request, response) {
+ return function (request) {
// we only like "POST" submissions for reports!
if (request.method !== "POST") {
do_throw("violation report should be a POST request");
diff --git a/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js b/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js
index 26758d261d..1c5fdabf31 100644
--- a/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js
+++ b/dom/security/test/unit/test_csp_upgrade_insecure_request_header.js
@@ -45,11 +45,11 @@ var tests = [
function ChannelListener() {}
ChannelListener.prototype = {
- onStartRequest(request) {},
- onDataAvailable(request, stream, offset, count) {
+ onStartRequest() {},
+ onDataAvailable() {
do_throw("Should not get any data!");
},
- onStopRequest(request, status) {
+ onStopRequest(request) {
var upgrade_insecure_header = false;
try {
if (request.getRequestHeader("Upgrade-Insecure-Requests")) {
@@ -76,7 +76,7 @@ function setupChannel(aContentType) {
return chan;
}
-function serverHandler(metadata, response) {
+function serverHandler() {
// no need to perform anything here
}
diff --git a/dom/security/test/unit/test_https_only_https_first_default_port.js b/dom/security/test/unit/test_https_only_https_first_default_port.js
index bd4d6717eb..06ffb80eee 100644
--- a/dom/security/test/unit/test_https_only_https_first_default_port.js
+++ b/dom/security/test/unit/test_https_only_https_first_default_port.js
@@ -41,13 +41,13 @@ const TESTS = [
function ChannelListener() {}
ChannelListener.prototype = {
- onStartRequest(request) {
+ onStartRequest() {
// dummy implementation
},
- onDataAvailable(request, stream, offset, count) {
+ onDataAvailable() {
do_throw("Should not get any data!");
},
- onStopRequest(request, status) {
+ onStopRequest(request) {
var chan = request.QueryInterface(Ci.nsIChannel);
let requestURL = chan.URI;
Assert.equal(
@@ -79,7 +79,7 @@ function setUpChannel() {
return chan;
}
-function serverHandler(metadata, response) {
+function serverHandler() {
// dummy implementation
}
diff --git a/dom/security/test/unit/test_https_only_https_first_prefs.js b/dom/security/test/unit/test_https_only_https_first_prefs.js
index 9c6ced1fcb..6c7e112d9b 100644
--- a/dom/security/test/unit/test_https_only_https_first_prefs.js
+++ b/dom/security/test/unit/test_https_only_https_first_prefs.js
@@ -272,10 +272,10 @@ ChannelListener.prototype = {
var authHeader = httpChan.getRequestHeader("Authorization");
Assert.equal(authHeader, "Basic user:pass", curTest.description);
},
- onDataAvailable(request, stream, offset, count) {
+ onDataAvailable() {
do_throw("Should not get any data!");
},
- onStopRequest(request, status) {
+ onStopRequest(request) {
var chan = request.QueryInterface(Ci.nsIChannel);
let requestURL = chan.URI;
Assert.equal(
@@ -331,7 +331,7 @@ function setUpChannel() {
return chan;
}
-function serverHandler(metadata, response) {
+function serverHandler() {
// dummy implementation
}
diff --git a/dom/security/trusted-types/TrustedHTML.cpp b/dom/security/trusted-types/TrustedHTML.cpp
new file mode 100644
index 0000000000..005cab8c63
--- /dev/null
+++ b/dom/security/trusted-types/TrustedHTML.cpp
@@ -0,0 +1,13 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/TrustedHTML.h"
+
+namespace mozilla::dom {
+
+IMPL_TRUSTED_TYPE_CLASS(TrustedHTML)
+
+} // namespace mozilla::dom
diff --git a/dom/security/trusted-types/TrustedHTML.h b/dom/security/trusted-types/TrustedHTML.h
new file mode 100644
index 0000000000..68a642c83a
--- /dev/null
+++ b/dom/security/trusted-types/TrustedHTML.h
@@ -0,0 +1,19 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_
+
+#include "mozilla/dom/TrustedTypeUtils.h"
+
+namespace mozilla::dom {
+
+// https://w3c.github.io/trusted-types/dist/spec/#trusted-html
+DECL_TRUSTED_TYPE_CLASS(TrustedHTML)
+
+} // namespace mozilla::dom
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDHTML_H_
diff --git a/dom/security/trusted-types/TrustedScript.cpp b/dom/security/trusted-types/TrustedScript.cpp
new file mode 100644
index 0000000000..496c53278a
--- /dev/null
+++ b/dom/security/trusted-types/TrustedScript.cpp
@@ -0,0 +1,13 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/TrustedScript.h"
+
+namespace mozilla::dom {
+
+IMPL_TRUSTED_TYPE_CLASS(TrustedScript)
+
+} // namespace mozilla::dom
diff --git a/dom/security/trusted-types/TrustedScript.h b/dom/security/trusted-types/TrustedScript.h
new file mode 100644
index 0000000000..0b6e0965ed
--- /dev/null
+++ b/dom/security/trusted-types/TrustedScript.h
@@ -0,0 +1,19 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_
+
+#include "mozilla/dom/TrustedTypeUtils.h"
+
+namespace mozilla::dom {
+
+// https://w3c.github.io/trusted-types/dist/spec/#trusted-script
+DECL_TRUSTED_TYPE_CLASS(TrustedScript)
+
+} // namespace mozilla::dom
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPT_H_
diff --git a/dom/security/trusted-types/TrustedScriptURL.cpp b/dom/security/trusted-types/TrustedScriptURL.cpp
new file mode 100644
index 0000000000..8de2448f91
--- /dev/null
+++ b/dom/security/trusted-types/TrustedScriptURL.cpp
@@ -0,0 +1,14 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/TrustedScriptURL.h"
+
+namespace mozilla::dom {
+
+// https://w3c.github.io/trusted-types/dist/spec/#trused-script-url
+IMPL_TRUSTED_TYPE_CLASS(TrustedScriptURL)
+
+} // namespace mozilla::dom
diff --git a/dom/security/trusted-types/TrustedScriptURL.h b/dom/security/trusted-types/TrustedScriptURL.h
new file mode 100644
index 0000000000..6e71235cb9
--- /dev/null
+++ b/dom/security/trusted-types/TrustedScriptURL.h
@@ -0,0 +1,18 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_
+
+#include "mozilla/dom/TrustedTypeUtils.h"
+
+namespace mozilla::dom {
+
+DECL_TRUSTED_TYPE_CLASS(TrustedScriptURL)
+
+} // namespace mozilla::dom
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDSCRIPTURL_H_
diff --git a/dom/security/trusted-types/TrustedTypePolicy.cpp b/dom/security/trusted-types/TrustedTypePolicy.cpp
new file mode 100644
index 0000000000..3c4e758ed0
--- /dev/null
+++ b/dom/security/trusted-types/TrustedTypePolicy.cpp
@@ -0,0 +1,43 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/TrustedTypePolicy.h"
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/dom/TrustedTypePolicyFactory.h"
+#include "mozilla/dom/TrustedTypesBinding.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TrustedTypePolicy, mParentObject)
+
+JSObject* TrustedTypePolicy::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return TrustedTypePolicy_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+UniquePtr<TrustedHTML> TrustedTypePolicy::CreateHTML(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const {
+ // TODO: implement the spec.
+ return MakeUnique<TrustedHTML>();
+}
+
+UniquePtr<TrustedScript> TrustedTypePolicy::CreateScript(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const {
+ // TODO: implement the spec.
+ return MakeUnique<TrustedScript>();
+}
+
+UniquePtr<TrustedScriptURL> TrustedTypePolicy::CreateScriptURL(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const {
+ // TODO: implement the spec.
+ return MakeUnique<TrustedScriptURL>();
+}
+
+} // namespace mozilla::dom
diff --git a/dom/security/trusted-types/TrustedTypePolicy.h b/dom/security/trusted-types/TrustedTypePolicy.h
new file mode 100644
index 0000000000..22d99947b3
--- /dev/null
+++ b/dom/security/trusted-types/TrustedTypePolicy.h
@@ -0,0 +1,72 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_
+
+#include "js/TypeDecls.h"
+#include "js/Value.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/DOMString.h"
+#include "mozilla/dom/TrustedHTML.h"
+#include "mozilla/dom/TrustedScript.h"
+#include "mozilla/dom/TrustedScriptURL.h"
+#include "nsISupportsImpl.h"
+#include "nsStringFwd.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla::dom {
+
+class TrustedTypePolicyFactory;
+
+// https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy
+class TrustedTypePolicy : public nsWrapperCache {
+ public:
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrustedTypePolicy)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(TrustedTypePolicy)
+
+ explicit TrustedTypePolicy(TrustedTypePolicyFactory* aParentObject)
+ : mParentObject{aParentObject} {}
+
+ // Required for Web IDL binding.
+ TrustedTypePolicyFactory* GetParentObject() const { return mParentObject; }
+
+ // Required for Web IDL binding.
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ // https://w3c.github.io/trusted-types/dist/spec/#trustedtypepolicy-name
+ void GetName(DOMString& aResult) const {
+ // TODO: impl.
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createhtml
+ UniquePtr<TrustedHTML> CreateHTML(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const;
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscript
+ UniquePtr<TrustedScript> CreateScript(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const;
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscripturl
+ UniquePtr<TrustedScriptURL> CreateScriptURL(
+ JSContext* aJSContext, const nsAString& aInput,
+ const Sequence<JS::Value>& aArguments) const;
+
+ private:
+ // Required because this class is ref-counted.
+ virtual ~TrustedTypePolicy() = default;
+
+ RefPtr<TrustedTypePolicyFactory> mParentObject;
+};
+
+} // namespace mozilla::dom
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICY_H_
diff --git a/dom/security/trusted-types/TrustedTypePolicyFactory.cpp b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp
new file mode 100644
index 0000000000..448c51eb3b
--- /dev/null
+++ b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp
@@ -0,0 +1,50 @@
+/* -*- 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/. */
+
+#include "mozilla/dom/TrustedTypePolicyFactory.h"
+
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/dom/TrustedTypePolicy.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TrustedTypePolicyFactory, mGlobalObject)
+
+JSObject* TrustedTypePolicyFactory::WrapObject(
+ JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
+ return TrustedTypePolicyFactory_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+already_AddRefed<TrustedTypePolicy> TrustedTypePolicyFactory::CreatePolicy(
+ const nsAString& aPolicyName,
+ const TrustedTypePolicyOptions& aPolicyOptions) {
+ // TODO: implement the spec.
+ return MakeRefPtr<TrustedTypePolicy>(this).forget();
+}
+
+UniquePtr<TrustedHTML> TrustedTypePolicyFactory::EmptyHTML() {
+ // Preserving the wrapper ensures:
+ // ```
+ // const e = trustedTypes.emptyHTML;
+ // e === trustedTypes.emptyHTML;
+ // ```
+ // which comes with the cost of keeping the factory, one per global, alive.
+ // An additional benefit is it saves the cost of re-instantiating potentially
+ // multiple emptyHML objects. Both, the JS- and the C++-objects.
+ dom::PreserveWrapper(this);
+
+ return MakeUnique<TrustedHTML>();
+}
+
+UniquePtr<TrustedScript> TrustedTypePolicyFactory::EmptyScript() {
+ // See the explanation in `EmptyHTML()`.
+ dom::PreserveWrapper(this);
+
+ return MakeUnique<TrustedScript>();
+}
+
+} // namespace mozilla::dom
diff --git a/dom/security/trusted-types/TrustedTypePolicyFactory.h b/dom/security/trusted-types/TrustedTypePolicyFactory.h
new file mode 100644
index 0000000000..fea5312cf8
--- /dev/null
+++ b/dom/security/trusted-types/TrustedTypePolicyFactory.h
@@ -0,0 +1,105 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_
+
+#include "js/TypeDecls.h"
+#include "mozilla/dom/TrustedHTML.h"
+#include "mozilla/dom/TrustedScript.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsIGlobalObject.h"
+#include "nsISupportsImpl.h"
+#include "nsStringFwd.h"
+#include "nsWrapperCache.h"
+
+template <typename T>
+struct already_AddRefed;
+
+class DOMString;
+
+namespace mozilla::dom {
+
+class TrustedTypePolicy;
+
+// https://w3c.github.io/trusted-types/dist/spec/#trusted-type-policy-factory
+class TrustedTypePolicyFactory : public nsWrapperCache {
+ public:
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(TrustedTypePolicyFactory)
+ NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(TrustedTypePolicyFactory)
+
+ explicit TrustedTypePolicyFactory(nsIGlobalObject* aGlobalObject)
+ : mGlobalObject{aGlobalObject} {}
+
+ // Required for Web IDL binding.
+ nsIGlobalObject* GetParentObject() const { return mGlobalObject; }
+
+ // Required for Web IDL binding.
+ JSObject* WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) override;
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-createpolicy
+ already_AddRefed<TrustedTypePolicy> CreatePolicy(
+ const nsAString& aPolicyName,
+ const TrustedTypePolicyOptions& aPolicyOptions);
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-ishtml
+ bool IsHTML(JSContext* aJSContext,
+ const JS::Handle<JS::Value>& aValue) const {
+ // TODO: impl.
+ return false;
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscript
+ bool IsScript(JSContext* aJSContext,
+ const JS::Handle<JS::Value>& aValue) const {
+ // TODO: impl.
+ return false;
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscripturl
+ bool IsScriptURL(JSContext* aJSContext,
+ const JS::Handle<JS::Value>& aValue) const {
+ // TODO: impl.
+ return false;
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyhtml
+ UniquePtr<TrustedHTML> EmptyHTML();
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyscript
+ UniquePtr<TrustedScript> EmptyScript();
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-getattributetype
+ void GetAttributeType(const nsAString& aTagName, const nsAString& aAttribute,
+ const nsAString& aElementNs, const nsAString& aAttrNs,
+ DOMString& aResult) {
+ // TODO: impl.
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-getpropertytype
+ void GetPropertyType(const nsAString& aTagName, const nsAString& aProperty,
+ const nsAString& aElementNs, DOMString& aResult) {
+ // TODO: impl
+ }
+
+ // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-defaultpolicy
+ TrustedTypePolicy* GetDefaultPolicy() const {
+ // TODO: impl
+ return nullptr;
+ }
+
+ private:
+ // Required because this class is ref-counted.
+ virtual ~TrustedTypePolicyFactory() = default;
+
+ RefPtr<nsIGlobalObject> mGlobalObject;
+};
+
+} // namespace mozilla::dom
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEPOLICYFACTORY_H_
diff --git a/dom/security/trusted-types/TrustedTypeUtils.h b/dom/security/trusted-types/TrustedTypeUtils.h
new file mode 100644
index 0000000000..90ffc50c38
--- /dev/null
+++ b/dom/security/trusted-types/TrustedTypeUtils.h
@@ -0,0 +1,35 @@
+/* -*- 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/. */
+
+#ifndef DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_
+#define DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_
+
+#include "mozilla/dom/DOMString.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+#include "mozilla/dom/TrustedTypesBinding.h"
+#include "nsStringFwd.h"
+
+#define DECL_TRUSTED_TYPE_CLASS(_class) \
+ class _class : public mozilla::dom::NonRefcountedDOMObject { \
+ public: \
+ /* Required for Web IDL binding. */ \
+ bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, \
+ JS::MutableHandle<JSObject*> aObject); \
+ \
+ void Stringify(nsAString& aResult) const { /* TODO: impl. */ \
+ } \
+ \
+ void ToJSON(DOMString& aResult) const { /* TODO: impl. */ \
+ } \
+ };
+
+#define IMPL_TRUSTED_TYPE_CLASS(_class) \
+ bool _class::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, \
+ JS::MutableHandle<JSObject*> aObject) { \
+ return _class##_Binding::Wrap(aCx, this, aGivenProto, aObject); \
+ }
+
+#endif // DOM_SECURITY_TRUSTED_TYPES_TRUSTEDTYPEUTILS_H_
diff --git a/dom/security/trusted-types/moz.build b/dom/security/trusted-types/moz.build
new file mode 100644
index 0000000000..159a54ff02
--- /dev/null
+++ b/dom/security/trusted-types/moz.build
@@ -0,0 +1,27 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+with Files("**"):
+ BUG_COMPONENT = ("Core", "DOM: Security")
+
+EXPORTS.mozilla.dom += [
+ "TrustedHTML.h",
+ "TrustedScript.h",
+ "TrustedScriptURL.h",
+ "TrustedTypePolicy.h",
+ "TrustedTypePolicyFactory.h",
+ "TrustedTypeUtils.h",
+]
+
+UNIFIED_SOURCES += [
+ "TrustedHTML.cpp",
+ "TrustedScript.cpp",
+ "TrustedScriptURL.cpp",
+ "TrustedTypePolicy.cpp",
+ "TrustedTypePolicyFactory.cpp",
+]
+
+FINAL_LIBRARY = "xul"