From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- dom/security/ReferrerInfo.cpp | 36 +-- dom/security/ReferrerInfo.h | 7 - .../featurepolicy/test/mochitest/mochitest.toml | 2 + .../test/mochitest/test_initial_aboutblank.html | 26 ++ dom/security/metrics.yaml | 153 ++++++++++++ dom/security/moz.build | 2 +- dom/security/nsCSPContext.cpp | 225 +++++++++++------ dom/security/nsCSPContext.h | 13 +- dom/security/nsCSPUtils.cpp | 51 ++-- dom/security/nsCSPUtils.h | 12 +- dom/security/nsContentSecurityUtils.cpp | 53 ++-- dom/security/nsHTTPSOnlyUtils.cpp | 63 ++++- dom/security/nsHTTPSOnlyUtils.h | 9 +- dom/security/test/csp/file_csp_error_messages.html | 33 +++ dom/security/test/csp/mochitest.toml | 3 + dom/security/test/csp/test_csp_error_messages.html | 75 ++++++ dom/security/test/general/browser.toml | 10 + .../browser_restrict_privileged_about_script.js | 2 +- .../test/general/browser_test_data_download.js | 4 +- .../test/general/browser_test_data_text_csv.js | 4 +- .../test/general/browser_test_http_download.js | 275 +++++++++++++++++++++ .../test/general/browser_test_report_blocking.js | 2 +- .../browser_test_toplevel_data_navigations.js | 2 +- .../browser_test_view_image_data_navigation.js | 4 +- dom/security/test/general/http_download_page.html | 23 ++ dom/security/test/general/http_download_server.sjs | 20 ++ .../test/general/test_block_script_wrong_mime.html | 6 +- .../test_block_toplevel_data_navigation.html | 2 +- dom/security/test/general/test_bug1277803.xhtml | 2 +- ...est_contentpolicytype_targeted_link_iframe.html | 2 +- dom/security/test/general/test_meta_referrer.html | 2 +- .../general/test_same_site_cookies_subrequest.html | 2 +- .../test_same_site_cookies_toplevel_nav.html | 2 +- .../test/https-first/browser_download_attribute.js | 2 +- .../test/https-first/browser_httpsfirst.js | 35 +++ .../https-first/browser_mixed_content_download.js | 2 +- .../test/https-first/browser_schemeless.js | 28 +++ dom/security/test/https-first/file_data_uri.html | 2 +- .../test/https-first/test_resource_upgrade.html | 2 +- dom/security/test/https-only/browser_hsts_host.js | 2 +- dom/security/test/https-only/browser_save_as.js | 14 +- .../test/https-only/browser_user_gesture.js | 2 +- .../test/https-only/file_upgrade_insecure.html | 2 +- .../file_websocket_exceptions_iframe.html | 6 +- .../test/https-only/test_redirect_upgrade.html | 4 +- .../test/https-only/test_resource_upgrade.html | 2 +- .../browser_test_mixed_content_download.js | 2 +- dom/security/test/referrer-policy/browser.toml | 4 +- .../referrer-policy/browser_fragment_navigation.js | 42 ---- .../referrer-policy/browser_session_history.js | 57 +++++ .../referrer-policy/file_fragment_navigation.sjs | 21 -- .../test/referrer-policy/file_session_history.sjs | 27 ++ .../test/referrer-policy/referrer_helper.js | 4 +- .../test/referrer-policy/test_img_referrer.html | 4 +- .../test/sec-fetch/browser_external_loads.js | 4 +- dom/security/test/sec-fetch/browser_navigation.js | 2 +- .../test_iframe_history_manipulation.html | 2 +- .../sec-fetch/test_iframe_src_metaRedirect.html | 2 +- .../sec-fetch/test_iframe_srcdoc_metaRedirect.html | 2 +- .../test_iframe_window_open_metaRedirect.html | 2 +- .../test/sec-fetch/test_trustworthy_loopback.html | 2 +- dom/security/test/sec-fetch/test_websocket.html | 6 +- dom/security/test/unit/test_csp_reports.js | 2 +- .../test_csp_upgrade_insecure_request_header.js | 8 +- .../test_https_only_https_first_default_port.js | 8 +- .../test/unit/test_https_only_https_first_prefs.js | 6 +- dom/security/trusted-types/TrustedHTML.cpp | 13 + dom/security/trusted-types/TrustedHTML.h | 19 ++ dom/security/trusted-types/TrustedScript.cpp | 13 + dom/security/trusted-types/TrustedScript.h | 19 ++ dom/security/trusted-types/TrustedScriptURL.cpp | 14 ++ dom/security/trusted-types/TrustedScriptURL.h | 18 ++ dom/security/trusted-types/TrustedTypePolicy.cpp | 43 ++++ dom/security/trusted-types/TrustedTypePolicy.h | 72 ++++++ .../trusted-types/TrustedTypePolicyFactory.cpp | 50 ++++ .../trusted-types/TrustedTypePolicyFactory.h | 105 ++++++++ dom/security/trusted-types/TrustedTypeUtils.h | 35 +++ dom/security/trusted-types/moz.build | 27 ++ 78 files changed, 1541 insertions(+), 324 deletions(-) create mode 100644 dom/security/featurepolicy/test/mochitest/test_initial_aboutblank.html create mode 100644 dom/security/metrics.yaml create mode 100644 dom/security/test/csp/file_csp_error_messages.html create mode 100644 dom/security/test/csp/test_csp_error_messages.html create mode 100644 dom/security/test/general/browser_test_http_download.js create mode 100644 dom/security/test/general/http_download_page.html create mode 100644 dom/security/test/general/http_download_server.sjs delete mode 100644 dom/security/test/referrer-policy/browser_fragment_navigation.js create mode 100644 dom/security/test/referrer-policy/browser_session_history.js delete mode 100644 dom/security/test/referrer-policy/file_fragment_navigation.sjs create mode 100644 dom/security/test/referrer-policy/file_session_history.sjs create mode 100644 dom/security/trusted-types/TrustedHTML.cpp create mode 100644 dom/security/trusted-types/TrustedHTML.h create mode 100644 dom/security/trusted-types/TrustedScript.cpp create mode 100644 dom/security/trusted-types/TrustedScript.h create mode 100644 dom/security/trusted-types/TrustedScriptURL.cpp create mode 100644 dom/security/trusted-types/TrustedScriptURL.h create mode 100644 dom/security/trusted-types/TrustedTypePolicy.cpp create mode 100644 dom/security/trusted-types/TrustedTypePolicy.h create mode 100644 dom/security/trusted-types/TrustedTypePolicyFactory.cpp create mode 100644 dom/security/trusted-types/TrustedTypePolicyFactory.h create mode 100644 dom/security/trusted-types/TrustedTypeUtils.h create mode 100644 dom/security/trusted-types/moz.build (limited to 'dom/security') 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(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(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(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( @@ -831,11 +812,8 @@ bool ReferrerInfo::ShouldIgnoreLessRestrictedPolicies( nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, true); - uint32_t idx = static_cast(aPolicy); - AutoTArray 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(ReferrerPolicy::EndGuard_) + ? UnderlyingValue( + MaxContiguousEnumValue::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 @@ + + + + Test feature policy - Initial about:blank + + + + + + + + + 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 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 params = {mViolatedDirectiveString, + effectiveDirective}; + mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample, + mLineNum, mColumnNum, + nsIScriptError::errorFlag); + break; + } + + case nsCSPContext::BlockedContentSource::eEval: { + AutoTArray params = {mViolatedDirectiveString, + effectiveDirective}; + mCSPContext->logToConsole(mReportOnlyFlag ? "CSPROEvalScriptViolation" + : "CSPEvalScriptViolation", + params, mSourceFile, mScriptSample, mLineNum, + mColumnNum, nsIScriptError::errorFlag); + break; + } + + case nsCSPContext::BlockedContentSource::eWasmEval: { + AutoTArray 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""_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 params = {mViolatedDirectiveString, source, + effectiveDirective}; + mCSPContext->logToConsole(errorName, params, mSourceFile, mScriptSample, + mLineNum, mColumnNum, + nsIScriptError::errorFlag); + } + } + } + RefPtr mTriggeringElement; nsCOMPtr mCSPEventListener; nsCOMPtr mBlockedURI; @@ -1512,7 +1589,8 @@ class CSPReportSenderRunnable final : public Runnable { bool mReportOnlyFlag; bool mReportSample; nsString mViolatedDirective; - nsString mEffectiveDirective; + nsString mViolatedDirectiveString; + CSPDirective mEffectiveDirective; nsCOMPtr 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& 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 contentLocation; aChannel->GetURI(getter_AddRefs(contentLocation)); - nsCOMPtr loadingPrincipal = loadInfo->GetLoadingPrincipal(); - if (!loadingPrincipal) { - loadingPrincipal = loadInfo->TriggeringPrincipal(); - } - // Creating a fake Loadinfo that is just used for the MCB check. - nsCOMPtr 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 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 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 -nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest(nsIChannel* aChannel, - nsresult aStatus) { - nsCOMPtr loadInfo = aChannel->LoadInfo(); +nsHTTPSOnlyUtils::PotentiallyDowngradeHttpsFirstRequest( + mozilla::net::DocumentLoadListener* aDocumentLoadListener, + nsresult aStatus) { + nsCOMPtr channel = aDocumentLoadListener->GetChannel(); + nsCOMPtr 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 httpChannel = do_QueryInterface(aChannel); + nsCOMPtr 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 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 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 @@ + + + + + Test some specialized CSP errors + + + + + + + + + + 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 + * , 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 @@ + + + + Test for the download attribute + + + hi + + + + 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 = [ // + ` + ); + } +} 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 aGivenProto) { + return TrustedTypePolicy_Binding::Wrap(aCx, this, aGivenProto); +} + +UniquePtr TrustedTypePolicy::CreateHTML( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +UniquePtr TrustedTypePolicy::CreateScript( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +UniquePtr TrustedTypePolicy::CreateScriptURL( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const { + // TODO: implement the spec. + return MakeUnique(); +} + +} // 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 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 CreateHTML( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscript + UniquePtr CreateScript( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicy-createscripturl + UniquePtr CreateScriptURL( + JSContext* aJSContext, const nsAString& aInput, + const Sequence& aArguments) const; + + private: + // Required because this class is ref-counted. + virtual ~TrustedTypePolicy() = default; + + RefPtr 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 aGivenProto) { + return TrustedTypePolicyFactory_Binding::Wrap(aCx, this, aGivenProto); +} + +already_AddRefed TrustedTypePolicyFactory::CreatePolicy( + const nsAString& aPolicyName, + const TrustedTypePolicyOptions& aPolicyOptions) { + // TODO: implement the spec. + return MakeRefPtr(this).forget(); +} + +UniquePtr 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(); +} + +UniquePtr TrustedTypePolicyFactory::EmptyScript() { + // See the explanation in `EmptyHTML()`. + dom::PreserveWrapper(this); + + return MakeUnique(); +} + +} // 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 +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 aGivenProto) override; + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-createpolicy + already_AddRefed 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& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscript + bool IsScript(JSContext* aJSContext, + const JS::Handle& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-isscripturl + bool IsScriptURL(JSContext* aJSContext, + const JS::Handle& aValue) const { + // TODO: impl. + return false; + } + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyhtml + UniquePtr EmptyHTML(); + + // https://w3c.github.io/trusted-types/dist/spec/#dom-trustedtypepolicyfactory-emptyscript + UniquePtr 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 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 aGivenProto, \ + JS::MutableHandle 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 aGivenProto, \ + JS::MutableHandle 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" -- cgit v1.2.3