From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- dom/security/CSPEvalChecker.cpp | 190 ++ dom/security/CSPEvalChecker.h | 32 + dom/security/DOMSecurityMonitor.cpp | 136 ++ dom/security/DOMSecurityMonitor.h | 43 + dom/security/FramingChecker.cpp | 231 +++ dom/security/FramingChecker.h | 49 + dom/security/PolicyTokenizer.cpp | 70 + dom/security/PolicyTokenizer.h | 78 + dom/security/ReferrerInfo.cpp | 1713 +++++++++++++++++ dom/security/ReferrerInfo.h | 469 +++++ dom/security/SRICheck.cpp | 516 +++++ dom/security/SRICheck.h | 105 + dom/security/SRILogHelper.h | 24 + dom/security/SRIMetadata.cpp | 187 ++ dom/security/SRIMetadata.h | 90 + dom/security/SecFetch.cpp | 411 ++++ dom/security/SecFetch.h | 27 + dom/security/featurepolicy/Feature.cpp | 76 + dom/security/featurepolicy/Feature.h | 65 + dom/security/featurepolicy/FeaturePolicy.cpp | 334 ++++ dom/security/featurepolicy/FeaturePolicy.h | 204 ++ dom/security/featurepolicy/FeaturePolicyParser.cpp | 157 ++ dom/security/featurepolicy/FeaturePolicyParser.h | 30 + dom/security/featurepolicy/FeaturePolicyUtils.cpp | 309 +++ dom/security/featurepolicy/FeaturePolicyUtils.h | 91 + dom/security/featurepolicy/fuzztest/fp_fuzzer.cpp | 67 + dom/security/featurepolicy/fuzztest/fp_fuzzer.dict | 54 + dom/security/featurepolicy/fuzztest/moz.build | 18 + dom/security/featurepolicy/moz.build | 36 + .../test/gtest/TestFeaturePolicyParser.cpp | 162 ++ dom/security/featurepolicy/test/gtest/moz.build | 13 + .../featurepolicy/test/mochitest/empty.html | 1 + .../featurepolicy/test/mochitest/mochitest.ini | 11 + .../test/mochitest/test_featureList.html | 44 + .../featurepolicy/test/mochitest/test_parser.html | 418 ++++ .../test/mochitest/test_parser.html^headers^ | 1 + dom/security/fuzztest/csp_fuzzer.cpp | 41 + dom/security/fuzztest/csp_fuzzer.dict | 95 + dom/security/fuzztest/moz.build | 18 + dom/security/moz.build | 82 + dom/security/nsCSPContext.cpp | 1998 ++++++++++++++++++++ dom/security/nsCSPContext.h | 235 +++ dom/security/nsCSPParser.cpp | 1299 +++++++++++++ dom/security/nsCSPParser.h | 217 +++ dom/security/nsCSPService.cpp | 408 ++++ dom/security/nsCSPService.h | 47 + dom/security/nsCSPUtils.cpp | 1623 ++++++++++++++++ dom/security/nsCSPUtils.h | 699 +++++++ dom/security/nsContentSecurityManager.cpp | 1793 ++++++++++++++++++ dom/security/nsContentSecurityManager.h | 94 + dom/security/nsContentSecurityUtils.cpp | 1608 ++++++++++++++++ dom/security/nsContentSecurityUtils.h | 92 + dom/security/nsHTTPSOnlyStreamListener.cpp | 275 +++ dom/security/nsHTTPSOnlyStreamListener.h | 50 + dom/security/nsHTTPSOnlyUtils.cpp | 1048 ++++++++++ dom/security/nsHTTPSOnlyUtils.h | 254 +++ dom/security/nsIHttpsOnlyModePermission.idl | 26 + dom/security/nsMixedContentBlocker.cpp | 1053 +++++++++++ dom/security/nsMixedContentBlocker.h | 96 + dom/security/sanitizer/Sanitizer.cpp | 187 ++ dom/security/sanitizer/Sanitizer.h | 107 ++ dom/security/sanitizer/moz.build | 37 + .../sanitizer/tests/mochitest/mochitest.ini | 6 + .../tests/mochitest/test_sanitizer_api.html | 139 ++ dom/security/test/cors/browser.ini | 9 + .../test/cors/browser_CORS-console-warnings.js | 101 + dom/security/test/cors/bug1456721.sjs | 20 + .../test/cors/file_CrossSiteXHR_cache_server.sjs | 59 + .../test/cors/file_CrossSiteXHR_inner.html | 121 ++ dom/security/test/cors/file_CrossSiteXHR_inner.jar | Bin 0 -> 1105 bytes .../test/cors/file_CrossSiteXHR_inner_data.sjs | 103 + .../test/cors/file_CrossSiteXHR_server.sjs | 231 +++ dom/security/test/cors/file_bug1456721.html | 74 + dom/security/test/cors/file_cors_logging_test.html | 1311 +++++++++++++ .../test/cors/file_cors_logging_test.html.css | 0 dom/security/test/cors/mochitest.ini | 16 + dom/security/test/cors/test_CrossSiteXHR.html | 1549 +++++++++++++++ .../test/cors/test_CrossSiteXHR_cache.html | 610 ++++++ .../test/cors/test_CrossSiteXHR_origin.html | 180 ++ dom/security/test/crashtests/1577572.html | 10 + dom/security/test/crashtests/1583044.html | 11 + dom/security/test/crashtests/crashtests.list | 2 + dom/security/test/csp/Ahem.ttf | Bin 0 -> 12480 bytes dom/security/test/csp/File | 0 dom/security/test/csp/browser.ini | 23 + .../browser_manifest-src-override-default-src.js | 125 ++ .../test/csp/browser_pdfjs_not_subject_to_csp.js | 48 + dom/security/test/csp/browser_test_bookmarklets.js | 82 + .../test/csp/browser_test_uir_optional_clicks.js | 36 + dom/security/test/csp/browser_test_web_manifest.js | 239 +++ .../csp/browser_test_web_manifest_mixed_content.js | 57 + dom/security/test/csp/dummy.pdf | Bin 0 -> 150611 bytes dom/security/test/csp/file_CSP.css | 20 + dom/security/test/csp/file_CSP.sjs | 24 + .../test/csp/file_allow_https_schemes.html | 14 + dom/security/test/csp/file_base_uri_server.sjs | 59 + dom/security/test/csp/file_blob_data_schemes.html | 49 + .../test/csp/file_blob_top_nav_block_modals.html | 18 + .../file_blob_top_nav_block_modals.html^headers^ | 1 + .../test/csp/file_blob_uri_blocks_modals.html | 27 + .../csp/file_blob_uri_blocks_modals.html^headers^ | 1 + dom/security/test/csp/file_block_all_mcb.sjs | 78 + ..._block_all_mixed_content_frame_navigation1.html | 19 + ..._block_all_mixed_content_frame_navigation2.html | 15 + ...ked_uri_in_violation_event_after_redirects.html | 39 + ...cked_uri_in_violation_event_after_redirects.sjs | 52 + .../csp/file_blocked_uri_redirect_frame_src.html | 10 + ...le_blocked_uri_redirect_frame_src.html^headers^ | 1 + .../file_blocked_uri_redirect_frame_src_server.sjs | 14 + dom/security/test/csp/file_bug1229639.html | 7 + .../test/csp/file_bug1229639.html^headers^ | 1 + dom/security/test/csp/file_bug1312272.html | 13 + .../test/csp/file_bug1312272.html^headers^ | 1 + dom/security/test/csp/file_bug1312272.js | 8 + dom/security/test/csp/file_bug1452037.html | 9 + dom/security/test/csp/file_bug1505412.sjs | 36 + dom/security/test/csp/file_bug1505412_frame.html | 14 + .../test/csp/file_bug1505412_frame.html^headers^ | 1 + dom/security/test/csp/file_bug1505412_reporter.sjs | 18 + dom/security/test/csp/file_bug1738418_child.html | 11 + dom/security/test/csp/file_bug1738418_parent.html | 11 + .../test/csp/file_bug1738418_parent.html^headers^ | 1 + dom/security/test/csp/file_bug1764343.html | 11 + dom/security/test/csp/file_bug1777572.html | 43 + dom/security/test/csp/file_bug663567.xsl | 27 + dom/security/test/csp/file_bug663567_allows.xml | 28 + .../test/csp/file_bug663567_allows.xml^headers^ | 1 + dom/security/test/csp/file_bug663567_blocks.xml | 28 + .../test/csp/file_bug663567_blocks.xml^headers^ | 1 + dom/security/test/csp/file_bug802872.html | 12 + dom/security/test/csp/file_bug802872.html^headers^ | 1 + dom/security/test/csp/file_bug802872.js | 47 + dom/security/test/csp/file_bug802872.sjs | 6 + .../test/csp/file_bug836922_npolicies.html | 12 + .../csp/file_bug836922_npolicies.html^headers^ | 2 + .../csp/file_bug836922_npolicies_ro_violation.sjs | 53 + .../csp/file_bug836922_npolicies_violation.sjs | 64 + dom/security/test/csp/file_bug885433_allows.html | 38 + .../test/csp/file_bug885433_allows.html^headers^ | 1 + dom/security/test/csp/file_bug885433_blocks.html | 37 + .../test/csp/file_bug885433_blocks.html^headers^ | 1 + dom/security/test/csp/file_bug886164.html | 15 + dom/security/test/csp/file_bug886164.html^headers^ | 1 + dom/security/test/csp/file_bug886164_2.html | 14 + .../test/csp/file_bug886164_2.html^headers^ | 1 + dom/security/test/csp/file_bug886164_3.html | 12 + .../test/csp/file_bug886164_3.html^headers^ | 1 + dom/security/test/csp/file_bug886164_4.html | 12 + .../test/csp/file_bug886164_4.html^headers^ | 1 + dom/security/test/csp/file_bug886164_5.html | 26 + .../test/csp/file_bug886164_5.html^headers^ | 1 + dom/security/test/csp/file_bug886164_6.html | 35 + .../test/csp/file_bug886164_6.html^headers^ | 1 + dom/security/test/csp/file_bug888172.html | 28 + dom/security/test/csp/file_bug888172.sjs | 47 + dom/security/test/csp/file_bug909029_none.html | 20 + .../test/csp/file_bug909029_none.html^headers^ | 1 + dom/security/test/csp/file_bug909029_star.html | 19 + .../test/csp/file_bug909029_star.html^headers^ | 1 + dom/security/test/csp/file_bug910139.sjs | 54 + dom/security/test/csp/file_bug910139.xml | 28 + dom/security/test/csp/file_bug910139.xsl | 27 + dom/security/test/csp/file_bug941404.html | 27 + dom/security/test/csp/file_bug941404_xhr.html | 5 + .../test/csp/file_bug941404_xhr.html^headers^ | 1 + dom/security/test/csp/file_child-src_iframe.html | 61 + .../test/csp/file_child-src_inner_frame.html | 21 + .../test/csp/file_child-src_service_worker.html | 30 + .../test/csp/file_child-src_service_worker.js | 3 + .../csp/file_child-src_shared_worker-redirect.html | 47 + .../test/csp/file_child-src_shared_worker.html | 35 + .../test/csp/file_child-src_shared_worker.js | 8 + .../csp/file_child-src_shared_worker_data.html | 37 + .../test/csp/file_child-src_worker-redirect.html | 47 + dom/security/test/csp/file_child-src_worker.html | 34 + dom/security/test/csp/file_child-src_worker.js | 3 + .../test/csp/file_child-src_worker_data.html | 33 + dom/security/test/csp/file_connect-src-fetch.html | 16 + dom/security/test/csp/file_connect-src.html | 21 + .../csp/file_csp_frame_ancestors_about_blank.html | 9 + ...e_csp_frame_ancestors_about_blank.html^headers^ | 2 + dom/security/test/csp/file_csp_meta_uir.html | 13 + dom/security/test/csp/file_data-uri_blocked.html | 15 + .../test/csp/file_data-uri_blocked.html^headers^ | 1 + .../test/csp/file_data_csp_inheritance.html | 24 + dom/security/test/csp/file_data_csp_merge.html | 26 + .../test/csp/file_data_doc_ignore_meta_csp.html | 22 + dom/security/test/csp/file_doccomment_meta.html | 28 + dom/security/test/csp/file_docwrite_meta.css | 3 + dom/security/test/csp/file_docwrite_meta.html | 26 + dom/security/test/csp/file_docwrite_meta.js | 3 + .../test/csp/file_dual_header_testserver.sjs | 45 + dom/security/test/csp/file_dummy_pixel.png | Bin 0 -> 70 bytes dom/security/test/csp/file_empty_directive.html | 11 + .../test/csp/file_empty_directive.html^headers^ | 1 + dom/security/test/csp/file_evalscript_main.html | 12 + .../test/csp/file_evalscript_main.html^headers^ | 2 + dom/security/test/csp/file_evalscript_main.js | 240 +++ .../test/csp/file_evalscript_main_allowed.html | 12 + .../csp/file_evalscript_main_allowed.html^headers^ | 2 + .../test/csp/file_evalscript_main_allowed.js | 193 ++ dom/security/test/csp/file_fontloader.sjs | 57 + dom/security/test/csp/file_fontloader.woff | Bin 0 -> 11140 bytes dom/security/test/csp/file_form-action.html | 15 + dom/security/test/csp/file_form_action_server.sjs | 32 + dom/security/test/csp/file_frame_ancestors_ro.html | 1 + .../test/csp/file_frame_ancestors_ro.html^headers^ | 1 + dom/security/test/csp/file_frame_src.js | 20 + .../test/csp/file_frame_src_child_governs.html | 10 + .../test/csp/file_frame_src_frame_governs.html | 10 + dom/security/test/csp/file_frame_src_inner.html | 5 + dom/security/test/csp/file_frameancestors.sjs | 69 + .../test/csp/file_frameancestors_main.html | 44 + dom/security/test/csp/file_frameancestors_main.js | 134 ++ .../test/csp/file_frameancestors_userpass.html | 10 + .../csp/file_frameancestors_userpass_frame_a.html | 12 + .../csp/file_frameancestors_userpass_frame_b.html | 12 + .../csp/file_frameancestors_userpass_frame_c.html | 8 + ...e_frameancestors_userpass_frame_c.html^headers^ | 1 + .../csp/file_frameancestors_userpass_frame_d.html | 8 + ...e_frameancestors_userpass_frame_d.html^headers^ | 1 + dom/security/test/csp/file_hash_source.html | 65 + .../test/csp/file_hash_source.html^headers^ | 2 + .../test/csp/file_iframe_parent_location_js.html | 10 + .../csp/file_iframe_sandbox_document_write.html | 21 + .../test/csp/file_iframe_sandbox_srcdoc.html | 11 + .../csp/file_iframe_sandbox_srcdoc.html^headers^ | 1 + dom/security/test/csp/file_iframe_srcdoc.sjs | 87 + .../test/csp/file_ignore_unsafe_inline.html | 26 + ...nore_unsafe_inline_multiple_policies_server.sjs | 56 + dom/security/test/csp/file_ignore_xfo.html | 10 + .../test/csp/file_ignore_xfo.html^headers^ | 3 + .../test/csp/file_image_document_pixel.png | Bin 0 -> 70 bytes .../csp/file_image_document_pixel.png^headers^ | 2 + dom/security/test/csp/file_image_nonce.html | 39 + .../test/csp/file_image_nonce.html^headers^ | 2 + .../test/csp/file_independent_iframe_csp.html | 43 + dom/security/test/csp/file_inlinescript.html | 15 + dom/security/test/csp/file_inlinestyle_main.html | 79 + .../test/csp/file_inlinestyle_main.html^headers^ | 2 + .../test/csp/file_inlinestyle_main_allowed.html | 84 + .../file_inlinestyle_main_allowed.html^headers^ | 2 + .../test/csp/file_invalid_source_expression.html | 11 + dom/security/test/csp/file_leading_wildcard.html | 11 + dom/security/test/csp/file_link_rel_preload.html | 19 + dom/security/test/csp/file_main.html | 55 + dom/security/test/csp/file_main.html^headers^ | 1 + dom/security/test/csp/file_main.js | 26 + dom/security/test/csp/file_meta_element.html | 27 + dom/security/test/csp/file_meta_header_dual.sjs | 101 + .../test/csp/file_meta_whitespace_skipping.html | 31 + .../csp/file_multi_policy_injection_bypass.html | 15 + ...ile_multi_policy_injection_bypass.html^headers^ | 1 + .../csp/file_multi_policy_injection_bypass_2.html | 15 + ...e_multi_policy_injection_bypass_2.html^headers^ | 1 + .../test/csp/file_multipart_testserver.sjs | 160 ++ dom/security/test/csp/file_navigate_to.html | 11 + dom/security/test/csp/file_navigate_to.sjs | 58 + .../test/csp/file_navigate_to_request.html | 17 + dom/security/test/csp/file_no_log_ignore_xfo.html | 10 + .../test/csp/file_no_log_ignore_xfo.html^headers^ | 2 + dom/security/test/csp/file_nonce_redirector.sjs | 28 + dom/security/test/csp/file_nonce_redirects.html | 23 + dom/security/test/csp/file_nonce_snapshot.sjs | 54 + dom/security/test/csp/file_nonce_source.html | 73 + .../test/csp/file_nonce_source.html^headers^ | 2 + dom/security/test/csp/file_null_baseuri.html | 21 + dom/security/test/csp/file_object_inherit.html | 21 + dom/security/test/csp/file_parent_location_js.html | 18 + dom/security/test/csp/file_path_matching.html | 10 + dom/security/test/csp/file_path_matching.js | 1 + .../test/csp/file_path_matching_incl_query.html | 10 + .../test/csp/file_path_matching_redirect.html | 10 + .../csp/file_path_matching_redirect_server.sjs | 12 + .../test/csp/file_pdfjs_not_subject_to_csp.html | 21 + dom/security/test/csp/file_ping.html | 19 + ...file_policyuri_regression_from_multipolicy.html | 9 + ...cyuri_regression_from_multipolicy.html^headers^ | 1 + ...le_policyuri_regression_from_multipolicy_policy | 1 + dom/security/test/csp/file_punycode_host_src.js | 2 + dom/security/test/csp/file_punycode_host_src.sjs | 47 + dom/security/test/csp/file_redirect_content.sjs | 41 + dom/security/test/csp/file_redirect_report.sjs | 17 + dom/security/test/csp/file_redirect_worker.sjs | 35 + dom/security/test/csp/file_redirects_main.html | 37 + dom/security/test/csp/file_redirects_page.sjs | 141 ++ dom/security/test/csp/file_redirects_resource.sjs | 172 ++ dom/security/test/csp/file_report.html | 13 + dom/security/test/csp/file_report_chromescript.js | 65 + .../test/csp/file_report_font_cache-1.html | 26 + .../test/csp/file_report_font_cache-2.html | 25 + .../csp/file_report_font_cache-2.html^headers^ | 1 + dom/security/test/csp/file_report_for_import.css | 1 + dom/security/test/csp/file_report_for_import.html | 10 + .../test/csp/file_report_for_import_server.sjs | 50 + ...e_report_uri_missing_in_report_only_header.html | 0 ...uri_missing_in_report_only_header.html^headers^ | 1 + dom/security/test/csp/file_ro_ignore_xfo.html | 10 + .../test/csp/file_ro_ignore_xfo.html^headers^ | 3 + dom/security/test/csp/file_sandbox_1.html | 16 + dom/security/test/csp/file_sandbox_10.html | 12 + dom/security/test/csp/file_sandbox_11.html | 25 + dom/security/test/csp/file_sandbox_12.html | 40 + dom/security/test/csp/file_sandbox_13.html | 25 + dom/security/test/csp/file_sandbox_2.html | 16 + dom/security/test/csp/file_sandbox_3.html | 13 + dom/security/test/csp/file_sandbox_4.html | 13 + dom/security/test/csp/file_sandbox_5.html | 26 + dom/security/test/csp/file_sandbox_6.html | 35 + dom/security/test/csp/file_sandbox_7.html | 15 + dom/security/test/csp/file_sandbox_8.html | 15 + dom/security/test/csp/file_sandbox_9.html | 12 + .../test/csp/file_sandbox_allow_scripts.html | 12 + .../csp/file_sandbox_allow_scripts.html^headers^ | 1 + dom/security/test/csp/file_sandbox_fail.js | 7 + dom/security/test/csp/file_sandbox_pass.js | 7 + .../test/csp/file_scheme_relative_sources.js | 1 + .../test/csp/file_scheme_relative_sources.sjs | 45 + dom/security/test/csp/file_script_template.html | 16 + dom/security/test/csp/file_script_template.js | 1 + .../csp/file_self_none_as_hostname_confusion.html | 11 + ...e_self_none_as_hostname_confusion.html^headers^ | 1 + dom/security/test/csp/file_sendbeacon.html | 21 + dom/security/test/csp/file_service_worker.html | 21 + dom/security/test/csp/file_service_worker.js | 1 + dom/security/test/csp/file_spawn_service_worker.js | 1 + dom/security/test/csp/file_spawn_shared_worker.js | 7 + dom/security/test/csp/file_spawn_worker.js | 1 + dom/security/test/csp/file_strict_dynamic.js | 1 + .../test/csp/file_strict_dynamic_default_src.html | 20 + .../test/csp/file_strict_dynamic_default_src.js | 1 + .../test/csp/file_strict_dynamic_js_url.html | 15 + .../file_strict_dynamic_non_parser_inserted.html | 17 + ..._strict_dynamic_non_parser_inserted_inline.html | 16 + ...e_strict_dynamic_parser_inserted_doc_write.html | 15 + ...ic_parser_inserted_doc_write_correct_nonce.html | 15 + .../csp/file_strict_dynamic_script_events.html | 14 + .../file_strict_dynamic_script_events_marquee.html | 14 + .../csp/file_strict_dynamic_script_extern.html | 10 + .../csp/file_strict_dynamic_script_inline.html | 14 + .../test/csp/file_strict_dynamic_unsafe_eval.html | 14 + .../test/csp/file_subframe_run_js_if_allowed.html | 13 + .../file_subframe_run_js_if_allowed.html^headers^ | 1 + .../test/csp/file_svg_inline_style_base.html | 9 + .../test/csp/file_svg_inline_style_csp.html | 10 + .../test/csp/file_svg_inline_style_server.sjs | 43 + .../csp/file_svg_srcset_inline_style_base.html | 9 + .../test/csp/file_svg_srcset_inline_style_csp.html | 10 + .../test/csp/file_test_browser_bookmarklets.html | 12 + .../file_test_browser_bookmarklets.html^headers^ | 2 + dom/security/test/csp/file_testserver.sjs | 67 + dom/security/test/csp/file_uir_top_nav.html | 17 + dom/security/test/csp/file_uir_top_nav_dummy.html | 12 + dom/security/test/csp/file_upgrade_insecure.html | 90 + .../test/csp/file_upgrade_insecure_cors.html | 49 + .../test/csp/file_upgrade_insecure_cors_server.sjs | 61 + .../csp/file_upgrade_insecure_docwrite_iframe.sjs | 55 + .../test/csp/file_upgrade_insecure_loopback.html | 25 + .../csp/file_upgrade_insecure_loopback_form.html | 17 + .../csp/file_upgrade_insecure_loopback_server.sjs | 22 + .../test/csp/file_upgrade_insecure_meta.html | 86 + .../test/csp/file_upgrade_insecure_navigation.sjs | 79 + .../file_upgrade_insecure_navigation_redirect.sjs | 50 + ..._insecure_navigation_redirect_cross_origin.html | 10 + ...e_insecure_navigation_redirect_same_origin.html | 10 + .../test/csp/file_upgrade_insecure_reporting.html | 23 + .../csp/file_upgrade_insecure_reporting_server.sjs | 87 + .../test/csp/file_upgrade_insecure_server.sjs | 112 ++ dom/security/test/csp/file_upgrade_insecure_wsh.py | 6 + dom/security/test/csp/file_web_manifest.html | 6 + dom/security/test/csp/file_web_manifest.json | 1 + .../test/csp/file_web_manifest.json^headers^ | 1 + dom/security/test/csp/file_web_manifest_https.html | 4 + dom/security/test/csp/file_web_manifest_https.json | 1 + .../test/csp/file_web_manifest_mixed_content.html | 9 + .../test/csp/file_web_manifest_remote.html | 8 + .../test/csp/file_websocket_csp_upgrade.html | 20 + dom/security/test/csp/file_websocket_explicit.html | 31 + dom/security/test/csp/file_websocket_self.html | 31 + dom/security/test/csp/file_websocket_self_wsh.py | 6 + dom/security/test/csp/file_win_open_blocked.html | 3 + .../test/csp/file_windowwatcher_frameA.html | 17 + .../test/csp/file_windowwatcher_subframeB.html | 12 + .../test/csp/file_windowwatcher_subframeC.html | 9 + .../test/csp/file_windowwatcher_subframeD.html | 6 + .../test/csp/file_windowwatcher_win_open.html | 15 + dom/security/test/csp/file_worker_src.js | 73 + .../test/csp/file_worker_src_child_governs.html | 9 + .../test/csp/file_worker_src_script_governs.html | 9 + .../test/csp/file_worker_src_worker_governs.html | 9 + dom/security/test/csp/file_xslt_inherits_csp.xml | 6 + .../test/csp/file_xslt_inherits_csp.xml^headers^ | 2 + dom/security/test/csp/file_xslt_inherits_csp.xsl | 26 + dom/security/test/csp/main_csp_worker.html | 439 +++++ .../test/csp/main_csp_worker.html^headers^ | 1 + dom/security/test/csp/mochitest.ini | 755 ++++++++ dom/security/test/csp/referrerdirective.sjs | 40 + dom/security/test/csp/test_301_redirect.html | 74 + dom/security/test/csp/test_302_redirect.html | 74 + dom/security/test/csp/test_303_redirect.html | 74 + dom/security/test/csp/test_307_redirect.html | 75 + dom/security/test/csp/test_CSP.html | 130 ++ .../test/csp/test_allow_https_schemes.html | 76 + dom/security/test/csp/test_base-uri.html | 124 ++ dom/security/test/csp/test_blob_data_schemes.html | 89 + .../test/csp/test_blob_uri_blocks_modals.html | 79 + .../test/csp/test_block_all_mixed_content.html | 99 + ...t_block_all_mixed_content_frame_navigation.html | 46 + .../test/csp/test_blocked_uri_in_reports.html | 80 + ...ked_uri_in_violation_event_after_redirects.html | 56 + .../csp/test_blocked_uri_redirect_frame_src.html | 60 + dom/security/test/csp/test_bug1229639.html | 51 + dom/security/test/csp/test_bug1242019.html | 51 + dom/security/test/csp/test_bug1312272.html | 32 + dom/security/test/csp/test_bug1388015.html | 46 + dom/security/test/csp/test_bug1452037.html | 41 + dom/security/test/csp/test_bug1505412.html | 50 + dom/security/test/csp/test_bug1579094.html | 31 + dom/security/test/csp/test_bug1738418.html | 28 + dom/security/test/csp/test_bug1764343.html | 116 ++ dom/security/test/csp/test_bug1777572.html | 40 + dom/security/test/csp/test_bug663567.html | 76 + dom/security/test/csp/test_bug802872.html | 53 + .../test/csp/test_bug836922_npolicies.html | 235 +++ dom/security/test/csp/test_bug885433.html | 61 + dom/security/test/csp/test_bug886164.html | 172 ++ dom/security/test/csp/test_bug888172.html | 73 + dom/security/test/csp/test_bug909029.html | 129 ++ dom/security/test/csp/test_bug910139.html | 66 + dom/security/test/csp/test_bug941404.html | 107 ++ dom/security/test/csp/test_child-src_iframe.html | 113 ++ .../test/csp/test_child-src_worker-redirect.html | 125 ++ dom/security/test/csp/test_child-src_worker.html | 148 ++ .../test/csp/test_child-src_worker_data.html | 126 ++ dom/security/test/csp/test_connect-src.html | 129 ++ .../csp/test_csp_frame_ancestors_about_blank.html | 59 + .../test/csp/test_csp_style_src_empty_hash.html | 32 + .../test/csp/test_csp_worker_inheritance.html | 20 + .../test/csp/test_data_csp_inheritance.html | 36 + dom/security/test/csp/test_data_csp_merge.html | 36 + .../test/csp/test_data_doc_ignore_meta_csp.html | 39 + dom/security/test/csp/test_docwrite_meta.html | 86 + dom/security/test/csp/test_dual_header.html | 66 + dom/security/test/csp/test_empty_directive.html | 51 + dom/security/test/csp/test_evalscript.html | 59 + .../test_evalscript_allowed_by_strict_dynamic.html | 36 + .../test_evalscript_blocked_by_strict_dynamic.html | 36 + dom/security/test/csp/test_fontloader.html | 98 + dom/security/test/csp/test_form-action.html | 105 + .../test/csp/test_form_action_blocks_url.html | 76 + dom/security/test/csp/test_frame_ancestors_ro.html | 69 + dom/security/test/csp/test_frame_src.html | 84 + dom/security/test/csp/test_frameancestors.html | 160 ++ .../test/csp/test_frameancestors_userpass.html | 148 ++ dom/security/test/csp/test_hash_source.html | 135 ++ dom/security/test/csp/test_iframe_sandbox.html | 240 +++ .../test/csp/test_iframe_sandbox_srcdoc.html | 62 + .../test/csp/test_iframe_sandbox_top_1.html | 80 + .../csp/test_iframe_sandbox_top_1.html^headers^ | 1 + dom/security/test/csp/test_iframe_srcdoc.html | 140 ++ .../test/csp/test_ignore_unsafe_inline.html | 122 ++ dom/security/test/csp/test_ignore_xfo.html | 120 ++ dom/security/test/csp/test_image_document.html | 35 + dom/security/test/csp/test_image_nonce.html | 60 + .../test/csp/test_independent_iframe_csp.html | 79 + dom/security/test/csp/test_inlinescript.html | 123 ++ dom/security/test/csp/test_inlinestyle.html | 107 ++ .../test/csp/test_invalid_source_expression.html | 57 + dom/security/test/csp/test_leading_wildcard.html | 101 + dom/security/test/csp/test_link_rel_preload.html | 80 + dom/security/test/csp/test_meta_csp_self.html | 63 + dom/security/test/csp/test_meta_element.html | 91 + dom/security/test/csp/test_meta_header_dual.html | 135 ++ .../test/csp/test_meta_whitespace_skipping.html | 81 + .../csp/test_multi_policy_injection_bypass.html | 119 ++ dom/security/test/csp/test_multipartchannel.html | 68 + dom/security/test/csp/test_navigate_to.html | 158 ++ dom/security/test/csp/test_nonce_redirects.html | 47 + dom/security/test/csp/test_nonce_snapshot.html | 35 + dom/security/test/csp/test_nonce_source.html | 122 ++ dom/security/test/csp/test_null_baseuri.html | 67 + dom/security/test/csp/test_object_inherit.html | 30 + dom/security/test/csp/test_parent_location_js.html | 38 + dom/security/test/csp/test_path_matching.html | 115 ++ .../test/csp/test_path_matching_redirect.html | 89 + dom/security/test/csp/test_ping.html | 103 + ...test_policyuri_regression_from_multipolicy.html | 27 + dom/security/test/csp/test_punycode_host_src.html | 81 + dom/security/test/csp/test_redirects.html | 143 ++ dom/security/test/csp/test_report.html | 113 ++ dom/security/test/csp/test_report_font_cache.html | 56 + dom/security/test/csp/test_report_for_import.html | 109 ++ ...t_report_uri_missing_in_report_only_header.html | 57 + dom/security/test/csp/test_sandbox.html | 249 +++ .../test/csp/test_sandbox_allow_scripts.html | 31 + .../test/csp/test_scheme_relative_sources.html | 91 + dom/security/test/csp/test_script_template.html | 60 + .../csp/test_security_policy_violation_event.html | 15 + .../csp/test_self_none_as_hostname_confusion.html | 55 + dom/security/test/csp/test_sendbeacon.html | 34 + dom/security/test/csp/test_service_worker.html | 62 + dom/security/test/csp/test_strict_dynamic.html | 133 ++ .../test/csp/test_strict_dynamic_default_src.html | 136 ++ .../csp/test_strict_dynamic_parser_inserted.html | 94 + .../test/csp/test_subframe_run_js_if_allowed.html | 33 + dom/security/test/csp/test_svg_inline_style.html | 135 ++ dom/security/test/csp/test_uir_top_nav.html | 53 + dom/security/test/csp/test_uir_windowwatcher.html | 31 + dom/security/test/csp/test_upgrade_insecure.html | 192 ++ .../test/csp/test_upgrade_insecure_cors.html | 86 + .../csp/test_upgrade_insecure_docwrite_iframe.html | 54 + .../test/csp/test_upgrade_insecure_loopback.html | 91 + .../test/csp/test_upgrade_insecure_navigation.html | 105 + .../test_upgrade_insecure_navigation_redirect.html | 67 + .../test/csp/test_upgrade_insecure_reporting.html | 69 + .../test/csp/test_websocket_localhost.html | 40 + dom/security/test/csp/test_websocket_self.html | 61 + dom/security/test/csp/test_win_open_blocked.html | 52 + dom/security/test/csp/test_worker_src.html | 105 + dom/security/test/csp/test_xslt_inherits_csp.html | 33 + dom/security/test/csp/worker.sjs | 114 ++ dom/security/test/csp/worker_helper.js | 91 + dom/security/test/general/browser.ini | 55 + .../test/general/browser_file_nonscript.js | 38 + .../browser_restrict_privileged_about_script.js | 70 + .../browser_same_site_cookies_bug1748693.js | 51 + ...rowser_test_assert_systemprincipal_documents.js | 41 + .../test/general/browser_test_data_download.js | 113 ++ .../test/general/browser_test_data_text_csv.js | 108 ++ .../general/browser_test_framing_error_pages.js | 53 + .../browser_test_referrer_loadInOtherProcess.js | 156 ++ .../test/general/browser_test_report_blocking.js | 218 +++ .../browser_test_toplevel_data_navigations.js | 70 + .../browser_test_view_image_data_navigation.js | 71 + .../test/general/browser_test_xfo_embed_object.js | 41 + dom/security/test/general/bug1277803.html | 11 + dom/security/test/general/chrome.ini | 11 + dom/security/test/general/closeWindow.sjs | 24 + dom/security/test/general/favicon_bug1277803.ico | Bin 0 -> 1406 bytes dom/security/test/general/file_1767581.js | 1 + dom/security/test/general/file_about_child.html | 11 + .../file_assert_systemprincipal_documents.html | 11 + ...le_assert_systemprincipal_documents_iframe.html | 9 + .../file_block_script_wrong_mime_server.sjs | 38 + .../file_block_subresource_redir_to_data.sjs | 33 + .../file_block_toplevel_data_navigation.html | 16 + .../file_block_toplevel_data_navigation2.html | 17 + .../file_block_toplevel_data_navigation3.html | 16 + .../general/file_block_toplevel_data_redirect.sjs | 13 + .../test/general/file_cache_splitting_isloaded.sjs | 35 + .../test/general/file_cache_splitting_server.sjs | 27 + .../test/general/file_cache_splitting_window.html | 17 + ...file_contentpolicytype_targeted_link_iframe.sjs | 45 + dom/security/test/general/file_data_download.html | 14 + dom/security/test/general/file_data_text_csv.html | 14 + .../test/general/file_framing_error_pages.sjs | 27 + .../test/general/file_framing_error_pages_csp.html | 7 + .../test/general/file_framing_error_pages_xfo.html | 7 + .../test/general/file_framing_xfo_embed.html | 7 + .../test/general/file_framing_xfo_embed_object.sjs | 7 + .../test/general/file_framing_xfo_object.html | 7 + dom/security/test/general/file_gpc_server.sjs | 14 + .../test/general/file_loads_nonscript.html | 49 + .../test/general/file_meta_referrer_in_head.html | 13 + .../general/file_meta_referrer_notin_head.html | 14 + dom/security/test/general/file_nonscript | 1 + dom/security/test/general/file_nonscript.html | 1 + dom/security/test/general/file_nonscript.json | 1 + dom/security/test/general/file_nonscript.txt | 1 + dom/security/test/general/file_nonscript.xyz | 1 + .../test/general/file_nosniff_navigation.sjs | 40 + .../test/general/file_nosniff_testserver.sjs | 61 + .../test/general/file_same_site_cookies_about.sjs | 99 + ...le_same_site_cookies_blob_iframe_inclusion.html | 34 + ...e_same_site_cookies_blob_iframe_navigation.html | 30 + .../general/file_same_site_cookies_bug1748693.sjs | 31 + ...file_same_site_cookies_cross_origin_context.sjs | 54 + .../general/file_same_site_cookies_from_script.sjs | 48 + .../test/general/file_same_site_cookies_iframe.sjs | 99 + .../general/file_same_site_cookies_redirect.sjs | 103 + .../general/file_same_site_cookies_subrequest.sjs | 82 + .../file_same_site_cookies_toplevel_nav.sjs | 96 + .../file_same_site_cookies_toplevel_set_cookie.sjs | 68 + dom/security/test/general/file_script.js | 1 + .../general/file_toplevel_data_meta_redirect.html | 10 + .../general/file_toplevel_data_navigations.sjs | 13 + .../file_view_bg_image_data_navigation.html | 16 + .../general/file_view_image_data_navigation.html | 12 + dom/security/test/general/file_xfo_error_page.sjs | 8 + dom/security/test/general/mochitest.ini | 95 + .../test/general/test_allow_opening_data_json.html | 39 + .../general/test_assert_about_page_no_csp.html | 30 + .../test/general/test_block_script_wrong_mime.html | 92 + .../test_block_subresource_redir_to_data.html | 68 + .../test_block_toplevel_data_img_navigation.html | 53 + .../test_block_toplevel_data_navigation.html | 134 ++ dom/security/test/general/test_bug1277803.xhtml | 65 + dom/security/test/general/test_bug1450853.html | 91 + .../test/general/test_bug1660452_http.html | 39 + .../test/general/test_bug1660452_https.html | 39 + dom/security/test/general/test_cache_split.html | 153 ++ ...est_contentpolicytype_targeted_link_iframe.html | 103 + dom/security/test/general/test_gpc.html | 51 + .../test/general/test_innerhtml_sanitizer.html | 74 + .../test/general/test_innerhtml_sanitizer.xhtml | 73 + dom/security/test/general/test_meta_referrer.html | 55 + dom/security/test/general/test_nosniff.html | 88 + .../test/general/test_nosniff_navigation.html | 35 + .../test/general/test_same_site_cookies_about.html | 116 ++ ...est_same_site_cookies_cross_origin_context.html | 93 + .../test_same_site_cookies_from_script.html | 86 + .../general/test_same_site_cookies_iframe.html | 168 ++ .../test_same_site_cookies_laxByDefault.html | 85 + .../general/test_same_site_cookies_redirect.html | 101 + .../general/test_same_site_cookies_subrequest.html | 113 ++ .../test_same_site_cookies_toplevel_nav.html | 117 ++ ...test_same_site_cookies_toplevel_set_cookie.html | 57 + dom/security/test/general/test_xfo_error_page.html | 35 + .../test/general/window_nosniff_navigation.html | 96 + dom/security/test/gtest/TestCSPParser.cpp | 1155 +++++++++++ dom/security/test/gtest/TestFilenameEvalParser.cpp | 453 +++++ dom/security/test/gtest/TestSecureContext.cpp | 121 ++ dom/security/test/gtest/TestSmartCrashTrimmer.cpp | 44 + .../test/gtest/TestUnexpectedPrivilegedLoads.cpp | 305 +++ dom/security/test/gtest/moz.build | 25 + dom/security/test/https-first/browser.ini | 35 + .../browser_beforeunload_permit_http.js | 208 ++ ...downgrade_mixed_content_auto_upgrade_console.js | 80 + .../https-first/browser_downgrade_view_source.js | 81 + .../test/https-first/browser_download_attribute.js | 125 ++ .../test/https-first/browser_httpsfirst.js | 74 + .../browser_httpsfirst_console_logging.js | 71 + .../browser_httpsfirst_speculative_connect.js | 69 + .../https-first/browser_mixed_content_console.js | 104 + .../https-first/browser_mixed_content_download.js | 156 ++ .../test/https-first/browser_navigation.js | 97 + .../test/https-first/browser_slow_download.js | 158 ++ .../test/https-first/browser_upgrade_onion.js | 60 + dom/security/test/https-first/download_page.html | 22 + dom/security/test/https-first/download_server.sjs | 16 + dom/security/test/https-first/file_bad_cert.sjs | 34 + .../https-first/file_beforeunload_permit_http.html | 9 + .../file_break_endless_upgrade_downgrade_loop.sjs | 61 + dom/security/test/https-first/file_data_uri.html | 16 + .../https-first/file_downgrade_500_responses.sjs | 70 + .../https-first/file_downgrade_bad_responses.sjs | 73 + .../file_downgrade_request_upgrade_request.sjs | 52 + .../https-first/file_downgrade_view_source.sjs | 30 + .../file_downgrade_with_different_path.sjs | 27 + .../test/https-first/file_download_attribute.html | 14 + .../test/https-first/file_download_attribute.sjs | 12 + .../test/https-first/file_form_submission.sjs | 84 + dom/security/test/https-first/file_fragment.html | 43 + .../file_httpsfirst_speculative_connect.html | 1 + .../https-first/file_httpsfirst_timeout_server.sjs | 13 + .../file_mixed_content_auto_upgrade.html | 12 + .../https-first/file_mixed_content_console.html | 13 + .../test/https-first/file_multiple_redirection.sjs | 87 + dom/security/test/https-first/file_navigation.html | 6 + dom/security/test/https-first/file_redirect.sjs | 58 + .../test/https-first/file_redirect_downgrade.sjs | 87 + .../test/https-first/file_referrer_policy.sjs | 102 + .../test/https-first/file_slow_download.html | 14 + .../test/https-first/file_slow_download.sjs | 26 + .../test/https-first/file_toplevel_cookies.sjs | 233 +++ .../test/https-first/file_upgrade_insecure.html | 72 + .../https-first/file_upgrade_insecure_server.sjs | 114 ++ dom/security/test/https-first/mochitest.ini | 44 + dom/security/test/https-first/pass.png | Bin 0 -> 1689 bytes dom/security/test/https-first/test.ogv | Bin 0 -> 2344665 bytes dom/security/test/https-first/test.wav | Bin 0 -> 353022 bytes dom/security/test/https-first/test_bad_cert.html | 67 + .../test_break_endless_upgrade_downgrade_loop.html | 80 + dom/security/test/https-first/test_data_uri.html | 51 + .../https-first/test_downgrade_500_responses.html | 63 + .../https-first/test_downgrade_bad_responses.html | 63 + .../test_downgrade_request_upgrade_request.html | 52 + .../test/https-first/test_form_submission.html | 122 ++ dom/security/test/https-first/test_fragment.html | 59 + .../https-first/test_multiple_redirection.html | 76 + .../test/https-first/test_redirect_downgrade.html | 59 + .../test/https-first/test_redirect_upgrade.html | 58 + .../test/https-first/test_referrer_policy.html | 237 +++ .../test/https-first/test_resource_upgrade.html | 118 ++ .../test/https-first/test_toplevel_cookies.html | 116 ++ dom/security/test/https-only/browser.ini | 39 + .../test/https-only/browser_background_redirect.js | 64 + .../test/https-only/browser_console_logging.js | 150 ++ .../test/https-only/browser_cors_mixedcontent.js | 124 ++ dom/security/test/https-only/browser_hsts_host.js | 182 ++ .../test/https-only/browser_httpsonly_prefs.js | 118 ++ .../browser_httpsonly_speculative_connect.js | 69 + .../test/https-only/browser_iframe_test.js | 223 +++ .../test/https-only/browser_redirect_tainting.js | 39 + .../browser_triggering_principal_exemption.js | 72 + .../test/https-only/browser_upgrade_exceptions.js | 86 + .../test/https-only/browser_user_gesture.js | 55 + .../https-only/browser_websocket_exceptions.js | 68 + .../test/https-only/file_background_redirect.sjs | 32 + .../file_break_endless_upgrade_downgrade_loop.sjs | 67 + .../test/https-only/file_console_logging.html | 16 + .../test/https-only/file_cors_mixedcontent.html | 42 + dom/security/test/https-only/file_fragment.html | 47 + .../test/https-only/file_fragment_noscript.html | 9 + .../file_http_background_auth_request.sjs | 16 + .../https-only/file_http_background_request.sjs | 15 + .../file_httpsonly_speculative_connect.html | 1 + dom/security/test/https-only/file_iframe_test.sjs | 58 + .../test/https-only/file_insecure_reload.sjs | 27 + dom/security/test/https-only/file_redirect.sjs | 37 + .../test/https-only/file_redirect_tainting.sjs | 39 + .../test/https-only/file_upgrade_insecure.html | 91 + .../https-only/file_upgrade_insecure_server.sjs | 112 ++ .../test/https-only/file_upgrade_insecure_wsh.py | 6 + .../test/https-only/file_user_gesture.html | 11 + .../test/https-only/file_websocket_exceptions.html | 9 + .../file_websocket_exceptions_iframe.html | 30 + dom/security/test/https-only/hsts_headers.sjs | 24 + dom/security/test/https-only/mochitest.ini | 43 + .../test_break_endless_upgrade_downgrade_loop.html | 89 + dom/security/test/https-only/test_fragment.html | 72 + .../test_http_background_auth_request.html | 113 ++ .../https-only/test_http_background_request.html | 125 ++ .../test/https-only/test_insecure_reload.html | 74 + .../test/https-only/test_redirect_upgrade.html | 58 + .../test/https-only/test_resource_upgrade.html | 122 ++ .../test/https-only/test_user_suggestion_box.html | 81 + .../auto_upgrading_identity.html | 11 + .../auto_upgrading_identity.png | Bin 0 -> 70 bytes dom/security/test/mixedcontentblocker/browser.ini | 28 + .../browser_auto_upgrading_identity.js | 55 + ...xedcontent_and_mixed_content_display_upgrade.js | 78 + .../browser_mixed_content_auth_download.js | 165 ++ ...r_mixed_content_auto_upgrade_display_console.js | 51 + .../browser_test_mixed_content_download.js | 333 ++++ .../test/mixedcontentblocker/download_page.html | 41 + .../test/mixedcontentblocker/download_server.sjs | 20 + .../file_auth_download_page.html | 22 + .../file_auth_download_server.sjs | 62 + .../test/mixedcontentblocker/file_bug1551886.html | 25 + .../file_bug803225_test_mailto.html | 13 + ...dcontent_and_mixed_content_display_upgrade.html | 14 + .../mixedcontentblocker/file_frameNavigation.html | 74 + .../file_frameNavigation_blankTarget.html | 33 + .../file_frameNavigation_grandchild.html | 57 + .../file_frameNavigation_innermost.html | 74 + .../file_frameNavigation_secure.html | 73 + .../file_frameNavigation_secure_grandchild.html | 58 + .../test/mixedcontentblocker/file_main.html | 338 ++++ .../mixedcontentblocker/file_main_bug803225.html | 175 ++ .../file_main_bug803225_websocket_wsh.py | 6 + ...mixed_content_auto_upgrade_display_console.html | 10 + .../test/mixedcontentblocker/file_redirect.html | 31 + .../mixedcontentblocker/file_redirect_handler.sjs | 35 + .../test/mixedcontentblocker/file_server.sjs | 131 ++ .../test/mixedcontentblocker/mochitest.ini | 40 + dom/security/test/mixedcontentblocker/pass.png | Bin 0 -> 1689 bytes dom/security/test/mixedcontentblocker/test.ogv | Bin 0 -> 2344665 bytes dom/security/test/mixedcontentblocker/test.wav | Bin 0 -> 353022 bytes .../test/mixedcontentblocker/test_bug1551886.html | 33 + .../test/mixedcontentblocker/test_bug803225.html | 157 ++ .../mixedcontentblocker/test_frameNavigation.html | 127 ++ .../test/mixedcontentblocker/test_main.html | 231 +++ .../test/mixedcontentblocker/test_redirect.html | 45 + dom/security/test/moz.build | 43 + dom/security/test/referrer-policy/browser.ini | 5 + ...rowser_referrer_disallow_cross_site_relaxing.js | 458 +++++ .../referrer-policy/browser_referrer_telemetry.js | 126 ++ .../referrer-policy/img_referrer_testserver.sjs | 337 ++++ dom/security/test/referrer-policy/mochitest.ini | 18 + .../test/referrer-policy/referrer_header.sjs | 6 + .../referrer_header_current_document_iframe.html | 12 + .../test/referrer-policy/referrer_helper.js | 133 ++ .../test/referrer-policy/referrer_page.sjs | 41 + .../test/referrer-policy/referrer_testserver.sjs | 691 +++++++ .../test/referrer-policy/test_img_referrer.html | 190 ++ .../test_referrer_header_current_document.html | 35 + .../referrer-policy/test_referrer_redirect.html | 123 ++ dom/security/test/sec-fetch/browser.ini | 10 + .../test/sec-fetch/browser_external_loads.js | 176 ++ dom/security/test/sec-fetch/browser_navigation.js | 178 ++ dom/security/test/sec-fetch/file_dummy_link.html | 9 + .../test/sec-fetch/file_dummy_link_location.html | 9 + dom/security/test/sec-fetch/file_no_cache.sjs | 28 + dom/security/test/sec-fetch/file_redirect.sjs | 34 + .../test/sec-fetch/file_trustworthy_loopback.html | 11 + dom/security/test/sec-fetch/file_websocket_wsh.py | 6 + dom/security/test/sec-fetch/mochitest.ini | 19 + .../test_iframe_history_manipulation.html | 85 + .../sec-fetch/test_iframe_src_metaRedirect.html | 95 + .../sec-fetch/test_iframe_srcdoc_metaRedirect.html | 95 + .../test_iframe_window_open_metaRedirect.html | 98 + .../test/sec-fetch/test_trustworthy_loopback.html | 77 + dom/security/test/sec-fetch/test_websocket.html | 74 + dom/security/test/sri/file_bug_1271796.css | 2 + .../test/sri/iframe_script_crossdomain.html | 135 ++ .../test/sri/iframe_script_sameorigin.html | 249 +++ .../test/sri/iframe_style_crossdomain.html | 117 ++ dom/security/test/sri/iframe_style_sameorigin.html | 164 ++ dom/security/test/sri/mochitest.ini | 46 + dom/security/test/sri/script.js | 1 + dom/security/test/sri/script.js^headers^ | 1 + dom/security/test/sri/script_301.js | 1 + dom/security/test/sri/script_301.js^headers^ | 2 + dom/security/test/sri/script_302.js | 1 + dom/security/test/sri/script_302.js^headers^ | 2 + dom/security/test/sri/script_401.js | 1 + dom/security/test/sri/script_401.js^headers^ | 2 + dom/security/test/sri/script_crossdomain1.js | 4 + .../test/sri/script_crossdomain1.js^headers^ | 1 + dom/security/test/sri/script_crossdomain2.js | 5 + dom/security/test/sri/script_crossdomain3.js | 1 + .../test/sri/script_crossdomain3.js^headers^ | 1 + dom/security/test/sri/script_crossdomain4.js | 1 + .../test/sri/script_crossdomain4.js^headers^ | 1 + dom/security/test/sri/script_crossdomain5.js | 1 + .../test/sri/script_crossdomain5.js^headers^ | 1 + dom/security/test/sri/style1.css | 3 + dom/security/test/sri/style1.css^headers^ | 1 + dom/security/test/sri/style2.css | 1 + dom/security/test/sri/style3.css | 3 + dom/security/test/sri/style4.css | 4 + dom/security/test/sri/style4.css^headers^ | 1 + dom/security/test/sri/style5.css | 4 + dom/security/test/sri/style6.css | 4 + dom/security/test/sri/style6.css^headers^ | 1 + dom/security/test/sri/style_301.css | 3 + dom/security/test/sri/style_301.css^headers^ | 2 + dom/security/test/sri/test_bug_1271796.html | 30 + dom/security/test/sri/test_bug_1364262.html | 34 + dom/security/test/sri/test_script_crossdomain.html | 15 + dom/security/test/sri/test_script_sameorigin.html | 15 + dom/security/test/sri/test_style_crossdomain.html | 15 + dom/security/test/sri/test_style_sameorigin.html | 15 + dom/security/test/unit/test_csp_reports.js | 299 +++ .../test_csp_upgrade_insecure_request_header.js | 102 + .../unit/test_deserialization_format_before_100.js | 244 +++ .../test_https_only_https_first_default_port.js | 107 ++ .../test/unit/test_https_only_https_first_prefs.js | 360 ++++ .../unit/test_isOriginPotentiallyTrustworthy.js | 51 + dom/security/test/unit/xpcshell.ini | 11 + 841 files changed, 65408 insertions(+) create mode 100644 dom/security/CSPEvalChecker.cpp create mode 100644 dom/security/CSPEvalChecker.h create mode 100644 dom/security/DOMSecurityMonitor.cpp create mode 100644 dom/security/DOMSecurityMonitor.h create mode 100644 dom/security/FramingChecker.cpp create mode 100644 dom/security/FramingChecker.h create mode 100644 dom/security/PolicyTokenizer.cpp create mode 100644 dom/security/PolicyTokenizer.h create mode 100644 dom/security/ReferrerInfo.cpp create mode 100644 dom/security/ReferrerInfo.h create mode 100644 dom/security/SRICheck.cpp create mode 100644 dom/security/SRICheck.h create mode 100644 dom/security/SRILogHelper.h create mode 100644 dom/security/SRIMetadata.cpp create mode 100644 dom/security/SRIMetadata.h create mode 100644 dom/security/SecFetch.cpp create mode 100644 dom/security/SecFetch.h create mode 100644 dom/security/featurepolicy/Feature.cpp create mode 100644 dom/security/featurepolicy/Feature.h create mode 100644 dom/security/featurepolicy/FeaturePolicy.cpp create mode 100644 dom/security/featurepolicy/FeaturePolicy.h create mode 100644 dom/security/featurepolicy/FeaturePolicyParser.cpp create mode 100644 dom/security/featurepolicy/FeaturePolicyParser.h create mode 100644 dom/security/featurepolicy/FeaturePolicyUtils.cpp create mode 100644 dom/security/featurepolicy/FeaturePolicyUtils.h create mode 100644 dom/security/featurepolicy/fuzztest/fp_fuzzer.cpp create mode 100644 dom/security/featurepolicy/fuzztest/fp_fuzzer.dict create mode 100644 dom/security/featurepolicy/fuzztest/moz.build create mode 100644 dom/security/featurepolicy/moz.build create mode 100644 dom/security/featurepolicy/test/gtest/TestFeaturePolicyParser.cpp create mode 100644 dom/security/featurepolicy/test/gtest/moz.build create mode 100644 dom/security/featurepolicy/test/mochitest/empty.html create mode 100644 dom/security/featurepolicy/test/mochitest/mochitest.ini create mode 100644 dom/security/featurepolicy/test/mochitest/test_featureList.html create mode 100644 dom/security/featurepolicy/test/mochitest/test_parser.html create mode 100644 dom/security/featurepolicy/test/mochitest/test_parser.html^headers^ create mode 100644 dom/security/fuzztest/csp_fuzzer.cpp create mode 100644 dom/security/fuzztest/csp_fuzzer.dict create mode 100644 dom/security/fuzztest/moz.build create mode 100644 dom/security/moz.build create mode 100644 dom/security/nsCSPContext.cpp create mode 100644 dom/security/nsCSPContext.h create mode 100644 dom/security/nsCSPParser.cpp create mode 100644 dom/security/nsCSPParser.h create mode 100644 dom/security/nsCSPService.cpp create mode 100644 dom/security/nsCSPService.h create mode 100644 dom/security/nsCSPUtils.cpp create mode 100644 dom/security/nsCSPUtils.h create mode 100644 dom/security/nsContentSecurityManager.cpp create mode 100644 dom/security/nsContentSecurityManager.h create mode 100644 dom/security/nsContentSecurityUtils.cpp create mode 100644 dom/security/nsContentSecurityUtils.h create mode 100644 dom/security/nsHTTPSOnlyStreamListener.cpp create mode 100644 dom/security/nsHTTPSOnlyStreamListener.h create mode 100644 dom/security/nsHTTPSOnlyUtils.cpp create mode 100644 dom/security/nsHTTPSOnlyUtils.h create mode 100644 dom/security/nsIHttpsOnlyModePermission.idl create mode 100644 dom/security/nsMixedContentBlocker.cpp create mode 100644 dom/security/nsMixedContentBlocker.h create mode 100644 dom/security/sanitizer/Sanitizer.cpp create mode 100644 dom/security/sanitizer/Sanitizer.h create mode 100644 dom/security/sanitizer/moz.build create mode 100644 dom/security/sanitizer/tests/mochitest/mochitest.ini create mode 100644 dom/security/sanitizer/tests/mochitest/test_sanitizer_api.html create mode 100644 dom/security/test/cors/browser.ini create mode 100644 dom/security/test/cors/browser_CORS-console-warnings.js create mode 100644 dom/security/test/cors/bug1456721.sjs create mode 100644 dom/security/test/cors/file_CrossSiteXHR_cache_server.sjs create mode 100644 dom/security/test/cors/file_CrossSiteXHR_inner.html create mode 100644 dom/security/test/cors/file_CrossSiteXHR_inner.jar create mode 100644 dom/security/test/cors/file_CrossSiteXHR_inner_data.sjs create mode 100644 dom/security/test/cors/file_CrossSiteXHR_server.sjs create mode 100644 dom/security/test/cors/file_bug1456721.html create mode 100644 dom/security/test/cors/file_cors_logging_test.html create mode 100644 dom/security/test/cors/file_cors_logging_test.html.css create mode 100644 dom/security/test/cors/mochitest.ini create mode 100644 dom/security/test/cors/test_CrossSiteXHR.html create mode 100644 dom/security/test/cors/test_CrossSiteXHR_cache.html create mode 100644 dom/security/test/cors/test_CrossSiteXHR_origin.html create mode 100644 dom/security/test/crashtests/1577572.html create mode 100644 dom/security/test/crashtests/1583044.html create mode 100644 dom/security/test/crashtests/crashtests.list create mode 100644 dom/security/test/csp/Ahem.ttf create mode 100644 dom/security/test/csp/File create mode 100644 dom/security/test/csp/browser.ini create mode 100644 dom/security/test/csp/browser_manifest-src-override-default-src.js create mode 100644 dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js create mode 100644 dom/security/test/csp/browser_test_bookmarklets.js create mode 100644 dom/security/test/csp/browser_test_uir_optional_clicks.js create mode 100644 dom/security/test/csp/browser_test_web_manifest.js create mode 100644 dom/security/test/csp/browser_test_web_manifest_mixed_content.js create mode 100644 dom/security/test/csp/dummy.pdf create mode 100644 dom/security/test/csp/file_CSP.css create mode 100644 dom/security/test/csp/file_CSP.sjs create mode 100644 dom/security/test/csp/file_allow_https_schemes.html create mode 100644 dom/security/test/csp/file_base_uri_server.sjs create mode 100644 dom/security/test/csp/file_blob_data_schemes.html create mode 100644 dom/security/test/csp/file_blob_top_nav_block_modals.html create mode 100644 dom/security/test/csp/file_blob_top_nav_block_modals.html^headers^ create mode 100644 dom/security/test/csp/file_blob_uri_blocks_modals.html create mode 100644 dom/security/test/csp/file_blob_uri_blocks_modals.html^headers^ create mode 100644 dom/security/test/csp/file_block_all_mcb.sjs create mode 100644 dom/security/test/csp/file_block_all_mixed_content_frame_navigation1.html create mode 100644 dom/security/test/csp/file_block_all_mixed_content_frame_navigation2.html create mode 100644 dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.html create mode 100644 dom/security/test/csp/file_blocked_uri_in_violation_event_after_redirects.sjs create mode 100644 dom/security/test/csp/file_blocked_uri_redirect_frame_src.html create mode 100644 dom/security/test/csp/file_blocked_uri_redirect_frame_src.html^headers^ create mode 100644 dom/security/test/csp/file_blocked_uri_redirect_frame_src_server.sjs create mode 100644 dom/security/test/csp/file_bug1229639.html create mode 100644 dom/security/test/csp/file_bug1229639.html^headers^ create mode 100644 dom/security/test/csp/file_bug1312272.html create mode 100644 dom/security/test/csp/file_bug1312272.html^headers^ create mode 100644 dom/security/test/csp/file_bug1312272.js create mode 100644 dom/security/test/csp/file_bug1452037.html create mode 100644 dom/security/test/csp/file_bug1505412.sjs create mode 100644 dom/security/test/csp/file_bug1505412_frame.html create mode 100644 dom/security/test/csp/file_bug1505412_frame.html^headers^ create mode 100644 dom/security/test/csp/file_bug1505412_reporter.sjs create mode 100644 dom/security/test/csp/file_bug1738418_child.html create mode 100644 dom/security/test/csp/file_bug1738418_parent.html create mode 100644 dom/security/test/csp/file_bug1738418_parent.html^headers^ create mode 100644 dom/security/test/csp/file_bug1764343.html create mode 100644 dom/security/test/csp/file_bug1777572.html create mode 100644 dom/security/test/csp/file_bug663567.xsl create mode 100644 dom/security/test/csp/file_bug663567_allows.xml create mode 100644 dom/security/test/csp/file_bug663567_allows.xml^headers^ create mode 100644 dom/security/test/csp/file_bug663567_blocks.xml create mode 100644 dom/security/test/csp/file_bug663567_blocks.xml^headers^ create mode 100644 dom/security/test/csp/file_bug802872.html create mode 100644 dom/security/test/csp/file_bug802872.html^headers^ create mode 100644 dom/security/test/csp/file_bug802872.js create mode 100644 dom/security/test/csp/file_bug802872.sjs create mode 100644 dom/security/test/csp/file_bug836922_npolicies.html create mode 100644 dom/security/test/csp/file_bug836922_npolicies.html^headers^ create mode 100644 dom/security/test/csp/file_bug836922_npolicies_ro_violation.sjs create mode 100644 dom/security/test/csp/file_bug836922_npolicies_violation.sjs create mode 100644 dom/security/test/csp/file_bug885433_allows.html create mode 100644 dom/security/test/csp/file_bug885433_allows.html^headers^ create mode 100644 dom/security/test/csp/file_bug885433_blocks.html create mode 100644 dom/security/test/csp/file_bug885433_blocks.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164.html create mode 100644 dom/security/test/csp/file_bug886164.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164_2.html create mode 100644 dom/security/test/csp/file_bug886164_2.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164_3.html create mode 100644 dom/security/test/csp/file_bug886164_3.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164_4.html create mode 100644 dom/security/test/csp/file_bug886164_4.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164_5.html create mode 100644 dom/security/test/csp/file_bug886164_5.html^headers^ create mode 100644 dom/security/test/csp/file_bug886164_6.html create mode 100644 dom/security/test/csp/file_bug886164_6.html^headers^ create mode 100644 dom/security/test/csp/file_bug888172.html create mode 100644 dom/security/test/csp/file_bug888172.sjs create mode 100644 dom/security/test/csp/file_bug909029_none.html create mode 100644 dom/security/test/csp/file_bug909029_none.html^headers^ create mode 100644 dom/security/test/csp/file_bug909029_star.html create mode 100644 dom/security/test/csp/file_bug909029_star.html^headers^ create mode 100644 dom/security/test/csp/file_bug910139.sjs create mode 100644 dom/security/test/csp/file_bug910139.xml create mode 100644 dom/security/test/csp/file_bug910139.xsl create mode 100644 dom/security/test/csp/file_bug941404.html create mode 100644 dom/security/test/csp/file_bug941404_xhr.html create mode 100644 dom/security/test/csp/file_bug941404_xhr.html^headers^ create mode 100644 dom/security/test/csp/file_child-src_iframe.html create mode 100644 dom/security/test/csp/file_child-src_inner_frame.html create mode 100644 dom/security/test/csp/file_child-src_service_worker.html create mode 100644 dom/security/test/csp/file_child-src_service_worker.js create mode 100644 dom/security/test/csp/file_child-src_shared_worker-redirect.html create mode 100644 dom/security/test/csp/file_child-src_shared_worker.html create mode 100644 dom/security/test/csp/file_child-src_shared_worker.js create mode 100644 dom/security/test/csp/file_child-src_shared_worker_data.html create mode 100644 dom/security/test/csp/file_child-src_worker-redirect.html create mode 100644 dom/security/test/csp/file_child-src_worker.html create mode 100644 dom/security/test/csp/file_child-src_worker.js create mode 100644 dom/security/test/csp/file_child-src_worker_data.html create mode 100644 dom/security/test/csp/file_connect-src-fetch.html create mode 100644 dom/security/test/csp/file_connect-src.html create mode 100644 dom/security/test/csp/file_csp_frame_ancestors_about_blank.html create mode 100644 dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^ create mode 100644 dom/security/test/csp/file_csp_meta_uir.html create mode 100644 dom/security/test/csp/file_data-uri_blocked.html create mode 100644 dom/security/test/csp/file_data-uri_blocked.html^headers^ create mode 100644 dom/security/test/csp/file_data_csp_inheritance.html create mode 100644 dom/security/test/csp/file_data_csp_merge.html create mode 100644 dom/security/test/csp/file_data_doc_ignore_meta_csp.html create mode 100644 dom/security/test/csp/file_doccomment_meta.html create mode 100644 dom/security/test/csp/file_docwrite_meta.css create mode 100644 dom/security/test/csp/file_docwrite_meta.html create mode 100644 dom/security/test/csp/file_docwrite_meta.js create mode 100644 dom/security/test/csp/file_dual_header_testserver.sjs create mode 100644 dom/security/test/csp/file_dummy_pixel.png create mode 100644 dom/security/test/csp/file_empty_directive.html create mode 100644 dom/security/test/csp/file_empty_directive.html^headers^ create mode 100644 dom/security/test/csp/file_evalscript_main.html create mode 100644 dom/security/test/csp/file_evalscript_main.html^headers^ create mode 100644 dom/security/test/csp/file_evalscript_main.js create mode 100644 dom/security/test/csp/file_evalscript_main_allowed.html create mode 100644 dom/security/test/csp/file_evalscript_main_allowed.html^headers^ create mode 100644 dom/security/test/csp/file_evalscript_main_allowed.js create mode 100644 dom/security/test/csp/file_fontloader.sjs create mode 100644 dom/security/test/csp/file_fontloader.woff create mode 100644 dom/security/test/csp/file_form-action.html create mode 100644 dom/security/test/csp/file_form_action_server.sjs create mode 100644 dom/security/test/csp/file_frame_ancestors_ro.html create mode 100644 dom/security/test/csp/file_frame_ancestors_ro.html^headers^ create mode 100644 dom/security/test/csp/file_frame_src.js create mode 100644 dom/security/test/csp/file_frame_src_child_governs.html create mode 100644 dom/security/test/csp/file_frame_src_frame_governs.html create mode 100644 dom/security/test/csp/file_frame_src_inner.html create mode 100644 dom/security/test/csp/file_frameancestors.sjs create mode 100644 dom/security/test/csp/file_frameancestors_main.html create mode 100644 dom/security/test/csp/file_frameancestors_main.js create mode 100644 dom/security/test/csp/file_frameancestors_userpass.html create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_a.html create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_b.html create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_c.html create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^ create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_d.html create mode 100644 dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^ create mode 100644 dom/security/test/csp/file_hash_source.html create mode 100644 dom/security/test/csp/file_hash_source.html^headers^ create mode 100644 dom/security/test/csp/file_iframe_parent_location_js.html create mode 100644 dom/security/test/csp/file_iframe_sandbox_document_write.html create mode 100644 dom/security/test/csp/file_iframe_sandbox_srcdoc.html create mode 100644 dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^ create mode 100644 dom/security/test/csp/file_iframe_srcdoc.sjs create mode 100644 dom/security/test/csp/file_ignore_unsafe_inline.html create mode 100644 dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs create mode 100644 dom/security/test/csp/file_ignore_xfo.html create mode 100644 dom/security/test/csp/file_ignore_xfo.html^headers^ create mode 100644 dom/security/test/csp/file_image_document_pixel.png create mode 100644 dom/security/test/csp/file_image_document_pixel.png^headers^ create mode 100644 dom/security/test/csp/file_image_nonce.html create mode 100644 dom/security/test/csp/file_image_nonce.html^headers^ create mode 100644 dom/security/test/csp/file_independent_iframe_csp.html create mode 100644 dom/security/test/csp/file_inlinescript.html create mode 100644 dom/security/test/csp/file_inlinestyle_main.html create mode 100644 dom/security/test/csp/file_inlinestyle_main.html^headers^ create mode 100644 dom/security/test/csp/file_inlinestyle_main_allowed.html create mode 100644 dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^ create mode 100644 dom/security/test/csp/file_invalid_source_expression.html create mode 100644 dom/security/test/csp/file_leading_wildcard.html create mode 100644 dom/security/test/csp/file_link_rel_preload.html create mode 100644 dom/security/test/csp/file_main.html create mode 100644 dom/security/test/csp/file_main.html^headers^ create mode 100644 dom/security/test/csp/file_main.js create mode 100644 dom/security/test/csp/file_meta_element.html create mode 100644 dom/security/test/csp/file_meta_header_dual.sjs create mode 100644 dom/security/test/csp/file_meta_whitespace_skipping.html create mode 100644 dom/security/test/csp/file_multi_policy_injection_bypass.html create mode 100644 dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^ create mode 100644 dom/security/test/csp/file_multi_policy_injection_bypass_2.html create mode 100644 dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^ create mode 100644 dom/security/test/csp/file_multipart_testserver.sjs create mode 100644 dom/security/test/csp/file_navigate_to.html create mode 100644 dom/security/test/csp/file_navigate_to.sjs create mode 100644 dom/security/test/csp/file_navigate_to_request.html create mode 100644 dom/security/test/csp/file_no_log_ignore_xfo.html create mode 100644 dom/security/test/csp/file_no_log_ignore_xfo.html^headers^ create mode 100644 dom/security/test/csp/file_nonce_redirector.sjs create mode 100644 dom/security/test/csp/file_nonce_redirects.html create mode 100644 dom/security/test/csp/file_nonce_snapshot.sjs create mode 100644 dom/security/test/csp/file_nonce_source.html create mode 100644 dom/security/test/csp/file_nonce_source.html^headers^ create mode 100644 dom/security/test/csp/file_null_baseuri.html create mode 100644 dom/security/test/csp/file_object_inherit.html create mode 100644 dom/security/test/csp/file_parent_location_js.html create mode 100644 dom/security/test/csp/file_path_matching.html create mode 100644 dom/security/test/csp/file_path_matching.js create mode 100644 dom/security/test/csp/file_path_matching_incl_query.html create mode 100644 dom/security/test/csp/file_path_matching_redirect.html create mode 100644 dom/security/test/csp/file_path_matching_redirect_server.sjs create mode 100644 dom/security/test/csp/file_pdfjs_not_subject_to_csp.html create mode 100644 dom/security/test/csp/file_ping.html create mode 100644 dom/security/test/csp/file_policyuri_regression_from_multipolicy.html create mode 100644 dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^ create mode 100644 dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy create mode 100644 dom/security/test/csp/file_punycode_host_src.js create mode 100644 dom/security/test/csp/file_punycode_host_src.sjs create mode 100644 dom/security/test/csp/file_redirect_content.sjs create mode 100644 dom/security/test/csp/file_redirect_report.sjs create mode 100644 dom/security/test/csp/file_redirect_worker.sjs create mode 100644 dom/security/test/csp/file_redirects_main.html create mode 100644 dom/security/test/csp/file_redirects_page.sjs create mode 100644 dom/security/test/csp/file_redirects_resource.sjs create mode 100644 dom/security/test/csp/file_report.html create mode 100644 dom/security/test/csp/file_report_chromescript.js create mode 100644 dom/security/test/csp/file_report_font_cache-1.html create mode 100644 dom/security/test/csp/file_report_font_cache-2.html create mode 100644 dom/security/test/csp/file_report_font_cache-2.html^headers^ create mode 100644 dom/security/test/csp/file_report_for_import.css create mode 100644 dom/security/test/csp/file_report_for_import.html create mode 100644 dom/security/test/csp/file_report_for_import_server.sjs create mode 100644 dom/security/test/csp/file_report_uri_missing_in_report_only_header.html create mode 100644 dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^ create mode 100644 dom/security/test/csp/file_ro_ignore_xfo.html create mode 100644 dom/security/test/csp/file_ro_ignore_xfo.html^headers^ create mode 100644 dom/security/test/csp/file_sandbox_1.html create mode 100644 dom/security/test/csp/file_sandbox_10.html create mode 100644 dom/security/test/csp/file_sandbox_11.html create mode 100644 dom/security/test/csp/file_sandbox_12.html create mode 100644 dom/security/test/csp/file_sandbox_13.html create mode 100644 dom/security/test/csp/file_sandbox_2.html create mode 100644 dom/security/test/csp/file_sandbox_3.html create mode 100644 dom/security/test/csp/file_sandbox_4.html create mode 100644 dom/security/test/csp/file_sandbox_5.html create mode 100644 dom/security/test/csp/file_sandbox_6.html create mode 100644 dom/security/test/csp/file_sandbox_7.html create mode 100644 dom/security/test/csp/file_sandbox_8.html create mode 100644 dom/security/test/csp/file_sandbox_9.html create mode 100644 dom/security/test/csp/file_sandbox_allow_scripts.html create mode 100644 dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ create mode 100644 dom/security/test/csp/file_sandbox_fail.js create mode 100644 dom/security/test/csp/file_sandbox_pass.js create mode 100644 dom/security/test/csp/file_scheme_relative_sources.js create mode 100644 dom/security/test/csp/file_scheme_relative_sources.sjs create mode 100644 dom/security/test/csp/file_script_template.html create mode 100644 dom/security/test/csp/file_script_template.js create mode 100644 dom/security/test/csp/file_self_none_as_hostname_confusion.html create mode 100644 dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^ create mode 100644 dom/security/test/csp/file_sendbeacon.html create mode 100644 dom/security/test/csp/file_service_worker.html create mode 100644 dom/security/test/csp/file_service_worker.js create mode 100644 dom/security/test/csp/file_spawn_service_worker.js create mode 100644 dom/security/test/csp/file_spawn_shared_worker.js create mode 100644 dom/security/test/csp/file_spawn_worker.js create mode 100644 dom/security/test/csp/file_strict_dynamic.js create mode 100644 dom/security/test/csp/file_strict_dynamic_default_src.html create mode 100644 dom/security/test/csp/file_strict_dynamic_default_src.js create mode 100644 dom/security/test/csp/file_strict_dynamic_js_url.html create mode 100644 dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html create mode 100644 dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html create mode 100644 dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html create mode 100644 dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html create mode 100644 dom/security/test/csp/file_strict_dynamic_script_events.html create mode 100644 dom/security/test/csp/file_strict_dynamic_script_events_marquee.html create mode 100644 dom/security/test/csp/file_strict_dynamic_script_extern.html create mode 100644 dom/security/test/csp/file_strict_dynamic_script_inline.html create mode 100644 dom/security/test/csp/file_strict_dynamic_unsafe_eval.html create mode 100644 dom/security/test/csp/file_subframe_run_js_if_allowed.html create mode 100644 dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^ create mode 100644 dom/security/test/csp/file_svg_inline_style_base.html create mode 100644 dom/security/test/csp/file_svg_inline_style_csp.html create mode 100644 dom/security/test/csp/file_svg_inline_style_server.sjs create mode 100644 dom/security/test/csp/file_svg_srcset_inline_style_base.html create mode 100644 dom/security/test/csp/file_svg_srcset_inline_style_csp.html create mode 100644 dom/security/test/csp/file_test_browser_bookmarklets.html create mode 100644 dom/security/test/csp/file_test_browser_bookmarklets.html^headers^ create mode 100644 dom/security/test/csp/file_testserver.sjs create mode 100644 dom/security/test/csp/file_uir_top_nav.html create mode 100644 dom/security/test/csp/file_uir_top_nav_dummy.html create mode 100644 dom/security/test/csp/file_upgrade_insecure.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_cors.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_cors_server.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_loopback.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_loopback_form.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_meta.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_navigation.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_reporting.html create mode 100644 dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_server.sjs create mode 100644 dom/security/test/csp/file_upgrade_insecure_wsh.py create mode 100644 dom/security/test/csp/file_web_manifest.html create mode 100644 dom/security/test/csp/file_web_manifest.json create mode 100644 dom/security/test/csp/file_web_manifest.json^headers^ create mode 100644 dom/security/test/csp/file_web_manifest_https.html create mode 100644 dom/security/test/csp/file_web_manifest_https.json create mode 100644 dom/security/test/csp/file_web_manifest_mixed_content.html create mode 100644 dom/security/test/csp/file_web_manifest_remote.html create mode 100644 dom/security/test/csp/file_websocket_csp_upgrade.html create mode 100644 dom/security/test/csp/file_websocket_explicit.html create mode 100644 dom/security/test/csp/file_websocket_self.html create mode 100644 dom/security/test/csp/file_websocket_self_wsh.py create mode 100644 dom/security/test/csp/file_win_open_blocked.html create mode 100644 dom/security/test/csp/file_windowwatcher_frameA.html create mode 100644 dom/security/test/csp/file_windowwatcher_subframeB.html create mode 100644 dom/security/test/csp/file_windowwatcher_subframeC.html create mode 100644 dom/security/test/csp/file_windowwatcher_subframeD.html create mode 100644 dom/security/test/csp/file_windowwatcher_win_open.html create mode 100644 dom/security/test/csp/file_worker_src.js create mode 100644 dom/security/test/csp/file_worker_src_child_governs.html create mode 100644 dom/security/test/csp/file_worker_src_script_governs.html create mode 100644 dom/security/test/csp/file_worker_src_worker_governs.html create mode 100644 dom/security/test/csp/file_xslt_inherits_csp.xml create mode 100644 dom/security/test/csp/file_xslt_inherits_csp.xml^headers^ create mode 100644 dom/security/test/csp/file_xslt_inherits_csp.xsl create mode 100644 dom/security/test/csp/main_csp_worker.html create mode 100644 dom/security/test/csp/main_csp_worker.html^headers^ create mode 100644 dom/security/test/csp/mochitest.ini create mode 100644 dom/security/test/csp/referrerdirective.sjs create mode 100644 dom/security/test/csp/test_301_redirect.html create mode 100644 dom/security/test/csp/test_302_redirect.html create mode 100644 dom/security/test/csp/test_303_redirect.html create mode 100644 dom/security/test/csp/test_307_redirect.html create mode 100644 dom/security/test/csp/test_CSP.html create mode 100644 dom/security/test/csp/test_allow_https_schemes.html create mode 100644 dom/security/test/csp/test_base-uri.html create mode 100644 dom/security/test/csp/test_blob_data_schemes.html create mode 100644 dom/security/test/csp/test_blob_uri_blocks_modals.html create mode 100644 dom/security/test/csp/test_block_all_mixed_content.html create mode 100644 dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html create mode 100644 dom/security/test/csp/test_blocked_uri_in_reports.html create mode 100644 dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html create mode 100644 dom/security/test/csp/test_blocked_uri_redirect_frame_src.html create mode 100644 dom/security/test/csp/test_bug1229639.html create mode 100644 dom/security/test/csp/test_bug1242019.html create mode 100644 dom/security/test/csp/test_bug1312272.html create mode 100644 dom/security/test/csp/test_bug1388015.html create mode 100644 dom/security/test/csp/test_bug1452037.html create mode 100644 dom/security/test/csp/test_bug1505412.html create mode 100644 dom/security/test/csp/test_bug1579094.html create mode 100644 dom/security/test/csp/test_bug1738418.html create mode 100644 dom/security/test/csp/test_bug1764343.html create mode 100644 dom/security/test/csp/test_bug1777572.html create mode 100644 dom/security/test/csp/test_bug663567.html create mode 100644 dom/security/test/csp/test_bug802872.html create mode 100644 dom/security/test/csp/test_bug836922_npolicies.html create mode 100644 dom/security/test/csp/test_bug885433.html create mode 100644 dom/security/test/csp/test_bug886164.html create mode 100644 dom/security/test/csp/test_bug888172.html create mode 100644 dom/security/test/csp/test_bug909029.html create mode 100644 dom/security/test/csp/test_bug910139.html create mode 100644 dom/security/test/csp/test_bug941404.html create mode 100644 dom/security/test/csp/test_child-src_iframe.html create mode 100644 dom/security/test/csp/test_child-src_worker-redirect.html create mode 100644 dom/security/test/csp/test_child-src_worker.html create mode 100644 dom/security/test/csp/test_child-src_worker_data.html create mode 100644 dom/security/test/csp/test_connect-src.html create mode 100644 dom/security/test/csp/test_csp_frame_ancestors_about_blank.html create mode 100644 dom/security/test/csp/test_csp_style_src_empty_hash.html create mode 100644 dom/security/test/csp/test_csp_worker_inheritance.html create mode 100644 dom/security/test/csp/test_data_csp_inheritance.html create mode 100644 dom/security/test/csp/test_data_csp_merge.html create mode 100644 dom/security/test/csp/test_data_doc_ignore_meta_csp.html create mode 100644 dom/security/test/csp/test_docwrite_meta.html create mode 100644 dom/security/test/csp/test_dual_header.html create mode 100644 dom/security/test/csp/test_empty_directive.html create mode 100644 dom/security/test/csp/test_evalscript.html create mode 100644 dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html create mode 100644 dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html create mode 100644 dom/security/test/csp/test_fontloader.html create mode 100644 dom/security/test/csp/test_form-action.html create mode 100644 dom/security/test/csp/test_form_action_blocks_url.html create mode 100644 dom/security/test/csp/test_frame_ancestors_ro.html create mode 100644 dom/security/test/csp/test_frame_src.html create mode 100644 dom/security/test/csp/test_frameancestors.html create mode 100644 dom/security/test/csp/test_frameancestors_userpass.html create mode 100644 dom/security/test/csp/test_hash_source.html create mode 100644 dom/security/test/csp/test_iframe_sandbox.html create mode 100644 dom/security/test/csp/test_iframe_sandbox_srcdoc.html create mode 100644 dom/security/test/csp/test_iframe_sandbox_top_1.html create mode 100644 dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^ create mode 100644 dom/security/test/csp/test_iframe_srcdoc.html create mode 100644 dom/security/test/csp/test_ignore_unsafe_inline.html create mode 100644 dom/security/test/csp/test_ignore_xfo.html create mode 100644 dom/security/test/csp/test_image_document.html create mode 100644 dom/security/test/csp/test_image_nonce.html create mode 100644 dom/security/test/csp/test_independent_iframe_csp.html create mode 100644 dom/security/test/csp/test_inlinescript.html create mode 100644 dom/security/test/csp/test_inlinestyle.html create mode 100644 dom/security/test/csp/test_invalid_source_expression.html create mode 100644 dom/security/test/csp/test_leading_wildcard.html create mode 100644 dom/security/test/csp/test_link_rel_preload.html create mode 100644 dom/security/test/csp/test_meta_csp_self.html create mode 100644 dom/security/test/csp/test_meta_element.html create mode 100644 dom/security/test/csp/test_meta_header_dual.html create mode 100644 dom/security/test/csp/test_meta_whitespace_skipping.html create mode 100644 dom/security/test/csp/test_multi_policy_injection_bypass.html create mode 100644 dom/security/test/csp/test_multipartchannel.html create mode 100644 dom/security/test/csp/test_navigate_to.html create mode 100644 dom/security/test/csp/test_nonce_redirects.html create mode 100644 dom/security/test/csp/test_nonce_snapshot.html create mode 100644 dom/security/test/csp/test_nonce_source.html create mode 100644 dom/security/test/csp/test_null_baseuri.html create mode 100644 dom/security/test/csp/test_object_inherit.html create mode 100644 dom/security/test/csp/test_parent_location_js.html create mode 100644 dom/security/test/csp/test_path_matching.html create mode 100644 dom/security/test/csp/test_path_matching_redirect.html create mode 100644 dom/security/test/csp/test_ping.html create mode 100644 dom/security/test/csp/test_policyuri_regression_from_multipolicy.html create mode 100644 dom/security/test/csp/test_punycode_host_src.html create mode 100644 dom/security/test/csp/test_redirects.html create mode 100644 dom/security/test/csp/test_report.html create mode 100644 dom/security/test/csp/test_report_font_cache.html create mode 100644 dom/security/test/csp/test_report_for_import.html create mode 100644 dom/security/test/csp/test_report_uri_missing_in_report_only_header.html create mode 100644 dom/security/test/csp/test_sandbox.html create mode 100644 dom/security/test/csp/test_sandbox_allow_scripts.html create mode 100644 dom/security/test/csp/test_scheme_relative_sources.html create mode 100644 dom/security/test/csp/test_script_template.html create mode 100644 dom/security/test/csp/test_security_policy_violation_event.html create mode 100644 dom/security/test/csp/test_self_none_as_hostname_confusion.html create mode 100644 dom/security/test/csp/test_sendbeacon.html create mode 100644 dom/security/test/csp/test_service_worker.html create mode 100644 dom/security/test/csp/test_strict_dynamic.html create mode 100644 dom/security/test/csp/test_strict_dynamic_default_src.html create mode 100644 dom/security/test/csp/test_strict_dynamic_parser_inserted.html create mode 100644 dom/security/test/csp/test_subframe_run_js_if_allowed.html create mode 100644 dom/security/test/csp/test_svg_inline_style.html create mode 100644 dom/security/test/csp/test_uir_top_nav.html create mode 100644 dom/security/test/csp/test_uir_windowwatcher.html create mode 100644 dom/security/test/csp/test_upgrade_insecure.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_cors.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_loopback.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_navigation.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html create mode 100644 dom/security/test/csp/test_upgrade_insecure_reporting.html create mode 100644 dom/security/test/csp/test_websocket_localhost.html create mode 100644 dom/security/test/csp/test_websocket_self.html create mode 100644 dom/security/test/csp/test_win_open_blocked.html create mode 100644 dom/security/test/csp/test_worker_src.html create mode 100644 dom/security/test/csp/test_xslt_inherits_csp.html create mode 100644 dom/security/test/csp/worker.sjs create mode 100644 dom/security/test/csp/worker_helper.js create mode 100644 dom/security/test/general/browser.ini create mode 100644 dom/security/test/general/browser_file_nonscript.js create mode 100644 dom/security/test/general/browser_restrict_privileged_about_script.js create mode 100644 dom/security/test/general/browser_same_site_cookies_bug1748693.js create mode 100644 dom/security/test/general/browser_test_assert_systemprincipal_documents.js create mode 100644 dom/security/test/general/browser_test_data_download.js create mode 100644 dom/security/test/general/browser_test_data_text_csv.js create mode 100644 dom/security/test/general/browser_test_framing_error_pages.js create mode 100644 dom/security/test/general/browser_test_referrer_loadInOtherProcess.js create mode 100644 dom/security/test/general/browser_test_report_blocking.js create mode 100644 dom/security/test/general/browser_test_toplevel_data_navigations.js create mode 100644 dom/security/test/general/browser_test_view_image_data_navigation.js create mode 100644 dom/security/test/general/browser_test_xfo_embed_object.js create mode 100644 dom/security/test/general/bug1277803.html create mode 100644 dom/security/test/general/chrome.ini create mode 100644 dom/security/test/general/closeWindow.sjs create mode 100644 dom/security/test/general/favicon_bug1277803.ico create mode 100644 dom/security/test/general/file_1767581.js create mode 100644 dom/security/test/general/file_about_child.html create mode 100644 dom/security/test/general/file_assert_systemprincipal_documents.html create mode 100644 dom/security/test/general/file_assert_systemprincipal_documents_iframe.html create mode 100644 dom/security/test/general/file_block_script_wrong_mime_server.sjs create mode 100644 dom/security/test/general/file_block_subresource_redir_to_data.sjs create mode 100644 dom/security/test/general/file_block_toplevel_data_navigation.html create mode 100644 dom/security/test/general/file_block_toplevel_data_navigation2.html create mode 100644 dom/security/test/general/file_block_toplevel_data_navigation3.html create mode 100644 dom/security/test/general/file_block_toplevel_data_redirect.sjs create mode 100644 dom/security/test/general/file_cache_splitting_isloaded.sjs create mode 100644 dom/security/test/general/file_cache_splitting_server.sjs create mode 100644 dom/security/test/general/file_cache_splitting_window.html create mode 100644 dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs create mode 100644 dom/security/test/general/file_data_download.html create mode 100644 dom/security/test/general/file_data_text_csv.html create mode 100644 dom/security/test/general/file_framing_error_pages.sjs create mode 100644 dom/security/test/general/file_framing_error_pages_csp.html create mode 100644 dom/security/test/general/file_framing_error_pages_xfo.html create mode 100644 dom/security/test/general/file_framing_xfo_embed.html create mode 100644 dom/security/test/general/file_framing_xfo_embed_object.sjs create mode 100644 dom/security/test/general/file_framing_xfo_object.html create mode 100644 dom/security/test/general/file_gpc_server.sjs create mode 100644 dom/security/test/general/file_loads_nonscript.html create mode 100644 dom/security/test/general/file_meta_referrer_in_head.html create mode 100644 dom/security/test/general/file_meta_referrer_notin_head.html create mode 100644 dom/security/test/general/file_nonscript create mode 100644 dom/security/test/general/file_nonscript.html create mode 100644 dom/security/test/general/file_nonscript.json create mode 100644 dom/security/test/general/file_nonscript.txt create mode 100644 dom/security/test/general/file_nonscript.xyz create mode 100644 dom/security/test/general/file_nosniff_navigation.sjs create mode 100644 dom/security/test/general/file_nosniff_testserver.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_about.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html create mode 100644 dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html create mode 100644 dom/security/test/general/file_same_site_cookies_bug1748693.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_from_script.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_iframe.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_redirect.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_subrequest.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs create mode 100644 dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs create mode 100644 dom/security/test/general/file_script.js create mode 100644 dom/security/test/general/file_toplevel_data_meta_redirect.html create mode 100644 dom/security/test/general/file_toplevel_data_navigations.sjs create mode 100644 dom/security/test/general/file_view_bg_image_data_navigation.html create mode 100644 dom/security/test/general/file_view_image_data_navigation.html create mode 100644 dom/security/test/general/file_xfo_error_page.sjs create mode 100644 dom/security/test/general/mochitest.ini create mode 100644 dom/security/test/general/test_allow_opening_data_json.html create mode 100644 dom/security/test/general/test_assert_about_page_no_csp.html create mode 100644 dom/security/test/general/test_block_script_wrong_mime.html create mode 100644 dom/security/test/general/test_block_subresource_redir_to_data.html create mode 100644 dom/security/test/general/test_block_toplevel_data_img_navigation.html create mode 100644 dom/security/test/general/test_block_toplevel_data_navigation.html create mode 100644 dom/security/test/general/test_bug1277803.xhtml create mode 100644 dom/security/test/general/test_bug1450853.html create mode 100644 dom/security/test/general/test_bug1660452_http.html create mode 100644 dom/security/test/general/test_bug1660452_https.html create mode 100644 dom/security/test/general/test_cache_split.html create mode 100644 dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html create mode 100644 dom/security/test/general/test_gpc.html create mode 100644 dom/security/test/general/test_innerhtml_sanitizer.html create mode 100644 dom/security/test/general/test_innerhtml_sanitizer.xhtml create mode 100644 dom/security/test/general/test_meta_referrer.html create mode 100644 dom/security/test/general/test_nosniff.html create mode 100644 dom/security/test/general/test_nosniff_navigation.html create mode 100644 dom/security/test/general/test_same_site_cookies_about.html create mode 100644 dom/security/test/general/test_same_site_cookies_cross_origin_context.html create mode 100644 dom/security/test/general/test_same_site_cookies_from_script.html create mode 100644 dom/security/test/general/test_same_site_cookies_iframe.html create mode 100644 dom/security/test/general/test_same_site_cookies_laxByDefault.html create mode 100644 dom/security/test/general/test_same_site_cookies_redirect.html create mode 100644 dom/security/test/general/test_same_site_cookies_subrequest.html create mode 100644 dom/security/test/general/test_same_site_cookies_toplevel_nav.html create mode 100644 dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html create mode 100644 dom/security/test/general/test_xfo_error_page.html create mode 100644 dom/security/test/general/window_nosniff_navigation.html create mode 100644 dom/security/test/gtest/TestCSPParser.cpp create mode 100644 dom/security/test/gtest/TestFilenameEvalParser.cpp create mode 100644 dom/security/test/gtest/TestSecureContext.cpp create mode 100644 dom/security/test/gtest/TestSmartCrashTrimmer.cpp create mode 100644 dom/security/test/gtest/TestUnexpectedPrivilegedLoads.cpp create mode 100644 dom/security/test/gtest/moz.build create mode 100644 dom/security/test/https-first/browser.ini create mode 100644 dom/security/test/https-first/browser_beforeunload_permit_http.js create mode 100644 dom/security/test/https-first/browser_downgrade_mixed_content_auto_upgrade_console.js create mode 100644 dom/security/test/https-first/browser_downgrade_view_source.js create mode 100644 dom/security/test/https-first/browser_download_attribute.js create mode 100644 dom/security/test/https-first/browser_httpsfirst.js create mode 100644 dom/security/test/https-first/browser_httpsfirst_console_logging.js create mode 100644 dom/security/test/https-first/browser_httpsfirst_speculative_connect.js create mode 100644 dom/security/test/https-first/browser_mixed_content_console.js create mode 100644 dom/security/test/https-first/browser_mixed_content_download.js create mode 100644 dom/security/test/https-first/browser_navigation.js create mode 100644 dom/security/test/https-first/browser_slow_download.js create mode 100644 dom/security/test/https-first/browser_upgrade_onion.js create mode 100644 dom/security/test/https-first/download_page.html create mode 100644 dom/security/test/https-first/download_server.sjs create mode 100644 dom/security/test/https-first/file_bad_cert.sjs create mode 100644 dom/security/test/https-first/file_beforeunload_permit_http.html create mode 100644 dom/security/test/https-first/file_break_endless_upgrade_downgrade_loop.sjs create mode 100644 dom/security/test/https-first/file_data_uri.html create mode 100644 dom/security/test/https-first/file_downgrade_500_responses.sjs create mode 100644 dom/security/test/https-first/file_downgrade_bad_responses.sjs create mode 100644 dom/security/test/https-first/file_downgrade_request_upgrade_request.sjs create mode 100644 dom/security/test/https-first/file_downgrade_view_source.sjs create mode 100644 dom/security/test/https-first/file_downgrade_with_different_path.sjs create mode 100644 dom/security/test/https-first/file_download_attribute.html create mode 100644 dom/security/test/https-first/file_download_attribute.sjs create mode 100644 dom/security/test/https-first/file_form_submission.sjs create mode 100644 dom/security/test/https-first/file_fragment.html create mode 100644 dom/security/test/https-first/file_httpsfirst_speculative_connect.html create mode 100644 dom/security/test/https-first/file_httpsfirst_timeout_server.sjs create mode 100644 dom/security/test/https-first/file_mixed_content_auto_upgrade.html create mode 100644 dom/security/test/https-first/file_mixed_content_console.html create mode 100644 dom/security/test/https-first/file_multiple_redirection.sjs create mode 100644 dom/security/test/https-first/file_navigation.html create mode 100644 dom/security/test/https-first/file_redirect.sjs create mode 100644 dom/security/test/https-first/file_redirect_downgrade.sjs create mode 100644 dom/security/test/https-first/file_referrer_policy.sjs create mode 100644 dom/security/test/https-first/file_slow_download.html create mode 100644 dom/security/test/https-first/file_slow_download.sjs create mode 100644 dom/security/test/https-first/file_toplevel_cookies.sjs create mode 100644 dom/security/test/https-first/file_upgrade_insecure.html create mode 100644 dom/security/test/https-first/file_upgrade_insecure_server.sjs create mode 100644 dom/security/test/https-first/mochitest.ini create mode 100644 dom/security/test/https-first/pass.png create mode 100644 dom/security/test/https-first/test.ogv create mode 100644 dom/security/test/https-first/test.wav create mode 100644 dom/security/test/https-first/test_bad_cert.html create mode 100644 dom/security/test/https-first/test_break_endless_upgrade_downgrade_loop.html create mode 100644 dom/security/test/https-first/test_data_uri.html create mode 100644 dom/security/test/https-first/test_downgrade_500_responses.html create mode 100644 dom/security/test/https-first/test_downgrade_bad_responses.html create mode 100644 dom/security/test/https-first/test_downgrade_request_upgrade_request.html create mode 100644 dom/security/test/https-first/test_form_submission.html create mode 100644 dom/security/test/https-first/test_fragment.html create mode 100644 dom/security/test/https-first/test_multiple_redirection.html create mode 100644 dom/security/test/https-first/test_redirect_downgrade.html create mode 100644 dom/security/test/https-first/test_redirect_upgrade.html create mode 100644 dom/security/test/https-first/test_referrer_policy.html create mode 100644 dom/security/test/https-first/test_resource_upgrade.html create mode 100644 dom/security/test/https-first/test_toplevel_cookies.html create mode 100644 dom/security/test/https-only/browser.ini create mode 100644 dom/security/test/https-only/browser_background_redirect.js create mode 100644 dom/security/test/https-only/browser_console_logging.js create mode 100644 dom/security/test/https-only/browser_cors_mixedcontent.js create mode 100644 dom/security/test/https-only/browser_hsts_host.js create mode 100644 dom/security/test/https-only/browser_httpsonly_prefs.js create mode 100644 dom/security/test/https-only/browser_httpsonly_speculative_connect.js create mode 100644 dom/security/test/https-only/browser_iframe_test.js create mode 100644 dom/security/test/https-only/browser_redirect_tainting.js create mode 100644 dom/security/test/https-only/browser_triggering_principal_exemption.js create mode 100644 dom/security/test/https-only/browser_upgrade_exceptions.js create mode 100644 dom/security/test/https-only/browser_user_gesture.js create mode 100644 dom/security/test/https-only/browser_websocket_exceptions.js create mode 100644 dom/security/test/https-only/file_background_redirect.sjs create mode 100644 dom/security/test/https-only/file_break_endless_upgrade_downgrade_loop.sjs create mode 100644 dom/security/test/https-only/file_console_logging.html create mode 100644 dom/security/test/https-only/file_cors_mixedcontent.html create mode 100644 dom/security/test/https-only/file_fragment.html create mode 100644 dom/security/test/https-only/file_fragment_noscript.html create mode 100644 dom/security/test/https-only/file_http_background_auth_request.sjs create mode 100644 dom/security/test/https-only/file_http_background_request.sjs create mode 100644 dom/security/test/https-only/file_httpsonly_speculative_connect.html create mode 100644 dom/security/test/https-only/file_iframe_test.sjs create mode 100644 dom/security/test/https-only/file_insecure_reload.sjs create mode 100644 dom/security/test/https-only/file_redirect.sjs create mode 100644 dom/security/test/https-only/file_redirect_tainting.sjs create mode 100644 dom/security/test/https-only/file_upgrade_insecure.html create mode 100644 dom/security/test/https-only/file_upgrade_insecure_server.sjs create mode 100644 dom/security/test/https-only/file_upgrade_insecure_wsh.py create mode 100644 dom/security/test/https-only/file_user_gesture.html create mode 100644 dom/security/test/https-only/file_websocket_exceptions.html create mode 100644 dom/security/test/https-only/file_websocket_exceptions_iframe.html create mode 100644 dom/security/test/https-only/hsts_headers.sjs create mode 100644 dom/security/test/https-only/mochitest.ini create mode 100644 dom/security/test/https-only/test_break_endless_upgrade_downgrade_loop.html create mode 100644 dom/security/test/https-only/test_fragment.html create mode 100644 dom/security/test/https-only/test_http_background_auth_request.html create mode 100644 dom/security/test/https-only/test_http_background_request.html create mode 100644 dom/security/test/https-only/test_insecure_reload.html create mode 100644 dom/security/test/https-only/test_redirect_upgrade.html create mode 100644 dom/security/test/https-only/test_resource_upgrade.html create mode 100644 dom/security/test/https-only/test_user_suggestion_box.html create mode 100644 dom/security/test/mixedcontentblocker/auto_upgrading_identity.html create mode 100644 dom/security/test/mixedcontentblocker/auto_upgrading_identity.png create mode 100644 dom/security/test/mixedcontentblocker/browser.ini create mode 100644 dom/security/test/mixedcontentblocker/browser_auto_upgrading_identity.js create mode 100644 dom/security/test/mixedcontentblocker/browser_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.js create mode 100644 dom/security/test/mixedcontentblocker/browser_mixed_content_auth_download.js create mode 100644 dom/security/test/mixedcontentblocker/browser_mixed_content_auto_upgrade_display_console.js create mode 100644 dom/security/test/mixedcontentblocker/browser_test_mixed_content_download.js create mode 100644 dom/security/test/mixedcontentblocker/download_page.html create mode 100644 dom/security/test/mixedcontentblocker/download_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_auth_download_page.html create mode 100644 dom/security/test/mixedcontentblocker/file_auth_download_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_bug1551886.html create mode 100644 dom/security/test/mixedcontentblocker/file_bug803225_test_mailto.html create mode 100644 dom/security/test/mixedcontentblocker/file_csp_block_all_mixedcontent_and_mixed_content_display_upgrade.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_blankTarget.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_grandchild.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_innermost.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_secure.html create mode 100644 dom/security/test/mixedcontentblocker/file_frameNavigation_secure_grandchild.html create mode 100644 dom/security/test/mixedcontentblocker/file_main.html create mode 100644 dom/security/test/mixedcontentblocker/file_main_bug803225.html create mode 100644 dom/security/test/mixedcontentblocker/file_main_bug803225_websocket_wsh.py create mode 100644 dom/security/test/mixedcontentblocker/file_mixed_content_auto_upgrade_display_console.html create mode 100644 dom/security/test/mixedcontentblocker/file_redirect.html create mode 100644 dom/security/test/mixedcontentblocker/file_redirect_handler.sjs create mode 100644 dom/security/test/mixedcontentblocker/file_server.sjs create mode 100644 dom/security/test/mixedcontentblocker/mochitest.ini create mode 100644 dom/security/test/mixedcontentblocker/pass.png create mode 100644 dom/security/test/mixedcontentblocker/test.ogv create mode 100644 dom/security/test/mixedcontentblocker/test.wav create mode 100644 dom/security/test/mixedcontentblocker/test_bug1551886.html create mode 100644 dom/security/test/mixedcontentblocker/test_bug803225.html create mode 100644 dom/security/test/mixedcontentblocker/test_frameNavigation.html create mode 100644 dom/security/test/mixedcontentblocker/test_main.html create mode 100644 dom/security/test/mixedcontentblocker/test_redirect.html create mode 100644 dom/security/test/moz.build create mode 100644 dom/security/test/referrer-policy/browser.ini create mode 100644 dom/security/test/referrer-policy/browser_referrer_disallow_cross_site_relaxing.js create mode 100644 dom/security/test/referrer-policy/browser_referrer_telemetry.js create mode 100644 dom/security/test/referrer-policy/img_referrer_testserver.sjs create mode 100644 dom/security/test/referrer-policy/mochitest.ini create mode 100644 dom/security/test/referrer-policy/referrer_header.sjs create mode 100644 dom/security/test/referrer-policy/referrer_header_current_document_iframe.html create mode 100644 dom/security/test/referrer-policy/referrer_helper.js create mode 100644 dom/security/test/referrer-policy/referrer_page.sjs create mode 100644 dom/security/test/referrer-policy/referrer_testserver.sjs create mode 100644 dom/security/test/referrer-policy/test_img_referrer.html create mode 100644 dom/security/test/referrer-policy/test_referrer_header_current_document.html create mode 100644 dom/security/test/referrer-policy/test_referrer_redirect.html create mode 100644 dom/security/test/sec-fetch/browser.ini create mode 100644 dom/security/test/sec-fetch/browser_external_loads.js create mode 100644 dom/security/test/sec-fetch/browser_navigation.js create mode 100644 dom/security/test/sec-fetch/file_dummy_link.html create mode 100644 dom/security/test/sec-fetch/file_dummy_link_location.html create mode 100644 dom/security/test/sec-fetch/file_no_cache.sjs create mode 100644 dom/security/test/sec-fetch/file_redirect.sjs create mode 100644 dom/security/test/sec-fetch/file_trustworthy_loopback.html create mode 100644 dom/security/test/sec-fetch/file_websocket_wsh.py create mode 100644 dom/security/test/sec-fetch/mochitest.ini create mode 100644 dom/security/test/sec-fetch/test_iframe_history_manipulation.html create mode 100644 dom/security/test/sec-fetch/test_iframe_src_metaRedirect.html create mode 100644 dom/security/test/sec-fetch/test_iframe_srcdoc_metaRedirect.html create mode 100644 dom/security/test/sec-fetch/test_iframe_window_open_metaRedirect.html create mode 100644 dom/security/test/sec-fetch/test_trustworthy_loopback.html create mode 100644 dom/security/test/sec-fetch/test_websocket.html create mode 100644 dom/security/test/sri/file_bug_1271796.css create mode 100644 dom/security/test/sri/iframe_script_crossdomain.html create mode 100644 dom/security/test/sri/iframe_script_sameorigin.html create mode 100644 dom/security/test/sri/iframe_style_crossdomain.html create mode 100644 dom/security/test/sri/iframe_style_sameorigin.html create mode 100644 dom/security/test/sri/mochitest.ini create mode 100644 dom/security/test/sri/script.js create mode 100644 dom/security/test/sri/script.js^headers^ create mode 100644 dom/security/test/sri/script_301.js create mode 100644 dom/security/test/sri/script_301.js^headers^ create mode 100644 dom/security/test/sri/script_302.js create mode 100644 dom/security/test/sri/script_302.js^headers^ create mode 100644 dom/security/test/sri/script_401.js create mode 100644 dom/security/test/sri/script_401.js^headers^ create mode 100644 dom/security/test/sri/script_crossdomain1.js create mode 100644 dom/security/test/sri/script_crossdomain1.js^headers^ create mode 100644 dom/security/test/sri/script_crossdomain2.js create mode 100644 dom/security/test/sri/script_crossdomain3.js create mode 100644 dom/security/test/sri/script_crossdomain3.js^headers^ create mode 100644 dom/security/test/sri/script_crossdomain4.js create mode 100644 dom/security/test/sri/script_crossdomain4.js^headers^ create mode 100644 dom/security/test/sri/script_crossdomain5.js create mode 100644 dom/security/test/sri/script_crossdomain5.js^headers^ create mode 100644 dom/security/test/sri/style1.css create mode 100644 dom/security/test/sri/style1.css^headers^ create mode 100644 dom/security/test/sri/style2.css create mode 100644 dom/security/test/sri/style3.css create mode 100644 dom/security/test/sri/style4.css create mode 100644 dom/security/test/sri/style4.css^headers^ create mode 100644 dom/security/test/sri/style5.css create mode 100644 dom/security/test/sri/style6.css create mode 100644 dom/security/test/sri/style6.css^headers^ create mode 100644 dom/security/test/sri/style_301.css create mode 100644 dom/security/test/sri/style_301.css^headers^ create mode 100644 dom/security/test/sri/test_bug_1271796.html create mode 100644 dom/security/test/sri/test_bug_1364262.html create mode 100644 dom/security/test/sri/test_script_crossdomain.html create mode 100644 dom/security/test/sri/test_script_sameorigin.html create mode 100644 dom/security/test/sri/test_style_crossdomain.html create mode 100644 dom/security/test/sri/test_style_sameorigin.html create mode 100644 dom/security/test/unit/test_csp_reports.js create mode 100644 dom/security/test/unit/test_csp_upgrade_insecure_request_header.js create mode 100644 dom/security/test/unit/test_deserialization_format_before_100.js create mode 100644 dom/security/test/unit/test_https_only_https_first_default_port.js create mode 100644 dom/security/test/unit/test_https_only_https_first_prefs.js create mode 100644 dom/security/test/unit/test_isOriginPotentiallyTrustworthy.js create mode 100644 dom/security/test/unit/xpcshell.ini (limited to 'dom/security') diff --git a/dom/security/CSPEvalChecker.cpp b/dom/security/CSPEvalChecker.cpp new file mode 100644 index 0000000000..8b46b96cd3 --- /dev/null +++ b/dom/security/CSPEvalChecker.cpp @@ -0,0 +1,190 @@ +/* -*- 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/CSPEvalChecker.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/ErrorResult.h" +#include "nsIParentChannel.h" +#include "nsGlobalWindowInner.h" +#include "nsContentSecurityUtils.h" +#include "nsContentUtils.h" +#include "nsCOMPtr.h" +#include "nsJSUtils.h" + +using namespace mozilla; +using namespace mozilla::dom; + +namespace { + +// We use the subjectPrincipal to assert that eval() is never +// executed in system privileged context. +nsresult CheckInternal(nsIContentSecurityPolicy* aCSP, + nsICSPEventListener* aCSPEventListener, + nsIPrincipal* aSubjectPrincipal, + const nsAString& aExpression, + const nsAString& aFileNameString, uint32_t aLineNum, + uint32_t aColumnNum, bool* aAllowed) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aAllowed); + + // The value is set at any "return", but better to have a default value here. + *aAllowed = false; + + // This is the non-CSP check for gating eval() use in the SystemPrincipal +#if !defined(ANDROID) + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + if (!nsContentSecurityUtils::IsEvalAllowed( + cx, aSubjectPrincipal->IsSystemPrincipal(), aExpression)) { + *aAllowed = false; + return NS_OK; + } +#endif + + if (!aCSP) { + *aAllowed = true; + return NS_OK; + } + + bool reportViolation = false; + nsresult rv = aCSP->GetAllowsEval(&reportViolation, aAllowed); + if (NS_WARN_IF(NS_FAILED(rv))) { + *aAllowed = false; + return rv; + } + + if (reportViolation) { + aCSP->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL, + nullptr, // triggering element + aCSPEventListener, aFileNameString, aExpression, + aLineNum, aColumnNum, u""_ns, u""_ns); + } + + return NS_OK; +} + +class WorkerCSPCheckRunnable final : public WorkerMainThreadRunnable { + public: + WorkerCSPCheckRunnable(WorkerPrivate* aWorkerPrivate, + const nsAString& aExpression, + const nsAString& aFileNameString, uint32_t aLineNum, + uint32_t aColumnNum) + : WorkerMainThreadRunnable(aWorkerPrivate, "CSP Eval Check"_ns), + mExpression(aExpression), + mFileNameString(aFileNameString), + mLineNum(aLineNum), + mColumnNum(aColumnNum), + mEvalAllowed(false) {} + + bool MainThreadRun() override { + mResult = CheckInternal( + mWorkerPrivate->GetCsp(), mWorkerPrivate->CSPEventListener(), + mWorkerPrivate->GetLoadingPrincipal(), mExpression, mFileNameString, + mLineNum, mColumnNum, &mEvalAllowed); + return true; + } + + nsresult GetResult(bool* aAllowed) { + MOZ_ASSERT(aAllowed); + *aAllowed = mEvalAllowed; + return mResult; + } + + private: + const nsString mExpression; + const nsString mFileNameString; + const uint32_t mLineNum; + const uint32_t mColumnNum; + bool mEvalAllowed; + nsresult mResult; +}; + +} // namespace + +/* static */ +nsresult CSPEvalChecker::CheckForWindow(JSContext* aCx, + nsGlobalWindowInner* aWindow, + const nsAString& aExpression, + bool* aAllowEval) { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aAllowEval); + + // The value is set at any "return", but better to have a default value here. + *aAllowEval = false; + + // if CSP is enabled, and setTimeout/setInterval was called with a string, + // disable the registration and log an error + nsCOMPtr doc = aWindow->GetExtantDoc(); + if (!doc) { + // if there's no document, we don't have to do anything. + *aAllowEval = true; + return NS_OK; + } + + nsresult rv = NS_OK; + + // Get the calling location. + uint32_t lineNum = 0; + uint32_t columnNum = 0; + nsAutoString fileNameString; + if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum, + &columnNum)) { + fileNameString.AssignLiteral("unknown"); + } + + nsCOMPtr csp = doc->GetCsp(); + rv = CheckInternal(csp, nullptr /* no CSPEventListener for window */, + doc->NodePrincipal(), aExpression, fileNameString, lineNum, + columnNum, aAllowEval); + if (NS_WARN_IF(NS_FAILED(rv))) { + *aAllowEval = false; + return rv; + } + + return NS_OK; +} + +/* static */ +nsresult CSPEvalChecker::CheckForWorker(JSContext* aCx, + WorkerPrivate* aWorkerPrivate, + const nsAString& aExpression, + bool* aAllowEval) { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(aAllowEval); + + // The value is set at any "return", but better to have a default value here. + *aAllowEval = false; + + // Get the calling location. + uint32_t lineNum = 0; + uint32_t columnNum = 0; + nsAutoString fileNameString; + if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum, + &columnNum)) { + fileNameString.AssignLiteral("unknown"); + } + + RefPtr r = new WorkerCSPCheckRunnable( + aWorkerPrivate, aExpression, fileNameString, lineNum, columnNum); + ErrorResult error; + r->Dispatch(Canceling, error); + if (NS_WARN_IF(error.Failed())) { + *aAllowEval = false; + return error.StealNSResult(); + } + + nsresult rv = r->GetResult(aAllowEval); + if (NS_WARN_IF(NS_FAILED(rv))) { + *aAllowEval = false; + return rv; + } + + return NS_OK; +} diff --git a/dom/security/CSPEvalChecker.h b/dom/security/CSPEvalChecker.h new file mode 100644 index 0000000000..c2a1f8d774 --- /dev/null +++ b/dom/security/CSPEvalChecker.h @@ -0,0 +1,32 @@ +/* -*- 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 mozilla_dom_CSPEvalChecker_h +#define mozilla_dom_CSPEvalChecker_h + +#include "nsString.h" + +struct JSContext; +class nsGlobalWindowInner; + +namespace mozilla::dom { + +class WorkerPrivate; + +class CSPEvalChecker final { + public: + static nsresult CheckForWindow(JSContext* aCx, nsGlobalWindowInner* aWindow, + const nsAString& aExpression, + bool* aAllowEval); + + static nsresult CheckForWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate, + const nsAString& aExpression, + bool* aAllowEval); +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_CSPEvalChecker_h diff --git a/dom/security/DOMSecurityMonitor.cpp b/dom/security/DOMSecurityMonitor.cpp new file mode 100644 index 0000000000..bbe0f2aeb6 --- /dev/null +++ b/dom/security/DOMSecurityMonitor.cpp @@ -0,0 +1,136 @@ +/* -*- 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 "DOMSecurityMonitor.h" +#include "nsContentUtils.h" + +#include "nsIChannel.h" +#include "nsILoadInfo.h" +#include "nsIPrincipal.h" +#include "nsIURI.h" +#include "nsJSUtils.h" +#include "xpcpublic.h" + +#include "mozilla/BasePrincipal.h" +#include "mozilla/StaticPrefs_dom.h" + +/* static */ +void DOMSecurityMonitor::AuditParsingOfHTMLXMLFragments( + nsIPrincipal* aPrincipal, const nsAString& aFragment) { + // if the fragment parser (e.g. innerHTML()) is not called in chrome: code + // or any of our about: pages, then there is nothing to do here. + if (!aPrincipal->IsSystemPrincipal() && !aPrincipal->SchemeIs("about")) { + return; + } + + // check if the fragment is empty, if so, we can return early. + if (aFragment.IsEmpty()) { + return; + } + + // check if there is a JS caller, if not, then we can can return early here + // because we only care about calls to the fragment parser (e.g. innerHTML) + // originating from JS code. + nsAutoString filename; + uint32_t lineNum = 0; + uint32_t columnNum = 0; + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + if (!cx || + !nsJSUtils::GetCallingLocation(cx, filename, &lineNum, &columnNum)) { + return; + } + + // check if we should skip assertion. Please only ever set this pref to + // true if really needed for testing purposes. + if (mozilla::StaticPrefs::dom_security_skip_html_fragment_assertion()) { + return; + } + + /* + * WARNING: Do not add any new entries to the htmlFragmentAllowlist + * without proper review from a dom:security peer! + */ + static nsLiteralCString htmlFragmentAllowlist[] = { + "chrome://global/content/elements/marquee.js"_ns, + nsLiteralCString( + "chrome://pocket/content/panels/js/vendor/jquery-2.1.1.min.js"), + nsLiteralCString("chrome://devtools/content/shared/sourceeditor/" + "codemirror/codemirror.bundle.js"), + nsLiteralCString( + "resource://activity-stream/data/content/activity-stream.bundle.js"), + nsLiteralCString("resource://devtools/client/debugger/src/components/" + "Editor/Breakpoint.js"), + nsLiteralCString("resource://devtools/client/debugger/src/components/" + "Editor/ColumnBreakpoint.js"), + nsLiteralCString( + "resource://devtools/client/shared/vendor/fluent-react.js"), + "resource://devtools/client/shared/vendor/react-dom.js"_ns, + nsLiteralCString( + "resource://devtools/client/shared/vendor/react-dom-dev.js"), + nsLiteralCString( + "resource://devtools/client/shared/widgets/FilterWidget.js"), + nsLiteralCString("resource://devtools/client/shared/widgets/tooltip/" + "inactive-css-tooltip-helper.js"), + "resource://devtools/client/shared/widgets/Spectrum.js"_ns, + "resource://gre/modules/narrate/VoiceSelect.sys.mjs"_ns, + "resource://normandy-vendor/ReactDOM.js"_ns, + // ------------------------------------------------------------------ + // test pages + // ------------------------------------------------------------------ + "chrome://mochikit/content/browser-harness.xhtml"_ns, + "chrome://mochikit/content/harness.xhtml"_ns, + "chrome://mochikit/content/tests/"_ns, + "chrome://mochitests/content/"_ns, + "chrome://reftest/content/"_ns, + }; + + for (const nsLiteralCString& allowlistEntry : htmlFragmentAllowlist) { + if (StringBeginsWith(NS_ConvertUTF16toUTF8(filename), allowlistEntry)) { + return; + } + } + + nsAutoCString uriSpec; + aPrincipal->GetAsciiSpec(uriSpec); + + // Ideally we should not call the fragment parser (e.g. innerHTML()) in + // chrome: code or any of our about: pages. If you hit that assertion, + // please do *not* add your filename to the allowlist above, but rather + // refactor your code. + fprintf(stderr, + "Do not call the fragment parser (e.g innerHTML()) in chrome code " + "or in about: pages, (uri: %s), (caller: %s, line: %d, col: %d), " + "(fragment: %s)", + uriSpec.get(), NS_ConvertUTF16toUTF8(filename).get(), lineNum, + columnNum, NS_ConvertUTF16toUTF8(aFragment).get()); + + xpc_DumpJSStack(true, true, false); + MOZ_ASSERT(false); +} + +/* static */ +void DOMSecurityMonitor::AuditUseOfJavaScriptURI(nsIChannel* aChannel) { + nsCOMPtr loadInfo = aChannel->LoadInfo(); + nsCOMPtr loadingPrincipal = loadInfo->GetLoadingPrincipal(); + + // We only ever have no loadingPrincipal in case of a new top-level load. + // The purpose of this assertion is to make sure we do not allow loading + // javascript: URIs in system privileged contexts. Hence there is nothing + // to do here in case there is no loadingPrincipal. + if (!loadingPrincipal) { + return; + } + + // if the javascript: URI is not loaded by a system privileged context + // or an about: page, there there is nothing to do here. + if (!loadingPrincipal->IsSystemPrincipal() && + !loadingPrincipal->SchemeIs("about")) { + return; + } + + MOZ_ASSERT(false, + "Do not use javascript: URIs in chrome code or in about: pages"); +} diff --git a/dom/security/DOMSecurityMonitor.h b/dom/security/DOMSecurityMonitor.h new file mode 100644 index 0000000000..457e8a143a --- /dev/null +++ b/dom/security/DOMSecurityMonitor.h @@ -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/. */ + +#ifndef mozilla_dom_DOMSecurityMonitor_h +#define mozilla_dom_DOMSecurityMonitor_h + +#include "nsStringFwd.h" + +class nsIChannel; +class nsIPrincipal; + +class DOMSecurityMonitor final { + public: + /* The fragment parser is triggered anytime JS calls innerHTML or similar + * JS functions which can generate HTML fragments. This generation of + * HTML might be dangerous, hence we should ensure that no new instances + * of innerHTML and similar functions are introduced in system privileged + * contexts, or also about: pages, in our codebase. + * + * If the auditor detects a new instance of innerHTML or similar + * function it will CRASH using a strong assertion. + */ + static void AuditParsingOfHTMLXMLFragments(nsIPrincipal* aPrincipal, + const nsAString& aFragment); + + /* The use of javascript: URIs in system privileged contexts or + * also about: pages is considered unsafe and discouraged. + * + * If the auditor detects a javascript: URI in a privileged + * context it will CRASH using a strong assertion. + * + */ + static void AuditUseOfJavaScriptURI(nsIChannel* aChannel); + + private: + DOMSecurityMonitor() = default; + ~DOMSecurityMonitor() = default; +}; + +#endif /* mozilla_dom_DOMSecurityMonitor_h */ diff --git a/dom/security/FramingChecker.cpp b/dom/security/FramingChecker.cpp new file mode 100644 index 0000000000..39fcea268a --- /dev/null +++ b/dom/security/FramingChecker.cpp @@ -0,0 +1,231 @@ +/* -*- 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 "FramingChecker.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsContentUtils.h" +#include "nsCSPUtils.h" +#include "nsDocShell.h" +#include "nsHttpChannel.h" +#include "nsContentSecurityUtils.h" +#include "nsGlobalWindowOuter.h" +#include "nsIChannel.h" +#include "nsIConsoleReportCollector.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIScriptError.h" +#include "nsNetUtil.h" +#include "nsQueryObject.h" +#include "nsTArray.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/dom/nsCSPUtils.h" +#include "mozilla/dom/LoadURIOptionsBinding.h" +#include "mozilla/dom/WindowGlobalParent.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/net/HttpBaseChannel.h" + +#include "nsIObserverService.h" + +using namespace mozilla; +using namespace mozilla::dom; + +/* static */ +void FramingChecker::ReportError(const char* aMessageTag, + nsIHttpChannel* aChannel, nsIURI* aURI, + const nsAString& aPolicy) { + MOZ_ASSERT(aChannel); + MOZ_ASSERT(aURI); + + nsCOMPtr httpChannel = do_QueryInterface(aChannel); + if (!httpChannel) { + return; + } + + // Get the URL spec + nsAutoCString spec; + nsresult rv = aURI->GetAsciiSpec(spec); + if (NS_FAILED(rv)) { + return; + } + + nsTArray params; + params.AppendElement(aPolicy); + params.AppendElement(NS_ConvertUTF8toUTF16(spec)); + + httpChannel->AddConsoleReport(nsIScriptError::errorFlag, "X-Frame-Options"_ns, + nsContentUtils::eSECURITY_PROPERTIES, spec, 0, + 0, nsDependentCString(aMessageTag), params); +} + +/* static */ +bool FramingChecker::CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel, + const nsAString& aPolicy) { + nsCOMPtr uri; + aHttpChannel->GetURI(getter_AddRefs(uri)); + + // return early if header does not have one of the values with meaning + if (!aPolicy.LowerCaseEqualsLiteral("deny") && + !aPolicy.LowerCaseEqualsLiteral("sameorigin")) { + ReportError("XFrameOptionsInvalid", aHttpChannel, uri, aPolicy); + return true; + } + + // If the X-Frame-Options value is SAMEORIGIN, then the top frame in the + // parent chain must be from the same origin as this document. + bool checkSameOrigin = aPolicy.LowerCaseEqualsLiteral("sameorigin"); + + nsCOMPtr loadInfo = aHttpChannel->LoadInfo(); + RefPtr ctx; + loadInfo->GetBrowsingContext(getter_AddRefs(ctx)); + + while (ctx) { + nsCOMPtr principal; + // Generally CheckOneFrameOptionsPolicy is consulted from within the + // DocumentLoadListener in the parent process. For loads of type object + // and embed it's called from the Document in the content process. + // After Bug 1646899 we should be able to remove that branching code for + // querying the principal. + if (XRE_IsParentProcess()) { + WindowGlobalParent* window = ctx->Canonical()->GetCurrentWindowGlobal(); + if (window) { + // Using the URI of the Principal and not the document because e.g. + // window.open inherits the principal and hence the URI of the + // opening context needed for same origin checks. + principal = window->DocumentPrincipal(); + } + } else if (nsPIDOMWindowOuter* windowOuter = ctx->GetDOMWindow()) { + principal = nsGlobalWindowOuter::Cast(windowOuter)->GetPrincipal(); + } + + if (principal && principal->IsSystemPrincipal()) { + return true; + } + + if (checkSameOrigin) { + bool isSameOrigin = principal && principal->IsSameOrigin(uri); + // one of the ancestors is not same origin as this document + if (!isSameOrigin) { + ReportError("XFrameOptionsDeny", aHttpChannel, uri, aPolicy); + return false; + } + } + ctx = ctx->GetParent(); + } + + // If the value of the header is DENY, and the previous condition is + // not met (current docshell is not the top docshell), prohibit the + // load. + if (aPolicy.LowerCaseEqualsLiteral("deny")) { + ReportError("XFrameOptionsDeny", aHttpChannel, uri, aPolicy); + return false; + } + + return true; +} + +// Ignore x-frame-options if CSP with frame-ancestors exists +static bool ShouldIgnoreFrameOptions(nsIChannel* aChannel, + nsIContentSecurityPolicy* aCSP) { + NS_ENSURE_TRUE(aChannel, false); + if (!aCSP) { + return false; + } + + bool enforcesFrameAncestors = false; + aCSP->GetEnforcesFrameAncestors(&enforcesFrameAncestors); + if (!enforcesFrameAncestors) { + // if CSP does not contain frame-ancestors, then there + // is nothing to do here. + return false; + } + + return true; +} + +// Check if X-Frame-Options permits this document to be loaded as a +// subdocument. This will iterate through and check any number of +// X-Frame-Options policies in the request (comma-separated in a header, +// multiple headers, etc). +/* static */ +bool FramingChecker::CheckFrameOptions(nsIChannel* aChannel, + nsIContentSecurityPolicy* aCsp, + bool& outIsFrameCheckingSkipped) { + if (!aChannel) { + return true; + } + + nsCOMPtr loadInfo = aChannel->LoadInfo(); + ExtContentPolicyType contentType = loadInfo->GetExternalContentPolicyType(); + + // xfo check only makes sense for subdocument and object loads, if this is + // not a load of such type, there is nothing to do here. + if (contentType != ExtContentPolicy::TYPE_SUBDOCUMENT && + contentType != ExtContentPolicy::TYPE_OBJECT) { + return true; + } + + nsCOMPtr httpChannel; + nsresult rv = nsContentSecurityUtils::GetHttpChannelFromPotentialMultiPart( + aChannel, getter_AddRefs(httpChannel)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + // xfo can only hang off an httpchannel, if this is not an httpChannel + // then there is nothing to do here. + if (!httpChannel) { + return true; + } + + // ignore XFO checks on channels that will be redirected + uint32_t responseStatus; + rv = httpChannel->GetResponseStatus(&responseStatus); + // GetResponseStatus returning failure is expected in several situations, so + // do not warn if it fails. + if (NS_FAILED(rv)) { + return true; + } + if (mozilla::net::nsHttpChannel::IsRedirectStatus(responseStatus)) { + return true; + } + + nsAutoCString xfoHeaderCValue; + Unused << httpChannel->GetResponseHeader("X-Frame-Options"_ns, + xfoHeaderCValue); + NS_ConvertUTF8toUTF16 xfoHeaderValue(xfoHeaderCValue); + + // if no header value, there's nothing to do. + if (xfoHeaderValue.IsEmpty()) { + return true; + } + + // xfo checks are ignored in case CSP frame-ancestors is present, + // if so, there is nothing to do here. + if (ShouldIgnoreFrameOptions(aChannel, aCsp)) { + outIsFrameCheckingSkipped = true; + return true; + } + + // iterate through all the header values (usually there's only one, but can + // be many. If any want to deny the load, deny the load. + nsCharSeparatedTokenizer tokenizer(xfoHeaderValue, ','); + while (tokenizer.hasMoreTokens()) { + const nsAString& tok = tokenizer.nextToken(); + if (!CheckOneFrameOptionsPolicy(httpChannel, tok)) { + // if xfo blocks the load we are notifying observers for + // testing purposes because there is no event to gather + // what an iframe load was blocked or not. + nsCOMPtr uri; + httpChannel->GetURI(getter_AddRefs(uri)); + nsCOMPtr observerService = + mozilla::services::GetObserverService(); + nsAutoString policy(tok); + observerService->NotifyObservers(uri, "xfo-on-violate-policy", + policy.get()); + return false; + } + } + return true; +} diff --git a/dom/security/FramingChecker.h b/dom/security/FramingChecker.h new file mode 100644 index 0000000000..45c43031e0 --- /dev/null +++ b/dom/security/FramingChecker.h @@ -0,0 +1,49 @@ +/* -*- 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 mozilla_dom_FramingChecker_h +#define mozilla_dom_FramingChecker_h + +#include "nsStringFwd.h" + +class nsIDocShell; +class nsIChannel; +class nsIHttpChannel; +class nsIDocShellTreeItem; +class nsIURI; +class nsIContentSecurityPolicy; + +namespace mozilla::dom { +class BrowsingContext; +} // namespace mozilla::dom + +class FramingChecker { + public: + // Determine if X-Frame-Options allows content to be framed + // as a subdocument + static bool CheckFrameOptions(nsIChannel* aChannel, + nsIContentSecurityPolicy* aCSP, + bool& outIsFrameCheckingSkipped); + + protected: + enum XFOHeader { eDENY, eSAMEORIGIN }; + + /** + * Logs to the window about a X-Frame-Options error. + * + * @param aMessageTag the error message identifier to log + * @param aChannel the HTTP Channel + * @param aURI the URI of the frame attempting to load + * @param aPolicy the header value string from the frame to the console. + */ + static void ReportError(const char* aMessageTag, nsIHttpChannel* aChannel, + nsIURI* aURI, const nsAString& aPolicy); + + static bool CheckOneFrameOptionsPolicy(nsIHttpChannel* aHttpChannel, + const nsAString& aPolicy); +}; + +#endif /* mozilla_dom_FramingChecker_h */ diff --git a/dom/security/PolicyTokenizer.cpp b/dom/security/PolicyTokenizer.cpp new file mode 100644 index 0000000000..8e28e6ce32 --- /dev/null +++ b/dom/security/PolicyTokenizer.cpp @@ -0,0 +1,70 @@ +/* -*- 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 "PolicyTokenizer.h" + +#include "mozilla/Logging.h" + +static mozilla::LogModule* GetPolicyTokenizerLog() { + static mozilla::LazyLogModule gPolicyTokenizerPRLog("PolicyTokenizer"); + return gPolicyTokenizerPRLog; +} + +#define POLICYTOKENIZERLOG(args) \ + MOZ_LOG(GetPolicyTokenizerLog(), mozilla::LogLevel::Debug, args) + +static const char16_t SEMICOL = ';'; + +PolicyTokenizer::PolicyTokenizer(const char16_t* aStart, const char16_t* aEnd) + : mCurChar(aStart), mEndChar(aEnd) { + POLICYTOKENIZERLOG(("PolicyTokenizer::PolicyTokenizer")); +} + +PolicyTokenizer::~PolicyTokenizer() { + POLICYTOKENIZERLOG(("PolicyTokenizer::~PolicyTokenizer")); +} + +void PolicyTokenizer::generateNextToken() { + skipWhiteSpaceAndSemicolon(); + MOZ_ASSERT(mCurToken.Length() == 0); + const char16_t* const start = mCurChar; + while (!atEnd() && !nsContentUtils::IsHTMLWhitespace(*mCurChar) && + *mCurChar != SEMICOL) { + mCurChar++; + } + if (start != mCurChar) { + mCurToken.Append(start, mCurChar - start); + } + POLICYTOKENIZERLOG(("PolicyTokenizer::generateNextToken: %s", + NS_ConvertUTF16toUTF8(mCurToken).get())); +} + +void PolicyTokenizer::generateTokens(policyTokens& outTokens) { + POLICYTOKENIZERLOG(("PolicyTokenizer::generateTokens")); + + // dirAndSrcs holds one set of [ name, src, src, src, ... ] + nsTArray dirAndSrcs; + + while (!atEnd()) { + generateNextToken(); + dirAndSrcs.AppendElement(mCurToken); + skipWhiteSpace(); + if (atEnd() || accept(SEMICOL)) { + outTokens.AppendElement(std::move(dirAndSrcs)); + dirAndSrcs.ClearAndRetainStorage(); + } + } +} + +void PolicyTokenizer::tokenizePolicy(const nsAString& aPolicyString, + policyTokens& outTokens) { + POLICYTOKENIZERLOG(("PolicyTokenizer::tokenizePolicy")); + + PolicyTokenizer tokenizer(aPolicyString.BeginReading(), + aPolicyString.EndReading()); + + tokenizer.generateTokens(outTokens); +} diff --git a/dom/security/PolicyTokenizer.h b/dom/security/PolicyTokenizer.h new file mode 100644 index 0000000000..1c3c18175d --- /dev/null +++ b/dom/security/PolicyTokenizer.h @@ -0,0 +1,78 @@ +/* -*- 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 PolicyTokenizer_h___ +#define PolicyTokenizer_h___ + +#include "nsContentUtils.h" +#include "nsString.h" + +/** + * How does the parsing work? + * + * We generate tokens by splitting the policy-string by whitespace and + * semicolon. Interally the tokens are represented as an array of string-arrays: + * + * [ + * [ name, src, src, src, ... ], + * [ name, src, src, src, ... ], + * [ name, src, src, src, ... ] + * ] + * + * for example: + * [ + * [ img-src, http://www.example.com, http:www.test.com ], + * [ default-src, 'self'], + * [ script-src, 'unsafe-eval', 'unsafe-inline' ], + * ] + */ + +using policyTokens = nsTArray>; + +class PolicyTokenizer { + public: + static void tokenizePolicy(const nsAString& aPolicyString, + policyTokens& outTokens); + + private: + PolicyTokenizer(const char16_t* aStart, const char16_t* aEnd); + ~PolicyTokenizer(); + + inline bool atEnd() { return mCurChar >= mEndChar; } + + inline void skipWhiteSpace() { + while (mCurChar < mEndChar && nsContentUtils::IsHTMLWhitespace(*mCurChar)) { + mCurChar++; + } + mCurToken.Truncate(); + } + + inline void skipWhiteSpaceAndSemicolon() { + while (mCurChar < mEndChar && + (*mCurChar == ';' || nsContentUtils::IsHTMLWhitespace(*mCurChar))) { + mCurChar++; + } + mCurToken.Truncate(); + } + + inline bool accept(char16_t aChar) { + NS_ASSERTION(mCurChar < mEndChar, "Trying to dereference mEndChar"); + if (*mCurChar == aChar) { + mCurToken.Append(*mCurChar++); + return true; + } + return false; + } + + void generateNextToken(); + void generateTokens(policyTokens& outTokens); + + const char16_t* mCurChar; + const char16_t* mEndChar; + nsString mCurToken; +}; + +#endif /* PolicyTokenizer_h___ */ diff --git a/dom/security/ReferrerInfo.cpp b/dom/security/ReferrerInfo.cpp new file mode 100644 index 0000000000..e9b999d430 --- /dev/null +++ b/dom/security/ReferrerInfo.cpp @@ -0,0 +1,1713 @@ +/* -*- 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/RefPtr.h" +#include "mozilla/dom/ReferrerPolicyBinding.h" +#include "nsIClassInfoImpl.h" +#include "nsIEffectiveTLDService.h" +#include "nsIHttpChannel.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" +#include "nsIOService.h" +#include "nsIPipe.h" +#include "nsIURL.h" + +#include "nsWhitespaceTokenizer.h" +#include "nsAlgorithm.h" +#include "nsContentUtils.h" +#include "nsCharSeparatedTokenizer.h" +#include "nsStreamUtils.h" +#include "ReferrerInfo.h" + +#include "mozilla/BasePrincipal.h" +#include "mozilla/ContentBlockingAllowList.h" +#include "mozilla/net/CookieJarSettings.h" +#include "mozilla/net/HttpBaseChannel.h" +#include "mozilla/dom/Document.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/RequestBinding.h" +#include "mozilla/StaticPrefs_network.h" +#include "mozilla/StorageAccess.h" +#include "mozilla/StyleSheet.h" +#include "mozilla/Telemetry.h" +#include "nsIWebProgressListener.h" + +static mozilla::LazyLogModule gReferrerInfoLog("ReferrerInfo"); +#define LOG(msg) MOZ_LOG(gReferrerInfoLog, mozilla::LogLevel::Debug, msg) +#define LOG_ENABLED() MOZ_LOG_TEST(gReferrerInfoLog, mozilla::LogLevel::Debug) + +using namespace mozilla::net; + +namespace mozilla::dom { + +// Implementation of ClassInfo is required to serialize/deserialize +NS_IMPL_CLASSINFO(ReferrerInfo, nullptr, nsIClassInfo::THREADSAFE, + REFERRERINFO_CID) + +NS_IMPL_ISUPPORTS_CI(ReferrerInfo, nsIReferrerInfo, nsISerializable) + +#define MAX_REFERRER_SENDING_POLICY 2 +#define MAX_CROSS_ORIGIN_SENDING_POLICY 2 +#define MAX_TRIMMING_POLICY 2 + +#define MIN_REFERRER_SENDING_POLICY 0 +#define MIN_CROSS_ORIGIN_SENDING_POLICY 0 +#define MIN_TRIMMING_POLICY 0 + +/* + * Default referrer policy to use + */ +enum DefaultReferrerPolicy : uint32_t { + eDefaultPolicyNoReferrer = 0, + eDefaultPolicySameOrgin = 1, + eDefaultPolicyStrictWhenXorigin = 2, + eDefaultPolicyNoReferrerWhenDownGrade = 3, +}; + +static uint32_t GetDefaultFirstPartyReferrerPolicyPref(bool aPrivateBrowsing) { + return aPrivateBrowsing + ? StaticPrefs::network_http_referer_defaultPolicy_pbmode() + : StaticPrefs::network_http_referer_defaultPolicy(); +} + +static uint32_t GetDefaultThirdPartyReferrerPolicyPref(bool aPrivateBrowsing) { + return aPrivateBrowsing + ? StaticPrefs::network_http_referer_defaultPolicy_trackers_pbmode() + : StaticPrefs::network_http_referer_defaultPolicy_trackers(); +} + +static ReferrerPolicy DefaultReferrerPolicyToReferrerPolicy( + uint32_t aDefaultToUse) { + switch (aDefaultToUse) { + case DefaultReferrerPolicy::eDefaultPolicyNoReferrer: + return ReferrerPolicy::No_referrer; + case DefaultReferrerPolicy::eDefaultPolicySameOrgin: + return ReferrerPolicy::Same_origin; + case DefaultReferrerPolicy::eDefaultPolicyStrictWhenXorigin: + return ReferrerPolicy::Strict_origin_when_cross_origin; + } + + return ReferrerPolicy::No_referrer_when_downgrade; +} + +struct LegacyReferrerPolicyTokenMap { + const char* mToken; + ReferrerPolicy mPolicy; +}; + +/* + * Parse ReferrerPolicy from token. + * The supported tokens are defined in ReferrerPolicy.webidl. + * The legacy tokens are "never", "default", "always" and + * "origin-when-crossorigin". The legacy tokens are only supported in meta + * referrer content + * + * @param aContent content string to be transformed into + * ReferrerPolicyEnum, e.g. "origin". + */ +ReferrerPolicy ReferrerPolicyFromToken(const nsAString& aContent, + bool allowedLegacyToken) { + nsString lowerContent(aContent); + ToLowerCase(lowerContent); + + if (allowedLegacyToken) { + static const LegacyReferrerPolicyTokenMap sLegacyReferrerPolicyToken[] = { + {"never", ReferrerPolicy::No_referrer}, + {"default", ReferrerPolicy::No_referrer_when_downgrade}, + {"always", ReferrerPolicy::Unsafe_url}, + {"origin-when-crossorigin", ReferrerPolicy::Origin_when_cross_origin}, + }; + + uint8_t numStr = (sizeof(sLegacyReferrerPolicyToken) / + sizeof(sLegacyReferrerPolicyToken[0])); + for (uint8_t i = 0; i < numStr; i++) { + if (lowerContent.EqualsASCII(sLegacyReferrerPolicyToken[i].mToken)) { + return sLegacyReferrerPolicyToken[i].mPolicy; + } + } + } + + // 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; +} + +// static +ReferrerPolicy ReferrerInfo::ReferrerPolicyFromMetaString( + const nsAString& aContent) { + // This is implemented as described in + // https://html.spec.whatwg.org/multipage/semantics.html#meta-referrer + // Meta referrer accepts both supported tokens in ReferrerPolicy.webidl and + // legacy tokens. + return ReferrerPolicyFromToken(aContent, true); +} + +// static +ReferrerPolicy ReferrerInfo::ReferrerPolicyAttributeFromString( + const nsAString& aContent) { + // This is implemented as described in + // https://html.spec.whatwg.org/multipage/infrastructure.html#referrer-policy-attribute + // referrerpolicy attribute only accepts supported tokens in + // ReferrerPolicy.webidl + return ReferrerPolicyFromToken(aContent, false); +} + +// static +ReferrerPolicy ReferrerInfo::ReferrerPolicyFromHeaderString( + const nsAString& aContent) { + // Multiple headers could be concatenated into one comma-separated + // list of policies. Need to tokenize the multiple headers. + ReferrerPolicyEnum referrerPolicy = ReferrerPolicy::_empty; + for (const auto& token : nsCharSeparatedTokenizer(aContent, ',').ToRange()) { + if (token.IsEmpty()) { + continue; + } + + // Referrer-Policy header only accepts supported tokens in + // ReferrerPolicy.webidl + ReferrerPolicyEnum policy = ReferrerPolicyFromToken(token, false); + // If there are multiple policies available, the last valid policy should be + // used. + // https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values + if (policy != ReferrerPolicy::_empty) { + referrerPolicy = policy; + } + } + 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( + StaticPrefs::network_http_sendRefererHeader_DoNotUseDirectly(), + MIN_REFERRER_SENDING_POLICY, MAX_REFERRER_SENDING_POLICY); +} + +/* static */ +uint32_t ReferrerInfo::GetUserXOriginSendingPolicy() { + return clamped( + StaticPrefs::network_http_referer_XOriginPolicy_DoNotUseDirectly(), + MIN_CROSS_ORIGIN_SENDING_POLICY, MAX_CROSS_ORIGIN_SENDING_POLICY); +} + +/* static */ +uint32_t ReferrerInfo::GetUserTrimmingPolicy() { + return clamped( + StaticPrefs::network_http_referer_trimmingPolicy_DoNotUseDirectly(), + MIN_TRIMMING_POLICY, MAX_TRIMMING_POLICY); +} + +/* static */ +uint32_t ReferrerInfo::GetUserXOriginTrimmingPolicy() { + return clamped( + StaticPrefs:: + network_http_referer_XOriginTrimmingPolicy_DoNotUseDirectly(), + MIN_TRIMMING_POLICY, MAX_TRIMMING_POLICY); +} + +/* static */ +ReferrerPolicy ReferrerInfo::GetDefaultReferrerPolicy(nsIHttpChannel* aChannel, + nsIURI* aURI, + bool aPrivateBrowsing) { + bool thirdPartyTrackerIsolated = false; + if (aChannel && aURI) { + nsCOMPtr loadInfo = aChannel->LoadInfo(); + nsCOMPtr cjs; + Unused << loadInfo->GetCookieJarSettings(getter_AddRefs(cjs)); + if (!cjs) { + bool shouldResistFingerprinting = + nsContentUtils::ShouldResistFingerprinting(aChannel); + cjs = aPrivateBrowsing + ? net::CookieJarSettings::Create(CookieJarSettings::ePrivate, + shouldResistFingerprinting) + : net::CookieJarSettings::Create(CookieJarSettings::eRegular, + shouldResistFingerprinting); + } + + // We only check if the channel is isolated if it's in the parent process + // with the rejection of third party contexts is enabled. We don't need to + // check this in content processes since the tracking state of the channel + // is unknown here and the referrer policy would be updated when the channel + // starts connecting in the parent process. + if (XRE_IsParentProcess() && cjs->GetRejectThirdPartyContexts()) { + uint32_t rejectedReason = 0; + thirdPartyTrackerIsolated = + !ShouldAllowAccessFor(aChannel, aURI, &rejectedReason) && + rejectedReason != + static_cast( + nsIWebProgressListener::STATE_COOKIES_PARTITIONED_FOREIGN); + // Here we intentionally do not notify about the rejection reason, if any + // in order to avoid this check to have any visible side-effects (e.g. a + // web console report.) + } + } + + // Select the appropriate pref starting with + // "network.http.referer.defaultPolicy" to use based on private-browsing + // ("pbmode") AND third-party trackers ("trackers"). + return DefaultReferrerPolicyToReferrerPolicy( + thirdPartyTrackerIsolated + ? GetDefaultThirdPartyReferrerPolicyPref(aPrivateBrowsing) + : GetDefaultFirstPartyReferrerPolicyPref(aPrivateBrowsing)); +} + +/* static */ +bool ReferrerInfo::IsReferrerSchemeAllowed(nsIURI* aReferrer) { + NS_ENSURE_TRUE(aReferrer, false); + + nsAutoCString scheme; + nsresult rv = aReferrer->GetScheme(scheme); + if (NS_WARN_IF(NS_FAILED(rv))) { + return false; + } + + return scheme.EqualsIgnoreCase("https") || scheme.EqualsIgnoreCase("http"); +} + +/* static */ +bool ReferrerInfo::ShouldResponseInheritReferrerInfo(nsIChannel* aChannel) { + if (!aChannel) { + return false; + } + + nsCOMPtr channelURI; + nsresult rv = aChannel->GetURI(getter_AddRefs(channelURI)); + NS_ENSURE_SUCCESS(rv, false); + + bool isAbout = channelURI->SchemeIs("about"); + if (!isAbout) { + return false; + } + + nsAutoCString aboutSpec; + rv = channelURI->GetSpec(aboutSpec); + NS_ENSURE_SUCCESS(rv, false); + + return aboutSpec.EqualsLiteral("about:srcdoc"); +} + +/* static */ +nsresult ReferrerInfo::HandleSecureToInsecureReferral( + nsIURI* aOriginalURI, nsIURI* aURI, ReferrerPolicyEnum aPolicy, + bool& aAllowed) { + NS_ENSURE_ARG(aOriginalURI); + NS_ENSURE_ARG(aURI); + + aAllowed = false; + + bool referrerIsHttpsScheme = aOriginalURI->SchemeIs("https"); + if (!referrerIsHttpsScheme) { + aAllowed = true; + return NS_OK; + } + + // It's ok to send referrer for https-to-http scenarios if the referrer + // policy is "unsafe-url", "origin", or "origin-when-cross-origin". + // in other referrer policies, https->http is not allowed... + bool uriIsHttpsScheme = aURI->SchemeIs("https"); + if (aPolicy != ReferrerPolicy::Unsafe_url && + aPolicy != ReferrerPolicy::Origin_when_cross_origin && + aPolicy != ReferrerPolicy::Origin && !uriIsHttpsScheme) { + return NS_OK; + } + + aAllowed = true; + return NS_OK; +} + +nsresult ReferrerInfo::HandleUserXOriginSendingPolicy(nsIURI* aURI, + nsIURI* aReferrer, + bool& aAllowed) const { + NS_ENSURE_ARG(aURI); + aAllowed = false; + + nsAutoCString uriHost; + nsAutoCString referrerHost; + + nsresult rv = aURI->GetAsciiHost(uriHost); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aReferrer->GetAsciiHost(referrerHost); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Send an empty referrer if xorigin and leaving a .onion domain. + if (StaticPrefs::network_http_referer_hideOnionSource() && + !uriHost.Equals(referrerHost) && + StringEndsWith(referrerHost, ".onion"_ns)) { + return NS_OK; + } + + switch (GetUserXOriginSendingPolicy()) { + // Check policy for sending referrer only when hosts match + case XOriginSendingPolicy::ePolicySendWhenSameHost: { + if (!uriHost.Equals(referrerHost)) { + return NS_OK; + } + break; + } + + case XOriginSendingPolicy::ePolicySendWhenSameDomain: { + nsCOMPtr eTLDService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + if (!eTLDService) { + // check policy for sending only when effective top level domain + // matches. this falls back on using host if eTLDService does not work + if (!uriHost.Equals(referrerHost)) { + return NS_OK; + } + break; + } + + nsAutoCString uriDomain; + nsAutoCString referrerDomain; + uint32_t extraDomains = 0; + + rv = eTLDService->GetBaseDomain(aURI, extraDomains, uriDomain); + if (rv == NS_ERROR_HOST_IS_IP_ADDRESS || + rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { + // uri is either an IP address, an alias such as 'localhost', an eTLD + // such as 'co.uk', or the empty string. Uses the normalized host in + // such cases. + rv = aURI->GetAsciiHost(uriDomain); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = eTLDService->GetBaseDomain(aReferrer, extraDomains, referrerDomain); + if (rv == NS_ERROR_HOST_IS_IP_ADDRESS || + rv == NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) { + // referrer is either an IP address, an alias such as 'localhost', an + // eTLD such as 'co.uk', or the empty string. Uses the normalized host + // in such cases. + rv = aReferrer->GetAsciiHost(referrerDomain); + } + + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!uriDomain.Equals(referrerDomain)) { + return NS_OK; + } + break; + } + + default: + break; + } + + aAllowed = true; + return NS_OK; +} + +// This roughly implements Step 3.1. of +// https://fetch.spec.whatwg.org/#append-a-request-origin-header +/* static */ +bool ReferrerInfo::ShouldSetNullOriginHeader(net::HttpBaseChannel* aChannel, + nsIURI* aOriginURI) { + MOZ_ASSERT(aChannel); + MOZ_ASSERT(aOriginURI); + + // If request’s mode is not "cors", then switch on request’s referrer policy: + RequestMode requestMode = RequestMode::No_cors; + MOZ_ALWAYS_SUCCEEDS(aChannel->GetRequestMode(&requestMode)); + if (requestMode == RequestMode::Cors) { + return false; + } + + nsCOMPtr referrerInfo; + NS_ENSURE_SUCCESS(aChannel->GetReferrerInfo(getter_AddRefs(referrerInfo)), + false); + if (!referrerInfo) { + return false; + } + + // "no-referrer": + enum ReferrerPolicy policy = referrerInfo->ReferrerPolicy(); + if (policy == ReferrerPolicy::No_referrer) { + // Set serializedOrigin to `null`. + // Note: Returning true is the same as setting the serializedOrigin to null + // in this method. + return true; + } + + // "no-referrer-when-downgrade": + // "strict-origin": + // "strict-origin-when-cross-origin": + // If request’s origin is a tuple origin, its scheme is "https", and + // request’s current URL’s scheme is not "https", then set serializedOrigin + // to `null`. + bool allowed = false; + nsCOMPtr uri; + NS_ENSURE_SUCCESS(aChannel->GetURI(getter_AddRefs(uri)), false); + if (NS_SUCCEEDED(ReferrerInfo::HandleSecureToInsecureReferral( + aOriginURI, uri, policy, allowed)) && + !allowed) { + return true; + } + + // "same-origin": + if (policy == ReferrerPolicy::Same_origin) { + // If request’s origin is not same origin with request’s current URL’s + // origin, then set serializedOrigin to `null`. + return ReferrerInfo::IsCrossOriginRequest(aChannel); + } + + // Otherwise: + // Do Nothing. + return false; +} + +nsresult ReferrerInfo::HandleUserReferrerSendingPolicy(nsIHttpChannel* aChannel, + bool& aAllowed) const { + aAllowed = false; + uint32_t referrerSendingPolicy; + uint32_t loadFlags; + nsresult rv = aChannel->GetLoadFlags(&loadFlags); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (loadFlags & nsIHttpChannel::LOAD_INITIAL_DOCUMENT_URI) { + referrerSendingPolicy = ReferrerSendingPolicy::ePolicySendWhenUserTrigger; + } else { + referrerSendingPolicy = ReferrerSendingPolicy::ePolicySendInlineContent; + } + if (GetUserReferrerSendingPolicy() < referrerSendingPolicy) { + return NS_OK; + } + + aAllowed = true; + return NS_OK; +} + +/* static */ +bool ReferrerInfo::IsCrossOriginRequest(nsIHttpChannel* aChannel) { + nsCOMPtr loadInfo = aChannel->LoadInfo(); + + if (!loadInfo->TriggeringPrincipal()->GetIsContentPrincipal()) { + LOG(("no triggering URI via loadInfo, assuming load is cross-origin")); + return true; + } + + if (LOG_ENABLED()) { + nsAutoCString triggeringURISpec; + loadInfo->TriggeringPrincipal()->GetAsciiSpec(triggeringURISpec); + LOG(("triggeringURI=%s\n", triggeringURISpec.get())); + } + + nsCOMPtr uri; + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + return !loadInfo->TriggeringPrincipal()->IsSameOrigin(uri); +} + +/* static */ +bool ReferrerInfo::IsCrossSiteRequest(nsIHttpChannel* aChannel) { + nsCOMPtr loadInfo = aChannel->LoadInfo(); + + if (!loadInfo->TriggeringPrincipal()->GetIsContentPrincipal()) { + LOG(("no triggering URI via loadInfo, assuming load is cross-site")); + return true; + } + + if (LOG_ENABLED()) { + nsAutoCString triggeringURISpec; + loadInfo->TriggeringPrincipal()->GetAsciiSpec(triggeringURISpec); + LOG(("triggeringURI=%s\n", triggeringURISpec.get())); + } + + nsCOMPtr uri; + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + bool isCrossSite = true; + rv = loadInfo->TriggeringPrincipal()->IsThirdPartyURI(uri, &isCrossSite); + if (NS_FAILED(rv)) { + return true; + } + + return isCrossSite; +} + +ReferrerInfo::TrimmingPolicy ReferrerInfo::ComputeTrimmingPolicy( + nsIHttpChannel* aChannel) const { + uint32_t trimmingPolicy = GetUserTrimmingPolicy(); + + switch (mPolicy) { + case ReferrerPolicy::Origin: + case ReferrerPolicy::Strict_origin: + trimmingPolicy = TrimmingPolicy::ePolicySchemeHostPort; + break; + + case ReferrerPolicy::Origin_when_cross_origin: + case ReferrerPolicy::Strict_origin_when_cross_origin: + if (trimmingPolicy != TrimmingPolicy::ePolicySchemeHostPort && + IsCrossOriginRequest(aChannel)) { + // Ignore set trimmingPolicy if it is already the strictest + // policy. + trimmingPolicy = TrimmingPolicy::ePolicySchemeHostPort; + } + break; + + // This function is called when a nonempty referrer value is allowed to + // send. For the next 3 policies: same-origin, no-referrer-when-downgrade, + // unsafe-url, without trimming we should have a full uri. And the trimming + // policy only depends on user prefs. + case ReferrerPolicy::Same_origin: + case ReferrerPolicy::No_referrer_when_downgrade: + case ReferrerPolicy::Unsafe_url: + if (trimmingPolicy != TrimmingPolicy::ePolicySchemeHostPort) { + // Ignore set trimmingPolicy if it is already the strictest + // policy. Apply the user cross-origin trimming policy if it's more + // restrictive than the general one. + if (GetUserXOriginTrimmingPolicy() != TrimmingPolicy::ePolicyFullURI && + IsCrossOriginRequest(aChannel)) { + trimmingPolicy = + std::max(trimmingPolicy, GetUserXOriginTrimmingPolicy()); + } + } + break; + + case ReferrerPolicy::No_referrer: + case ReferrerPolicy::_empty: + default: + MOZ_ASSERT_UNREACHABLE("Unexpected value"); + break; + } + + return static_cast(trimmingPolicy); +} + +nsresult ReferrerInfo::LimitReferrerLength( + nsIHttpChannel* aChannel, nsIURI* aReferrer, TrimmingPolicy aTrimmingPolicy, + nsACString& aInAndOutTrimmedReferrer) const { + if (!StaticPrefs::network_http_referer_referrerLengthLimit()) { + return NS_OK; + } + + if (aInAndOutTrimmedReferrer.Length() <= + StaticPrefs::network_http_referer_referrerLengthLimit()) { + return NS_OK; + } + + nsAutoString referrerLengthLimit; + referrerLengthLimit.AppendInt( + StaticPrefs::network_http_referer_referrerLengthLimit()); + if (aTrimmingPolicy == ePolicyFullURI || + aTrimmingPolicy == ePolicySchemeHostPortPath) { + // If referrer header is over max Length, down to origin + nsresult rv = GetOriginFromReferrerURI(aReferrer, aInAndOutTrimmedReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Step 6 within https://w3c.github.io/webappsec-referrer-policy/#strip-url + // states that the trailing "/" does not need to get stripped. However, + // GetOriginFromReferrerURI() also removes any trailing "/" hence we have to + // add it back here. + aInAndOutTrimmedReferrer.AppendLiteral("/"); + if (aInAndOutTrimmedReferrer.Length() <= + StaticPrefs::network_http_referer_referrerLengthLimit()) { + AutoTArray params = { + referrerLengthLimit, NS_ConvertUTF8toUTF16(aInAndOutTrimmedReferrer)}; + LogMessageToConsole(aChannel, "ReferrerLengthOverLimitation", params); + return NS_OK; + } + } + + // If we end up here either the trimmingPolicy is equal to + // 'ePolicySchemeHostPort' or the 'origin' of any other policy is still over + // the length limit. If so, truncate the referrer entirely. + AutoTArray params = { + referrerLengthLimit, NS_ConvertUTF8toUTF16(aInAndOutTrimmedReferrer)}; + LogMessageToConsole(aChannel, "ReferrerOriginLengthOverLimitation", params); + aInAndOutTrimmedReferrer.Truncate(); + + return NS_OK; +} + +nsresult ReferrerInfo::GetOriginFromReferrerURI(nsIURI* aReferrer, + nsACString& aResult) const { + MOZ_ASSERT(aReferrer); + aResult.Truncate(); + // We want the IDN-normalized PrePath. That's not something currently + // available and there doesn't yet seem to be justification for adding it to + // the interfaces, so just build it up from scheme+AsciiHostPort + nsAutoCString scheme, asciiHostPort; + nsresult rv = aReferrer->GetScheme(scheme); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + aResult = scheme; + aResult.AppendLiteral("://"); + // Note we explicitly cleared UserPass above, so do not need to build it. + rv = aReferrer->GetAsciiHostPort(asciiHostPort); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + aResult.Append(asciiHostPort); + return NS_OK; +} + +nsresult ReferrerInfo::TrimReferrerWithPolicy(nsIURI* aReferrer, + TrimmingPolicy aTrimmingPolicy, + nsACString& aResult) const { + MOZ_ASSERT(aReferrer); + + if (aTrimmingPolicy == TrimmingPolicy::ePolicyFullURI) { + return aReferrer->GetAsciiSpec(aResult); + } + + nsresult rv = GetOriginFromReferrerURI(aReferrer, aResult); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (aTrimmingPolicy == TrimmingPolicy::ePolicySchemeHostPortPath) { + nsCOMPtr url(do_QueryInterface(aReferrer)); + if (url) { + nsAutoCString path; + rv = url->GetFilePath(path); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + aResult.Append(path); + return NS_OK; + } + } + + // Step 6 within https://w3c.github.io/webappsec-referrer-policy/#strip-url + // states that the trailing "/" does not need to get stripped. However, + // GetOriginFromReferrerURI() also removes any trailing "/" hence we have to + // add it back here. + aResult.AppendLiteral("/"); + return NS_OK; +} + +bool ReferrerInfo::ShouldIgnoreLessRestrictedPolicies( + nsIHttpChannel* aChannel, const ReferrerPolicyEnum aPolicy) const { + MOZ_ASSERT(aChannel); + + // We only care about the less restricted policies. + if (aPolicy != ReferrerPolicy::Unsafe_url && + aPolicy != ReferrerPolicy::No_referrer_when_downgrade && + aPolicy != ReferrerPolicy::Origin_when_cross_origin) { + return false; + } + + nsCOMPtr loadInfo = aChannel->LoadInfo(); + bool isPrivate = NS_UsePrivateBrowsing(aChannel); + + // Return early if we don't want to ignore less restricted policies for the + // top navigation. + if (loadInfo->GetExternalContentPolicyType() == + ExtContentPolicy::TYPE_DOCUMENT) { + bool isEnabledForTopNavigation = + isPrivate + ? StaticPrefs:: + network_http_referer_disallowCrossSiteRelaxingDefault_pbmode_top_navigation() + : StaticPrefs:: + network_http_referer_disallowCrossSiteRelaxingDefault_top_navigation(); + if (!isEnabledForTopNavigation) { + return false; + } + + // We have to get the value of the contentBlockingAllowList earlier because + // the channel hasn't been opened yet here. Note that we only need to do + // this for first-party navigation. For third-party loads, the value is + // inherited from the parent. + if (XRE_IsParentProcess()) { + nsCOMPtr cookieJarSettings; + Unused << loadInfo->GetCookieJarSettings( + getter_AddRefs(cookieJarSettings)); + + net::CookieJarSettings::Cast(cookieJarSettings) + ->UpdateIsOnContentBlockingAllowList(aChannel); + } + } + + // We don't ignore less restricted referrer policies if ETP is toggled off. + // This would affect iframe loads and top navigation. For iframes, it will + // stop ignoring if the first-party site toggled ETP off. For top navigation, + // it depends on the ETP toggle for the destination site. + if (ContentBlockingAllowList::Check(aChannel)) { + return false; + } + + bool isCrossSite = IsCrossSiteRequest(aChannel); + bool isEnabled = + isPrivate + ? StaticPrefs:: + network_http_referer_disallowCrossSiteRelaxingDefault_pbmode() + : StaticPrefs:: + network_http_referer_disallowCrossSiteRelaxingDefault(); + + if (!isEnabled) { + // Log the warning message to console to inform that we will ignore + // less restricted policies for cross-site requests in the future. + if (isCrossSite) { + nsCOMPtr uri; + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + NS_ENSURE_SUCCESS(rv, false); + + AutoTArray params = { + NS_ConvertUTF8toUTF16(uri->GetSpecOrDefault())}; + LogMessageToConsole(aChannel, "ReferrerPolicyDisallowRelaxingWarning", + params); + } + return false; + } + + // Check if the channel is triggered by the system or the extension. + auto* triggerBasePrincipal = + BasePrincipal::Cast(loadInfo->TriggeringPrincipal()); + if (triggerBasePrincipal->IsSystemPrincipal() || + triggerBasePrincipal->AddonPolicy()) { + return false; + } + + if (isCrossSite) { + // Log the console message to say that the less restricted policy was + // ignored. + nsCOMPtr uri; + 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(uri->GetSpecOrDefault())}; + LogMessageToConsole(aChannel, "ReferrerPolicyDisallowRelaxingMessage", + params); + } + + return isCrossSite; +} + +void ReferrerInfo::LogMessageToConsole( + nsIHttpChannel* aChannel, const char* aMsg, + const nsTArray& aParams) const { + MOZ_ASSERT(aChannel); + + nsCOMPtr uri; + nsresult rv = aChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + uint64_t windowID = 0; + + rv = aChannel->GetTopLevelContentWindowId(&windowID); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + if (!windowID) { + nsCOMPtr loadGroup; + rv = aChannel->GetLoadGroup(getter_AddRefs(loadGroup)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + if (loadGroup) { + windowID = nsContentUtils::GetInnerWindowID(loadGroup); + } + } + + nsAutoString localizedMsg; + rv = nsContentUtils::FormatLocalizedString( + nsContentUtils::eSECURITY_PROPERTIES, aMsg, aParams, localizedMsg); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + rv = nsContentUtils::ReportToConsoleByWindowID( + localizedMsg, nsIScriptError::infoFlag, "Security"_ns, windowID, uri); + Unused << NS_WARN_IF(NS_FAILED(rv)); +} + +ReferrerPolicy ReferrerPolicyIDLToReferrerPolicy( + nsIReferrerInfo::ReferrerPolicyIDL aReferrerPolicy) { + switch (aReferrerPolicy) { + case nsIReferrerInfo::EMPTY: + return ReferrerPolicy::_empty; + break; + case nsIReferrerInfo::NO_REFERRER: + return ReferrerPolicy::No_referrer; + break; + case nsIReferrerInfo::NO_REFERRER_WHEN_DOWNGRADE: + return ReferrerPolicy::No_referrer_when_downgrade; + break; + case nsIReferrerInfo::ORIGIN: + return ReferrerPolicy::Origin; + break; + case nsIReferrerInfo::ORIGIN_WHEN_CROSS_ORIGIN: + return ReferrerPolicy::Origin_when_cross_origin; + break; + case nsIReferrerInfo::UNSAFE_URL: + return ReferrerPolicy::Unsafe_url; + break; + case nsIReferrerInfo::SAME_ORIGIN: + return ReferrerPolicy::Same_origin; + break; + case nsIReferrerInfo::STRICT_ORIGIN: + return ReferrerPolicy::Strict_origin; + break; + case nsIReferrerInfo::STRICT_ORIGIN_WHEN_CROSS_ORIGIN: + return ReferrerPolicy::Strict_origin_when_cross_origin; + break; + default: + MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value"); + break; + } + + return ReferrerPolicy::_empty; +} + +nsIReferrerInfo::ReferrerPolicyIDL ReferrerPolicyToReferrerPolicyIDL( + ReferrerPolicy aReferrerPolicy) { + switch (aReferrerPolicy) { + case ReferrerPolicy::_empty: + return nsIReferrerInfo::EMPTY; + break; + case ReferrerPolicy::No_referrer: + return nsIReferrerInfo::NO_REFERRER; + break; + case ReferrerPolicy::No_referrer_when_downgrade: + return nsIReferrerInfo::NO_REFERRER_WHEN_DOWNGRADE; + break; + case ReferrerPolicy::Origin: + return nsIReferrerInfo::ORIGIN; + break; + case ReferrerPolicy::Origin_when_cross_origin: + return nsIReferrerInfo::ORIGIN_WHEN_CROSS_ORIGIN; + break; + case ReferrerPolicy::Unsafe_url: + return nsIReferrerInfo::UNSAFE_URL; + break; + case ReferrerPolicy::Same_origin: + return nsIReferrerInfo::SAME_ORIGIN; + break; + case ReferrerPolicy::Strict_origin: + return nsIReferrerInfo::STRICT_ORIGIN; + break; + case ReferrerPolicy::Strict_origin_when_cross_origin: + return nsIReferrerInfo::STRICT_ORIGIN_WHEN_CROSS_ORIGIN; + break; + default: + MOZ_ASSERT_UNREACHABLE("Invalid ReferrerPolicy value"); + break; + } + + return nsIReferrerInfo::EMPTY; +} + +ReferrerInfo::ReferrerInfo() + : mOriginalReferrer(nullptr), + mPolicy(ReferrerPolicy::_empty), + mOriginalPolicy(ReferrerPolicy::_empty), + mSendReferrer(true), + mInitialized(false), + mOverridePolicyByDefault(false) {} + +ReferrerInfo::ReferrerInfo(const Document& aDoc) : ReferrerInfo() { + InitWithDocument(&aDoc); +} + +ReferrerInfo::ReferrerInfo(const Element& aElement) : ReferrerInfo() { + InitWithElement(&aElement); +} + +ReferrerInfo::ReferrerInfo(nsIURI* aOriginalReferrer, + ReferrerPolicyEnum aPolicy, bool aSendReferrer, + const Maybe& aComputedReferrer) + : mOriginalReferrer(aOriginalReferrer), + mPolicy(aPolicy), + mOriginalPolicy(aPolicy), + mSendReferrer(aSendReferrer), + mInitialized(true), + mOverridePolicyByDefault(false), + mComputedReferrer(aComputedReferrer) {} + +ReferrerInfo::ReferrerInfo(const ReferrerInfo& rhs) + : mOriginalReferrer(rhs.mOriginalReferrer), + mPolicy(rhs.mPolicy), + mOriginalPolicy(rhs.mOriginalPolicy), + mSendReferrer(rhs.mSendReferrer), + mInitialized(rhs.mInitialized), + mOverridePolicyByDefault(rhs.mOverridePolicyByDefault), + mComputedReferrer(rhs.mComputedReferrer) {} + +already_AddRefed ReferrerInfo::Clone() const { + RefPtr copy(new ReferrerInfo(*this)); + return copy.forget(); +} + +already_AddRefed ReferrerInfo::CloneWithNewPolicy( + ReferrerPolicyEnum aPolicy) const { + RefPtr copy(new ReferrerInfo(*this)); + copy->mPolicy = aPolicy; + copy->mOriginalPolicy = aPolicy; + return copy.forget(); +} + +already_AddRefed ReferrerInfo::CloneWithNewSendReferrer( + bool aSendReferrer) const { + RefPtr copy(new ReferrerInfo(*this)); + copy->mSendReferrer = aSendReferrer; + return copy.forget(); +} + +already_AddRefed ReferrerInfo::CloneWithNewOriginalReferrer( + nsIURI* aOriginalReferrer) const { + RefPtr copy(new ReferrerInfo(*this)); + copy->mOriginalReferrer = aOriginalReferrer; + return copy.forget(); +} + +NS_IMETHODIMP +ReferrerInfo::GetOriginalReferrer(nsIURI** aOriginalReferrer) { + *aOriginalReferrer = mOriginalReferrer; + NS_IF_ADDREF(*aOriginalReferrer); + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::GetReferrerPolicy( + JSContext* aCx, nsIReferrerInfo::ReferrerPolicyIDL* aReferrerPolicy) { + *aReferrerPolicy = ReferrerPolicyToReferrerPolicyIDL(mPolicy); + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::GetReferrerPolicyString(nsACString& aResult) { + aResult.AssignASCII(ReferrerPolicyToString(mPolicy)); + return NS_OK; +} + +ReferrerPolicy ReferrerInfo::ReferrerPolicy() { return mPolicy; } + +NS_IMETHODIMP +ReferrerInfo::GetSendReferrer(bool* aSendReferrer) { + *aSendReferrer = mSendReferrer; + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::Equals(nsIReferrerInfo* aOther, bool* aResult) { + NS_ENSURE_TRUE(aOther, NS_ERROR_INVALID_ARG); + MOZ_ASSERT(mInitialized); + if (aOther == this) { + *aResult = true; + return NS_OK; + } + + *aResult = false; + ReferrerInfo* other = static_cast(aOther); + MOZ_ASSERT(other->mInitialized); + + if (mPolicy != other->mPolicy || mSendReferrer != other->mSendReferrer || + mOverridePolicyByDefault != other->mOverridePolicyByDefault || + mComputedReferrer != other->mComputedReferrer) { + return NS_OK; + } + + if (!mOriginalReferrer != !other->mOriginalReferrer) { + // One or the other has mOriginalReferrer, but not both... not equal + return NS_OK; + } + + bool originalReferrerEquals; + if (mOriginalReferrer && + (NS_FAILED(mOriginalReferrer->Equals(other->mOriginalReferrer, + &originalReferrerEquals)) || + !originalReferrerEquals)) { + return NS_OK; + } + + *aResult = true; + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::GetComputedReferrerSpec(nsAString& aComputedReferrerSpec) { + aComputedReferrerSpec.Assign( + mComputedReferrer.isSome() + ? NS_ConvertUTF8toUTF16(mComputedReferrer.value()) + : EmptyString()); + return NS_OK; +} + +already_AddRefed ReferrerInfo::GetComputedReferrer() { + if (!mComputedReferrer.isSome() || mComputedReferrer.value().IsEmpty()) { + return nullptr; + } + + nsCOMPtr result; + nsresult rv = NS_NewURI(getter_AddRefs(result), mComputedReferrer.value()); + if (NS_FAILED(rv)) { + return nullptr; + } + + return result.forget(); +} + +HashNumber ReferrerInfo::Hash() const { + MOZ_ASSERT(mInitialized); + nsAutoCString originalReferrerSpec; + if (mOriginalReferrer) { + Unused << mOriginalReferrer->GetSpec(originalReferrerSpec); + } + + return mozilla::AddToHash( + static_cast(mPolicy), mSendReferrer, mOverridePolicyByDefault, + mozilla::HashString(originalReferrerSpec), + mozilla::HashString(mComputedReferrer.isSome() ? mComputedReferrer.value() + : ""_ns)); +} + +NS_IMETHODIMP +ReferrerInfo::Init(nsIReferrerInfo::ReferrerPolicyIDL aReferrerPolicy, + bool aSendReferrer, nsIURI* aOriginalReferrer) { + MOZ_ASSERT(!mInitialized); + if (mInitialized) { + return NS_ERROR_ALREADY_INITIALIZED; + }; + + mPolicy = ReferrerPolicyIDLToReferrerPolicy(aReferrerPolicy); + mOriginalPolicy = mPolicy; + mSendReferrer = aSendReferrer; + mOriginalReferrer = aOriginalReferrer; + mInitialized = true; + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::InitWithDocument(const Document* aDocument) { + MOZ_ASSERT(!mInitialized); + if (mInitialized) { + return NS_ERROR_ALREADY_INITIALIZED; + }; + + mPolicy = aDocument->GetReferrerPolicy(); + mOriginalPolicy = mPolicy; + mSendReferrer = true; + mOriginalReferrer = aDocument->GetDocumentURIAsReferrer(); + mInitialized = true; + return NS_OK; +} + +/** + * Check whether the given node has referrerpolicy attribute and parse + * referrer policy from the attribute. + * Currently, referrerpolicy attribute is supported in a, area, img, iframe, + * script, or link element. + */ +static ReferrerPolicy ReferrerPolicyFromAttribute(const Element& aElement) { + if (!aElement.IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area, + nsGkAtoms::script, nsGkAtoms::iframe, + nsGkAtoms::link, nsGkAtoms::img)) { + return ReferrerPolicy::_empty; + } + return aElement.GetReferrerPolicyAsEnum(); +} + +static bool HasRelNoReferrer(const Element& aElement) { + // rel=noreferrer is only supported in , , and
+ if (!aElement.IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area, + nsGkAtoms::form) && + !aElement.IsSVGElement(nsGkAtoms::a)) { + return false; + } + + nsAutoString rel; + aElement.GetAttr(nsGkAtoms::rel, rel); + nsWhitespaceTokenizerTemplate tok(rel); + + while (tok.hasMoreTokens()) { + const nsAString& token = tok.nextToken(); + if (token.LowerCaseEqualsLiteral("noreferrer")) { + return true; + } + } + + return false; +} + +NS_IMETHODIMP +ReferrerInfo::InitWithElement(const Element* aElement) { + MOZ_ASSERT(!mInitialized); + if (mInitialized) { + return NS_ERROR_ALREADY_INITIALIZED; + }; + + // Referrer policy from referrerpolicy attribute will have a higher priority + // than referrer policy from tag and Referrer-Policy header. + mPolicy = ReferrerPolicyFromAttribute(*aElement); + if (mPolicy == ReferrerPolicy::_empty) { + // Fallback to use document's referrer poicy if we don't have referrer + // policy from attribute. + mPolicy = aElement->OwnerDoc()->GetReferrerPolicy(); + } + + mOriginalPolicy = mPolicy; + mSendReferrer = !HasRelNoReferrer(*aElement); + mOriginalReferrer = aElement->OwnerDoc()->GetDocumentURIAsReferrer(); + + mInitialized = true; + return NS_OK; +} + +/* static */ +already_AddRefed +ReferrerInfo::CreateFromOtherAndPolicyOverride( + nsIReferrerInfo* aOther, ReferrerPolicyEnum aPolicyOverride) { + MOZ_ASSERT(aOther); + ReferrerPolicyEnum policy = aPolicyOverride != ReferrerPolicy::_empty + ? aPolicyOverride + : aOther->ReferrerPolicy(); + + nsCOMPtr referrer = aOther->GetComputedReferrer(); + nsCOMPtr referrerInfo = + new ReferrerInfo(referrer, policy, aOther->GetSendReferrer()); + return referrerInfo.forget(); +} + +/* static */ +already_AddRefed +ReferrerInfo::CreateFromDocumentAndPolicyOverride( + Document* aDoc, ReferrerPolicyEnum aPolicyOverride) { + MOZ_ASSERT(aDoc); + ReferrerPolicyEnum policy = aPolicyOverride != ReferrerPolicy::_empty + ? aPolicyOverride + : aDoc->GetReferrerPolicy(); + nsCOMPtr referrerInfo = + new ReferrerInfo(aDoc->GetDocumentURIAsReferrer(), policy); + return referrerInfo.forget(); +} + +/* static */ +already_AddRefed ReferrerInfo::CreateForFetch( + nsIPrincipal* aPrincipal, Document* aDoc) { + MOZ_ASSERT(aPrincipal); + + nsCOMPtr referrerInfo; + if (!aPrincipal || aPrincipal->IsSystemPrincipal()) { + referrerInfo = new ReferrerInfo(nullptr); + return referrerInfo.forget(); + } + + if (!aDoc) { + aPrincipal->CreateReferrerInfo(ReferrerPolicy::_empty, + getter_AddRefs(referrerInfo)); + return referrerInfo.forget(); + } + + // If it weren't for history.push/replaceState, we could just use the + // principal's URI here. But since we want changes to the URI effected + // by push/replaceState to be reflected in the XHR referrer, we have to + // be more clever. + // + // If the document's original URI (before any push/replaceStates) matches + // our principal, then we use the document's current URI (after + // push/replaceStates). Otherwise (if the document is, say, a data: + // URI), we just use the principal's URI. + nsCOMPtr docCurURI = aDoc->GetDocumentURI(); + nsCOMPtr docOrigURI = aDoc->GetOriginalURI(); + + if (docCurURI && docOrigURI) { + bool equal = false; + aPrincipal->EqualsURI(docOrigURI, &equal); + if (equal) { + referrerInfo = new ReferrerInfo(docCurURI, aDoc->GetReferrerPolicy()); + return referrerInfo.forget(); + } + } + aPrincipal->CreateReferrerInfo(aDoc->GetReferrerPolicy(), + getter_AddRefs(referrerInfo)); + return referrerInfo.forget(); +} + +/* static */ +already_AddRefed ReferrerInfo::CreateForExternalCSSResources( + mozilla::StyleSheet* aExternalSheet, ReferrerPolicyEnum aPolicy) { + MOZ_ASSERT(aExternalSheet && !aExternalSheet->IsInline()); + nsCOMPtr referrerInfo; + + // Step 2 + // https://w3c.github.io/webappsec-referrer-policy/#integration-with-css + // Use empty policy at the beginning and update it later from Referrer-Policy + // header. + referrerInfo = new ReferrerInfo(aExternalSheet->GetSheetURI(), aPolicy); + return referrerInfo.forget(); +} + +/* static */ +already_AddRefed +ReferrerInfo::CreateForInternalCSSAndSVGResources(Document* aDocument) { + MOZ_ASSERT(aDocument); + return do_AddRef(new ReferrerInfo(aDocument->GetDocumentURI(), + aDocument->GetReferrerPolicy())); +} + +nsresult ReferrerInfo::ComputeReferrer(nsIHttpChannel* aChannel) { + NS_ENSURE_ARG(aChannel); + MOZ_ASSERT(NS_IsMainThread()); + + // If the referrerInfo is passed around when redirect, just use the last + // computedReferrer to recompute + nsCOMPtr referrer; + nsresult rv = NS_OK; + mOverridePolicyByDefault = false; + + if (mComputedReferrer.isSome()) { + if (mComputedReferrer.value().IsEmpty()) { + return NS_OK; + } + + rv = NS_NewURI(getter_AddRefs(referrer), mComputedReferrer.value()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + mComputedReferrer.reset(); + // Emplace mComputedReferrer with an empty string, which means we have + // computed the referrer and the result referrer value is empty (not send + // referrer). So any early return later than this line will use that empty + // referrer. + mComputedReferrer.emplace(""_ns); + + if (!mSendReferrer || !mOriginalReferrer || + mPolicy == ReferrerPolicy::No_referrer) { + return NS_OK; + } + + if (mPolicy == ReferrerPolicy::_empty || + ShouldIgnoreLessRestrictedPolicies(aChannel, mOriginalPolicy)) { + nsCOMPtr loadInfo = aChannel->LoadInfo(); + OriginAttributes attrs = loadInfo->GetOriginAttributes(); + bool isPrivate = attrs.mPrivateBrowsingId > 0; + + nsCOMPtr uri; + rv = aChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mPolicy = GetDefaultReferrerPolicy(aChannel, uri, isPrivate); + mOverridePolicyByDefault = true; + } + + // This is for the case where the ETP toggle is off. In this case, we need to + // reset the referrer and the policy if the original policy is different from + // the current policy in order to recompute the referrer policy with the + // original policy. + if (!mOverridePolicyByDefault && mOriginalPolicy != ReferrerPolicy::_empty && + mPolicy != mOriginalPolicy) { + referrer = nullptr; + mPolicy = mOriginalPolicy; + } + + if (mPolicy == ReferrerPolicy::No_referrer) { + return NS_OK; + } + + bool isUserReferrerSendingAllowed = false; + rv = HandleUserReferrerSendingPolicy(aChannel, isUserReferrerSendingAllowed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!isUserReferrerSendingAllowed) { + return NS_OK; + } + + // Enforce Referrer allowlist, only http, https scheme are allowed + if (!IsReferrerSchemeAllowed(mOriginalReferrer)) { + return NS_OK; + } + + nsCOMPtr uri; + rv = aChannel->GetURI(getter_AddRefs(uri)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isSecureToInsecureAllowed = false; + rv = HandleSecureToInsecureReferral(mOriginalReferrer, uri, mPolicy, + isSecureToInsecureAllowed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!isSecureToInsecureAllowed) { + return NS_OK; + } + + // Don't send referrer when the request is cross-origin and policy is + // "same-origin". + if (mPolicy == ReferrerPolicy::Same_origin && + IsCrossOriginRequest(aChannel)) { + return NS_OK; + } + + // Strip away any fragment per RFC 2616 section 14.36 + // and Referrer Policy section 6.3.5. + if (!referrer) { + rv = NS_GetURIWithoutRef(mOriginalReferrer, getter_AddRefs(referrer)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + bool isUserXOriginAllowed = false; + rv = HandleUserXOriginSendingPolicy(uri, referrer, isUserXOriginAllowed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!isUserXOriginAllowed) { + return NS_OK; + } + + // Handle user pref network.http.referer.spoofSource, send spoofed referrer if + // desired + if (StaticPrefs::network_http_referer_spoofSource()) { + nsCOMPtr userSpoofReferrer; + rv = NS_GetURIWithoutRef(uri, getter_AddRefs(userSpoofReferrer)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + referrer = userSpoofReferrer; + } + + // strip away any userpass; we don't want to be giving out passwords ;-) + // This is required by Referrer Policy stripping algorithm. + nsCOMPtr exposableURI = nsIOService::CreateExposableURI(referrer); + referrer = exposableURI; + + TrimmingPolicy trimmingPolicy = ComputeTrimmingPolicy(aChannel); + + nsAutoCString trimmedReferrer; + // We first trim the referrer according to the policy by calling + // 'TrimReferrerWithPolicy' and right after we have to call + // 'LimitReferrerLength' (using the same arguments) because the trimmed + // referrer might exceed the allowed max referrer length. + rv = TrimReferrerWithPolicy(referrer, trimmingPolicy, trimmedReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = LimitReferrerLength(aChannel, referrer, trimmingPolicy, trimmedReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // finally, remember the referrer spec. + mComputedReferrer.reset(); + mComputedReferrer.emplace(trimmedReferrer); + + return NS_OK; +} + +/* ===== nsISerializable implementation ====== */ + +nsresult ReferrerInfo::ReadTailDataBeforeGecko100( + const uint32_t& aData, nsIObjectInputStream* aInputStream) { + MOZ_ASSERT(aInputStream); + + nsCOMPtr reader; + nsCOMPtr writer; + + // We need to create a new pipe in order to read the aData and the rest of + // the input stream together in the old format. This would also help us with + // handling big endian correctly. + NS_NewPipe(getter_AddRefs(reader), getter_AddRefs(writer)); + + nsCOMPtr binaryPipeWriter = + NS_NewObjectOutputStream(writer); + + // Write back the aData so that we can read bytes from it and handle big + // endian correctly. + nsresult rv = binaryPipeWriter->Write32(aData); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr binaryPipeReader = + NS_NewObjectInputStream(reader); + + rv = binaryPipeReader->ReadBoolean(&mSendReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isComputed; + rv = binaryPipeReader->ReadBoolean(&isComputed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // We need to handle the following string if isComputed is true. + if (isComputed) { + // Comsume the following 2 bytes from the input stream. They are the half + // part of the length prefix of the following string. + uint16_t data; + rv = aInputStream->Read16(&data); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Write the bytes to the pipe so that we can read the length of the string. + rv = binaryPipeWriter->Write16(data); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + uint32_t length; + rv = binaryPipeReader->Read32(&length); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Consume the string body from the input stream. + nsAutoCString computedReferrer; + rv = NS_ConsumeStream(aInputStream, length, computedReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mComputedReferrer.emplace(computedReferrer); + + // Read the remaining two bytes and write to the pipe. + uint16_t remain; + rv = aInputStream->Read16(&remain); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = binaryPipeWriter->Write16(remain); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + rv = binaryPipeReader->ReadBoolean(&mInitialized); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = binaryPipeReader->ReadBoolean(&mOverridePolicyByDefault); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::Read(nsIObjectInputStream* aStream) { + bool nonNull; + nsresult rv = aStream->ReadBoolean(&nonNull); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (nonNull) { + nsAutoCString spec; + nsresult rv = aStream->ReadCString(spec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = NS_NewURI(getter_AddRefs(mOriginalReferrer), spec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } else { + mOriginalReferrer = nullptr; + } + + // ReferrerPolicy.webidl has different order with ReferrerPolicyIDL. We store + // to disk using the order of ReferrerPolicyIDL, so we convert to + // ReferrerPolicyIDL to make it be compatible to the old format. + uint32_t policy; + rv = aStream->Read32(&policy); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mPolicy = ReferrerPolicyIDLToReferrerPolicy( + static_cast(policy)); + + uint32_t originalPolicy; + rv = aStream->Read32(&originalPolicy); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // See https://bugzilla.mozilla.org/show_bug.cgi?id=1784045#c6 for more + // details. + // + // We need to differentiate the old format and the new format here in order + // to be able to read both formats. The check here helps us with verifying + // which format it is. + if (MOZ_UNLIKELY(originalPolicy > 0xFF)) { + mOriginalPolicy = mPolicy; + + return ReadTailDataBeforeGecko100(originalPolicy, aStream); + } + + mOriginalPolicy = ReferrerPolicyIDLToReferrerPolicy( + static_cast(originalPolicy)); + + rv = aStream->ReadBoolean(&mSendReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isComputed; + rv = aStream->ReadBoolean(&isComputed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (isComputed) { + nsAutoCString computedReferrer; + rv = aStream->ReadCString(computedReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + mComputedReferrer.emplace(computedReferrer); + } + + rv = aStream->ReadBoolean(&mInitialized); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->ReadBoolean(&mOverridePolicyByDefault); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +NS_IMETHODIMP +ReferrerInfo::Write(nsIObjectOutputStream* aStream) { + bool nonNull = (mOriginalReferrer != nullptr); + nsresult rv = aStream->WriteBoolean(nonNull); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (nonNull) { + nsAutoCString spec; + nsresult rv = mOriginalReferrer->GetSpec(spec); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteStringZ(spec.get()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + rv = aStream->Write32(ReferrerPolicyToReferrerPolicyIDL(mPolicy)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->Write32(ReferrerPolicyToReferrerPolicyIDL(mOriginalPolicy)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteBoolean(mSendReferrer); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool isComputed = mComputedReferrer.isSome(); + rv = aStream->WriteBoolean(isComputed); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (isComputed) { + rv = aStream->WriteStringZ(mComputedReferrer.value().get()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + rv = aStream->WriteBoolean(mInitialized); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = aStream->WriteBoolean(mOverridePolicyByDefault); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return NS_OK; +} + +void ReferrerInfo::RecordTelemetry(nsIHttpChannel* aChannel) { +#ifdef DEBUG + MOZ_ASSERT(!mTelemetryRecorded); + mTelemetryRecorded = true; +#endif // DEBUG + + // The telemetry probe has 18 buckets. The first 9 buckets are for same-site + // requests and the rest 9 buckets are for cross-site requests. + uint32_t telemetryOffset = + IsCrossSiteRequest(aChannel) + ? static_cast(ReferrerPolicy::EndGuard_) + : 0; + + Telemetry::Accumulate(Telemetry::REFERRER_POLICY_COUNT, + static_cast(mPolicy) + telemetryOffset); +} + +} // namespace mozilla::dom diff --git a/dom/security/ReferrerInfo.h b/dom/security/ReferrerInfo.h new file mode 100644 index 0000000000..ec28b6d0ea --- /dev/null +++ b/dom/security/ReferrerInfo.h @@ -0,0 +1,469 @@ +/* -*- 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 mozilla_dom_ReferrerInfo_h +#define mozilla_dom_ReferrerInfo_h + +#include "nsCOMPtr.h" +#include "nsIReferrerInfo.h" +#include "nsReadableUtils.h" +#include "mozilla/Maybe.h" +#include "mozilla/HashFunctions.h" +#include "mozilla/dom/ReferrerPolicyBinding.h" + +#define REFERRERINFOF_CONTRACTID "@mozilla.org/referrer-info;1" +// 041a129f-10ce-4bda-a60d-e027a26d5ed0 +#define REFERRERINFO_CID \ + { \ + 0x041a129f, 0x10ce, 0x4bda, { \ + 0xa6, 0x0d, 0xe0, 0x27, 0xa2, 0x6d, 0x5e, 0xd0 \ + } \ + } + +class nsIHttpChannel; +class nsIURI; +class nsIChannel; +class nsILoadInfo; +class nsINode; +class nsIPrincipal; + +namespace mozilla { +class StyleSheet; +class URLAndReferrerInfo; + +namespace net { +class HttpBaseChannel; +class nsHttpChannel; +} // namespace net +} // namespace mozilla + +namespace mozilla::dom { + +/** + * The ReferrerInfo class holds the raw referrer and potentially a referrer + * policy which allows to query the computed referrer which should be applied to + * a channel as the actual referrer value. + * + * The ReferrerInfo class solely contains readonly fields and represents a 1:1 + * sync to the referrer header of the corresponding channel. In turn that means + * the class is immutable - so any modifications require to clone the current + * ReferrerInfo. + * + * For example if a request undergoes a redirect, the new channel + * will need a new ReferrerInfo clone with members being updated accordingly. + */ + +class ReferrerInfo : public nsIReferrerInfo { + public: + typedef enum ReferrerPolicy ReferrerPolicyEnum; + ReferrerInfo(); + + explicit ReferrerInfo( + nsIURI* aOriginalReferrer, + ReferrerPolicyEnum aPolicy = ReferrerPolicy::_empty, + bool aSendReferrer = true, + const Maybe& aComputedReferrer = Maybe()); + + // Creates already initialized ReferrerInfo from an element or a document. + explicit ReferrerInfo(const Element&); + explicit ReferrerInfo(const Document&); + + // create an exact copy of the ReferrerInfo + already_AddRefed Clone() const; + + // create an copy of the ReferrerInfo with new referrer policy + already_AddRefed CloneWithNewPolicy( + ReferrerPolicyEnum aPolicy) const; + + // create an copy of the ReferrerInfo with new send referrer + already_AddRefed CloneWithNewSendReferrer( + bool aSendReferrer) const; + + // create an copy of the ReferrerInfo with new original referrer + already_AddRefed CloneWithNewOriginalReferrer( + nsIURI* aOriginalReferrer) const; + + // Record the telemetry for the referrer policy. + void RecordTelemetry(nsIHttpChannel* aChannel); + + /* + * Helper function to create a new ReferrerInfo object from other. We will not + * pass in any computed values and override referrer policy if needed + * + * @param aOther the other referrerInfo object to init from. + * @param aPolicyOverride referrer policy to override if necessary. + */ + static already_AddRefed CreateFromOtherAndPolicyOverride( + nsIReferrerInfo* aOther, ReferrerPolicyEnum aPolicyOverride); + + /* + * Helper function to create a new ReferrerInfo object from a given document + * and override referrer policy if needed (for example, when parsing link + * header or speculative loading). + * + * @param aDocument the document to init referrerInfo object. + * @param aPolicyOverride referrer policy to override if necessary. + */ + static already_AddRefed CreateFromDocumentAndPolicyOverride( + Document* aDoc, ReferrerPolicyEnum aPolicyOverride); + + /* + * Implements step 3.1 and 3.3 of the Determine request's Referrer algorithm + * from the Referrer Policy specification. + * + * https://w3c.github.io/webappsec/specs/referrer-policy/#determine-requests-referrer + */ + static already_AddRefed CreateForFetch( + nsIPrincipal* aPrincipal, Document* aDoc); + + /** + * Helper function to create new ReferrerInfo object from a given external + * stylesheet. The returned nsIReferrerInfo object will be used for any + * requests or resources referenced by the sheet. + * + * @param aSheet the stylesheet to init referrerInfo. + * @param aPolicy referrer policy from header if there's any. + */ + static already_AddRefed CreateForExternalCSSResources( + StyleSheet* aExternalSheet, + ReferrerPolicyEnum aPolicy = ReferrerPolicy::_empty); + + /** + * Helper function to create new ReferrerInfo object from a given document. + * The returned nsIReferrerInfo object will be used for any requests or + * resources referenced by internal stylesheet (for example style="" or + * wrapped by + + diff --git a/dom/security/test/csp/file_bug885433_allows.html^headers^ b/dom/security/test/csp/file_bug885433_allows.html^headers^ new file mode 100644 index 0000000000..767b9ca926 --- /dev/null +++ b/dom/security/test/csp/file_bug885433_allows.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: img-src 'self'; diff --git a/dom/security/test/csp/file_bug885433_blocks.html b/dom/security/test/csp/file_bug885433_blocks.html new file mode 100644 index 0000000000..2279b33e46 --- /dev/null +++ b/dom/security/test/csp/file_bug885433_blocks.html @@ -0,0 +1,37 @@ + + + + +
    +
  1. Inline script blocked (this text should be black)
  2. +
  3. Eval script blocked (this text should be black)
  4. +
  5. Inline style blocked (this text should be black)
  6. +
+ + + + + + diff --git a/dom/security/test/csp/file_bug885433_blocks.html^headers^ b/dom/security/test/csp/file_bug885433_blocks.html^headers^ new file mode 100644 index 0000000000..f82598b673 --- /dev/null +++ b/dom/security/test/csp/file_bug885433_blocks.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self'; diff --git a/dom/security/test/csp/file_bug886164.html b/dom/security/test/csp/file_bug886164.html new file mode 100644 index 0000000000..ec8c9e7e92 --- /dev/null +++ b/dom/security/test/csp/file_bug886164.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug886164.html^headers^ b/dom/security/test/csp/file_bug886164.html^headers^ new file mode 100644 index 0000000000..4c6fa3c26a --- /dev/null +++ b/dom/security/test/csp/file_bug886164.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' diff --git a/dom/security/test/csp/file_bug886164_2.html b/dom/security/test/csp/file_bug886164_2.html new file mode 100644 index 0000000000..83d36c55ae --- /dev/null +++ b/dom/security/test/csp/file_bug886164_2.html @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug886164_2.html^headers^ b/dom/security/test/csp/file_bug886164_2.html^headers^ new file mode 100644 index 0000000000..4c6fa3c26a --- /dev/null +++ b/dom/security/test/csp/file_bug886164_2.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' diff --git a/dom/security/test/csp/file_bug886164_3.html b/dom/security/test/csp/file_bug886164_3.html new file mode 100644 index 0000000000..8b4313000f --- /dev/null +++ b/dom/security/test/csp/file_bug886164_3.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug886164_3.html^headers^ b/dom/security/test/csp/file_bug886164_3.html^headers^ new file mode 100644 index 0000000000..6581fd425e --- /dev/null +++ b/dom/security/test/csp/file_bug886164_3.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none' diff --git a/dom/security/test/csp/file_bug886164_4.html b/dom/security/test/csp/file_bug886164_4.html new file mode 100644 index 0000000000..41137ea017 --- /dev/null +++ b/dom/security/test/csp/file_bug886164_4.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug886164_4.html^headers^ b/dom/security/test/csp/file_bug886164_4.html^headers^ new file mode 100644 index 0000000000..6581fd425e --- /dev/null +++ b/dom/security/test/csp/file_bug886164_4.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none' diff --git a/dom/security/test/csp/file_bug886164_5.html b/dom/security/test/csp/file_bug886164_5.html new file mode 100644 index 0000000000..82c10f20c0 --- /dev/null +++ b/dom/security/test/csp/file_bug886164_5.html @@ -0,0 +1,26 @@ + + + + + + + I am sandboxed but with only inline "allow-scripts" + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug886164_5.html^headers^ b/dom/security/test/csp/file_bug886164_5.html^headers^ new file mode 100644 index 0000000000..3abc190552 --- /dev/null +++ b/dom/security/test/csp/file_bug886164_5.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none' 'unsafe-inline'; diff --git a/dom/security/test/csp/file_bug886164_6.html b/dom/security/test/csp/file_bug886164_6.html new file mode 100644 index 0000000000..f6567b470e --- /dev/null +++ b/dom/security/test/csp/file_bug886164_6.html @@ -0,0 +1,35 @@ + + + + + + + + + + I am sandboxed but with "allow-scripts" + + + + + First name: + Last name: + + + +
click me + + diff --git a/dom/security/test/csp/file_bug886164_6.html^headers^ b/dom/security/test/csp/file_bug886164_6.html^headers^ new file mode 100644 index 0000000000..6f9fc3f25d --- /dev/null +++ b/dom/security/test/csp/file_bug886164_6.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' 'unsafe-inline'; diff --git a/dom/security/test/csp/file_bug888172.html b/dom/security/test/csp/file_bug888172.html new file mode 100644 index 0000000000..27cf9b00ab --- /dev/null +++ b/dom/security/test/csp/file_bug888172.html @@ -0,0 +1,28 @@ + + + +
    +
  1. Inline script (green if allowed, black if blocked)
  2. +
  3. Eval script (green if allowed, black if blocked)
  4. +
  5. Inline style (green if allowed, black if blocked)
  6. +
+ + + + + + diff --git a/dom/security/test/csp/file_bug888172.sjs b/dom/security/test/csp/file_bug888172.sjs new file mode 100644 index 0000000000..adc0f7740c --- /dev/null +++ b/dom/security/test/csp/file_bug888172.sjs @@ -0,0 +1,47 @@ +// SJS file for CSP mochitests + +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +function loadHTMLFromFile(path) { + // Load the HTML to return in the response from file. + // Since it's relative to the cwd of the test runner, we start there and + // append to get to the actual path of the file. + var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + var dirs = path.split("/"); + for (var i = 0; i < dirs.length; i++) { + testHTMLFile.append(dirs[i]); + } + var testHTMLFileStream = Components.classes[ + "@mozilla.org/network/file-input-stream;1" + ].createInstance(Components.interfaces.nsIFileInputStream); + testHTMLFileStream.init(testHTMLFile, -1, 0, 0); + var testHTML = NetUtil.readInputStreamToString( + testHTMLFileStream, + testHTMLFileStream.available() + ); + return testHTML; +} + +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // Deliver the CSP policy encoded in the URI + if (query.csp) { + response.setHeader("Content-Security-Policy", unescape(query.csp), false); + } + + // Send HTML to test allowed/blocked behaviors + response.setHeader("Content-Type", "text/html", false); + response.write( + loadHTMLFromFile("tests/dom/security/test/csp/file_bug888172.html") + ); +} diff --git a/dom/security/test/csp/file_bug909029_none.html b/dom/security/test/csp/file_bug909029_none.html new file mode 100644 index 0000000000..0d4934a4a3 --- /dev/null +++ b/dom/security/test/csp/file_bug909029_none.html @@ -0,0 +1,20 @@ + + + + + + + +

This should be green

+

This should be black

+ + + + + diff --git a/dom/security/test/csp/file_bug909029_none.html^headers^ b/dom/security/test/csp/file_bug909029_none.html^headers^ new file mode 100644 index 0000000000..ecb3458750 --- /dev/null +++ b/dom/security/test/csp/file_bug909029_none.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src * ; style-src 'none' 'unsafe-inline'; diff --git a/dom/security/test/csp/file_bug909029_star.html b/dom/security/test/csp/file_bug909029_star.html new file mode 100644 index 0000000000..bcb907a965 --- /dev/null +++ b/dom/security/test/csp/file_bug909029_star.html @@ -0,0 +1,19 @@ + + + + + + +

This should be green

+

This should be black

+ + + + + diff --git a/dom/security/test/csp/file_bug909029_star.html^headers^ b/dom/security/test/csp/file_bug909029_star.html^headers^ new file mode 100644 index 0000000000..eccc1c0110 --- /dev/null +++ b/dom/security/test/csp/file_bug909029_star.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src *; style-src * 'unsafe-inline'; diff --git a/dom/security/test/csp/file_bug910139.sjs b/dom/security/test/csp/file_bug910139.sjs new file mode 100644 index 0000000000..56647134f8 --- /dev/null +++ b/dom/security/test/csp/file_bug910139.sjs @@ -0,0 +1,54 @@ +// Server side js file for bug 910139, see file test_bug910139.html for details. + +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +function loadResponseFromFile(path) { + var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + var dirs = path.split("/"); + for (var i = 0; i < dirs.length; i++) { + testHTMLFile.append(dirs[i]); + } + var testHTMLFileStream = Components.classes[ + "@mozilla.org/network/file-input-stream;1" + ].createInstance(Components.interfaces.nsIFileInputStream); + testHTMLFileStream.init(testHTMLFile, -1, 0, 0); + var testHTML = NetUtil.readInputStreamToString( + testHTMLFileStream, + testHTMLFileStream.available() + ); + return testHTML; +} + +var policies = [ + "default-src 'self'; script-src 'self'", // CSP for checkAllowed + "default-src 'self'; script-src *.example.com", // CSP for checkBlocked +]; + +function getPolicy() { + var index; + // setState only accepts strings as arguments + if (!getState("counter")) { + index = 0; + setState("counter", index.toString()); + } else { + index = parseInt(getState("counter")); + ++index; + setState("counter", index.toString()); + } + return policies[index]; +} + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // set the required CSP + response.setHeader("Content-Security-Policy", getPolicy(), false); + + // return the requested XML file. + response.write( + loadResponseFromFile("tests/dom/security/test/csp/file_bug910139.xml") + ); +} diff --git a/dom/security/test/csp/file_bug910139.xml b/dom/security/test/csp/file_bug910139.xml new file mode 100644 index 0000000000..29feba9418 --- /dev/null +++ b/dom/security/test/csp/file_bug910139.xml @@ -0,0 +1,28 @@ + + + + + Empire Burlesque + Bob Dylan + USA + Columbia + 10.90 + 1985 + + + Hide your heart + Bonnie Tyler + UK + CBS Records + 9.90 + 1988 + + + Greatest Hits + Dolly Parton + USA + RCA + 9.90 + 1982 + + diff --git a/dom/security/test/csp/file_bug910139.xsl b/dom/security/test/csp/file_bug910139.xsl new file mode 100644 index 0000000000..b99abca099 --- /dev/null +++ b/dom/security/test/csp/file_bug910139.xsl @@ -0,0 +1,27 @@ + + + + + + + +

this xml file should be formatted using an xsl file(lower iframe should contain xml dump)!

+ + + + + + + + + + + + + +
TitleArtistPrice
+ + +
+
+ diff --git a/dom/security/test/csp/file_bug941404.html b/dom/security/test/csp/file_bug941404.html new file mode 100644 index 0000000000..3a2e636e0b --- /dev/null +++ b/dom/security/test/csp/file_bug941404.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_bug941404_xhr.html b/dom/security/test/csp/file_bug941404_xhr.html new file mode 100644 index 0000000000..22e176f208 --- /dev/null +++ b/dom/security/test/csp/file_bug941404_xhr.html @@ -0,0 +1,5 @@ + + + + + diff --git a/dom/security/test/csp/file_bug941404_xhr.html^headers^ b/dom/security/test/csp/file_bug941404_xhr.html^headers^ new file mode 100644 index 0000000000..1e5f70cc37 --- /dev/null +++ b/dom/security/test/csp/file_bug941404_xhr.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none' 'unsafe-inline' 'unsafe-eval' diff --git a/dom/security/test/csp/file_child-src_iframe.html b/dom/security/test/csp/file_child-src_iframe.html new file mode 100644 index 0000000000..18749011b9 --- /dev/null +++ b/dom/security/test/csp/file_child-src_iframe.html @@ -0,0 +1,61 @@ + + + + Bug 1045891 + + + + + + diff --git a/dom/security/test/csp/file_child-src_inner_frame.html b/dom/security/test/csp/file_child-src_inner_frame.html new file mode 100644 index 0000000000..f0c4e66fa0 --- /dev/null +++ b/dom/security/test/csp/file_child-src_inner_frame.html @@ -0,0 +1,21 @@ + + + + Bug 1045891 + + + + + + diff --git a/dom/security/test/csp/file_child-src_service_worker.html b/dom/security/test/csp/file_child-src_service_worker.html new file mode 100644 index 0000000000..b291a4a4e8 --- /dev/null +++ b/dom/security/test/csp/file_child-src_service_worker.html @@ -0,0 +1,30 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_service_worker.js b/dom/security/test/csp/file_child-src_service_worker.js new file mode 100644 index 0000000000..b8445fb175 --- /dev/null +++ b/dom/security/test/csp/file_child-src_service_worker.js @@ -0,0 +1,3 @@ +this.addEventListener("install", function (event) { + close(); +}); diff --git a/dom/security/test/csp/file_child-src_shared_worker-redirect.html b/dom/security/test/csp/file_child-src_shared_worker-redirect.html new file mode 100644 index 0000000000..313915302e --- /dev/null +++ b/dom/security/test/csp/file_child-src_shared_worker-redirect.html @@ -0,0 +1,47 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_shared_worker.html b/dom/security/test/csp/file_child-src_shared_worker.html new file mode 100644 index 0000000000..ce0c0261ed --- /dev/null +++ b/dom/security/test/csp/file_child-src_shared_worker.html @@ -0,0 +1,35 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_shared_worker.js b/dom/security/test/csp/file_child-src_shared_worker.js new file mode 100644 index 0000000000..dbcdf9c9d7 --- /dev/null +++ b/dom/security/test/csp/file_child-src_shared_worker.js @@ -0,0 +1,8 @@ +onconnect = function (e) { + var port = e.ports[0]; + port.addEventListener("message", function (e) { + port.postMessage("success"); + }); + + port.start(); +}; diff --git a/dom/security/test/csp/file_child-src_shared_worker_data.html b/dom/security/test/csp/file_child-src_shared_worker_data.html new file mode 100644 index 0000000000..a4befe4ca3 --- /dev/null +++ b/dom/security/test/csp/file_child-src_shared_worker_data.html @@ -0,0 +1,37 @@ + + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_worker-redirect.html b/dom/security/test/csp/file_child-src_worker-redirect.html new file mode 100644 index 0000000000..b0029935c2 --- /dev/null +++ b/dom/security/test/csp/file_child-src_worker-redirect.html @@ -0,0 +1,47 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_worker.html b/dom/security/test/csp/file_child-src_worker.html new file mode 100644 index 0000000000..a9fdbb3282 --- /dev/null +++ b/dom/security/test/csp/file_child-src_worker.html @@ -0,0 +1,34 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_child-src_worker.js b/dom/security/test/csp/file_child-src_worker.js new file mode 100644 index 0000000000..a6bb5e8044 --- /dev/null +++ b/dom/security/test/csp/file_child-src_worker.js @@ -0,0 +1,3 @@ +onmessage = function (e) { + postMessage("worker"); +}; diff --git a/dom/security/test/csp/file_child-src_worker_data.html b/dom/security/test/csp/file_child-src_worker_data.html new file mode 100644 index 0000000000..e9e22f01da --- /dev/null +++ b/dom/security/test/csp/file_child-src_worker_data.html @@ -0,0 +1,33 @@ + + + + Bug 1045891 + + + + + diff --git a/dom/security/test/csp/file_connect-src-fetch.html b/dom/security/test/csp/file_connect-src-fetch.html new file mode 100644 index 0000000000..ff9b2f740b --- /dev/null +++ b/dom/security/test/csp/file_connect-src-fetch.html @@ -0,0 +1,16 @@ + + + + Bug 1139667 - Test mapping of fetch() to connect-src + + + + + diff --git a/dom/security/test/csp/file_connect-src.html b/dom/security/test/csp/file_connect-src.html new file mode 100644 index 0000000000..17a940a0e0 --- /dev/null +++ b/dom/security/test/csp/file_connect-src.html @@ -0,0 +1,21 @@ + + + + Bug 1031530 - Test mapping of XMLHttpRequest to connect-src + + + + + diff --git a/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html new file mode 100644 index 0000000000..6ce361a438 --- /dev/null +++ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html @@ -0,0 +1,9 @@ + + + + Helper file for Bug 1668071 - CSP frame-ancestors in about:blank + + + CSP frame-ancestors in about:blank + + diff --git a/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^ new file mode 100644 index 0000000000..e5d129c3e8 --- /dev/null +++ b/dom/security/test/csp/file_csp_frame_ancestors_about_blank.html^headers^ @@ -0,0 +1,2 @@ +Cache-Control: no-cache +Content-Security-Policy: frame-ancestors http://mochi.test:8888 http://mochi.xorigin-test:8888 diff --git a/dom/security/test/csp/file_csp_meta_uir.html b/dom/security/test/csp/file_csp_meta_uir.html new file mode 100644 index 0000000000..dba1030975 --- /dev/null +++ b/dom/security/test/csp/file_csp_meta_uir.html @@ -0,0 +1,13 @@ + + + + + Hello World + + + + + + diff --git a/dom/security/test/csp/file_data-uri_blocked.html b/dom/security/test/csp/file_data-uri_blocked.html new file mode 100644 index 0000000000..59b7b25902 --- /dev/null +++ b/dom/security/test/csp/file_data-uri_blocked.html @@ -0,0 +1,15 @@ + + + + + + Test for Bug 587377 + + + + + + + diff --git a/dom/security/test/csp/file_data-uri_blocked.html^headers^ b/dom/security/test/csp/file_data-uri_blocked.html^headers^ new file mode 100644 index 0000000000..4248cca188 --- /dev/null +++ b/dom/security/test/csp/file_data-uri_blocked.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' 'report-sample'; img-src 'none' 'report-sample' diff --git a/dom/security/test/csp/file_data_csp_inheritance.html b/dom/security/test/csp/file_data_csp_inheritance.html new file mode 100644 index 0000000000..4ae2fedc69 --- /dev/null +++ b/dom/security/test/csp/file_data_csp_inheritance.html @@ -0,0 +1,24 @@ + + + + Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP + + + + + + + + + + diff --git a/dom/security/test/csp/file_data_csp_merge.html b/dom/security/test/csp/file_data_csp_merge.html new file mode 100644 index 0000000000..88ae8febe5 --- /dev/null +++ b/dom/security/test/csp/file_data_csp_merge.html @@ -0,0 +1,26 @@ + + + + Bug 1386183 - Meta CSP on data: URI iframe should be merged with toplevel CSP + + + + + + + + + + diff --git a/dom/security/test/csp/file_data_doc_ignore_meta_csp.html b/dom/security/test/csp/file_data_doc_ignore_meta_csp.html new file mode 100644 index 0000000000..9d6e9834dd --- /dev/null +++ b/dom/security/test/csp/file_data_doc_ignore_meta_csp.html @@ -0,0 +1,22 @@ + + + + Bug 1382869: data document should ignore meta csp + + + + + + + diff --git a/dom/security/test/csp/file_doccomment_meta.html b/dom/security/test/csp/file_doccomment_meta.html new file mode 100644 index 0000000000..a0f36a4bfe --- /dev/null +++ b/dom/security/test/csp/file_doccomment_meta.html @@ -0,0 +1,28 @@ + + + + Bug 663570 - Test doc.write(meta csp) + + + + + + + --> + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_docwrite_meta.css b/dom/security/test/csp/file_docwrite_meta.css new file mode 100644 index 0000000000..de725038b6 --- /dev/null +++ b/dom/security/test/csp/file_docwrite_meta.css @@ -0,0 +1,3 @@ +body { + background-color: rgb(255, 0, 0); +} diff --git a/dom/security/test/csp/file_docwrite_meta.html b/dom/security/test/csp/file_docwrite_meta.html new file mode 100644 index 0000000000..292de3bec5 --- /dev/null +++ b/dom/security/test/csp/file_docwrite_meta.html @@ -0,0 +1,26 @@ + + + + Bug 663570 - Test doc.write(meta csp) + + + + + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_docwrite_meta.js b/dom/security/test/csp/file_docwrite_meta.js new file mode 100644 index 0000000000..722adc235e --- /dev/null +++ b/dom/security/test/csp/file_docwrite_meta.js @@ -0,0 +1,3 @@ +// set a variable on the document which we can check to verify +// whether the external script was loaded or blocked +document.myMetaCSPScript = "external-JS-loaded"; diff --git a/dom/security/test/csp/file_dual_header_testserver.sjs b/dom/security/test/csp/file_dual_header_testserver.sjs new file mode 100644 index 0000000000..0efe186d57 --- /dev/null +++ b/dom/security/test/csp/file_dual_header_testserver.sjs @@ -0,0 +1,45 @@ +/* + * Custom sjs file serving a test page using *two* CSP policies. + * See Bug 1036399 - Multiple CSP policies should be combined towards an intersection + */ + +const TIGHT_POLICY = "default-src 'self'"; +const LOOSE_POLICY = "default-src 'self' 'unsafe-inline'"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + var csp = ""; + // deliver *TWO* comma separated policies which is in fact the same as serving + // to separate CSP headers (AppendPolicy is called twice). + if (request.queryString == "tight") { + // script execution will be *blocked* + csp = TIGHT_POLICY + ", " + LOOSE_POLICY; + } else { + // script execution will be *allowed* + csp = LOOSE_POLICY + ", " + LOOSE_POLICY; + } + response.setHeader("Content-Security-Policy", csp, false); + + // Send HTML to test allowed/blocked behaviors + response.setHeader("Content-Type", "text/html", false); + + // generate an html file that contains a div container which is updated + // in case the inline script is *not* blocked by CSP. + var html = + "" + + "" + + "" + + "Testpage for Bug 1036399" + + "" + + "" + + "
blocked
" + + "" + + "" + + ""; + + response.write(html); +} diff --git a/dom/security/test/csp/file_dummy_pixel.png b/dom/security/test/csp/file_dummy_pixel.png new file mode 100644 index 0000000000..52c591798e Binary files /dev/null and b/dom/security/test/csp/file_dummy_pixel.png differ diff --git a/dom/security/test/csp/file_empty_directive.html b/dom/security/test/csp/file_empty_directive.html new file mode 100644 index 0000000000..16196bb19f --- /dev/null +++ b/dom/security/test/csp/file_empty_directive.html @@ -0,0 +1,11 @@ + + + + + Bug 587377 - CSP keywords "'self'" and "'none'" are easy to confuse with host names "self" and "none" + + + + + diff --git a/dom/security/test/csp/file_empty_directive.html^headers^ b/dom/security/test/csp/file_empty_directive.html^headers^ new file mode 100644 index 0000000000..50dbe57bb9 --- /dev/null +++ b/dom/security/test/csp/file_empty_directive.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: ; diff --git a/dom/security/test/csp/file_evalscript_main.html b/dom/security/test/csp/file_evalscript_main.html new file mode 100644 index 0000000000..e83c1d9ed7 --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main.html @@ -0,0 +1,12 @@ + + + CSP eval script tests + + + + + Foo. + + + diff --git a/dom/security/test/csp/file_evalscript_main.html^headers^ b/dom/security/test/csp/file_evalscript_main.html^headers^ new file mode 100644 index 0000000000..b91ba384d9 --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main.html^headers^ @@ -0,0 +1,2 @@ +Cache-Control: no-cache +Content-Security-Policy: default-src 'self' diff --git a/dom/security/test/csp/file_evalscript_main.js b/dom/security/test/csp/file_evalscript_main.js new file mode 100644 index 0000000000..cc2c3fbe73 --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main.js @@ -0,0 +1,240 @@ +// some javascript for the CSP eval() tests + +function logResult(str, passed) { + var elt = document.createElement("div"); + var color = passed ? "#cfc;" : "#fcc"; + elt.setAttribute( + "style", + "background-color:" + + color + + "; width:100%; border:1px solid black; padding:3px; margin:4px;" + ); + elt.innerHTML = str; + document.body.appendChild(elt); +} + +window._testResults = {}; + +// check values for return values from blocked timeout or intervals +var verifyZeroRetVal = (function (window) { + return function (val, details) { + logResult( + (val === 0 ? "PASS: " : "FAIL: ") + + "Blocked interval/timeout should have zero return value; " + + details, + val === 0 + ); + window.parent.verifyZeroRetVal(val, details); + }; +})(window); + +// callback for when stuff is allowed by CSP +var onevalexecuted = (function (window) { + return function (shouldrun, what, data) { + window._testResults[what] = "ran"; + window.parent.scriptRan(shouldrun, what, data); + logResult( + (shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, + shouldrun + ); + }; +})(window); + +// callback for when stuff is blocked +var onevalblocked = (function (window) { + return function (shouldrun, what, data) { + window._testResults[what] = "blocked"; + window.parent.scriptBlocked(shouldrun, what, data); + logResult( + (shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, + !shouldrun + ); + }; +})(window); + +// Defer until document is loaded so that we can write the pretty result boxes +// out. +addEventListener( + "load", + function () { + // setTimeout(String) test -- mutate something in the window._testResults + // obj, then check it. + { + var str_setTimeoutWithStringRan = + 'onevalexecuted(false, "setTimeout(String)", "setTimeout with a string was enabled.");'; + function fcn_setTimeoutWithStringCheck() { + if (this._testResults["setTimeout(String)"] !== "ran") { + onevalblocked( + false, + "setTimeout(String)", + "setTimeout with a string was blocked" + ); + } + } + setTimeout(fcn_setTimeoutWithStringCheck.bind(window), 10); + var res = setTimeout(str_setTimeoutWithStringRan, 10); + verifyZeroRetVal(res, "setTimeout(String)"); + } + + // setInterval(String) test -- mutate something in the window._testResults + // obj, then check it. + { + var str_setIntervalWithStringRan = + 'onevalexecuted(false, "setInterval(String)", "setInterval with a string was enabled.");'; + function fcn_setIntervalWithStringCheck() { + if (this._testResults["setInterval(String)"] !== "ran") { + onevalblocked( + false, + "setInterval(String)", + "setInterval with a string was blocked" + ); + } + } + setTimeout(fcn_setIntervalWithStringCheck.bind(window), 10); + var res = setInterval(str_setIntervalWithStringRan, 10); + verifyZeroRetVal(res, "setInterval(String)"); + + // emergency cleanup, just in case. + if (res != 0) { + setTimeout(function () { + clearInterval(res); + }, 15); + } + } + + // setTimeout(function) test -- mutate something in the window._testResults + // obj, then check it. + { + function fcn_setTimeoutWithFunctionRan() { + onevalexecuted( + true, + "setTimeout(function)", + "setTimeout with a function was enabled." + ); + } + function fcn_setTimeoutWithFunctionCheck() { + if (this._testResults["setTimeout(function)"] !== "ran") { + onevalblocked( + true, + "setTimeout(function)", + "setTimeout with a function was blocked" + ); + } + } + setTimeout(fcn_setTimeoutWithFunctionRan.bind(window), 10); + setTimeout(fcn_setTimeoutWithFunctionCheck.bind(window), 10); + } + + // eval() test -- should throw exception as per spec + try { + eval('onevalexecuted(false, "eval(String)", "eval() was enabled.");'); + } catch (e) { + onevalblocked(false, "eval(String)", "eval() was blocked"); + } + + // eval(foo,bar) test -- should throw exception as per spec + try { + eval( + 'onevalexecuted(false, "eval(String,scope)", "eval() was enabled.");', + 1 + ); + } catch (e) { + onevalblocked( + false, + "eval(String,object)", + "eval() with scope was blocked" + ); + } + + // [foo,bar].sort(eval) test -- should throw exception as per spec + try { + [ + 'onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");', + 1, + ].sort(eval); + } catch (e) { + onevalblocked( + false, + "[String, obj].sort(eval)", + "eval() with scope via sort was blocked" + ); + } + + // [].sort.call([foo,bar], eval) test -- should throw exception as per spec + try { + [].sort.call( + [ + 'onevalexecuted(false, "[String, obj].sort(eval)", "eval() was enabled.");', + 1, + ], + eval + ); + } catch (e) { + onevalblocked( + false, + "[].sort.call([String, obj], eval)", + "eval() with scope via sort/call was blocked" + ); + } + + // new Function() test -- should throw exception as per spec + try { + var fcn = new Function( + 'onevalexecuted(false, "new Function(String)", "new Function(String) was enabled.");' + ); + fcn(); + } catch (e) { + onevalblocked( + false, + "new Function(String)", + "new Function(String) was blocked." + ); + } + + // ShadowRealm.prototype.evaluate -- should throw exception as per spec. + try { + var sr = new ShadowRealm(); + sr.evaluate("var x = 10"); + onevalexecuted( + false, + "ShadowRealm.prototype.evaluate(String)", + "ShadowRealm.prototype.evaluate(String) was enabled." + ); + } catch (e) { + onevalblocked( + false, + "ShadowRealm.prototype.evaluate(String)", + "ShadowRealm.prototype.evaluate(String) was blocked." + ); + } + + // setTimeout(eval, 0, str) + { + // error is not catchable here, instead, we're going to side-effect + // 'worked'. + var worked = false; + + setTimeout(eval, 0, "worked = true"); + setTimeout( + function (worked) { + if (worked) { + onevalexecuted( + false, + "setTimeout(eval, 0, str)", + "setTimeout(eval, 0, string) was enabled." + ); + } else { + onevalblocked( + false, + "setTimeout(eval, 0, str)", + "setTimeout(eval, 0, str) was blocked." + ); + } + }, + 0, + worked + ); + } + }, + false +); diff --git a/dom/security/test/csp/file_evalscript_main_allowed.html b/dom/security/test/csp/file_evalscript_main_allowed.html new file mode 100644 index 0000000000..274972d9bd --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main_allowed.html @@ -0,0 +1,12 @@ + + + CSP eval script tests + + + + + Foo. + + + diff --git a/dom/security/test/csp/file_evalscript_main_allowed.html^headers^ b/dom/security/test/csp/file_evalscript_main_allowed.html^headers^ new file mode 100644 index 0000000000..0cb5288bec --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main_allowed.html^headers^ @@ -0,0 +1,2 @@ +Cache-Control: no-cache +Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-eval' diff --git a/dom/security/test/csp/file_evalscript_main_allowed.js b/dom/security/test/csp/file_evalscript_main_allowed.js new file mode 100644 index 0000000000..69c1cce00e --- /dev/null +++ b/dom/security/test/csp/file_evalscript_main_allowed.js @@ -0,0 +1,193 @@ +// some javascript for the CSP eval() tests +// all of these evals should succeed, as the document loading this script +// has script-src 'self' 'unsafe-eval' + +function logResult(str, passed) { + var elt = document.createElement("div"); + var color = passed ? "#cfc;" : "#fcc"; + elt.setAttribute( + "style", + "background-color:" + + color + + "; width:100%; border:1px solid black; padding:3px; margin:4px;" + ); + elt.innerHTML = str; + document.body.appendChild(elt); +} + +// callback for when stuff is allowed by CSP +var onevalexecuted = (function (window) { + return function (shouldrun, what, data) { + window.parent.scriptRan(shouldrun, what, data); + logResult( + (shouldrun ? "PASS: " : "FAIL: ") + what + " : " + data, + shouldrun + ); + }; +})(window); + +// callback for when stuff is blocked +var onevalblocked = (function (window) { + return function (shouldrun, what, data) { + window.parent.scriptBlocked(shouldrun, what, data); + logResult( + (shouldrun ? "FAIL: " : "PASS: ") + what + " : " + data, + !shouldrun + ); + }; +})(window); + +// Defer until document is loaded so that we can write the pretty result boxes +// out. +addEventListener( + "load", + function () { + // setTimeout(String) test -- should pass + try { + setTimeout( + 'onevalexecuted(true, "setTimeout(String)", "setTimeout with a string was enabled.");', + 10 + ); + } catch (e) { + onevalblocked( + true, + "setTimeout(String)", + "setTimeout with a string was blocked" + ); + } + + // setTimeout(function) test -- should pass + try { + setTimeout(function () { + onevalexecuted( + true, + "setTimeout(function)", + "setTimeout with a function was enabled." + ); + }, 10); + } catch (e) { + onevalblocked( + true, + "setTimeout(function)", + "setTimeout with a function was blocked" + ); + } + + // eval() test + try { + eval('onevalexecuted(true, "eval(String)", "eval() was enabled.");'); + } catch (e) { + onevalblocked(true, "eval(String)", "eval() was blocked"); + } + + // eval(foo,bar) test + try { + eval( + 'onevalexecuted(true, "eval(String,scope)", "eval() was enabled.");', + 1 + ); + } catch (e) { + onevalblocked( + true, + "eval(String,object)", + "eval() with scope was blocked" + ); + } + + // [foo,bar].sort(eval) test + try { + [ + 'onevalexecuted(true, "[String, obj].sort(eval)", "eval() was enabled.");', + 1, + ].sort(eval); + } catch (e) { + onevalblocked( + true, + "[String, obj].sort(eval)", + "eval() with scope via sort was blocked" + ); + } + + // [].sort.call([foo,bar], eval) test + try { + [].sort.call( + [ + 'onevalexecuted(true, "[String, obj].sort(eval)", "eval() was enabled.");', + 1, + ], + eval + ); + } catch (e) { + onevalblocked( + true, + "[].sort.call([String, obj], eval)", + "eval() with scope via sort/call was blocked" + ); + } + + // new Function() test + try { + var fcn = new Function( + 'onevalexecuted(true, "new Function(String)", "new Function(String) was enabled.");' + ); + fcn(); + } catch (e) { + onevalblocked( + true, + "new Function(String)", + "new Function(String) was blocked." + ); + } + + // ShadowRealm.prototype.evaluate + try { + var sr = new ShadowRealm(); + sr.evaluate("var x = 10"); + onevalexecuted( + true, + "ShadowRealm.prototype.evaluate(String)", + "ShadowRealm.prototype.evaluate(String) was enabled." + ); + } catch (e) { + onevalblocked( + true, + "ShadowRealm.prototype.evaluate(String)", + "ShadowRealm.prototype.evaluate(String) was blocked." + ); + } + + function checkResult() { + //alert(bar); + if (bar) { + onevalexecuted( + true, + "setTimeout(eval, 0, str)", + "setTimeout(eval, 0, string) was enabled." + ); + } else { + onevalblocked( + true, + "setTimeout(eval, 0, str)", + "setTimeout(eval, 0, str) was blocked." + ); + } + } + + var bar = false; + + function foo() { + bar = true; + } + + window.foo = foo; + + // setTimeout(eval, 0, str) + + // error is not catchable here + + setTimeout(eval, 0, "window.foo();"); + + setTimeout(checkResult.bind(this), 0); + }, + false +); diff --git a/dom/security/test/csp/file_fontloader.sjs b/dom/security/test/csp/file_fontloader.sjs new file mode 100644 index 0000000000..b9b5e602fe --- /dev/null +++ b/dom/security/test/csp/file_fontloader.sjs @@ -0,0 +1,57 @@ +// custom *.sjs for Bug 1195172 +// CSP: 'block-all-mixed-content' + +const PRE_HEAD = + "" + + '' + + "Bug 1195172 - CSP should block font from cache"; + +const CSP_BLOCK = + ''; + +const CSP_ALLOW = + ''; + +const CSS = + ""; + +const POST_HEAD_AND_BODY = + "" + + "" + + "
Just testing the font
" + + "" + + ""; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + var queryString = request.queryString; + + if (queryString == "baseline") { + response.write(PRE_HEAD + POST_HEAD_AND_BODY); + return; + } + if (queryString == "no-csp") { + response.write(PRE_HEAD + CSS + POST_HEAD_AND_BODY); + return; + } + if (queryString == "csp-block") { + response.write(PRE_HEAD + CSP_BLOCK + CSS + POST_HEAD_AND_BODY); + return; + } + if (queryString == "csp-allow") { + response.write(PRE_HEAD + CSP_ALLOW + CSS + POST_HEAD_AND_BODY); + return; + } + // we should never get here, but just in case return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_fontloader.woff b/dom/security/test/csp/file_fontloader.woff new file mode 100644 index 0000000000..fbf7390d59 Binary files /dev/null and b/dom/security/test/csp/file_fontloader.woff differ diff --git a/dom/security/test/csp/file_form-action.html b/dom/security/test/csp/file_form-action.html new file mode 100644 index 0000000000..cfff156bae --- /dev/null +++ b/dom/security/test/csp/file_form-action.html @@ -0,0 +1,15 @@ + + + + Bug 529697 - Test mapping of form submission to form-action + + +
+ +
+ + + diff --git a/dom/security/test/csp/file_form_action_server.sjs b/dom/security/test/csp/file_form_action_server.sjs new file mode 100644 index 0000000000..0c79736d47 --- /dev/null +++ b/dom/security/test/csp/file_form_action_server.sjs @@ -0,0 +1,32 @@ +// Custom *.sjs file specifically for the needs of Bug 1251043 + +const FRAME = ` + + + + Bug 1251043 - Test form-action blocks URL + + + + CONTROL-TEXT +
+ +
+ + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // PART 1: Return a frame including the FORM and the CSP + if (request.queryString === "loadframe") { + response.write(FRAME); + return; + } + + // PART 2: We should never get here because the form + // should not be submitted. Just in case; return + // something unexpected so the test fails! + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html b/dom/security/test/csp/file_frame_ancestors_ro.html new file mode 100644 index 0000000000..ff5ae9cf9f --- /dev/null +++ b/dom/security/test/csp/file_frame_ancestors_ro.html @@ -0,0 +1 @@ +Child Document diff --git a/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ new file mode 100644 index 0000000000..d018af3a96 --- /dev/null +++ b/dom/security/test/csp/file_frame_ancestors_ro.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy-Report-Only: frame-ancestors 'none'; report-uri http://mochi.test:8888/foo.sjs diff --git a/dom/security/test/csp/file_frame_src.js b/dom/security/test/csp/file_frame_src.js new file mode 100644 index 0000000000..d30bc0ec62 --- /dev/null +++ b/dom/security/test/csp/file_frame_src.js @@ -0,0 +1,20 @@ +let testframe = document.getElementById("testframe"); +testframe.onload = function () { + parent.postMessage( + { + result: "frame-allowed", + href: document.location.href, + }, + "*" + ); +}; +testframe.onerror = function () { + parent.postMessage( + { + result: "frame-blocked", + href: document.location.href, + }, + "*" + ); +}; +testframe.src = "file_frame_src_inner.html"; diff --git a/dom/security/test/csp/file_frame_src_child_governs.html b/dom/security/test/csp/file_frame_src_child_governs.html new file mode 100644 index 0000000000..a51cb75be2 --- /dev/null +++ b/dom/security/test/csp/file_frame_src_child_governs.html @@ -0,0 +1,10 @@ + + + + "; + + + + + + diff --git a/dom/security/test/csp/file_frame_src_frame_governs.html b/dom/security/test/csp/file_frame_src_frame_governs.html new file mode 100644 index 0000000000..2c5d5857f2 --- /dev/null +++ b/dom/security/test/csp/file_frame_src_frame_governs.html @@ -0,0 +1,10 @@ + + + + "; + + + + + + diff --git a/dom/security/test/csp/file_frame_src_inner.html b/dom/security/test/csp/file_frame_src_inner.html new file mode 100644 index 0000000000..4a2fc6095a --- /dev/null +++ b/dom/security/test/csp/file_frame_src_inner.html @@ -0,0 +1,5 @@ + + +dummy iframe + + diff --git a/dom/security/test/csp/file_frameancestors.sjs b/dom/security/test/csp/file_frameancestors.sjs new file mode 100644 index 0000000000..25d4b3fe08 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors.sjs @@ -0,0 +1,69 @@ +// SJS file for CSP frame ancestor mochitests +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + var isPreflight = request.method == "OPTIONS"; + + //avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // grab the desired policy from the query, and then serve a page + if (query.csp) { + response.setHeader("Content-Security-Policy", unescape(query.csp), false); + } + if (query.scriptedreport) { + // spit back a script that records that the page loaded + response.setHeader("Content-Type", "text/javascript", false); + if (query.double) { + response.write( + 'window.parent.parent.parent.postMessage({call: "frameLoaded", testname: "' + + query.scriptedreport + + '", uri: "window.location.toString()"}, "*");' + ); + } else { + response.write( + 'window.parent.parent.postMessage({call: "frameLoaded", testname: "' + + query.scriptedreport + + '", uri: "window.location.toString()"}, "*");' + ); + } + } else if (query.internalframe) { + // spit back an internal iframe (one that might be blocked) + response.setHeader("Content-Type", "text/html", false); + response.write(""); + if (query.double) { + response.write( + '' + ); + } else { + response.write( + '' + ); + } + response.write(""); + response.write(unescape(query.internalframe)); + response.write(""); + } else if (query.externalframe) { + // spit back an internal iframe (one that won't be blocked, and probably + // has no CSP) + response.setHeader("Content-Type", "text/html", false); + response.write(""); + response.write(""); + response.write(unescape(query.externalframe)); + response.write(""); + } else { + // default case: error. + response.setHeader("Content-Type", "text/html", false); + response.write(""); + response.write("ERROR: not sure what to serve."); + response.write(""); + } +} diff --git a/dom/security/test/csp/file_frameancestors_main.html b/dom/security/test/csp/file_frameancestors_main.html new file mode 100644 index 0000000000..97f9cb9ac5 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_main.html @@ -0,0 +1,44 @@ + + + CSP frame ancestors tests + + + + + + + + + aa_allow: /* innermost frame allows a */
+
+ + aa_block: /* innermost frame denies a */
+
+ + ab_allow: /* innermost frame allows a */
+
+ + ab_block: /* innermost frame denies a */
+
+ + aba_allow: /* innermost frame allows b,a */
+
+ + aba_block: /* innermost frame denies b */
+
+ + aba2_block: /* innermost frame denies a */
+
+ + abb_allow: /* innermost frame allows b,a */
+
+ + abb_block: /* innermost frame denies b */
+
+ + abb2_block: /* innermost frame denies a */
+
+ + + + diff --git a/dom/security/test/csp/file_frameancestors_main.js b/dom/security/test/csp/file_frameancestors_main.js new file mode 100644 index 0000000000..2c5caf739f --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_main.js @@ -0,0 +1,134 @@ +// Script to populate the test frames in the frame ancestors mochitest. +// +function setupFrames() { + var $ = function (v) { + return document.getElementById(v); + }; + var base = { + self: "/tests/dom/security/test/csp/file_frameancestors.sjs", + a: "http://mochi.test:8888/tests/dom/security/test/csp/file_frameancestors.sjs", + b: "http://example.com/tests/dom/security/test/csp/file_frameancestors.sjs", + }; + + // In both cases (base.a, base.b) the path starts with /tests/. Let's make sure this + // path within the CSP policy is completely ignored when enforcing frame ancestors. + // To test this behavior we use /foo/ and /bar/ as dummy values for the path. + var host = { + a: "http://mochi.test:8888/foo/", + b: "http://example.com:80/bar/", + }; + + var innerframeuri = null; + var elt = null; + + elt = $("aa_allow"); + elt.src = + base.a + + "?testid=aa_allow&internalframe=aa_a&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'" + ); + + elt = $("aa_block"); + elt.src = + base.a + + "?testid=aa_block&internalframe=aa_b&csp=" + + escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'"); + + elt = $("ab_allow"); + elt.src = + base.b + + "?testid=ab_allow&internalframe=ab_a&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'" + ); + + elt = $("ab_block"); + elt.src = + base.b + + "?testid=ab_block&internalframe=ab_b&csp=" + + escape("default-src 'none'; frame-ancestors 'none'; script-src 'self'"); + + /* .... two-level framing */ + elt = $("aba_allow"); + innerframeuri = + base.a + + "?testid=aba_allow&double=1&internalframe=aba_a&csp=" + + escape( + "default-src 'none'; frame-ancestors " + + host.a + + " " + + host.b + + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); + + elt = $("aba_block"); + innerframeuri = + base.a + + "?testid=aba_allow&double=1&internalframe=aba_b&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); + + elt = $("aba2_block"); + innerframeuri = + base.a + + "?testid=aba_allow&double=1&internalframe=aba2_b&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.b + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); + + elt = $("abb_allow"); + innerframeuri = + base.b + + "?testid=abb_allow&double=1&internalframe=abb_a&csp=" + + escape( + "default-src 'none'; frame-ancestors " + + host.a + + " " + + host.b + + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); + + elt = $("abb_block"); + innerframeuri = + base.b + + "?testid=abb_allow&double=1&internalframe=abb_b&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.a + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); + + elt = $("abb2_block"); + innerframeuri = + base.b + + "?testid=abb_allow&double=1&internalframe=abb2_b&csp=" + + escape( + "default-src 'none'; frame-ancestors " + host.b + "; script-src 'self'" + ); + elt.src = + base.b + + "?externalframe=" + + escape(''); +} + +window.addEventListener("load", setupFrames); diff --git a/dom/security/test/csp/file_frameancestors_userpass.html b/dom/security/test/csp/file_frameancestors_userpass.html new file mode 100644 index 0000000000..c840995b6c --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass.html @@ -0,0 +1,10 @@ + + + CSP frame ancestors tests + + + Nested Frames
+
+
+ + diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_a.html b/dom/security/test/csp/file_frameancestors_userpass_frame_a.html new file mode 100644 index 0000000000..d5a5bb604b --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_a.html @@ -0,0 +1,12 @@ + + + Nested frame + + + + IFRAME A
+
+ + diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_b.html b/dom/security/test/csp/file_frameancestors_userpass_frame_b.html new file mode 100644 index 0000000000..87055ef149 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_b.html @@ -0,0 +1,12 @@ + + + Nested frame + + + + IFRAME B
+
+ + diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_c.html b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html new file mode 100644 index 0000000000..159e6c4633 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html @@ -0,0 +1,8 @@ + + + Nested frame + + + Nested frame C content + + diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^ new file mode 100644 index 0000000000..9e7dfefcda --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_c.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none'; frame-ancestors http://mochi.test:8888/ ; script-src 'self'; diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_d.html b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html new file mode 100644 index 0000000000..0cb49c4836 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html @@ -0,0 +1,8 @@ + + + Nested frame + + + Nested frame D content + + diff --git a/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^ new file mode 100644 index 0000000000..019fcea026 --- /dev/null +++ b/dom/security/test/csp/file_frameancestors_userpass_frame_d.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'none'; frame-ancestors http://sampleuser:samplepass@example.com/ ; script-src 'self'; diff --git a/dom/security/test/csp/file_hash_source.html b/dom/security/test/csp/file_hash_source.html new file mode 100644 index 0000000000..47eba6cf3e --- /dev/null +++ b/dom/security/test/csp/file_hash_source.html @@ -0,0 +1,65 @@ + + + + +

blocked

+

blocked

+

blocked

+

blocked

+

blocked

+

blocked

+

blocked

+

blocked

+

blocked

+ + + + + + + + + + + + + + + + + + + + + +

+

+

+

+

+

+

+

+

+ + + + + + + + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_hash_source.html^headers^ b/dom/security/test/csp/file_hash_source.html^headers^ new file mode 100644 index 0000000000..785d63391e --- /dev/null +++ b/dom/security/test/csp/file_hash_source.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI=' 'nonce-jPRxvuRHbiQnCWVuoCMAvQ==' 'sha256-z7rzCkbOJqi08lga3CVQ3b+3948ZbJWaSxsBs8zPliE=' 'sha512-tMLuv22jJ5RHkvLNlv0otvA2fgw6PF16HKu6wy0ZDQ3M7UKzoygs1uxIMSfjMttgWrB5WRvIr35zrTZppMYBVw==' 'sha384-XjAD+FxZfipkxna4id1JrR2QP6OYUZfAxpn9+yHOmT1VSLVa9SQR/dz7CEb7jw7w' 'sha1-LHErkMxKGcSpa/znpzmKYkKnI30=' 'md5-/m4wX3YU+IHs158KwKOBWg=='; style-src 'sha256-UpNH6x+Ux99QTW1fJikQsVbBERJruIC98et0YDVKKHQ=' 'nonce-ftL2UbGHlSEaZTLWMwtA5Q==' 'sha256-0IPbWW5IDJ/juvETq60oTnhC+XzOqdYp5/UBsBKCaOY=' 'sha512-EpcDbSuvFv0HIyKtU5tQMN7UtBMeEbljz1dWPfy7PNCa1RYdHKwdJWT1tie41evq/ZUL1rzadSVdEzq3jl6Twg==' 'sha384-c5W8ON4WyeA2zEOGdrOGhRmRYI8+2UzUUmhGQFjUFP6yiPZx9FGEV3UOiQ+tIshF' 'sha1-T/+b4sxCIiJxDr6XS9dAEyHKt2M=' 'md5-oNrgrtzOZduwDYYi1yo12g=='; +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_iframe_parent_location_js.html b/dom/security/test/csp/file_iframe_parent_location_js.html new file mode 100644 index 0000000000..0d980f9925 --- /dev/null +++ b/dom/security/test/csp/file_iframe_parent_location_js.html @@ -0,0 +1,10 @@ + + + Test setting parent location to javascript: + + + + + diff --git a/dom/security/test/csp/file_iframe_sandbox_document_write.html b/dom/security/test/csp/file_iframe_sandbox_document_write.html new file mode 100644 index 0000000000..a3a0952941 --- /dev/null +++ b/dom/security/test/csp/file_iframe_sandbox_document_write.html @@ -0,0 +1,21 @@ + + + + + + sandboxed with allow-scripts + + diff --git a/dom/security/test/csp/file_iframe_sandbox_srcdoc.html b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html new file mode 100644 index 0000000000..bc700ed68f --- /dev/null +++ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html @@ -0,0 +1,11 @@ + + + + + Bug 1073952 - CSP should restrict scripts in srcdoc iframe even if sandboxed + + + + + diff --git a/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^ new file mode 100644 index 0000000000..cf869e07d4 --- /dev/null +++ b/dom/security/test/csp/file_iframe_sandbox_srcdoc.html^headers^ @@ -0,0 +1 @@ +content-security-policy: default-src *; diff --git a/dom/security/test/csp/file_iframe_srcdoc.sjs b/dom/security/test/csp/file_iframe_srcdoc.sjs new file mode 100644 index 0000000000..9f8774e4cc --- /dev/null +++ b/dom/security/test/csp/file_iframe_srcdoc.sjs @@ -0,0 +1,87 @@ +// Custom *.sjs file specifically for the needs of +// https://bugzilla.mozilla.org/show_bug.cgi?id=1073952 + +"use strict"; +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const SCRIPT = ` + `; + +const SIMPLE_IFRAME_SRCDOC = + ` + + + + + + + `; + +const INNER_SRCDOC_IFRAME = ` + `; + +const NESTED_IFRAME_SRCDOC = + ` + + + + + + + `; + +const INNER_DATAURI_IFRAME = ` + `; + +const NESTED_IFRAME_SRCDOC_DATAURI = + ` + + + + + + + `; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + response.setHeader("Cache-Control", "no-cache", false); + if (typeof query.get("csp") === "string") { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + response.setHeader("Content-Type", "text/html", false); + + if (query.get("action") === "simple_iframe_srcdoc") { + response.write(SIMPLE_IFRAME_SRCDOC); + return; + } + + if (query.get("action") === "nested_iframe_srcdoc") { + response.write(NESTED_IFRAME_SRCDOC); + return; + } + + if (query.get("action") === "nested_iframe_srcdoc_datauri") { + response.write(NESTED_IFRAME_SRCDOC_DATAURI); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_ignore_unsafe_inline.html b/dom/security/test/csp/file_ignore_unsafe_inline.html new file mode 100644 index 0000000000..773184201c --- /dev/null +++ b/dom/security/test/csp/file_ignore_unsafe_inline.html @@ -0,0 +1,26 @@ + + + +Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified + + +
a
+ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs b/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs new file mode 100644 index 0000000000..c27aee0f42 --- /dev/null +++ b/dom/security/test/csp/file_ignore_unsafe_inline_multiple_policies_server.sjs @@ -0,0 +1,56 @@ +// custom *.sjs file specifically for the needs of: +// * Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified +// * Bug 1198422: should not block inline script if default-src is not specified + +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +function loadHTMLFromFile(path) { + // Load the HTML to return in the response from file. + // Since it's relative to the cwd of the test runner, we start there and + // append to get to the actual path of the file. + var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + var dirs = path.split("/"); + for (var i = 0; i < dirs.length; i++) { + testHTMLFile.append(dirs[i]); + } + var testHTMLFileStream = Components.classes[ + "@mozilla.org/network/file-input-stream;1" + ].createInstance(Components.interfaces.nsIFileInputStream); + testHTMLFileStream.init(testHTMLFile, -1, 0, 0); + var testHTML = NetUtil.readInputStreamToString( + testHTMLFileStream, + testHTMLFileStream.available() + ); + return testHTML; +} + +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + var csp1 = query.csp1 ? unescape(query.csp1) : ""; + var csp2 = query.csp2 ? unescape(query.csp2) : ""; + var file = unescape(query.file); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // deliver the CSP encoded in the URI + // please note that comma separation of two policies + // acts like sending *two* separate policies + var csp = csp1; + if (csp2 !== "") { + csp += ", " + csp2; + } + response.setHeader("Content-Security-Policy", csp, false); + + // Send HTML to test allowed/blocked behaviors + response.setHeader("Content-Type", "text/html", false); + + response.write(loadHTMLFromFile(file)); +} diff --git a/dom/security/test/csp/file_ignore_xfo.html b/dom/security/test/csp/file_ignore_xfo.html new file mode 100644 index 0000000000..6746a3adba --- /dev/null +++ b/dom/security/test/csp/file_ignore_xfo.html @@ -0,0 +1,10 @@ + + + + + Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists + + +
Ignoring XFO because of CSP
+ + diff --git a/dom/security/test/csp/file_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ignore_xfo.html^headers^ new file mode 100644 index 0000000000..e93f9e3ecb --- /dev/null +++ b/dom/security/test/csp/file_ignore_xfo.html^headers^ @@ -0,0 +1,3 @@ +Content-Security-Policy: frame-ancestors http://mochi.test:8888 +X-Frame-Options: deny +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_image_document_pixel.png b/dom/security/test/csp/file_image_document_pixel.png new file mode 100644 index 0000000000..52c591798e Binary files /dev/null and b/dom/security/test/csp/file_image_document_pixel.png differ diff --git a/dom/security/test/csp/file_image_document_pixel.png^headers^ b/dom/security/test/csp/file_image_document_pixel.png^headers^ new file mode 100644 index 0000000000..7c727854d0 --- /dev/null +++ b/dom/security/test/csp/file_image_document_pixel.png^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: default-src https://bug1627235.test.com +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_image_nonce.html b/dom/security/test/csp/file_image_nonce.html new file mode 100644 index 0000000000..5d57bb8372 --- /dev/null +++ b/dom/security/test/csp/file_image_nonce.html @@ -0,0 +1,39 @@ + + + + + Bug 1355801: Nonce should not apply to images + + + + + + + + + + diff --git a/dom/security/test/csp/file_image_nonce.html^headers^ b/dom/security/test/csp/file_image_nonce.html^headers^ new file mode 100644 index 0000000000..0d63558c46 --- /dev/null +++ b/dom/security/test/csp/file_image_nonce.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: img-src 'nonce-abc'; +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_independent_iframe_csp.html b/dom/security/test/csp/file_independent_iframe_csp.html new file mode 100644 index 0000000000..0581f5ea85 --- /dev/null +++ b/dom/security/test/csp/file_independent_iframe_csp.html @@ -0,0 +1,43 @@ + + + + Bug 1419222 - iFrame CSP should not affect parent document CSP + + + + + + + diff --git a/dom/security/test/csp/file_inlinescript.html b/dom/security/test/csp/file_inlinescript.html new file mode 100644 index 0000000000..55a9b9b180 --- /dev/null +++ b/dom/security/test/csp/file_inlinescript.html @@ -0,0 +1,15 @@ + + + CSP inline script tests + + + + + + + testlink + + + diff --git a/dom/security/test/csp/file_inlinestyle_main.html b/dom/security/test/csp/file_inlinestyle_main.html new file mode 100644 index 0000000000..a0d2969883 --- /dev/null +++ b/dom/security/test/csp/file_inlinestyle_main.html @@ -0,0 +1,79 @@ + + + + CSP inline script tests + + + + + + + + + + +
Link tag (external) stylesheet test (should be green)
+
Inline stylesheet test (should be black)
+
Attribute stylesheet test (should be black)
+
cssText test (should be black)
+
modify rule from style sheet via cssText(should be green)
+ + + + + + + This shouldn't be red since the animation should be blocked by CSP. + + + + + + + This shouldn't be red since the animation should be blocked by CSP. + + + + + + + This shouldn't be red since the animation should be blocked by CSP. + + + + + + This shouldn't be red since the <set> should be blocked by CSP. + + + + + diff --git a/dom/security/test/csp/file_inlinestyle_main.html^headers^ b/dom/security/test/csp/file_inlinestyle_main.html^headers^ new file mode 100644 index 0000000000..7b6a251679 --- /dev/null +++ b/dom/security/test/csp/file_inlinestyle_main.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline' +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_inlinestyle_main_allowed.html b/dom/security/test/csp/file_inlinestyle_main_allowed.html new file mode 100644 index 0000000000..9b533ef074 --- /dev/null +++ b/dom/security/test/csp/file_inlinestyle_main_allowed.html @@ -0,0 +1,84 @@ + + + + CSP inline script tests + + + + + + + + + + +
Link tag (external) stylesheet test (should be green)
+
Inline stylesheet test (should be green)
+
Attribute stylesheet test (should be green)
+
style.cssText test (should be green)
+
modify rule from style sheet via cssText(should be green)
+ + + + + + + This should be green since the animation should be allowed by CSP. + + + + + + + This should be green since the animation should be allowed by CSP. + + + + + + + This should be green since the animation should be allowed by CSP. + + + + + + This should be green since the <set> should be allowed by CSP. + + + + + diff --git a/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^ b/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^ new file mode 100644 index 0000000000..621d2536b0 --- /dev/null +++ b/dom/security/test/csp/file_inlinestyle_main_allowed.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: default-src 'self' ; script-src 'self' 'unsafe-inline' ; style-src 'self' 'unsafe-inline' +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_invalid_source_expression.html b/dom/security/test/csp/file_invalid_source_expression.html new file mode 100644 index 0000000000..83bb0ec0ca --- /dev/null +++ b/dom/security/test/csp/file_invalid_source_expression.html @@ -0,0 +1,11 @@ + + + + Bug 1086612 - CSP: Let source expression be the empty set in case no valid source can be parsed + + +
blocked
+ + + + diff --git a/dom/security/test/csp/file_leading_wildcard.html b/dom/security/test/csp/file_leading_wildcard.html new file mode 100644 index 0000000000..ea5e993447 --- /dev/null +++ b/dom/security/test/csp/file_leading_wildcard.html @@ -0,0 +1,11 @@ + + + + Bug 1032303 - CSP - Keep FULL STOP when matching *.foo.com to disallow loads from foo.com + + + + + + + diff --git a/dom/security/test/csp/file_link_rel_preload.html b/dom/security/test/csp/file_link_rel_preload.html new file mode 100644 index 0000000000..8af49a77fe --- /dev/null +++ b/dom/security/test/csp/file_link_rel_preload.html @@ -0,0 +1,19 @@ + + + + Bug 1599791 - Test link rel=preload + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_main.html b/dom/security/test/csp/file_main.html new file mode 100644 index 0000000000..ddc8382617 --- /dev/null +++ b/dom/security/test/csp/file_main.html @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
arbitrary good
+
arbitrary_bad
+ + diff --git a/dom/security/test/csp/file_main.html^headers^ b/dom/security/test/csp/file_main.html^headers^ new file mode 100644 index 0000000000..3338de389b --- /dev/null +++ b/dom/security/test/csp/file_main.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' blob: ; style-src 'unsafe-inline' 'self' diff --git a/dom/security/test/csp/file_main.js b/dom/security/test/csp/file_main.js new file mode 100644 index 0000000000..01dd43cbf5 --- /dev/null +++ b/dom/security/test/csp/file_main.js @@ -0,0 +1,26 @@ +function doXHR(uri) { + try { + var xhr = new XMLHttpRequest(); + xhr.open("GET", uri); + xhr.send(); + } catch (ex) {} +} + +doXHR( + "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_good" +); +doXHR( + "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=xhr_bad" +); +fetch( + "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_good" +); +fetch( + "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=fetch_bad" +); +navigator.sendBeacon( + "http://mochi.test:8888/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_good" +); +navigator.sendBeacon( + "http://example.com/tests/dom/security/test/csp/file_CSP.sjs?testid=beacon_bad" +); diff --git a/dom/security/test/csp/file_meta_element.html b/dom/security/test/csp/file_meta_element.html new file mode 100644 index 0000000000..17f19c7c86 --- /dev/null +++ b/dom/security/test/csp/file_meta_element.html @@ -0,0 +1,27 @@ + + + + + + Bug 663570 - Implement Content Security Policy via meta tag + + + + + + + + + + diff --git a/dom/security/test/csp/file_meta_header_dual.sjs b/dom/security/test/csp/file_meta_header_dual.sjs new file mode 100644 index 0000000000..445b3e444e --- /dev/null +++ b/dom/security/test/csp/file_meta_header_dual.sjs @@ -0,0 +1,101 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 663570 - Implement Content Security Policy via meta tag + +const HTML_HEAD = + "" + + "" + + "" + + "" + + "Bug 663570 - Implement Content Security Policy via <meta> tag"; + +const HTML_BODY = + "" + + "" + + "" + + "" + + "" + + ""; + +const META_CSP_BLOCK_IMG = + ''; + +const META_CSP_ALLOW_IMG = + ''; + +const HEADER_CSP_BLOCK_IMG = "img-src 'none';"; + +const HEADER_CSP_ALLOW_IMG = "img-src http://mochi.test:8888"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + var queryString = request.queryString; + + if (queryString === "test1") { + /* load image without any CSP */ + response.write(HTML_HEAD + HTML_BODY); + return; + } + + if (queryString === "test2") { + /* load image where meta denies load */ + response.write(HTML_HEAD + META_CSP_BLOCK_IMG + HTML_BODY); + return; + } + + if (queryString === "test3") { + /* load image where meta allows load */ + response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY); + return; + } + + if (queryString === "test4") { + /* load image where meta allows but header blocks */ + response.setHeader("Content-Security-Policy", HEADER_CSP_BLOCK_IMG, false); + response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY); + return; + } + + if (queryString === "test5") { + /* load image where meta blocks but header allows */ + response.setHeader("Content-Security-Policy", HEADER_CSP_ALLOW_IMG, false); + response.write(HTML_HEAD + META_CSP_BLOCK_IMG + HTML_BODY); + return; + } + + if (queryString === "test6") { + /* load image where meta allows and header allows */ + response.setHeader("Content-Security-Policy", HEADER_CSP_ALLOW_IMG, false); + response.write(HTML_HEAD + META_CSP_ALLOW_IMG + HTML_BODY); + return; + } + + if (queryString === "test7") { + /* load image where meta1 allows but meta2 blocks */ + response.write( + HTML_HEAD + META_CSP_ALLOW_IMG + META_CSP_BLOCK_IMG + HTML_BODY + ); + return; + } + + if (queryString === "test8") { + /* load image where meta1 allows and meta2 allows */ + response.write( + HTML_HEAD + META_CSP_ALLOW_IMG + META_CSP_ALLOW_IMG + HTML_BODY + ); + return; + } + + // we should never get here, but just in case, return + // something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_meta_whitespace_skipping.html b/dom/security/test/csp/file_meta_whitespace_skipping.html new file mode 100644 index 0000000000..c0cfc8cc28 --- /dev/null +++ b/dom/security/test/csp/file_meta_whitespace_skipping.html @@ -0,0 +1,31 @@ + + + + + + + Bug 1261634 - Update whitespace skipping for meta csp + + + + + + diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass.html b/dom/security/test/csp/file_multi_policy_injection_bypass.html new file mode 100644 index 0000000000..a3cb415a9e --- /dev/null +++ b/dom/security/test/csp/file_multi_policy_injection_bypass.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^ b/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^ new file mode 100644 index 0000000000..e1b64a9220 --- /dev/null +++ b/dom/security/test/csp/file_multi_policy_injection_bypass.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self', default-src * diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass_2.html b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html new file mode 100644 index 0000000000..3fa6c7ab91 --- /dev/null +++ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^ new file mode 100644 index 0000000000..b523073cd3 --- /dev/null +++ b/dom/security/test/csp/file_multi_policy_injection_bypass_2.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' , default-src * diff --git a/dom/security/test/csp/file_multipart_testserver.sjs b/dom/security/test/csp/file_multipart_testserver.sjs new file mode 100644 index 0000000000..571dd4006d --- /dev/null +++ b/dom/security/test/csp/file_multipart_testserver.sjs @@ -0,0 +1,160 @@ +// SJS file specifically for the needs of bug +// Bug 1416045/Bug 1223743 - CSP: Check baseChannel for CSP when loading multipart channel + +var CSP = "script-src 'unsafe-inline', img-src 'none'"; +var rootCSP = "script-src 'unsafe-inline'"; +var part1CSP = "img-src *"; +var part2CSP = "img-src 'none'"; +var BOUNDARY = "fooboundary"; + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +var RESPONSE = ` + +`; + +var RESPONSE1 = ` + + + +`; + +var RESPONSE2 = ` + + + +`; + +function setGlobalState(data, key) { + x = { + data, + QueryInterface(iid) { + return this; + }, + }; + x.wrappedJSObject = x; + setObjectState(key, x); +} + +function getGlobalState(key) { + var data; + getObjectState(key, function (x) { + data = x && x.wrappedJSObject.data; + }); + return data; +} + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString == "doc") { + response.setHeader("Content-Security-Policy", CSP, false); + response.setHeader( + "Content-Type", + "multipart/x-mixed-replace; boundary=" + BOUNDARY, + false + ); + response.write(BOUNDARY + "\r\n"); + response.write(RESPONSE); + response.write(BOUNDARY + "\r\n"); + return; + } + + if (request.queryString == "partcspdoc") { + response.setHeader("Content-Security-Policy", rootCSP, false); + response.setHeader( + "Content-Type", + "multipart/x-mixed-replace; boundary=" + BOUNDARY, + false + ); + response.setStatusLine(request.httpVersion, 200, "OK"); + response.processAsync(); + response.write("--" + BOUNDARY + "\r\n"); + sendNextPart(response, 1); + return; + } + + if (request.queryString == "sendnextpart") { + response.setStatusLine(request.httpVersion, 204, "No content"); + var blockedResponse = getGlobalState("root-document-response"); + if (typeof blockedResponse == "object") { + sendNextPart(blockedResponse, 2); + sendClose(blockedResponse); + } else { + dump("Couldn't find the stored response object."); + } + return; + } + + if (request.queryString == "img") { + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + // we should never get here - return something unexpected + response.write("d'oh"); +} + +function sendClose(response) { + response.write("--" + BOUNDARY + "--\r\n"); + response.finish(); +} + +function sendNextPart(response, partNumber) { + response.write("Content-type: text/html" + "\r\n"); + if (partNumber == 1) { + response.write("Content-Security-Policy:" + part1CSP + "\r\n"); + response.write(RESPONSE1); + setGlobalState(response, "root-document-response"); + } else { + response.write("Content-Security-Policy:" + part2CSP + "\r\n"); + response.write(RESPONSE2); + } + response.write("--" + BOUNDARY + "\r\n"); +} diff --git a/dom/security/test/csp/file_navigate_to.html b/dom/security/test/csp/file_navigate_to.html new file mode 100644 index 0000000000..f6ea36d389 --- /dev/null +++ b/dom/security/test/csp/file_navigate_to.html @@ -0,0 +1,11 @@ + + + + Bug 1529068 Implement CSP 'navigate-to' directive + + + + + diff --git a/dom/security/test/csp/file_navigate_to.sjs b/dom/security/test/csp/file_navigate_to.sjs new file mode 100644 index 0000000000..d1cffb74cc --- /dev/null +++ b/dom/security/test/csp/file_navigate_to.sjs @@ -0,0 +1,58 @@ +// Custom *.sjs file specifically for the needs of +// https://bugzilla.mozilla.org/show_bug.cgi?id=1529068 + +"use strict"; +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const TEST_NAVIGATION_HEAD = ` + + + + Bug 1529068 Implement CSP 'navigate-to' directive`; + +const TEST_NAVIGATION_AFTER_META = ` + + + + + + `; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + if (query.get("redir")) { + response.setStatusLine(request.httpVersion, "302", "Found"); + response.setHeader("Location", query.get("redir"), false); + return; + } + + response.write(TEST_NAVIGATION_HEAD); + + // We need meta to set multiple CSP headers. + if (query.get("csp")) { + response.write( + '' + ); + } + if (query.get("csp2")) { + response.write( + '' + ); + } + + response.write( + TEST_NAVIGATION_AFTER_META + query.get("target") + TEST_NAVIGATION_FOOT + ); +} diff --git a/dom/security/test/csp/file_navigate_to_request.html b/dom/security/test/csp/file_navigate_to_request.html new file mode 100644 index 0000000000..4f82525599 --- /dev/null +++ b/dom/security/test/csp/file_navigate_to_request.html @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/dom/security/test/csp/file_no_log_ignore_xfo.html b/dom/security/test/csp/file_no_log_ignore_xfo.html new file mode 100644 index 0000000000..fc5528a35c --- /dev/null +++ b/dom/security/test/csp/file_no_log_ignore_xfo.html @@ -0,0 +1,10 @@ + + + + + Bug 1722252: "Content-Security-Policy: Ignoring ‘x-frame-options’ because of ‘frame-ancestors’ directive." warning message even when no "x-frame-options" header present + + +
Do not log xfo ignore warning when no xfo is set.
+ + diff --git a/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^ b/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^ new file mode 100644 index 0000000000..1fbbf3de99 --- /dev/null +++ b/dom/security/test/csp/file_no_log_ignore_xfo.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: frame-ancestors http://mochi.test:8888 +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_nonce_redirector.sjs b/dom/security/test/csp/file_nonce_redirector.sjs new file mode 100644 index 0000000000..b56b9ded37 --- /dev/null +++ b/dom/security/test/csp/file_nonce_redirector.sjs @@ -0,0 +1,28 @@ +// custom *.sjs file for +// Bug 1469150:Scripts with valid nonce get blocked if URL redirects. + +const URL_PATH = "example.com/tests/dom/security/test/csp/"; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + let queryStr = request.queryString; + + if (queryStr === "redirect") { + response.setStatusLine("1.1", 302, "Found"); + response.setHeader( + "Location", + "https://" + URL_PATH + "file_nonce_redirector.sjs?load", + false + ); + return; + } + + if (queryStr === "load") { + response.setHeader("Content-Type", "application/javascript", false); + response.write("console.log('script loaded');"); + return; + } + + // we should never get here - return something unexpected + response.write("d'oh"); +} diff --git a/dom/security/test/csp/file_nonce_redirects.html b/dom/security/test/csp/file_nonce_redirects.html new file mode 100644 index 0000000000..e291164900 --- /dev/null +++ b/dom/security/test/csp/file_nonce_redirects.html @@ -0,0 +1,23 @@ + + + + + + Bug 1469150:Scripts with valid nonce get blocked if URL redirects + + + + + + + + diff --git a/dom/security/test/csp/file_nonce_snapshot.sjs b/dom/security/test/csp/file_nonce_snapshot.sjs new file mode 100644 index 0000000000..2b114fd87e --- /dev/null +++ b/dom/security/test/csp/file_nonce_snapshot.sjs @@ -0,0 +1,54 @@ +"use strict"; + +const TEST_FRAME = ` + + + + + + `; + +const SCRIPT = "window.parent.postMessage('script-loaded', '*');"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + let queryString = request.queryString; + + if (queryString === "load-frame") { + response.setHeader( + "Content-Security-Policy", + "script-src 'nonce-123456789'", + false + ); + response.setHeader("Content-Type", "text/html", false); + response.write(TEST_FRAME); + return; + } + + if (queryString === "redir-script") { + response.setStatusLine("1.1", 302, "Found"); + response.setHeader( + "Location", + "file_nonce_snapshot.sjs?load-script", + false + ); + return; + } + + if (queryString === "load-script") { + response.setHeader("Content-Type", "application/javascript", false); + response.write(SCRIPT); + return; + } + + // we should never get here but just in case return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_nonce_source.html b/dom/security/test/csp/file_nonce_source.html new file mode 100644 index 0000000000..01d4046c37 --- /dev/null +++ b/dom/security/test/csp/file_nonce_source.html @@ -0,0 +1,73 @@ + + + + + + + + + + + +
    +
  1. (inline script with correct nonce) This text should be green.
  2. +
  3. (inline script with incorrect nonce) This text should be black.
  4. +
  5. (inline script with correct nonce for styles, but not for scripts) This text should be black.
  6. +
  7. (inline script with no nonce) This text should be black.
  8. +
+ + + + + + + + + + + + + + + + + + + + +
    +
  1. + (inline style with correct nonce) This text should be green +
  2. +
  3. + (inline style with incorrect nonce) This text should be black +
  4. +
  5. + (inline style with correct script, not style, nonce) This text should be black +
  6. +
  7. + (inline style with no nonce) This text should be black +
  8. +
+ + + + + + diff --git a/dom/security/test/csp/file_nonce_source.html^headers^ b/dom/security/test/csp/file_nonce_source.html^headers^ new file mode 100644 index 0000000000..865e5fe984 --- /dev/null +++ b/dom/security/test/csp/file_nonce_source.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: script-src 'self' 'nonce-correctscriptnonce' 'nonce-anothercorrectscriptnonce'; style-src 'nonce-correctstylenonce'; +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_null_baseuri.html b/dom/security/test/csp/file_null_baseuri.html new file mode 100644 index 0000000000..f995688b13 --- /dev/null +++ b/dom/security/test/csp/file_null_baseuri.html @@ -0,0 +1,21 @@ + + + + Bug 1121857 - document.baseURI should not get blocked if baseURI is null + + + + + diff --git a/dom/security/test/csp/file_object_inherit.html b/dom/security/test/csp/file_object_inherit.html new file mode 100644 index 0000000000..76c9764162 --- /dev/null +++ b/dom/security/test/csp/file_object_inherit.html @@ -0,0 +1,21 @@ + + + + Bug 1457100: Test OBJECT inherits CSP if needed + + + + + + + + + + diff --git a/dom/security/test/csp/file_parent_location_js.html b/dom/security/test/csp/file_parent_location_js.html new file mode 100644 index 0000000000..9c56f49905 --- /dev/null +++ b/dom/security/test/csp/file_parent_location_js.html @@ -0,0 +1,18 @@ + + + Test setting parent location to javascript: + + + + + + + diff --git a/dom/security/test/csp/file_path_matching.html b/dom/security/test/csp/file_path_matching.html new file mode 100644 index 0000000000..662fbfb8af --- /dev/null +++ b/dom/security/test/csp/file_path_matching.html @@ -0,0 +1,10 @@ + + + + Bug 808292 - Implement path-level host-source matching to CSP + + +
blocked
+ + + diff --git a/dom/security/test/csp/file_path_matching.js b/dom/security/test/csp/file_path_matching.js new file mode 100644 index 0000000000..09286d42e9 --- /dev/null +++ b/dom/security/test/csp/file_path_matching.js @@ -0,0 +1 @@ +document.getElementById("testdiv").innerHTML = "allowed"; diff --git a/dom/security/test/csp/file_path_matching_incl_query.html b/dom/security/test/csp/file_path_matching_incl_query.html new file mode 100644 index 0000000000..50af2b1437 --- /dev/null +++ b/dom/security/test/csp/file_path_matching_incl_query.html @@ -0,0 +1,10 @@ + + + + Bug 1147026 - CSP should ignore query string when checking a resource load + + +
blocked
+ + + diff --git a/dom/security/test/csp/file_path_matching_redirect.html b/dom/security/test/csp/file_path_matching_redirect.html new file mode 100644 index 0000000000..a16cc90ec6 --- /dev/null +++ b/dom/security/test/csp/file_path_matching_redirect.html @@ -0,0 +1,10 @@ + + + + Bug 808292 - Implement path-level host-source matching to CSP + + +
blocked
+ + + diff --git a/dom/security/test/csp/file_path_matching_redirect_server.sjs b/dom/security/test/csp/file_path_matching_redirect_server.sjs new file mode 100644 index 0000000000..bed3a1dccf --- /dev/null +++ b/dom/security/test/csp/file_path_matching_redirect_server.sjs @@ -0,0 +1,12 @@ +// Redirect server specifically to handle redirects +// for path-level host-source matching +// see https://bugzilla.mozilla.org/show_bug.cgi?id=808292 + +function handleRequest(request, response) { + var newLocation = + "http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js"; + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Location", newLocation, false); +} diff --git a/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html new file mode 100644 index 0000000000..da5c7f0a6e --- /dev/null +++ b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html @@ -0,0 +1,21 @@ + + + + + + +
+ + + + diff --git a/dom/security/test/csp/file_ping.html b/dom/security/test/csp/file_ping.html new file mode 100644 index 0000000000..8aaf34cc3a --- /dev/null +++ b/dom/security/test/csp/file_ping.html @@ -0,0 +1,19 @@ + + + + Bug 1100181 - CSP: Enforce connect-src when submitting pings + + + + + Send ping + + + + + diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html new file mode 100644 index 0000000000..2a75eef7e8 --- /dev/null +++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html @@ -0,0 +1,9 @@ + + + +
Inline script didn't run
+ + + diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^ new file mode 100644 index 0000000000..c4ff8ea9fd --- /dev/null +++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy.html^headers^ @@ -0,0 +1 @@ +content-security-policy-report-only: policy-uri /tests/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy diff --git a/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy b/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy new file mode 100644 index 0000000000..a5c610cd7b --- /dev/null +++ b/dom/security/test/csp/file_policyuri_regression_from_multipolicy_policy @@ -0,0 +1 @@ +default-src 'self'; diff --git a/dom/security/test/csp/file_punycode_host_src.js b/dom/security/test/csp/file_punycode_host_src.js new file mode 100644 index 0000000000..9728e2fecc --- /dev/null +++ b/dom/security/test/csp/file_punycode_host_src.js @@ -0,0 +1,2 @@ +const LOADED = true; +parent.postMessage({ result: "script-allowed" }, "*"); diff --git a/dom/security/test/csp/file_punycode_host_src.sjs b/dom/security/test/csp/file_punycode_host_src.sjs new file mode 100644 index 0000000000..184c6b1041 --- /dev/null +++ b/dom/security/test/csp/file_punycode_host_src.sjs @@ -0,0 +1,47 @@ +// custom *.sjs for Bug 1224225 +// Punycode in CSP host sources + +const HTML_PART1 = + "" + + '' + + "Bug 1224225 - CSP source matching should work for punycoded domain names" + + "" + + "" + + "" + + "" + + ""; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + Components.utils.importGlobalProperties(["URLSearchParams"]); + const query = new URLSearchParams(request.queryString); + + if (query.get("csp")) { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + if (query.get("action") == "script-unicode-csp-punycode") { + response.write(HTML_PART1 + TESTCASE1 + HTML_PART2); + return; + } + if (query.get("action") == "script-punycode-csp-punycode") { + response.write(HTML_PART1 + TESTCASE2 + HTML_PART2); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_redirect_content.sjs b/dom/security/test/csp/file_redirect_content.sjs new file mode 100644 index 0000000000..f1eab21b08 --- /dev/null +++ b/dom/security/test/csp/file_redirect_content.sjs @@ -0,0 +1,41 @@ +// https://bugzilla.mozilla.org/show_bug.cgi?id=650386 +// This SJS file serves file_redirect_content.html +// with a CSP that will trigger a violation and that will report it +// to file_redirect_report.sjs +// +// This handles 301, 302, 303 and 307 redirects. The HTTP status code +// returned/type of redirect to do comes from the query string +// parameter passed in from the test_bug650386_* files and then also +// uses that value in the report-uri parameter of the CSP +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + + // this gets used in the CSP as part of the report URI. + var redirect = request.queryString; + + if (redirect < 301 || (redirect > 303 && redirect <= 306) || redirect > 307) { + // if we somehow got some bogus redirect code here, + // do a 302 redirect to the same URL as the report URI + // redirects to - this will fail the test. + var loc = "http://example.com/some/fake/path"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", loc, false); + return; + } + + var csp = + "default-src 'self';report-uri http://mochi.test:8888/tests/dom/security/test/csp/file_redirect_report.sjs?" + + redirect; + + response.setHeader("Content-Security-Policy", csp, false); + + // the actual file content. + // this image load will (intentionally) fail due to the CSP policy of default-src: 'self' + // specified by the CSP string above. + var content = + ''; + + response.write(content); + + return; +} diff --git a/dom/security/test/csp/file_redirect_report.sjs b/dom/security/test/csp/file_redirect_report.sjs new file mode 100644 index 0000000000..9cc7e65486 --- /dev/null +++ b/dom/security/test/csp/file_redirect_report.sjs @@ -0,0 +1,17 @@ +// https://bugzilla.mozilla.org/show_bug.cgi?id=650386 +// This SJS file serves as CSP violation report target +// and issues a redirect, to make sure the browser does not post to the target +// of the redirect, per CSP spec. +// This handles 301, 302, 303 and 307 redirects. The HTTP status code +// returned/type of redirect to do comes from the query string +// parameter +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + + var redirect = request.queryString; + + var loc = "http://example.com/some/fake/path"; + response.setStatusLine("1.1", redirect, "Found"); + response.setHeader("Location", loc, false); + return; +} diff --git a/dom/security/test/csp/file_redirect_worker.sjs b/dom/security/test/csp/file_redirect_worker.sjs new file mode 100644 index 0000000000..0c1082021a --- /dev/null +++ b/dom/security/test/csp/file_redirect_worker.sjs @@ -0,0 +1,35 @@ +// SJS file to serve resources for CSP redirect tests +// This file redirects to a specified resource. +const THIS_SITE = "http://mochi.test:8888"; +const OTHER_SITE = "http://example.com"; + +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + var resource = query.path; + + response.setHeader("Cache-Control", "no-cache", false); + var loc = ""; + + // redirect to a resource on this site + if (query.redir == "same") { + loc = THIS_SITE + resource + "#" + query.page_id; + } + + // redirect to a resource on a different site + else if (query.redir == "other") { + loc = OTHER_SITE + resource + "#" + query.page_id; + } + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", loc, false); + + response.write( + '' + ); + return; +} diff --git a/dom/security/test/csp/file_redirects_main.html b/dom/security/test/csp/file_redirects_main.html new file mode 100644 index 0000000000..d05af88fe8 --- /dev/null +++ b/dom/security/test/csp/file_redirects_main.html @@ -0,0 +1,37 @@ + + +CSP redirect tests + + +
+ + + + diff --git a/dom/security/test/csp/file_redirects_page.sjs b/dom/security/test/csp/file_redirects_page.sjs new file mode 100644 index 0000000000..31c951cc65 --- /dev/null +++ b/dom/security/test/csp/file_redirects_page.sjs @@ -0,0 +1,141 @@ +// SJS file for CSP redirect mochitests +// This file serves pages which can optionally specify a Content Security Policy +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs"; + + // CSP header value + response.setHeader( + "Content-Security-Policy", + "default-src 'self' blob: ; style-src 'self' 'unsafe-inline'", + false + ); + + // downloadable font that redirects to another site + if (query.testid == "font-src") { + var resp = + '' + + '
test
'; + response.write(resp); + return; + } + + // iframe that redirects to another site + if (query.testid == "frame-src") { + response.write( + '' + ); + return; + } + + // image that redirects to another site + if (query.testid == "img-src") { + response.write( + '' + ); + return; + } + + // video content that redirects to another site + if (query.testid == "media-src") { + response.write( + '' + ); + return; + } + + // object content that redirects to another site + if (query.testid == "object-src") { + response.write( + '' + ); + return; + } + + // external script that redirects to another site + if (query.testid == "script-src") { + response.write( + '' + ); + return; + } + + // external stylesheet that redirects to another site + if (query.testid == "style-src") { + response.write( + '' + ); + return; + } + + // script that XHR's to a resource that redirects to another site + if (query.testid == "xhr-src") { + response.write(''); + return; + } + + // for bug949706 + if (query.testid == "img-src-from-css") { + // loads a stylesheet, which in turn loads an image that redirects. + response.write( + '' + ); + return; + } + + if (query.testid == "from-worker") { + // loads a script; launches a worker; that worker uses importscript; which then gets redirected + // So it's: + // ' + ); + return; + } + + if (query.testid == "from-blob-worker") { + // loads a script; launches a worker; that worker uses importscript; which then gets redirected + // So it's: + // ' + ); + return; + } +} diff --git a/dom/security/test/csp/file_redirects_resource.sjs b/dom/security/test/csp/file_redirects_resource.sjs new file mode 100644 index 0000000000..66551970c8 --- /dev/null +++ b/dom/security/test/csp/file_redirects_resource.sjs @@ -0,0 +1,172 @@ +// SJS file to serve resources for CSP redirect tests +// This file mimics serving resources, e.g. fonts, images, etc., which a CSP +// can include. The resource may redirect to a different resource, if specified. +function handleRequest(request, response) { + var query = {}; + request.queryString.split("&").forEach(function (val) { + var [name, value] = val.split("="); + query[name] = unescape(value); + }); + + var thisSite = "http://mochi.test:8888"; + var otherSite = "http://example.com"; + var resource = "/tests/dom/security/test/csp/file_redirects_resource.sjs"; + + response.setHeader("Cache-Control", "no-cache", false); + + // redirect to a resource on this site + if (query.redir == "same") { + var loc = thisSite + resource + "?res=" + query.res + "&testid=" + query.id; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", loc, false); + return; + } + + // redirect to a resource on a different site + else if (query.redir == "other") { + var loc = + otherSite + resource + "?res=" + query.res + "&testid=" + query.id; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", loc, false); + return; + } + + // not a redirect. serve some content. + // the content doesn't have to be valid, since we're only checking whether + // the request for the content was sent or not. + + // downloadable font + if (query.res == "font") { + response.setHeader("Access-Control-Allow-Origin", "*", false); + response.setHeader("Content-Type", "text/plain", false); + response.write("font data..."); + return; + } + + // iframe with arbitrary content + if (query.res == "iframe") { + response.setHeader("Content-Type", "text/html", false); + response.write("iframe content..."); + return; + } + + // image + if (query.res == "image") { + response.setHeader("Content-Type", "image/gif", false); + response.write("image data..."); + return; + } + + // media content, e.g. Ogg video + if (query.res == "media") { + response.setHeader("Content-Type", "video/ogg", false); + response.write("video data..."); + return; + } + + // plugin content, e.g. + if (query.res == "object") { + response.setHeader("Content-Type", "text/html", false); + response.write("object data..."); + return; + } + + // script + if (query.res == "script") { + response.setHeader("Content-Type", "application/javascript", false); + response.write("some script..."); + return; + } + + // external stylesheet + if (query.res == "style") { + response.setHeader("Content-Type", "text/css", false); + response.write("css data..."); + return; + } + + // internal stylesheet that loads an image from an external site + if (query.res == "cssLoader") { + let bgURL = thisSite + resource + "?redir=other&res=image&id=" + query.id; + response.setHeader("Content-Type", "text/css", false); + response.write("body { background:url('" + bgURL + "'); }"); + return; + } + + // script that loads an internal worker that uses importScripts on a redirect + // to an external script. + if (query.res == "loadWorkerThatMakesRequests") { + // this creates a worker (same origin) that imports a redirecting script. + let workerURL = + thisSite + resource + "?res=makeRequestsWorker&id=" + query.id; + response.setHeader("Content-Type", "application/javascript", false); + response.write("new Worker('" + workerURL + "');"); + return; + } + + // script that loads an internal worker that uses importScripts on a redirect + // to an external script. + if (query.res == "loadBlobWorkerThatMakesRequests") { + // this creates a worker (same origin) that imports a redirecting script. + let workerURL = + thisSite + resource + "?res=makeRequestsWorker&id=" + query.id; + response.setHeader("Content-Type", "application/javascript", false); + response.write( + "var x = new XMLHttpRequest(); x.open('GET', '" + workerURL + "'); " + ); + response.write("x.responseType = 'blob'; x.send(); "); + response.write( + "x.onload = () => { new Worker(URL.createObjectURL(x.response)); };" + ); + return; + } + + // source for a worker that simply calls importScripts on a script that + // redirects. + if (query.res == "makeRequestsWorker") { + // this is code for a worker that imports a redirected script. + let scriptURL = + thisSite + + resource + + "?redir=other&res=script&id=script-src-redir-" + + query.id; + let xhrURL = + thisSite + + resource + + "?redir=other&res=xhr-resp&id=xhr-src-redir-" + + query.id; + let fetchURL = + thisSite + + resource + + "?redir=other&res=xhr-resp&id=fetch-src-redir-" + + query.id; + response.setHeader("Content-Type", "application/javascript", false); + response.write("try { importScripts('" + scriptURL + "'); } catch(ex) {} "); + response.write( + "var x = new XMLHttpRequest(); x.open('GET', '" + xhrURL + "'); x.send();" + ); + response.write("fetch('" + fetchURL + "');"); + return; + } + + // script that invokes XHR + if (query.res == "xhr") { + response.setHeader("Content-Type", "application/javascript", false); + var resp = + 'var x = new XMLHttpRequest();x.open("GET", "' + + thisSite + + resource + + '?redir=other&res=xhr-resp&id=xhr-src-redir", false);\n' + + "x.send(null);"; + response.write(resp); + return; + } + + // response to XHR + if (query.res == "xhr-resp") { + response.setHeader("Access-Control-Allow-Origin", "*", false); + response.setHeader("Content-Type", "text/html", false); + response.write("XHR response..."); + return; + } +} diff --git a/dom/security/test/csp/file_report.html b/dom/security/test/csp/file_report.html new file mode 100644 index 0000000000..fb18af8057 --- /dev/null +++ b/dom/security/test/csp/file_report.html @@ -0,0 +1,13 @@ + + + + Bug 1033424 - Test csp-report properties + + + + + diff --git a/dom/security/test/csp/file_report_chromescript.js b/dom/security/test/csp/file_report_chromescript.js new file mode 100644 index 0000000000..56364605dc --- /dev/null +++ b/dom/security/test/csp/file_report_chromescript.js @@ -0,0 +1,65 @@ +/* eslint-env mozilla/chrome-script */ + +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +Cu.importGlobalProperties(["TextDecoder"]); + +const reportURI = "http://mochi.test:8888/foo.sjs"; + +var openingObserver = { + observe(subject, topic, data) { + // subject should be an nsURI + if (subject.QueryInterface == undefined) { + return; + } + + var message = { report: "", error: false }; + + if (topic == "http-on-opening-request") { + var asciiSpec = subject.QueryInterface(Ci.nsIHttpChannel).URI.asciiSpec; + if (asciiSpec !== reportURI) { + return; + } + + var reportText = false; + try { + // Verify that the report was properly formatted. + // We'll parse the report text as JSON and verify that the properties + // have expected values. + var reportText = "{}"; + var uploadStream = subject.QueryInterface( + Ci.nsIUploadChannel + ).uploadStream; + + if (uploadStream) { + // get the bytes from the request body + var binstream = Cc["@mozilla.org/binaryinputstream;1"].createInstance( + Ci.nsIBinaryInputStream + ); + binstream.setInputStream(uploadStream); + + let bytes = NetUtil.readInputStream(binstream); + + // rewind stream as we are supposed to - there will be an assertion later if we don't. + uploadStream + .QueryInterface(Ci.nsISeekableStream) + .seek(Ci.nsISeekableStream.NS_SEEK_SET, 0); + + let textDecoder = new TextDecoder(); + reportText = textDecoder.decode(bytes); + } + + message.report = reportText; + } catch (e) { + message.error = e.toString(); + } + + sendAsyncMessage("opening-request-completed", message); + } + }, +}; + +Services.obs.addObserver(openingObserver, "http-on-opening-request"); +addMessageListener("finish", function () { + Services.obs.removeObserver(openingObserver, "http-on-opening-request"); +}); diff --git a/dom/security/test/csp/file_report_font_cache-1.html b/dom/security/test/csp/file_report_font_cache-1.html new file mode 100644 index 0000000000..59b4908f83 --- /dev/null +++ b/dom/security/test/csp/file_report_font_cache-1.html @@ -0,0 +1,26 @@ + + +

A

+

A

+

A

+ diff --git a/dom/security/test/csp/file_report_font_cache-2.html b/dom/security/test/csp/file_report_font_cache-2.html new file mode 100644 index 0000000000..cea9cea663 --- /dev/null +++ b/dom/security/test/csp/file_report_font_cache-2.html @@ -0,0 +1,25 @@ + + +

A

+ diff --git a/dom/security/test/csp/file_report_font_cache-2.html^headers^ b/dom/security/test/csp/file_report_font_cache-2.html^headers^ new file mode 100644 index 0000000000..493f850baa --- /dev/null +++ b/dom/security/test/csp/file_report_font_cache-2.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: font-src 'none'; report-uri http://mochi.test:8888/foo.sjs diff --git a/dom/security/test/csp/file_report_for_import.css b/dom/security/test/csp/file_report_for_import.css new file mode 100644 index 0000000000..b578b77b33 --- /dev/null +++ b/dom/security/test/csp/file_report_for_import.css @@ -0,0 +1 @@ +@import url("http://example.com/tests/dom/security/test/csp/file_report_for_import_server.sjs?stylesheet"); diff --git a/dom/security/test/csp/file_report_for_import.html b/dom/security/test/csp/file_report_for_import.html new file mode 100644 index 0000000000..77a36faea1 --- /dev/null +++ b/dom/security/test/csp/file_report_for_import.html @@ -0,0 +1,10 @@ + + + + Bug 1048048 - Test sending csp-report when using import in css + + + + empty body, just testing @import in the included css for bug 1048048 + + diff --git a/dom/security/test/csp/file_report_for_import_server.sjs b/dom/security/test/csp/file_report_for_import_server.sjs new file mode 100644 index 0000000000..624c7e657b --- /dev/null +++ b/dom/security/test/csp/file_report_for_import_server.sjs @@ -0,0 +1,50 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1048048 - CSP violation report not sent for @import + +const CC = Components.Constructor; +const BinaryInputStream = CC( + "@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream" +); + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + var queryString = request.queryString; + + // (1) lets process the queryresult request async and + // wait till we have received the image request. + if (queryString === "queryresult") { + response.processAsync(); + setObjectState("queryResult", response); + return; + } + + // (2) handle the csp-report and return the JSON back to + // the testfile using the afore stored xml request in (1). + if (queryString === "report") { + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + + // send the report back to the XML request for verification + var report = new BinaryInputStream(request.bodyInputStream); + var avail; + var bytes = []; + while ((avail = report.available()) > 0) { + Array.prototype.push.apply(bytes, report.readByteArray(avail)); + } + var data = String.fromCharCode.apply(null, bytes); + queryResponse.bodyOutputStream.write(data, data.length); + queryResponse.finish(); + }); + return; + } + + // we should not get here ever, but just in case return + // something unexpected. + response.write("doh!"); +} diff --git a/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^ b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^ new file mode 100644 index 0000000000..3f2fdfe9e6 --- /dev/null +++ b/dom/security/test/csp/file_report_uri_missing_in_report_only_header.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy-Report-Only: default-src 'self'; diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html b/dom/security/test/csp/file_ro_ignore_xfo.html new file mode 100644 index 0000000000..85e7f0092c --- /dev/null +++ b/dom/security/test/csp/file_ro_ignore_xfo.html @@ -0,0 +1,10 @@ + + + + + Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists + + +
Ignoring XFO because of CSP_RO
+ + \ No newline at end of file diff --git a/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ new file mode 100644 index 0000000000..ab8366f061 --- /dev/null +++ b/dom/security/test/csp/file_ro_ignore_xfo.html^headers^ @@ -0,0 +1,3 @@ +Content-Security-Policy-Report-Only: frame-ancestors http://mochi.test:8888 +X-Frame-Options: deny +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_sandbox_1.html b/dom/security/test/csp/file_sandbox_1.html new file mode 100644 index 0000000000..ce1e80c865 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_1.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_10.html b/dom/security/test/csp/file_sandbox_10.html new file mode 100644 index 0000000000..f934497eee --- /dev/null +++ b/dom/security/test/csp/file_sandbox_10.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_11.html b/dom/security/test/csp/file_sandbox_11.html new file mode 100644 index 0000000000..087b5651a9 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_11.html @@ -0,0 +1,25 @@ + + + + + + + I am sandboxed but with only inline "allow-scripts" + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_12.html b/dom/security/test/csp/file_sandbox_12.html new file mode 100644 index 0000000000..79631bd394 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_12.html @@ -0,0 +1,40 @@ + + + + + + + + + + I am sandboxed but with "allow-same-origin" and allow-scripts" + + + + + + + + +
+ First name: + Last name: + +
+ + click me + + diff --git a/dom/security/test/csp/file_sandbox_13.html b/dom/security/test/csp/file_sandbox_13.html new file mode 100644 index 0000000000..96286db8d5 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_13.html @@ -0,0 +1,25 @@ + + + + + + + I am sandboxed but with only inline "allow-scripts" + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_2.html b/dom/security/test/csp/file_sandbox_2.html new file mode 100644 index 0000000000..b37aa1bcef --- /dev/null +++ b/dom/security/test/csp/file_sandbox_2.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_3.html b/dom/security/test/csp/file_sandbox_3.html new file mode 100644 index 0000000000..ba808e47d5 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_3.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_4.html b/dom/security/test/csp/file_sandbox_4.html new file mode 100644 index 0000000000..b2d4ed0940 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_4.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_5.html b/dom/security/test/csp/file_sandbox_5.html new file mode 100644 index 0000000000..c08849b689 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_5.html @@ -0,0 +1,26 @@ + + + + + + + I am sandboxed but with only inline "allow-scripts" + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_6.html b/dom/security/test/csp/file_sandbox_6.html new file mode 100644 index 0000000000..44705f4d2b --- /dev/null +++ b/dom/security/test/csp/file_sandbox_6.html @@ -0,0 +1,35 @@ + + + + + + + + + + I am sandboxed but with "allow-same-origin" and allow-scripts" + + + +
+ First name: + Last name: + +
+ + click me + + diff --git a/dom/security/test/csp/file_sandbox_7.html b/dom/security/test/csp/file_sandbox_7.html new file mode 100644 index 0000000000..3b249d4101 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_7.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_8.html b/dom/security/test/csp/file_sandbox_8.html new file mode 100644 index 0000000000..4f9cd89161 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_8.html @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_9.html b/dom/security/test/csp/file_sandbox_9.html new file mode 100644 index 0000000000..29ffc191cd --- /dev/null +++ b/dom/security/test/csp/file_sandbox_9.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html b/dom/security/test/csp/file_sandbox_allow_scripts.html new file mode 100644 index 0000000000..faab9f0fc6 --- /dev/null +++ b/dom/security/test/csp/file_sandbox_allow_scripts.html @@ -0,0 +1,12 @@ + + + + + Bug 1396320: Fix CSP sandbox regression for allow-scripts + + + + + diff --git a/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ new file mode 100644 index 0000000000..4705ce9ded --- /dev/null +++ b/dom/security/test/csp/file_sandbox_allow_scripts.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: sandbox allow-scripts; diff --git a/dom/security/test/csp/file_sandbox_fail.js b/dom/security/test/csp/file_sandbox_fail.js new file mode 100644 index 0000000000..7f43927ddf --- /dev/null +++ b/dom/security/test/csp/file_sandbox_fail.js @@ -0,0 +1,7 @@ +function ok(result, desc) { + window.parent.postMessage({ ok: result, desc }, "*"); +} +ok( + false, + "documents sandboxed with allow-scripts should NOT be able to run " + + // have an inline script that reports back to the parent whether + // the script got loaded or not from within the sandboxed iframe. + "" + + "" + + ""; + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Content-Security-Policy", policy, false); + + response.write(html); +} diff --git a/dom/security/test/csp/file_script_template.html b/dom/security/test/csp/file_script_template.html new file mode 100644 index 0000000000..3819592912 --- /dev/null +++ b/dom/security/test/csp/file_script_template.html @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/dom/security/test/csp/file_script_template.js b/dom/security/test/csp/file_script_template.js new file mode 100644 index 0000000000..d75869f763 --- /dev/null +++ b/dom/security/test/csp/file_script_template.js @@ -0,0 +1 @@ +// dummy *.js file diff --git a/dom/security/test/csp/file_self_none_as_hostname_confusion.html b/dom/security/test/csp/file_self_none_as_hostname_confusion.html new file mode 100644 index 0000000000..16196bb19f --- /dev/null +++ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html @@ -0,0 +1,11 @@ + + + + + Bug 587377 - CSP keywords "'self'" and "'none'" are easy to confuse with host names "self" and "none" + + + + + diff --git a/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^ new file mode 100644 index 0000000000..26af7ed9b5 --- /dev/null +++ b/dom/security/test/csp/file_self_none_as_hostname_confusion.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' SELF; diff --git a/dom/security/test/csp/file_sendbeacon.html b/dom/security/test/csp/file_sendbeacon.html new file mode 100644 index 0000000000..13202c65ff --- /dev/null +++ b/dom/security/test/csp/file_sendbeacon.html @@ -0,0 +1,21 @@ + + + + + + Bug 1234813 - sendBeacon should not throw if blocked by Content Policy + + + + + + + diff --git a/dom/security/test/csp/file_service_worker.html b/dom/security/test/csp/file_service_worker.html new file mode 100644 index 0000000000..b819946983 --- /dev/null +++ b/dom/security/test/csp/file_service_worker.html @@ -0,0 +1,21 @@ + + + + Bug 1208559 - ServiceWorker registration not governed by CSP + + + + + diff --git a/dom/security/test/csp/file_service_worker.js b/dom/security/test/csp/file_service_worker.js new file mode 100644 index 0000000000..1bf583f4cc --- /dev/null +++ b/dom/security/test/csp/file_service_worker.js @@ -0,0 +1 @@ +dump("service workers: hello world"); diff --git a/dom/security/test/csp/file_spawn_service_worker.js b/dom/security/test/csp/file_spawn_service_worker.js new file mode 100644 index 0000000000..b262fa10a3 --- /dev/null +++ b/dom/security/test/csp/file_spawn_service_worker.js @@ -0,0 +1 @@ +// dummy file diff --git a/dom/security/test/csp/file_spawn_shared_worker.js b/dom/security/test/csp/file_spawn_shared_worker.js new file mode 100644 index 0000000000..e4f53b9ce1 --- /dev/null +++ b/dom/security/test/csp/file_spawn_shared_worker.js @@ -0,0 +1,7 @@ +onconnect = function (e) { + var port = e.ports[0]; + port.addEventListener("message", function (e) { + port.postMessage("shared worker is executing"); + }); + port.start(); +}; diff --git a/dom/security/test/csp/file_spawn_worker.js b/dom/security/test/csp/file_spawn_worker.js new file mode 100644 index 0000000000..acde7408c1 --- /dev/null +++ b/dom/security/test/csp/file_spawn_worker.js @@ -0,0 +1 @@ +postMessage("worker is executing"); diff --git a/dom/security/test/csp/file_strict_dynamic.js b/dom/security/test/csp/file_strict_dynamic.js new file mode 100644 index 0000000000..09286d42e9 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic.js @@ -0,0 +1 @@ +document.getElementById("testdiv").innerHTML = "allowed"; diff --git a/dom/security/test/csp/file_strict_dynamic_default_src.html b/dom/security/test/csp/file_strict_dynamic_default_src.html new file mode 100644 index 0000000000..0ea79e2a96 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_default_src.html @@ -0,0 +1,20 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + + +
blocked
+ + + + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_default_src.js b/dom/security/test/csp/file_strict_dynamic_default_src.js new file mode 100644 index 0000000000..09286d42e9 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_default_src.js @@ -0,0 +1 @@ +document.getElementById("testdiv").innerHTML = "allowed"; diff --git a/dom/security/test/csp/file_strict_dynamic_js_url.html b/dom/security/test/csp/file_strict_dynamic_js_url.html new file mode 100644 index 0000000000..bd53b0adb2 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_js_url.html @@ -0,0 +1,15 @@ + + + + Bug 1316826 - 'strict-dynamic' blocking DOM event handlers + + +
blocked
+ +click me + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html new file mode 100644 index 0000000000..c51fefd72e --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted.html @@ -0,0 +1,17 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html new file mode 100644 index 0000000000..10a0f32e4b --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_non_parser_inserted_inline.html @@ -0,0 +1,16 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html new file mode 100644 index 0000000000..2a3a7d4998 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write.html @@ -0,0 +1,15 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html new file mode 100644 index 0000000000..9938ef2dcd --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html @@ -0,0 +1,15 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_script_events.html b/dom/security/test/csp/file_strict_dynamic_script_events.html new file mode 100644 index 0000000000..0889583821 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_script_events.html @@ -0,0 +1,14 @@ + + + + Bug 1316826 - 'strict-dynamic' blocking DOM event handlers + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html b/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html new file mode 100644 index 0000000000..701ef32269 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_script_events_marquee.html @@ -0,0 +1,14 @@ + + + + Bug 1316826 - 'strict-dynamic' blocking DOM event handlers + + +
blocked
+ + + Bug 1316826 + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_script_extern.html b/dom/security/test/csp/file_strict_dynamic_script_extern.html new file mode 100644 index 0000000000..94b6aefb19 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_script_extern.html @@ -0,0 +1,10 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + diff --git a/dom/security/test/csp/file_strict_dynamic_script_inline.html b/dom/security/test/csp/file_strict_dynamic_script_inline.html new file mode 100644 index 0000000000..d17a58f279 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_script_inline.html @@ -0,0 +1,14 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + diff --git a/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html b/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html new file mode 100644 index 0000000000..f0b26da915 --- /dev/null +++ b/dom/security/test/csp/file_strict_dynamic_unsafe_eval.html @@ -0,0 +1,14 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + +
blocked
+ + + + + \ No newline at end of file diff --git a/dom/security/test/csp/file_subframe_run_js_if_allowed.html b/dom/security/test/csp/file_subframe_run_js_if_allowed.html new file mode 100644 index 0000000000..3ba970ce84 --- /dev/null +++ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html @@ -0,0 +1,13 @@ + + + +click + + diff --git a/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^ new file mode 100644 index 0000000000..233b359310 --- /dev/null +++ b/dom/security/test/csp/file_subframe_run_js_if_allowed.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src *; script-src 'unsafe-inline' diff --git a/dom/security/test/csp/file_svg_inline_style_base.html b/dom/security/test/csp/file_svg_inline_style_base.html new file mode 100644 index 0000000000..4d7ce0cd6e --- /dev/null +++ b/dom/security/test/csp/file_svg_inline_style_base.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dom/security/test/csp/file_svg_inline_style_csp.html b/dom/security/test/csp/file_svg_inline_style_csp.html new file mode 100644 index 0000000000..040ee02e19 --- /dev/null +++ b/dom/security/test/csp/file_svg_inline_style_csp.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/dom/security/test/csp/file_svg_inline_style_server.sjs b/dom/security/test/csp/file_svg_inline_style_server.sjs new file mode 100644 index 0000000000..6073f36f62 --- /dev/null +++ b/dom/security/test/csp/file_svg_inline_style_server.sjs @@ -0,0 +1,43 @@ +"use strict"; + +const SVG_IMG = ` + + + `; + +const SVG_IMG_NO_INLINE_STYLE = ` + + `; + +function handleRequest(request, response) { + const query = request.queryString; + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "image/svg+xml", false); + + if (query.includes("svg_inline_style_csp")) { + response.setHeader("Content-Security-Policy", "default-src 'none'", false); + response.write(SVG_IMG); + return; + } + + if (query.includes("svg_inline_style_nocsp")) { + response.write(SVG_IMG); + return; + } + + if (query.includes("svg_no_inline_style")) { + response.write(SVG_IMG_NO_INLINE_STYLE); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_svg_srcset_inline_style_base.html b/dom/security/test/csp/file_svg_srcset_inline_style_base.html new file mode 100644 index 0000000000..1754c557f0 --- /dev/null +++ b/dom/security/test/csp/file_svg_srcset_inline_style_base.html @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dom/security/test/csp/file_svg_srcset_inline_style_csp.html b/dom/security/test/csp/file_svg_srcset_inline_style_csp.html new file mode 100644 index 0000000000..418d714882 --- /dev/null +++ b/dom/security/test/csp/file_svg_srcset_inline_style_csp.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/dom/security/test/csp/file_test_browser_bookmarklets.html b/dom/security/test/csp/file_test_browser_bookmarklets.html new file mode 100644 index 0000000000..cb12e4efd0 --- /dev/null +++ b/dom/security/test/csp/file_test_browser_bookmarklets.html @@ -0,0 +1,12 @@ + + + + + + + Document + + +

Test-Document

+ + \ No newline at end of file diff --git a/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^ b/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^ new file mode 100644 index 0000000000..e138f234fb --- /dev/null +++ b/dom/security/test/csp/file_test_browser_bookmarklets.html^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: script-src 'none' +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_testserver.sjs b/dom/security/test/csp/file_testserver.sjs new file mode 100644 index 0000000000..0363fc2c7a --- /dev/null +++ b/dom/security/test/csp/file_testserver.sjs @@ -0,0 +1,67 @@ +// SJS file for CSP mochitests +"use strict"; +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); +Components.utils.importGlobalProperties(["URLSearchParams"]); + +function loadHTMLFromFile(path) { + // Load the HTML to return in the response from file. + // Since it's relative to the cwd of the test runner, we start there and + // append to get to the actual path of the file. + const testHTMLFile = Components.classes[ + "@mozilla.org/file/directory_service;1" + ] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + + const testHTMLFileStream = Components.classes[ + "@mozilla.org/network/file-input-stream;1" + ].createInstance(Components.interfaces.nsIFileInputStream); + + path + .split("/") + .filter(path => path) + .reduce((file, path) => { + testHTMLFile.append(path); + return testHTMLFile; + }, testHTMLFile); + testHTMLFileStream.init(testHTMLFile, -1, 0, 0); + const isAvailable = testHTMLFileStream.available(); + return NetUtil.readInputStreamToString(testHTMLFileStream, isAvailable); +} + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // Deliver the CSP policy encoded in the URL + if (query.has("csp")) { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + + // Deliver the CSP report-only policy encoded in the URI + if (query.has("cspRO")) { + response.setHeader( + "Content-Security-Policy-Report-Only", + query.get("cspRO"), + false + ); + } + + // Deliver the CORS header in the URL + if (query.has("cors")) { + response.setHeader("Access-Control-Allow-Origin", query.get("cors"), false); + } + + // Send HTML to test allowed/blocked behaviors + let type = "text/html"; + if (query.has("type")) { + type = query.get("type"); + } + + response.setHeader("Content-Type", type, false); + if (query.has("file")) { + response.write(loadHTMLFromFile(query.get("file"))); + } +} diff --git a/dom/security/test/csp/file_uir_top_nav.html b/dom/security/test/csp/file_uir_top_nav.html new file mode 100644 index 0000000000..28263e9db7 --- /dev/null +++ b/dom/security/test/csp/file_uir_top_nav.html @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/dom/security/test/csp/file_uir_top_nav_dummy.html b/dom/security/test/csp/file_uir_top_nav_dummy.html new file mode 100644 index 0000000000..65762f1c71 --- /dev/null +++ b/dom/security/test/csp/file_uir_top_nav_dummy.html @@ -0,0 +1,12 @@ + + + +just a dummy page to check uir applies to top level navigations + + + diff --git a/dom/security/test/csp/file_upgrade_insecure.html b/dom/security/test/csp/file_upgrade_insecure.html new file mode 100644 index 0000000000..9c4ba597f3 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure.html @@ -0,0 +1,90 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + + + + + + + + + + + + + + + +
foo
+ + + + + + + + + + + + +
+ + +
+ + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_cors.html b/dom/security/test/csp/file_upgrade_insecure_cors.html new file mode 100644 index 0000000000..e675c62e9f --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_cors.html @@ -0,0 +1,49 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs b/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs new file mode 100644 index 0000000000..83957560c3 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs @@ -0,0 +1,61 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1139297 - Implement CSP upgrade-insecure-requests directive + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // perform sanity check and make sure that all requests get upgraded to use https + if (request.scheme !== "https") { + response.write("request not https"); + return; + } + + var queryString = request.queryString; + + // TEST 1 + if (queryString === "test1") { + var newLocation = + "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test1"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + if (queryString === "redir-test1") { + response.write("test1-no-cors-ok"); + return; + } + + // TEST 2 + if (queryString === "test2") { + var newLocation = + "http://test1.example.com:443/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test2"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + if (queryString === "redir-test2") { + response.write("test2-no-cors-diffport-ok"); + return; + } + + // TEST 3 + response.setHeader("Access-Control-Allow-Headers", "content-type", false); + response.setHeader("Access-Control-Allow-Methods", "POST, GET", false); + response.setHeader("Access-Control-Allow-Origin", "*", false); + + if (queryString === "test3") { + var newLocation = + "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_cors_server.sjs?redir-test3"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + if (queryString === "redir-test3") { + response.write("test3-cors-ok"); + return; + } + + // we should not get here, but just in case return something unexpected + response.write("d'oh"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs b/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs new file mode 100644 index 0000000000..a7fb0a2176 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs @@ -0,0 +1,55 @@ +// custom *.sjs for Bug 1273430 +// META CSP: upgrade-insecure-requests + +// important: the IFRAME_URL is *http* and needs to be upgraded to *https* by upgrade-insecure-requests +const IFRAME_URL = + "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_docwrite_iframe.sjs?docwriteframe"; + +const TEST_FRAME = + ` + + + TEST_FRAME + + + + + + `; + +// doc.write(iframe) sends a post message to the parent indicating the current +// location so the parent can make sure the request was upgraded to *https*. +const DOC_WRITE_FRAME = ` + + + DOC_WRITE_FRAME + + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + var queryString = request.queryString; + + if (queryString === "testframe") { + response.write(TEST_FRAME); + return; + } + + if (queryString === "docwriteframe") { + response.write(DOC_WRITE_FRAME); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback.html b/dom/security/test/csp/file_upgrade_insecure_loopback.html new file mode 100644 index 0000000000..b824604b6e --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_loopback.html @@ -0,0 +1,25 @@ + + + + + Bug 1447784 - Implement CSP upgrade-insecure-requests directive + + + + + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback_form.html b/dom/security/test/csp/file_upgrade_insecure_loopback_form.html new file mode 100644 index 0000000000..ed6b3b8542 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_loopback_form.html @@ -0,0 +1,17 @@ + + + + + Bug 1661423 - don't apply upgrade-insecure-requests on form submissions to localhost + + + +
+ +
> + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs b/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs new file mode 100644 index 0000000000..ff7931a1d4 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_loopback_server.sjs @@ -0,0 +1,22 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1447784 - Implement CSP upgrade-insecure-requests directive + +function handleRequest(request, response) { + response.setHeader("Access-Control-Allow-Headers", "content-type", false); + response.setHeader("Access-Control-Allow-Methods", "GET", false); + response.setHeader("Access-Control-Allow-Origin", "*", false); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // perform sanity check and make sure that all requests get upgraded to use https + if (request.scheme !== "https") { + response.write("request-not-https"); + return; + } else { + response.write("request-is-https"); + } + + // we should not get here, but just in case return something unexpected + response.write("d'oh"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_meta.html b/dom/security/test/csp/file_upgrade_insecure_meta.html new file mode 100644 index 0000000000..a84a8c254d --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_meta.html @@ -0,0 +1,86 @@ + + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + + + + + + + + + + + + + + + +
foo
+ + + + + + + + + + + + +
+ + +
+ + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs new file mode 100644 index 0000000000..51afa39bf7 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_navigation.sjs @@ -0,0 +1,79 @@ +// Custom *.sjs file specifically for the needs of +// https://bugzilla.mozilla.org/show_bug.cgi?id=1271173 + +"use strict"; +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const TEST_NAVIGATIONAL_UPGRADE = ` + + + + + clickme + + + `; + +const FRAME_NAV = ` + + + + + + + `; + +const DOC_NAV = ` + + + + + + + `; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + if (query.get("csp")) { + response.setHeader("Content-Security-Policy", query.get("csp"), false); + } + + if (query.get("action") === "perform_navigation") { + response.write(TEST_NAVIGATIONAL_UPGRADE); + return; + } + + if (query.get("action") === "framenav") { + response.write(FRAME_NAV); + return; + } + + if (query.get("action") === "docnav") { + response.write(DOC_NAV); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs new file mode 100644 index 0000000000..3f7f8158e0 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs @@ -0,0 +1,50 @@ +"use strict"; + +const FINAL_DOCUMENT = ` + + + final document + + + `; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + const query = request.queryString; + + if (query === "same_origin_redirect") { + let newLocation = + "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?finaldoc_same_origin_redirect"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + + if (query === "cross_origin_redirect") { + let newLocation = + "http://test1.example.com/tests/dom/security/test/csp/file_upgrade_insecure_navigation_redirect.sjs?finaldoc_cross_origin_redirect"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + + if ( + query === "finaldoc_same_origin_redirect" || + query === "finaldoc_cross_origin_redirect" + ) { + response.write(FINAL_DOCUMENT); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html new file mode 100644 index 0000000000..dff2c9faf3 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_cross_origin.html @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html new file mode 100644 index 0000000000..811850e08c --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_navigation_redirect_same_origin.html @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_reporting.html b/dom/security/test/csp/file_upgrade_insecure_reporting.html new file mode 100644 index 0000000000..c78e9a784d --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_reporting.html @@ -0,0 +1,23 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs b/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs new file mode 100644 index 0000000000..e5ea844bba --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs @@ -0,0 +1,87 @@ +// Custom *.sjs specifically for the needs of Bug +// Bug 1139297 - Implement CSP upgrade-insecure-requests directive + +const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm"); + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const REPORT_URI = + "https://example.com/tests/dom/security/test/csp/file_upgrade_insecure_reporting_server.sjs?report"; +const POLICY = "upgrade-insecure-requests; default-src https: 'unsafe-inline'"; +const POLICY_RO = + "default-src https: 'unsafe-inline'; report-uri " + REPORT_URI; + +function loadHTMLFromFile(path) { + // Load the HTML to return in the response from file. + // Since it's relative to the cwd of the test runner, we start there and + // append to get to the actual path of the file. + var testHTMLFile = Components.classes["@mozilla.org/file/directory_service;1"] + .getService(Components.interfaces.nsIProperties) + .get("CurWorkD", Components.interfaces.nsIFile); + var dirs = path.split("/"); + for (var i = 0; i < dirs.length; i++) { + testHTMLFile.append(dirs[i]); + } + var testHTMLFileStream = Components.classes[ + "@mozilla.org/network/file-input-stream;1" + ].createInstance(Components.interfaces.nsIFileInputStream); + testHTMLFileStream.init(testHTMLFile, -1, 0, 0); + var testHTML = NetUtil.readInputStreamToString( + testHTMLFileStream, + testHTMLFileStream.available() + ); + return testHTML; +} + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // (1) Store the query that will report back whether the violation report was received + if (request.queryString == "queryresult") { + response.processAsync(); + setObjectState("queryResult", response); + return; + } + + // (2) We load a page using a CSP and a report only CSP + if (request.queryString == "toplevel") { + response.setHeader("Content-Security-Policy", POLICY, false); + response.setHeader("Content-Security-Policy-Report-Only", POLICY_RO, false); + response.setHeader("Content-Type", "text/html", false); + response.write( + loadHTMLFromFile( + "tests/dom/security/test/csp/file_upgrade_insecure_reporting.html" + ) + ); + return; + } + + // (3) Return the image back to the client + if (request.queryString == "img") { + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + // (4) Finally we receive the report, let's return the request from (1) + // signaling that we received the report correctly + if (request.queryString == "report") { + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + queryResponse.write("report-ok"); + queryResponse.finish(); + }); + return; + } + + // we should never get here, but just in case ... + response.setHeader("Content-Type", "text/plain"); + response.write("doh!"); +} diff --git a/dom/security/test/csp/file_upgrade_insecure_server.sjs b/dom/security/test/csp/file_upgrade_insecure_server.sjs new file mode 100644 index 0000000000..05d027c078 --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_server.sjs @@ -0,0 +1,112 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1139297 - Implement CSP upgrade-insecure-requests directive + +const TOTAL_EXPECTED_REQUESTS = 11; + +const IFRAME_CONTENT = + "" + + "" + + "" + + "Bug 1139297 - Implement CSP upgrade-insecure-requests directive" + + "" + + "" + + "" + + "" + + ""; + +const expectedQueries = [ + "script", + "style", + "img", + "iframe", + "form", + "xhr", + "media", + "object", + "font", + "img-redir", + "nested-img", +]; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + var queryString = request.queryString; + + // initialize server variables and save the object state + // of the initial request, which returns async once the + // server has processed all requests. + if (queryString == "queryresult") { + setState("totaltests", TOTAL_EXPECTED_REQUESTS.toString()); + setState("receivedQueries", ""); + response.processAsync(); + setObjectState("queryResult", response); + return; + } + + // handle img redirect (https->http) + if (queryString == "redirect-image") { + var newLocation = + "http://example.com/tests/dom/security/test/csp/file_upgrade_insecure_server.sjs?img-redir"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + + // just in case error handling for unexpected queries + if (expectedQueries.indexOf(queryString) == -1) { + response.write("doh!"); + return; + } + + // make sure all the requested queries are indeed https + queryString += request.scheme == "https" ? "-ok" : "-error"; + + var receivedQueries = getState("receivedQueries"); + + // images, scripts, etc. get queried twice, do not + // confuse the server by storing the preload as + // well as the actual load. If either the preload + // or the actual load is not https, then we would + // append "-error" in the array and the test would + // fail at the end. + if (receivedQueries.includes(queryString)) { + return; + } + + // append the result to the total query string array + if (receivedQueries != "") { + receivedQueries += ","; + } + receivedQueries += queryString; + setState("receivedQueries", receivedQueries); + + // keep track of how many more requests the server + // is expecting + var totaltests = parseInt(getState("totaltests")); + totaltests -= 1; + setState("totaltests", totaltests.toString()); + + // return content (img) for the nested iframe to test + // that subresource requests within nested contexts + // get upgraded as well. We also have to return + // the iframe context in case of an error so we + // can test both, using upgrade-insecure as well + // as the base case of not using upgrade-insecure. + if (queryString == "iframe-ok" || queryString == "iframe-error") { + response.write(IFRAME_CONTENT); + } + + // if we have received all the requests, we return + // the result back. + if (totaltests == 0) { + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + var receivedQueries = getState("receivedQueries"); + queryResponse.write(receivedQueries); + queryResponse.finish(); + }); + } +} diff --git a/dom/security/test/csp/file_upgrade_insecure_wsh.py b/dom/security/test/csp/file_upgrade_insecure_wsh.py new file mode 100644 index 0000000000..b7159c742b --- /dev/null +++ b/dom/security/test/csp/file_upgrade_insecure_wsh.py @@ -0,0 +1,6 @@ +def web_socket_do_extra_handshake(request): + pass + + +def web_socket_transfer_data(request): + pass diff --git a/dom/security/test/csp/file_web_manifest.html b/dom/security/test/csp/file_web_manifest.html new file mode 100644 index 0000000000..0f6a67460e --- /dev/null +++ b/dom/security/test/csp/file_web_manifest.html @@ -0,0 +1,6 @@ + + + + + +

Support Page for Web Manifest Tests

\ No newline at end of file diff --git a/dom/security/test/csp/file_web_manifest.json b/dom/security/test/csp/file_web_manifest.json new file mode 100644 index 0000000000..eb88b50445 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest.json @@ -0,0 +1 @@ +{ "name": "loaded" } diff --git a/dom/security/test/csp/file_web_manifest.json^headers^ b/dom/security/test/csp/file_web_manifest.json^headers^ new file mode 100644 index 0000000000..e0e00c4be0 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest.json^headers^ @@ -0,0 +1 @@ +Access-Control-Allow-Origin: http://example.org \ No newline at end of file diff --git a/dom/security/test/csp/file_web_manifest_https.html b/dom/security/test/csp/file_web_manifest_https.html new file mode 100644 index 0000000000..b0ff9ef853 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest_https.html @@ -0,0 +1,4 @@ + + + +

Support Page for Web Manifest Tests

\ No newline at end of file diff --git a/dom/security/test/csp/file_web_manifest_https.json b/dom/security/test/csp/file_web_manifest_https.json new file mode 100644 index 0000000000..eb88b50445 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest_https.json @@ -0,0 +1 @@ +{ "name": "loaded" } diff --git a/dom/security/test/csp/file_web_manifest_mixed_content.html b/dom/security/test/csp/file_web_manifest_mixed_content.html new file mode 100644 index 0000000000..55f17c0f92 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest_mixed_content.html @@ -0,0 +1,9 @@ + + + + + +

Support Page for Web Manifest Tests

+

Used to try to load a resource over an insecure connection to trigger mixed content blocking.

\ No newline at end of file diff --git a/dom/security/test/csp/file_web_manifest_remote.html b/dom/security/test/csp/file_web_manifest_remote.html new file mode 100644 index 0000000000..7ecf8eec43 --- /dev/null +++ b/dom/security/test/csp/file_web_manifest_remote.html @@ -0,0 +1,8 @@ + + + + +

Support Page for Web Manifest Tests

+

Loads a manifest from mochi.test:8888 with CORS set to "*".

\ No newline at end of file diff --git a/dom/security/test/csp/file_websocket_csp_upgrade.html b/dom/security/test/csp/file_websocket_csp_upgrade.html new file mode 100644 index 0000000000..9302a6e637 --- /dev/null +++ b/dom/security/test/csp/file_websocket_csp_upgrade.html @@ -0,0 +1,20 @@ + + + + + Bug 1729897: Allow unsecure websocket from localhost page with CSP: upgrade-insecure + + + + + + diff --git a/dom/security/test/csp/file_websocket_explicit.html b/dom/security/test/csp/file_websocket_explicit.html new file mode 100644 index 0000000000..51462ab741 --- /dev/null +++ b/dom/security/test/csp/file_websocket_explicit.html @@ -0,0 +1,31 @@ + + + + + Bug 1345615: Allow websocket schemes when using 'self' in CSP + + + + + + diff --git a/dom/security/test/csp/file_websocket_self.html b/dom/security/test/csp/file_websocket_self.html new file mode 100644 index 0000000000..3ff5f05580 --- /dev/null +++ b/dom/security/test/csp/file_websocket_self.html @@ -0,0 +1,31 @@ + + + + + Bug 1345615: Allow websocket schemes when using 'self' in CSP + + + + + + diff --git a/dom/security/test/csp/file_websocket_self_wsh.py b/dom/security/test/csp/file_websocket_self_wsh.py new file mode 100644 index 0000000000..eb45e224f3 --- /dev/null +++ b/dom/security/test/csp/file_websocket_self_wsh.py @@ -0,0 +1,6 @@ +def web_socket_do_extra_handshake(request): + pass + + +def web_socket_transfer_data(request): + pass diff --git a/dom/security/test/csp/file_win_open_blocked.html b/dom/security/test/csp/file_win_open_blocked.html new file mode 100644 index 0000000000..2d0828a872 --- /dev/null +++ b/dom/security/test/csp/file_win_open_blocked.html @@ -0,0 +1,3 @@ + diff --git a/dom/security/test/csp/file_windowwatcher_frameA.html b/dom/security/test/csp/file_windowwatcher_frameA.html new file mode 100644 index 0000000000..9e544142ce --- /dev/null +++ b/dom/security/test/csp/file_windowwatcher_frameA.html @@ -0,0 +1,17 @@ + + + +frame A
+ + + + + + + diff --git a/dom/security/test/csp/file_windowwatcher_subframeB.html b/dom/security/test/csp/file_windowwatcher_subframeB.html new file mode 100644 index 0000000000..e7ef422313 --- /dev/null +++ b/dom/security/test/csp/file_windowwatcher_subframeB.html @@ -0,0 +1,12 @@ + + + +subFrame B + + + + diff --git a/dom/security/test/csp/file_windowwatcher_subframeC.html b/dom/security/test/csp/file_windowwatcher_subframeC.html new file mode 100644 index 0000000000..b97c40432e --- /dev/null +++ b/dom/security/test/csp/file_windowwatcher_subframeC.html @@ -0,0 +1,9 @@ + + + + + + +subFrame C + + diff --git a/dom/security/test/csp/file_windowwatcher_subframeD.html b/dom/security/test/csp/file_windowwatcher_subframeD.html new file mode 100644 index 0000000000..2f778ea4cd --- /dev/null +++ b/dom/security/test/csp/file_windowwatcher_subframeD.html @@ -0,0 +1,6 @@ + + + +subFrame D + + diff --git a/dom/security/test/csp/file_windowwatcher_win_open.html b/dom/security/test/csp/file_windowwatcher_win_open.html new file mode 100644 index 0000000000..0237e49377 --- /dev/null +++ b/dom/security/test/csp/file_windowwatcher_win_open.html @@ -0,0 +1,15 @@ + + + +Opened Window
+ + + + diff --git a/dom/security/test/csp/file_worker_src.js b/dom/security/test/csp/file_worker_src.js new file mode 100644 index 0000000000..ce60379fef --- /dev/null +++ b/dom/security/test/csp/file_worker_src.js @@ -0,0 +1,73 @@ +var mySharedWorker = new SharedWorker("file_spawn_shared_worker.js"); +mySharedWorker.port.onmessage = function (ev) { + parent.postMessage( + { + result: "shared-worker-allowed", + href: document.location.href, + }, + "*" + ); + mySharedWorker.port.close(); +}; +mySharedWorker.onerror = function (evt) { + evt.preventDefault(); + parent.postMessage( + { + result: "shared-worker-blocked", + href: document.location.href, + }, + "*" + ); + mySharedWorker.port.close(); +}; +mySharedWorker.port.start(); +mySharedWorker.port.postMessage("foo"); + +// -------------------------------------------- + +let myWorker = new Worker("file_spawn_worker.js"); +myWorker.onmessage = function (event) { + parent.postMessage( + { + result: "worker-allowed", + href: document.location.href, + }, + "*" + ); +}; +myWorker.onerror = function (event) { + parent.postMessage( + { + result: "worker-blocked", + href: document.location.href, + }, + "*" + ); +}; + +// -------------------------------------------- + +navigator.serviceWorker + .register("file_spawn_service_worker.js") + .then(function (reg) { + // registration worked + reg.unregister().then(function () { + parent.postMessage( + { + result: "service-worker-allowed", + href: document.location.href, + }, + "*" + ); + }); + }) + .catch(function (error) { + // registration failed + parent.postMessage( + { + result: "service-worker-blocked", + href: document.location.href, + }, + "*" + ); + }); diff --git a/dom/security/test/csp/file_worker_src_child_governs.html b/dom/security/test/csp/file_worker_src_child_governs.html new file mode 100644 index 0000000000..ca8a683aac --- /dev/null +++ b/dom/security/test/csp/file_worker_src_child_governs.html @@ -0,0 +1,9 @@ + + + + "; + + + + + diff --git a/dom/security/test/csp/file_worker_src_script_governs.html b/dom/security/test/csp/file_worker_src_script_governs.html new file mode 100644 index 0000000000..0385fee57c --- /dev/null +++ b/dom/security/test/csp/file_worker_src_script_governs.html @@ -0,0 +1,9 @@ + + + + "; + + + + + diff --git a/dom/security/test/csp/file_worker_src_worker_governs.html b/dom/security/test/csp/file_worker_src_worker_governs.html new file mode 100644 index 0000000000..93c8f61225 --- /dev/null +++ b/dom/security/test/csp/file_worker_src_worker_governs.html @@ -0,0 +1,9 @@ + + + + "; + + + + + diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xml b/dom/security/test/csp/file_xslt_inherits_csp.xml new file mode 100644 index 0000000000..a6d99c3081 --- /dev/null +++ b/dom/security/test/csp/file_xslt_inherits_csp.xml @@ -0,0 +1,6 @@ + + + + + This is some Title + diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^ b/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^ new file mode 100644 index 0000000000..635af0a4d9 --- /dev/null +++ b/dom/security/test/csp/file_xslt_inherits_csp.xml^headers^ @@ -0,0 +1,2 @@ +Content-Security-Policy: script-src 'self' +Cache-Control: no-cache diff --git a/dom/security/test/csp/file_xslt_inherits_csp.xsl b/dom/security/test/csp/file_xslt_inherits_csp.xsl new file mode 100644 index 0000000000..82a4b0ad97 --- /dev/null +++ b/dom/security/test/csp/file_xslt_inherits_csp.xsl @@ -0,0 +1,26 @@ + + + + + + + + <xsl:value-of select="$title"/> + + + + +

+ Below is some inline JavaScript generating some red text. +

+ +

+ + + link with lineOnClick + + + + diff --git a/dom/security/test/csp/main_csp_worker.html b/dom/security/test/csp/main_csp_worker.html new file mode 100644 index 0000000000..8957e3fd25 --- /dev/null +++ b/dom/security/test/csp/main_csp_worker.html @@ -0,0 +1,439 @@ + + + + Bug 1475849: Test CSP worker inheritance + + + + + + + + + + diff --git a/dom/security/test/csp/main_csp_worker.html^headers^ b/dom/security/test/csp/main_csp_worker.html^headers^ new file mode 100644 index 0000000000..4597e01040 --- /dev/null +++ b/dom/security/test/csp/main_csp_worker.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: default-src 'self' blob: 'unsafe-inline' diff --git a/dom/security/test/csp/mochitest.ini b/dom/security/test/csp/mochitest.ini new file mode 100644 index 0000000000..a19aa9d2ca --- /dev/null +++ b/dom/security/test/csp/mochitest.ini @@ -0,0 +1,755 @@ +[DEFAULT] +support-files = + file_base_uri_server.sjs + file_blob_data_schemes.html + file_blob_uri_blocks_modals.html + file_blob_uri_blocks_modals.html^headers^ + file_blob_top_nav_block_modals.html + file_blob_top_nav_block_modals.html^headers^ + file_connect-src.html + file_connect-src-fetch.html + file_CSP.css + file_CSP.sjs + file_dummy_pixel.png + file_allow_https_schemes.html + file_bug663567.xsl + file_bug663567_allows.xml + file_bug663567_allows.xml^headers^ + file_bug663567_blocks.xml + file_bug663567_blocks.xml^headers^ + file_bug802872.html + file_bug802872.html^headers^ + file_bug802872.js + file_bug802872.sjs + file_bug885433_allows.html + file_bug885433_allows.html^headers^ + file_bug885433_blocks.html + file_bug885433_blocks.html^headers^ + file_bug888172.html + file_bug888172.sjs + file_evalscript_main.js + file_evalscript_main_allowed.js + file_evalscript_main.html + file_evalscript_main.html^headers^ + file_evalscript_main_allowed.html + file_evalscript_main_allowed.html^headers^ + file_frameancestors_main.html + file_frameancestors_main.js + file_frameancestors.sjs + file_frameancestors_userpass.html + file_frameancestors_userpass_frame_a.html + file_frameancestors_userpass_frame_b.html + file_frameancestors_userpass_frame_c.html + file_frameancestors_userpass_frame_c.html^headers^ + file_frameancestors_userpass_frame_d.html + file_frameancestors_userpass_frame_d.html^headers^ + file_inlinescript.html + file_inlinestyle_main.html + file_inlinestyle_main.html^headers^ + file_inlinestyle_main_allowed.html + file_inlinestyle_main_allowed.html^headers^ + file_invalid_source_expression.html + file_main.html + file_main.html^headers^ + file_main.js + file_web_manifest.html + file_web_manifest_remote.html + file_web_manifest_https.html + file_web_manifest.json + file_web_manifest.json^headers^ + file_web_manifest_https.json + file_web_manifest_mixed_content.html + file_bug836922_npolicies.html + file_bug836922_npolicies.html^headers^ + file_bug836922_npolicies_ro_violation.sjs + file_bug836922_npolicies_violation.sjs + file_bug886164.html + file_bug886164.html^headers^ + file_bug886164_2.html + file_bug886164_2.html^headers^ + file_bug886164_3.html + file_bug886164_3.html^headers^ + file_bug886164_4.html + file_bug886164_4.html^headers^ + file_bug886164_5.html + file_bug886164_5.html^headers^ + file_bug886164_6.html + file_bug886164_6.html^headers^ + file_redirects_main.html + file_redirects_page.sjs + file_redirects_resource.sjs + file_bug910139.sjs + file_bug910139.xml + file_bug910139.xsl + file_bug909029_star.html + file_bug909029_star.html^headers^ + file_bug909029_none.html + file_bug909029_none.html^headers^ + file_bug1229639.html + file_bug1229639.html^headers^ + file_bug1312272.html + file_bug1312272.js + file_bug1312272.html^headers^ + file_bug1452037.html + file_bug1505412.sjs + file_bug1505412_reporter.sjs + file_bug1505412_frame.html + file_bug1505412_frame.html^headers^ + file_policyuri_regression_from_multipolicy.html + file_policyuri_regression_from_multipolicy.html^headers^ + file_policyuri_regression_from_multipolicy_policy + file_nonce_source.html + file_nonce_source.html^headers^ + file_nonce_redirects.html + file_nonce_redirector.sjs + file_bug941404.html + file_bug941404_xhr.html + file_bug941404_xhr.html^headers^ + file_frame_ancestors_ro.html + file_frame_ancestors_ro.html^headers^ + file_hash_source.html + file_dual_header_testserver.sjs + file_hash_source.html^headers^ + file_scheme_relative_sources.js + file_scheme_relative_sources.sjs + file_ignore_unsafe_inline.html + file_ignore_unsafe_inline_multiple_policies_server.sjs + file_self_none_as_hostname_confusion.html + file_self_none_as_hostname_confusion.html^headers^ + file_empty_directive.html + file_empty_directive.html^headers^ + file_path_matching.html + file_path_matching_incl_query.html + file_path_matching.js + file_path_matching_redirect.html + file_path_matching_redirect_server.sjs + file_testserver.sjs + file_report_uri_missing_in_report_only_header.html + file_report_uri_missing_in_report_only_header.html^headers^ + file_report.html + file_report_chromescript.js + file_redirect_content.sjs + file_redirect_report.sjs + file_subframe_run_js_if_allowed.html + file_subframe_run_js_if_allowed.html^headers^ + file_leading_wildcard.html + file_multi_policy_injection_bypass.html + file_multi_policy_injection_bypass.html^headers^ + file_multi_policy_injection_bypass_2.html + file_multi_policy_injection_bypass_2.html^headers^ + file_null_baseuri.html + file_form-action.html + referrerdirective.sjs + file_upgrade_insecure.html + file_upgrade_insecure_meta.html + file_upgrade_insecure_server.sjs + file_upgrade_insecure_wsh.py + file_upgrade_insecure_reporting.html + file_upgrade_insecure_reporting_server.sjs + file_upgrade_insecure_cors.html + file_upgrade_insecure_cors_server.sjs + file_upgrade_insecure_loopback.html + file_upgrade_insecure_loopback_form.html + file_upgrade_insecure_loopback_server.sjs + file_report_for_import.css + file_report_for_import.html + file_report_for_import_server.sjs + file_service_worker.html + file_service_worker.js + file_child-src_iframe.html + file_child-src_inner_frame.html + file_child-src_worker.html + file_child-src_worker_data.html + file_child-src_worker-redirect.html + file_child-src_worker.js + file_child-src_service_worker.html + file_child-src_service_worker.js + file_child-src_shared_worker.html + file_child-src_shared_worker_data.html + file_child-src_shared_worker-redirect.html + file_child-src_shared_worker.js + file_redirect_worker.sjs + file_meta_element.html + file_meta_header_dual.sjs + file_docwrite_meta.html + file_doccomment_meta.html + file_docwrite_meta.css + file_docwrite_meta.js + file_multipart_testserver.sjs + file_fontloader.sjs + file_fontloader.woff + file_block_all_mcb.sjs + file_block_all_mixed_content_frame_navigation1.html + file_block_all_mixed_content_frame_navigation2.html + file_form_action_server.sjs + !/image/test/mochitest/blue.png + file_meta_whitespace_skipping.html + file_ping.html + test_iframe_sandbox_top_1.html^headers^ + file_iframe_sandbox_document_write.html + file_sandbox_pass.js + file_sandbox_fail.js + file_sandbox_1.html + file_sandbox_2.html + file_sandbox_3.html + file_sandbox_4.html + file_sandbox_5.html + file_sandbox_6.html + file_sandbox_7.html + file_sandbox_8.html + file_sandbox_9.html + file_sandbox_10.html + file_sandbox_11.html + file_sandbox_12.html + file_sandbox_13.html + file_sendbeacon.html + file_upgrade_insecure_docwrite_iframe.sjs + file_data-uri_blocked.html + file_data-uri_blocked.html^headers^ + file_strict_dynamic_js_url.html + file_strict_dynamic_script_events.html + file_strict_dynamic_script_events_marquee.html + file_strict_dynamic_script_inline.html + file_strict_dynamic_script_extern.html + file_strict_dynamic.js + file_strict_dynamic_parser_inserted_doc_write.html + file_strict_dynamic_parser_inserted_doc_write_correct_nonce.html + file_strict_dynamic_non_parser_inserted.html + file_strict_dynamic_non_parser_inserted_inline.html + file_strict_dynamic_unsafe_eval.html + file_strict_dynamic_default_src.html + file_strict_dynamic_default_src.js + file_upgrade_insecure_navigation.sjs + file_punycode_host_src.sjs + file_punycode_host_src.js + file_iframe_srcdoc.sjs + file_iframe_sandbox_srcdoc.html + file_iframe_sandbox_srcdoc.html^headers^ + file_websocket_self.html + file_websocket_csp_upgrade.html + file_websocket_explicit.html + file_websocket_self_wsh.py + file_win_open_blocked.html + file_image_nonce.html + file_image_nonce.html^headers^ + file_ignore_xfo.html + file_ignore_xfo.html^headers^ + file_ro_ignore_xfo.html + file_ro_ignore_xfo.html^headers^ + file_no_log_ignore_xfo.html + file_no_log_ignore_xfo.html^headers^ + file_data_csp_inheritance.html + file_data_csp_merge.html + file_data_doc_ignore_meta_csp.html + file_report_font_cache-1.html + file_report_font_cache-2.html + file_report_font_cache-2.html^headers^ + Ahem.ttf + file_independent_iframe_csp.html +prefs = + security.mixed_content.upgrade_display_content=false + javascript.options.experimental.shadow_realms=true + +[test_base-uri.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_blob_data_schemes.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_blob_uri_blocks_modals.html] +skip-if = + xorigin + os == "linux" + (asan || tsan) # alert should be blocked by CSP - got false, expected true + http3 + fission && os == "android" # Bug 1827756 +[test_bug1764343.html] +support-files = file_bug1764343.html +[test_bug1777572.html] +support-files = file_bug1777572.html +skip-if = + toolkit == 'android' # This unusual window.close/open test times out on Android. +[test_connect-src.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_CSP.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_bug1452037.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_allow_https_schemes.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug663567.html] +skip-if = + fission && xorigin && debug && os == "win" # Bug 1716406 - New fission platform triage + fission && os == "android" # Bug 1827314 +[test_bug802872.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_bug885433.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug888172.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug1505412.html] +skip-if = + !debug + fission && os == "android" # Bug 1827967 +[test_evalscript.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_evalscript_blocked_by_strict_dynamic.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_evalscript_allowed_by_strict_dynamic.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_frameancestors.html] +skip-if = + xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object + http3 + fission && os == "android" # Bug 1827756 +[test_frameancestors_userpass.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_inlinescript.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_inlinestyle.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_invalid_source_expression.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug836922_npolicies.html] +skip-if = + verify + http3 + fission && os == "android" # Bug 1827756 +[test_bug886164.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_redirects.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_bug910139.html] +skip-if = + verify + fission && os == "android" # Bug 1827756 +[test_bug909029.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug1229639.html] +skip-if = + http3 + fission && os == "android" # Bug 1827324 +[test_bug1579094.html] +skip-if = + fission && os == "android" # Bug 1828011 +[test_frame_ancestors_ro.html] +skip-if = + http3 +[test_policyuri_regression_from_multipolicy.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_nonce_source.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_nonce_redirects.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug941404.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_form-action.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_hash_source.html] +skip-if = + fission && xorigin && debug # Bug 1716406 - New fission platform triage +[test_scheme_relative_sources.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_ignore_unsafe_inline.html] +skip-if = + xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object, [Child 3789, Main Thread] WARNING: NS_ENSURE_TRUE(request) failed: file /builds/worker/checkouts/gecko/netwerk/base/nsLoadGroup.cpp, line 591 + fission && os == "android" # Bug 1827756 +[test_self_none_as_hostname_confusion.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_empty_directive.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_path_matching.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_path_matching_redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_report_uri_missing_in_report_only_header.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_report.html] +fail-if = xorigin +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_301_redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_302_redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_303_redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_307_redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_subframe_run_js_if_allowed.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_leading_wildcard.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_multi_policy_injection_bypass.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_null_baseuri.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_dual_header.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_win_open_blocked.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure.html] +skip-if = + os == 'linux' && bits == 64 # Bug 1620516 + os == "android" # Bug 1777028 +[test_upgrade_insecure_reporting.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure_cors.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure_loopback.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_report_for_import.html] +fail-if = xorigin +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_blocked_uri_in_reports.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_service_worker.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_child-src_worker.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_child-src_worker_data.html] +skip-if = + http3 +[test_child-src_worker-redirect.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_child-src_iframe.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_meta_element.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_meta_header_dual.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_docwrite_meta.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_multipartchannel.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_fontloader.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_block_all_mixed_content.html] +tags = mcb +skip-if = + fission && os == "android" # Bug 1827756 +[test_block_all_mixed_content_frame_navigation.html] +tags = mcb +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_form_action_blocks_url.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_meta_whitespace_skipping.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_iframe_sandbox.html] +skip-if = + fission && xorigin && debug && (os == "win" || os == "linux") # Bug 1716406 - New fission platform triage + http3 +[test_iframe_sandbox_top_1.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_sandbox.html] +skip-if = true # Bug 1657934 +[test_ping.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_sendbeacon.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure_docwrite_iframe.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_bug1242019.html] +skip-if = + http3 + fission && os == "android" # Bug 1827677 +[test_bug1312272.html] +skip-if = + fission && os == "android" # Bug 1827729 +[test_strict_dynamic.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_strict_dynamic_parser_inserted.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_strict_dynamic_default_src.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure_navigation.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_punycode_host_src.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_iframe_sandbox_srcdoc.html] +skip-if = + fission && xorigin && debug && os == "win" # Bug 1716406 - New fission platform triage +[test_iframe_srcdoc.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_image_nonce.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_websocket_self.html] +skip-if = + toolkit == 'android' # no websocket support Bug 982828 + http3 +[test_websocket_localhost.html] +skip-if = + toolkit == 'android' # no websocket support Bug 982828 + http3 +[test_ignore_xfo.html] +skip-if = + xorigin # JavaScript error: http://mochi.xorigin-test:8888/tests/SimpleTest/TestRunner.js, line 157: SecurityError: Permission denied to access property "wrappedJSObject" on cross-origin object + http3 + fission && os == "android" # Bug 1827756 +[test_data_csp_inheritance.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_data_csp_merge.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_report_font_cache.html] +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_data_doc_ignore_meta_csp.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_meta_csp_self.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_uir_top_nav.html] +support-files = + file_uir_top_nav.html + file_uir_top_nav_dummy.html +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_sandbox_allow_scripts.html] +support-files = + file_sandbox_allow_scripts.html + file_sandbox_allow_scripts.html^headers^ +skip-if = + fission && os == "android" # Bug 1827756 +[test_worker_src.html] +support-files = + file_worker_src_worker_governs.html + file_worker_src_child_governs.html + file_worker_src_script_governs.html + file_worker_src.js + file_spawn_worker.js + file_spawn_shared_worker.js + file_spawn_service_worker.js +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_frame_src.html] +support-files = + file_frame_src_frame_governs.html + file_frame_src_child_governs.html + file_frame_src.js + file_frame_src_inner.html +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_security_policy_violation_event.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_csp_worker_inheritance.html] +support-files = + worker.sjs + worker_helper.js + main_csp_worker.html + main_csp_worker.html^headers^ +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_nonce_snapshot.html] +support-files = + file_nonce_snapshot.sjs +skip-if = + fission && os == "android" # Bug 1827756 +[test_uir_windowwatcher.html] +support-files = + file_windowwatcher_frameA.html + file_windowwatcher_subframeB.html + file_windowwatcher_subframeC.html + file_windowwatcher_subframeD.html + file_windowwatcher_win_open.html +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_script_template.html] +support-files = + file_script_template.html + file_script_template.js +skip-if = + fission && os == "android" # Bug 1827756 +[test_parent_location_js.html] +support-files = + file_parent_location_js.html + file_iframe_parent_location_js.html +skip-if = + fission && os == "android" # Bug 1827756 +[test_navigate_to.html] +support-files = + file_navigate_to.sjs + file_navigate_to_request.html +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_independent_iframe_csp.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_xslt_inherits_csp.html] +support-files = + file_xslt_inherits_csp.xml + file_xslt_inherits_csp.xml^headers^ + file_xslt_inherits_csp.xsl +skip-if = + fission && os == "android" # Bug 1827756 +[test_object_inherit.html] +support-files = + file_object_inherit.html +skip-if = + fission && os == "android" # Bug 1827756 +[test_link_rel_preload.html] +support-files = + file_link_rel_preload.html +skip-if = + fission && os == "android" # Bug 1827756 +[test_image_document.html] +support-files = + file_image_document_pixel.png + file_image_document_pixel.png^headers^ +skip-if = + fission && os == "android" # Bug 1827756 +[test_svg_inline_style.html] +support-files = + file_svg_inline_style_base.html + file_svg_inline_style_csp.html + file_svg_srcset_inline_style_base.html + file_svg_srcset_inline_style_csp.html + file_svg_inline_style_server.sjs +skip-if = + fission && os == "android" # Bug 1827756 +[test_upgrade_insecure_navigation_redirect.html] +support-files = + file_upgrade_insecure_navigation_redirect.sjs + file_upgrade_insecure_navigation_redirect_same_origin.html + file_upgrade_insecure_navigation_redirect_cross_origin.html +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_csp_style_src_empty_hash.html] +skip-if = + fission && os == "android" # Bug 1827756 +[test_csp_frame_ancestors_about_blank.html] +support-files = + file_csp_frame_ancestors_about_blank.html + file_csp_frame_ancestors_about_blank.html^headers^ +skip-if = + fission && os == "android" # Bug 1827756 +[test_blocked_uri_redirect_frame_src.html] +support-files = + file_blocked_uri_redirect_frame_src.html + file_blocked_uri_redirect_frame_src.html^headers^ + file_blocked_uri_redirect_frame_src_server.sjs +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_blocked_uri_in_violation_event_after_redirects.html] +support-files = + file_blocked_uri_in_violation_event_after_redirects.html + file_blocked_uri_in_violation_event_after_redirects.sjs +skip-if = + http3 + fission && os == "android" # Bug 1827756 +[test_bug1738418.html] +support-files = + file_bug1738418_parent.html + file_bug1738418_parent.html^headers^ + file_bug1738418_child.html +skip-if = + fission && os == "android" # Bug 1827314 diff --git a/dom/security/test/csp/referrerdirective.sjs b/dom/security/test/csp/referrerdirective.sjs new file mode 100644 index 0000000000..267eaaede2 --- /dev/null +++ b/dom/security/test/csp/referrerdirective.sjs @@ -0,0 +1,40 @@ +// Used for bug 965727 to serve up really simple scripts reflecting the +// referrer sent to load this back to the loader. + +function handleRequest(request, response) { + // skip speculative loads. + + var splits = request.queryString.split("&"); + var params = {}; + splits.forEach(function (v) { + let parts = v.split("="); + params[parts[0]] = unescape(parts[1]); + }); + + var loadType = params.type; + var referrerLevel = "error"; + + if (request.hasHeader("Referer")) { + var referrer = request.getHeader("Referer"); + if (referrer.indexOf("file_testserver.sjs") > -1) { + referrerLevel = "full"; + } else { + referrerLevel = "origin"; + } + } else { + referrerLevel = "none"; + } + + var theScript = + 'window.postResult("' + loadType + '", "' + referrerLevel + '");'; + response.setHeader( + "Content-Type", + "application/javascript; charset=utf-8", + false + ); + response.setHeader("Cache-Control", "no-cache", false); + + if (request.method != "OPTIONS") { + response.write(theScript); + } +} diff --git a/dom/security/test/csp/test_301_redirect.html b/dom/security/test/csp/test_301_redirect.html new file mode 100644 index 0000000000..0aaed5bcf2 --- /dev/null +++ b/dom/security/test/csp/test_301_redirect.html @@ -0,0 +1,74 @@ + + + + + Test for Bug 650386 + + + + +Mozilla Bug 650386 +

+ +
+
+
+ + diff --git a/dom/security/test/csp/test_302_redirect.html b/dom/security/test/csp/test_302_redirect.html new file mode 100644 index 0000000000..330c1a64e9 --- /dev/null +++ b/dom/security/test/csp/test_302_redirect.html @@ -0,0 +1,74 @@ + + + + + Test for Bug 650386 + + + + +Mozilla Bug 650386 +

+ +
+
+
+ + diff --git a/dom/security/test/csp/test_303_redirect.html b/dom/security/test/csp/test_303_redirect.html new file mode 100644 index 0000000000..ecff523967 --- /dev/null +++ b/dom/security/test/csp/test_303_redirect.html @@ -0,0 +1,74 @@ + + + + + Test for Bug 650386 + + + + +Mozilla Bug 650386 +

+ +
+
+
+ + diff --git a/dom/security/test/csp/test_307_redirect.html b/dom/security/test/csp/test_307_redirect.html new file mode 100644 index 0000000000..40ebd592b3 --- /dev/null +++ b/dom/security/test/csp/test_307_redirect.html @@ -0,0 +1,75 @@ + + + + + Test for Bug 650386 + + + + +Mozilla Bug 650386 +

+ +
+
+
+ + diff --git a/dom/security/test/csp/test_CSP.html b/dom/security/test/csp/test_CSP.html new file mode 100644 index 0000000000..babb9db9bc --- /dev/null +++ b/dom/security/test/csp/test_CSP.html @@ -0,0 +1,130 @@ + + + + Test for Content Security Policy Connections + + + + +

+ + + + + + diff --git a/dom/security/test/csp/test_allow_https_schemes.html b/dom/security/test/csp/test_allow_https_schemes.html new file mode 100644 index 0000000000..be1f030fb9 --- /dev/null +++ b/dom/security/test/csp/test_allow_https_schemes.html @@ -0,0 +1,76 @@ + + + + Bug 826805 - Allow http and https for scheme-less sources + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_base-uri.html b/dom/security/test/csp/test_base-uri.html new file mode 100644 index 0000000000..4d5c5504af --- /dev/null +++ b/dom/security/test/csp/test_base-uri.html @@ -0,0 +1,124 @@ + + + + Bug 1045897 - Test CSP base-uri directive + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_blob_data_schemes.html b/dom/security/test/csp/test_blob_data_schemes.html new file mode 100644 index 0000000000..37a22db050 --- /dev/null +++ b/dom/security/test/csp/test_blob_data_schemes.html @@ -0,0 +1,89 @@ + + + + Bug 1086999 - Wildcard should not match blob:, data: + + + + + + + + + + diff --git a/dom/security/test/csp/test_blob_uri_blocks_modals.html b/dom/security/test/csp/test_blob_uri_blocks_modals.html new file mode 100644 index 0000000000..3f8de94ed2 --- /dev/null +++ b/dom/security/test/csp/test_blob_uri_blocks_modals.html @@ -0,0 +1,79 @@ + + + + + Bug 1432170 - Block alert box and new window open as per the sandbox + allow-scripts CSP + + + + + + + + diff --git a/dom/security/test/csp/test_block_all_mixed_content.html b/dom/security/test/csp/test_block_all_mixed_content.html new file mode 100644 index 0000000000..d60f904b6c --- /dev/null +++ b/dom/security/test/csp/test_block_all_mixed_content.html @@ -0,0 +1,99 @@ + + + + + Bug 1122236 - CSP: Implement block-all-mixed-content + + + + + + + + + + diff --git a/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html b/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html new file mode 100644 index 0000000000..b32c1fccd5 --- /dev/null +++ b/dom/security/test/csp/test_block_all_mixed_content_frame_navigation.html @@ -0,0 +1,46 @@ + + + + + Bug 1122236 - CSP: Implement block-all-mixed-content + + + + + + + + + + diff --git a/dom/security/test/csp/test_blocked_uri_in_reports.html b/dom/security/test/csp/test_blocked_uri_in_reports.html new file mode 100644 index 0000000000..f40d98efc5 --- /dev/null +++ b/dom/security/test/csp/test_blocked_uri_in_reports.html @@ -0,0 +1,80 @@ + + + + Bug 1069762 - Check blocked-uri in csp-reports after redirect + + + + + + + + + + diff --git a/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html b/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html new file mode 100644 index 0000000000..6965cbeb92 --- /dev/null +++ b/dom/security/test/csp/test_blocked_uri_in_violation_event_after_redirects.html @@ -0,0 +1,56 @@ + + + + Bug 1542194 - Check blockedURI in violation reports after redirects + + + + + + + + + + diff --git a/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html b/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html new file mode 100644 index 0000000000..a946718bc2 --- /dev/null +++ b/dom/security/test/csp/test_blocked_uri_redirect_frame_src.html @@ -0,0 +1,60 @@ + + + + Bug 1687342 - Check blocked-uri in csp-reports after frame redirect + + + + + + + + + + diff --git a/dom/security/test/csp/test_bug1229639.html b/dom/security/test/csp/test_bug1229639.html new file mode 100644 index 0000000000..e224fe1ffb --- /dev/null +++ b/dom/security/test/csp/test_bug1229639.html @@ -0,0 +1,51 @@ + + + + + Bug 1229639 - Percent encoded CSP path matching. + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_bug1242019.html b/dom/security/test/csp/test_bug1242019.html new file mode 100644 index 0000000000..14e8f74baa --- /dev/null +++ b/dom/security/test/csp/test_bug1242019.html @@ -0,0 +1,51 @@ + + + + + + Test for Bug 1242019 + + + + +Mozilla Bug 1242019 +

+ + + +
+
+
+
+ + diff --git a/dom/security/test/csp/test_bug1312272.html b/dom/security/test/csp/test_bug1312272.html new file mode 100644 index 0000000000..b06b08d092 --- /dev/null +++ b/dom/security/test/csp/test_bug1312272.html @@ -0,0 +1,32 @@ + + + + + + Test for bug 1312272 + + + + + + + + + + diff --git a/dom/security/test/csp/test_bug1388015.html b/dom/security/test/csp/test_bug1388015.html new file mode 100644 index 0000000000..5ca0605688 --- /dev/null +++ b/dom/security/test/csp/test_bug1388015.html @@ -0,0 +1,46 @@ + + + + + Bug 1388015 - Test if Firefox respect Port in Wildcard Host + + + + + + + + Should be Blocked + + + diff --git a/dom/security/test/csp/test_bug1452037.html b/dom/security/test/csp/test_bug1452037.html new file mode 100644 index 0000000000..fa46e91291 --- /dev/null +++ b/dom/security/test/csp/test_bug1452037.html @@ -0,0 +1,41 @@ + + + + Test if "script-src: sha-... " Allowlists "javascript:" URIs + + + + + + + + + + diff --git a/dom/security/test/csp/test_bug1505412.html b/dom/security/test/csp/test_bug1505412.html new file mode 100644 index 0000000000..717af2054b --- /dev/null +++ b/dom/security/test/csp/test_bug1505412.html @@ -0,0 +1,50 @@ + + + + + Bug 1505412 CSP-RO reports violations in inline-scripts with nonce + + + + + +

+ + + Test for 1505412 + + + + + \ No newline at end of file diff --git a/dom/security/test/csp/test_bug1579094.html b/dom/security/test/csp/test_bug1579094.html new file mode 100644 index 0000000000..b3568586d4 --- /dev/null +++ b/dom/security/test/csp/test_bug1579094.html @@ -0,0 +1,31 @@ + + + + Test if Wildcard CSP supports ExternalProtocol + + + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_bug1764343.html b/dom/security/test/csp/test_bug1764343.html new file mode 100644 index 0000000000..1af9a710fe --- /dev/null +++ b/dom/security/test/csp/test_bug1764343.html @@ -0,0 +1,116 @@ + + + + + Bug 1764343 - CSP inheritance for same-origin iframes + + + + + + + + + + + + diff --git a/dom/security/test/csp/test_bug1777572.html b/dom/security/test/csp/test_bug1777572.html new file mode 100644 index 0000000000..f735f4fb6a --- /dev/null +++ b/dom/security/test/csp/test_bug1777572.html @@ -0,0 +1,40 @@ + + + + + bug 1777572 + + + + + +

+ +

+
+
diff --git a/dom/security/test/csp/test_bug663567.html b/dom/security/test/csp/test_bug663567.html
new file mode 100644
index 0000000000..137d459654
--- /dev/null
+++ b/dom/security/test/csp/test_bug663567.html
@@ -0,0 +1,76 @@
+
+
+
+  Test if XSLT stylesheet is subject to document's CSP
+  
+  
+  
+
+
+  

+ + + + + + + diff --git a/dom/security/test/csp/test_bug802872.html b/dom/security/test/csp/test_bug802872.html new file mode 100644 index 0000000000..956159ddcc --- /dev/null +++ b/dom/security/test/csp/test_bug802872.html @@ -0,0 +1,53 @@ + + + + Bug 802872 + + + + + +

+ + + + + + diff --git a/dom/security/test/csp/test_bug836922_npolicies.html b/dom/security/test/csp/test_bug836922_npolicies.html new file mode 100644 index 0000000000..e418969e3d --- /dev/null +++ b/dom/security/test/csp/test_bug836922_npolicies.html @@ -0,0 +1,235 @@ + + + + Test for Content Security Policy multiple policy support (regular and Report-Only mode) + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_bug885433.html b/dom/security/test/csp/test_bug885433.html new file mode 100644 index 0000000000..c7c17d25b6 --- /dev/null +++ b/dom/security/test/csp/test_bug885433.html @@ -0,0 +1,61 @@ + + + + Test for Content Security Policy inline stylesheets stuff + + + + +

+ + + + + + + + diff --git a/dom/security/test/csp/test_bug886164.html b/dom/security/test/csp/test_bug886164.html new file mode 100644 index 0000000000..5347d42ed8 --- /dev/null +++ b/dom/security/test/csp/test_bug886164.html @@ -0,0 +1,172 @@ + + + + + Bug 886164 - Enforce CSP in sandboxed iframe + + + + +

+ + + + + + + + + + + diff --git a/dom/security/test/csp/test_bug888172.html b/dom/security/test/csp/test_bug888172.html new file mode 100644 index 0000000000..a78258e21f --- /dev/null +++ b/dom/security/test/csp/test_bug888172.html @@ -0,0 +1,73 @@ + + + + Bug 888172 - CSP 1.0 does not process 'unsafe-inline' or 'unsafe-eval' for default-src + + + + +

+ + + + + + + + + diff --git a/dom/security/test/csp/test_bug909029.html b/dom/security/test/csp/test_bug909029.html new file mode 100644 index 0000000000..7a3ac81a1b --- /dev/null +++ b/dom/security/test/csp/test_bug909029.html @@ -0,0 +1,129 @@ + + + + Bug 909029 - CSP source-lists ignore some source expressions like 'unsafe-inline' when * or 'none' are used (e.g., style-src, script-src) + + + + + + + + diff --git a/dom/security/test/csp/test_bug910139.html b/dom/security/test/csp/test_bug910139.html new file mode 100644 index 0000000000..bbebedf877 --- /dev/null +++ b/dom/security/test/csp/test_bug910139.html @@ -0,0 +1,66 @@ + + + + CSP should block XSLT as script, not as style + + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_bug941404.html b/dom/security/test/csp/test_bug941404.html new file mode 100644 index 0000000000..7c35c38aa1 --- /dev/null +++ b/dom/security/test/csp/test_bug941404.html @@ -0,0 +1,107 @@ + + + + + Bug 941404 - Data documents should not set CSP + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_child-src_iframe.html b/dom/security/test/csp/test_child-src_iframe.html new file mode 100644 index 0000000000..2b85e280bd --- /dev/null +++ b/dom/security/test/csp/test_child-src_iframe.html @@ -0,0 +1,113 @@ + + + + Bug 1045891 + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_child-src_worker-redirect.html b/dom/security/test/csp/test_child-src_worker-redirect.html new file mode 100644 index 0000000000..a1b1c9c2b4 --- /dev/null +++ b/dom/security/test/csp/test_child-src_worker-redirect.html @@ -0,0 +1,125 @@ + + + + Bug 1045891 + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_child-src_worker.html b/dom/security/test/csp/test_child-src_worker.html new file mode 100644 index 0000000000..154e533551 --- /dev/null +++ b/dom/security/test/csp/test_child-src_worker.html @@ -0,0 +1,148 @@ + + + + Bug 1045891 + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_child-src_worker_data.html b/dom/security/test/csp/test_child-src_worker_data.html new file mode 100644 index 0000000000..9d36e73e0c --- /dev/null +++ b/dom/security/test/csp/test_child-src_worker_data.html @@ -0,0 +1,126 @@ + + + + Bug 1045891 + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_connect-src.html b/dom/security/test/csp/test_connect-src.html new file mode 100644 index 0000000000..1ae4482dd8 --- /dev/null +++ b/dom/security/test/csp/test_connect-src.html @@ -0,0 +1,129 @@ + + + + Bug 1031530 and Bug 1139667 - Test mapping of XMLHttpRequest and fetch() to connect-src + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html b/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html new file mode 100644 index 0000000000..8f57d9e133 --- /dev/null +++ b/dom/security/test/csp/test_csp_frame_ancestors_about_blank.html @@ -0,0 +1,59 @@ + + + + + Bug 1668071 - CSP frame-ancestors in about:blank + + + + + + + + diff --git a/dom/security/test/csp/test_csp_style_src_empty_hash.html b/dom/security/test/csp/test_csp_style_src_empty_hash.html new file mode 100644 index 0000000000..b500c196e6 --- /dev/null +++ b/dom/security/test/csp/test_csp_style_src_empty_hash.html @@ -0,0 +1,32 @@ + + + + Bug 1609122 - Empty Style Element with valid style-src hash + + + + + + + + + + + diff --git a/dom/security/test/csp/test_csp_worker_inheritance.html b/dom/security/test/csp/test_csp_worker_inheritance.html new file mode 100644 index 0000000000..ebf6bea8a6 --- /dev/null +++ b/dom/security/test/csp/test_csp_worker_inheritance.html @@ -0,0 +1,20 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + + + + Test for Bug 1475849 + + +

+ + + + + + diff --git a/dom/security/test/csp/test_data_csp_inheritance.html b/dom/security/test/csp/test_data_csp_inheritance.html new file mode 100644 index 0000000000..dd7f3174a2 --- /dev/null +++ b/dom/security/test/csp/test_data_csp_inheritance.html @@ -0,0 +1,36 @@ + + + + Bug 1381761 - Treating 'data:' documents as unique, opaque origins should still inherit the CSP + + + + + + + + + + diff --git a/dom/security/test/csp/test_data_csp_merge.html b/dom/security/test/csp/test_data_csp_merge.html new file mode 100644 index 0000000000..87219c406d --- /dev/null +++ b/dom/security/test/csp/test_data_csp_merge.html @@ -0,0 +1,36 @@ + + + + Bug 1386183 - Meta CSP on data: URI iframe should be merged with toplevel CSP + + + + + + + + + + diff --git a/dom/security/test/csp/test_data_doc_ignore_meta_csp.html b/dom/security/test/csp/test_data_doc_ignore_meta_csp.html new file mode 100644 index 0000000000..6f0a3fbbf6 --- /dev/null +++ b/dom/security/test/csp/test_data_doc_ignore_meta_csp.html @@ -0,0 +1,39 @@ + + + + Bug 1382869: data document should ignore meta csp + + + + + + + + + diff --git a/dom/security/test/csp/test_docwrite_meta.html b/dom/security/test/csp/test_docwrite_meta.html new file mode 100644 index 0000000000..776f1bb32f --- /dev/null +++ b/dom/security/test/csp/test_docwrite_meta.html @@ -0,0 +1,86 @@ + + + + + Bug 663570 - Implement Content Security Policy via meta tag + + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_dual_header.html b/dom/security/test/csp/test_dual_header.html new file mode 100644 index 0000000000..cfea86103b --- /dev/null +++ b/dom/security/test/csp/test_dual_header.html @@ -0,0 +1,66 @@ + + + + Bug 1036399 - Multiple CSP policies should be combined towards an intersection + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_empty_directive.html b/dom/security/test/csp/test_empty_directive.html new file mode 100644 index 0000000000..81c5df8403 --- /dev/null +++ b/dom/security/test/csp/test_empty_directive.html @@ -0,0 +1,51 @@ + + + + + + Test for Bug 1439425 + + + + +Mozilla Bug 1439425 +

+ + + +
+
+
+
+ + diff --git a/dom/security/test/csp/test_evalscript.html b/dom/security/test/csp/test_evalscript.html new file mode 100644 index 0000000000..bf1621f81e --- /dev/null +++ b/dom/security/test/csp/test_evalscript.html @@ -0,0 +1,59 @@ + + + + Test for Content Security Policy "no eval" base restriction + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html b/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html new file mode 100644 index 0000000000..29c3e87287 --- /dev/null +++ b/dom/security/test/csp/test_evalscript_allowed_by_strict_dynamic.html @@ -0,0 +1,36 @@ + + + + + + Bug 1439330 - CSP: eval is not blocked if 'strict-dynamic' is enabled + + + + + + + + \ No newline at end of file diff --git a/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html b/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html new file mode 100644 index 0000000000..179e865459 --- /dev/null +++ b/dom/security/test/csp/test_evalscript_blocked_by_strict_dynamic.html @@ -0,0 +1,36 @@ + + + + + + Bug 1439330 - CSP: eval is not blocked if 'strict-dynamic' is enabled + + + + + + + + \ No newline at end of file diff --git a/dom/security/test/csp/test_fontloader.html b/dom/security/test/csp/test_fontloader.html new file mode 100644 index 0000000000..2f68223af1 --- /dev/null +++ b/dom/security/test/csp/test_fontloader.html @@ -0,0 +1,98 @@ + + + + + Bug 1122236 - CSP: Implement block-all-mixed-content + + + + + + + + + + + + + diff --git a/dom/security/test/csp/test_form-action.html b/dom/security/test/csp/test_form-action.html new file mode 100644 index 0000000000..7bbc52a116 --- /dev/null +++ b/dom/security/test/csp/test_form-action.html @@ -0,0 +1,105 @@ + + + + Bug 529697 - Test mapping of form submission to form-action + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_form_action_blocks_url.html b/dom/security/test/csp/test_form_action_blocks_url.html new file mode 100644 index 0000000000..f835504ff4 --- /dev/null +++ b/dom/security/test/csp/test_form_action_blocks_url.html @@ -0,0 +1,76 @@ + + + + Bug 1251043 - Test form-action blocks URL + + + + + + + + + + diff --git a/dom/security/test/csp/test_frame_ancestors_ro.html b/dom/security/test/csp/test_frame_ancestors_ro.html new file mode 100644 index 0000000000..1cfe6be1cd --- /dev/null +++ b/dom/security/test/csp/test_frame_ancestors_ro.html @@ -0,0 +1,69 @@ + + + + Test for frame-ancestors support in Content-Security-Policy-Report-Only + + + + + + + + diff --git a/dom/security/test/csp/test_frame_src.html b/dom/security/test/csp/test_frame_src.html new file mode 100644 index 0000000000..f87549b72b --- /dev/null +++ b/dom/security/test/csp/test_frame_src.html @@ -0,0 +1,84 @@ + + + + + Bug 1302667 - Test frame-src + + + + + + + + + diff --git a/dom/security/test/csp/test_frameancestors.html b/dom/security/test/csp/test_frameancestors.html new file mode 100644 index 0000000000..8b44ba72fb --- /dev/null +++ b/dom/security/test/csp/test_frameancestors.html @@ -0,0 +1,160 @@ + + + + Test for Content Security Policy Frame Ancestors directive + + + + +

+ + + + + + diff --git a/dom/security/test/csp/test_frameancestors_userpass.html b/dom/security/test/csp/test_frameancestors_userpass.html new file mode 100644 index 0000000000..332318fe17 --- /dev/null +++ b/dom/security/test/csp/test_frameancestors_userpass.html @@ -0,0 +1,148 @@ + + + + Test for Userpass in Frame Ancestors directive + + + + +

+ + + + + + diff --git a/dom/security/test/csp/test_hash_source.html b/dom/security/test/csp/test_hash_source.html new file mode 100644 index 0000000000..2334ae0101 --- /dev/null +++ b/dom/security/test/csp/test_hash_source.html @@ -0,0 +1,135 @@ + + + + Test CSP 1.1 hash-source for inline scripts and styles + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_iframe_sandbox.html b/dom/security/test/csp/test_iframe_sandbox.html new file mode 100644 index 0000000000..cd7417bc8b --- /dev/null +++ b/dom/security/test/csp/test_iframe_sandbox.html @@ -0,0 +1,240 @@ + + + + + + Tests for Bug 671389 + + + + + + Mozilla Bug 671389 - Implement CSP sandbox directive +

+
+
+ + diff --git a/dom/security/test/csp/test_iframe_sandbox_srcdoc.html b/dom/security/test/csp/test_iframe_sandbox_srcdoc.html new file mode 100644 index 0000000000..9c36aa5447 --- /dev/null +++ b/dom/security/test/csp/test_iframe_sandbox_srcdoc.html @@ -0,0 +1,62 @@ + + + + + Bug 1073952 - CSP should restrict scripts in srcdoc iframe even if sandboxed + + + + +

Bug 1073952

+ + + + diff --git a/dom/security/test/csp/test_iframe_sandbox_top_1.html b/dom/security/test/csp/test_iframe_sandbox_top_1.html new file mode 100644 index 0000000000..c1ade7ac6c --- /dev/null +++ b/dom/security/test/csp/test_iframe_sandbox_top_1.html @@ -0,0 +1,80 @@ + + + + + + Tests for Bug 671389 + + + + + + +Mozilla Bug 671389 - Implement CSP sandbox directive +

+
+ I am a top-level page sandboxed with "allow-scripts allow-forms + allow-same-origin". +
+ + diff --git a/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^ b/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^ new file mode 100644 index 0000000000..d9cd0606e7 --- /dev/null +++ b/dom/security/test/csp/test_iframe_sandbox_top_1.html^headers^ @@ -0,0 +1 @@ +Content-Security-Policy: sAnDbOx aLLow-FOrms aLlOw-ScRiPtS ALLOW-same-origin diff --git a/dom/security/test/csp/test_iframe_srcdoc.html b/dom/security/test/csp/test_iframe_srcdoc.html new file mode 100644 index 0000000000..04694aa5e0 --- /dev/null +++ b/dom/security/test/csp/test_iframe_srcdoc.html @@ -0,0 +1,140 @@ + + + + Bug 1073952 - Test CSP enforcement within iframe srcdoc + + + + + + + + + + diff --git a/dom/security/test/csp/test_ignore_unsafe_inline.html b/dom/security/test/csp/test_ignore_unsafe_inline.html new file mode 100644 index 0000000000..09d08157da --- /dev/null +++ b/dom/security/test/csp/test_ignore_unsafe_inline.html @@ -0,0 +1,122 @@ + + + + Bug 1004703 - ignore 'unsafe-inline' if nonce- or hash-source specified + + + + + + + + + + diff --git a/dom/security/test/csp/test_ignore_xfo.html b/dom/security/test/csp/test_ignore_xfo.html new file mode 100644 index 0000000000..5dbfecd18d --- /dev/null +++ b/dom/security/test/csp/test_ignore_xfo.html @@ -0,0 +1,120 @@ + + + + Bug 1024557: Ignore x-frame-options if CSP with frame-ancestors exists + + + + + + + + + + + + diff --git a/dom/security/test/csp/test_image_document.html b/dom/security/test/csp/test_image_document.html new file mode 100644 index 0000000000..eba83f95a7 --- /dev/null +++ b/dom/security/test/csp/test_image_document.html @@ -0,0 +1,35 @@ + + + + + Bug 1627235: Test CSP for images loaded as iframe + + + + + + + + + + diff --git a/dom/security/test/csp/test_image_nonce.html b/dom/security/test/csp/test_image_nonce.html new file mode 100644 index 0000000000..dd6bc13922 --- /dev/null +++ b/dom/security/test/csp/test_image_nonce.html @@ -0,0 +1,60 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/test_independent_iframe_csp.html b/dom/security/test/csp/test_independent_iframe_csp.html new file mode 100644 index 0000000000..9549263a11 --- /dev/null +++ b/dom/security/test/csp/test_independent_iframe_csp.html @@ -0,0 +1,79 @@ + + + + + Bug 1419222 - iFrame CSP should not affect parent document CSP + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_inlinescript.html b/dom/security/test/csp/test_inlinescript.html new file mode 100644 index 0000000000..99b055f0c7 --- /dev/null +++ b/dom/security/test/csp/test_inlinescript.html @@ -0,0 +1,123 @@ + + + + + Test for Content Security Policy Frame Ancestors directive + + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_inlinestyle.html b/dom/security/test/csp/test_inlinestyle.html new file mode 100644 index 0000000000..dc15dc5078 --- /dev/null +++ b/dom/security/test/csp/test_inlinestyle.html @@ -0,0 +1,107 @@ + + + + Test for Content Security Policy inline stylesheets stuff + + + + +

+ + + + + + + + diff --git a/dom/security/test/csp/test_invalid_source_expression.html b/dom/security/test/csp/test_invalid_source_expression.html new file mode 100644 index 0000000000..c170dc2a27 --- /dev/null +++ b/dom/security/test/csp/test_invalid_source_expression.html @@ -0,0 +1,57 @@ + + + + Bug 1086612 - CSP: Let source expression be the empty set in case no valid source can be parsed + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_leading_wildcard.html b/dom/security/test/csp/test_leading_wildcard.html new file mode 100644 index 0000000000..53994b0013 --- /dev/null +++ b/dom/security/test/csp/test_leading_wildcard.html @@ -0,0 +1,101 @@ + + + + Bug 1032303 - CSP - Keep FULL STOP when matching *.foo.com to disallow loads from foo.com + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_link_rel_preload.html b/dom/security/test/csp/test_link_rel_preload.html new file mode 100644 index 0000000000..18f236d56a --- /dev/null +++ b/dom/security/test/csp/test_link_rel_preload.html @@ -0,0 +1,80 @@ + + + + Bug 1599791 - Test link rel=preload + + + + + + + + diff --git a/dom/security/test/csp/test_meta_csp_self.html b/dom/security/test/csp/test_meta_csp_self.html new file mode 100644 index 0000000000..8d7d5812a9 --- /dev/null +++ b/dom/security/test/csp/test_meta_csp_self.html @@ -0,0 +1,63 @@ + + + + Bug 1387871 - CSP: Test 'self' within meta csp in data: URI iframe + + + + + + + + + diff --git a/dom/security/test/csp/test_meta_element.html b/dom/security/test/csp/test_meta_element.html new file mode 100644 index 0000000000..42cddbacbf --- /dev/null +++ b/dom/security/test/csp/test_meta_element.html @@ -0,0 +1,91 @@ + + + + + Bug 663570 - Implement Content Security Policy via <meta> tag + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_meta_header_dual.html b/dom/security/test/csp/test_meta_header_dual.html new file mode 100644 index 0000000000..679512d068 --- /dev/null +++ b/dom/security/test/csp/test_meta_header_dual.html @@ -0,0 +1,135 @@ + + + + + Bug 663570 - Implement Content Security Policy via meta tag + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_meta_whitespace_skipping.html b/dom/security/test/csp/test_meta_whitespace_skipping.html new file mode 100644 index 0000000000..2f622c3a33 --- /dev/null +++ b/dom/security/test/csp/test_meta_whitespace_skipping.html @@ -0,0 +1,81 @@ + + + + + Bug 1261634 - Update whitespace skipping for meta csp + + + + + + + + + + diff --git a/dom/security/test/csp/test_multi_policy_injection_bypass.html b/dom/security/test/csp/test_multi_policy_injection_bypass.html new file mode 100644 index 0000000000..cbb981405b --- /dev/null +++ b/dom/security/test/csp/test_multi_policy_injection_bypass.html @@ -0,0 +1,119 @@ + + + + + Test for Bug 717511 + + + + +

+ + + + + + + + diff --git a/dom/security/test/csp/test_multipartchannel.html b/dom/security/test/csp/test_multipartchannel.html new file mode 100644 index 0000000000..2708611e6d --- /dev/null +++ b/dom/security/test/csp/test_multipartchannel.html @@ -0,0 +1,68 @@ + + + + + Bug 1416045/Bug 1223743 - CSP: Check baseChannel for CSP when loading multipart channel + + + + + + + + + + + diff --git a/dom/security/test/csp/test_navigate_to.html b/dom/security/test/csp/test_navigate_to.html new file mode 100644 index 0000000000..357b35bb05 --- /dev/null +++ b/dom/security/test/csp/test_navigate_to.html @@ -0,0 +1,158 @@ + + + + Bug 1529068 Implement CSP 'navigate-to' directive + + + + + +

+
+ +
+ + + + diff --git a/dom/security/test/csp/test_nonce_redirects.html b/dom/security/test/csp/test_nonce_redirects.html new file mode 100644 index 0000000000..9b9e5e347d --- /dev/null +++ b/dom/security/test/csp/test_nonce_redirects.html @@ -0,0 +1,47 @@ + + + + + Bug 1469150:Scripts with valid nonce get blocked if URL redirects + + + + + + + + + + diff --git a/dom/security/test/csp/test_nonce_snapshot.html b/dom/security/test/csp/test_nonce_snapshot.html new file mode 100644 index 0000000000..6670d6868f --- /dev/null +++ b/dom/security/test/csp/test_nonce_snapshot.html @@ -0,0 +1,35 @@ + + + + + Bug 1509738 - Snapshot nonce at load start time + + + + + + + + + diff --git a/dom/security/test/csp/test_nonce_source.html b/dom/security/test/csp/test_nonce_source.html new file mode 100644 index 0000000000..e11452c6e1 --- /dev/null +++ b/dom/security/test/csp/test_nonce_source.html @@ -0,0 +1,122 @@ + + + + Test CSP 1.1 nonce-source for scripts and styles + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_null_baseuri.html b/dom/security/test/csp/test_null_baseuri.html new file mode 100644 index 0000000000..324b644f83 --- /dev/null +++ b/dom/security/test/csp/test_null_baseuri.html @@ -0,0 +1,67 @@ + + + + Bug 1121857 - document.baseURI should not get blocked if baseURI is null + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_object_inherit.html b/dom/security/test/csp/test_object_inherit.html new file mode 100644 index 0000000000..0d563bde3f --- /dev/null +++ b/dom/security/test/csp/test_object_inherit.html @@ -0,0 +1,30 @@ + + + + Bug 1457100: Test OBJECT inherits CSP if needed + + + + + + + + + diff --git a/dom/security/test/csp/test_parent_location_js.html b/dom/security/test/csp/test_parent_location_js.html new file mode 100644 index 0000000000..d456c809f2 --- /dev/null +++ b/dom/security/test/csp/test_parent_location_js.html @@ -0,0 +1,38 @@ + + + + Bug 1550414: Add CSP test for setting parent location to javascript: + + + + + + + + + diff --git a/dom/security/test/csp/test_path_matching.html b/dom/security/test/csp/test_path_matching.html new file mode 100644 index 0000000000..a54de0a25c --- /dev/null +++ b/dom/security/test/csp/test_path_matching.html @@ -0,0 +1,115 @@ + + + + Bug 808292 - Implement path-level host-source matching to CSP + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_path_matching_redirect.html b/dom/security/test/csp/test_path_matching_redirect.html new file mode 100644 index 0000000000..d3b2771d0a --- /dev/null +++ b/dom/security/test/csp/test_path_matching_redirect.html @@ -0,0 +1,89 @@ + + + + Bug 808292 - Implement path-level host-source matching to CSP (redirects) + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_ping.html b/dom/security/test/csp/test_ping.html new file mode 100644 index 0000000000..3f911b7b6a --- /dev/null +++ b/dom/security/test/csp/test_ping.html @@ -0,0 +1,103 @@ + + + + Bug 1100181 - CSP: Enforce connect-src when submitting pings + + + + + + + + + + diff --git a/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html b/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html new file mode 100644 index 0000000000..8838f2fc45 --- /dev/null +++ b/dom/security/test/csp/test_policyuri_regression_from_multipolicy.html @@ -0,0 +1,27 @@ + + + + Test for Bug 924708 + + + + + + + + + diff --git a/dom/security/test/csp/test_punycode_host_src.html b/dom/security/test/csp/test_punycode_host_src.html new file mode 100644 index 0000000000..3735275d34 --- /dev/null +++ b/dom/security/test/csp/test_punycode_host_src.html @@ -0,0 +1,81 @@ + + + + + Bug 1224225 - CSP source matching should work for punycoded domain names + + + + + + + + + + diff --git a/dom/security/test/csp/test_redirects.html b/dom/security/test/csp/test_redirects.html new file mode 100644 index 0000000000..9cc569ed72 --- /dev/null +++ b/dom/security/test/csp/test_redirects.html @@ -0,0 +1,143 @@ + + + + Tests for Content Security Policy during redirects + + + + +

+ + + +

+
+
+
+
+
diff --git a/dom/security/test/csp/test_report.html b/dom/security/test/csp/test_report.html
new file mode 100644
index 0000000000..fc10cd0341
--- /dev/null
+++ b/dom/security/test/csp/test_report.html
@@ -0,0 +1,113 @@
+
+
+
+
+  Test for Bug 548193
+  
+  
+
+
+

+ + + + + + + diff --git a/dom/security/test/csp/test_report_font_cache.html b/dom/security/test/csp/test_report_font_cache.html new file mode 100644 index 0000000000..40577a1e00 --- /dev/null +++ b/dom/security/test/csp/test_report_font_cache.html @@ -0,0 +1,56 @@ + + + + + + diff --git a/dom/security/test/csp/test_report_for_import.html b/dom/security/test/csp/test_report_for_import.html new file mode 100644 index 0000000000..ddeee3b507 --- /dev/null +++ b/dom/security/test/csp/test_report_for_import.html @@ -0,0 +1,109 @@ + + + + + Test for Bug 548193 + + + + +

+ + + + + + + diff --git a/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html b/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html new file mode 100644 index 0000000000..0bdfd57bc9 --- /dev/null +++ b/dom/security/test/csp/test_report_uri_missing_in_report_only_header.html @@ -0,0 +1,57 @@ + + + + + + Test for Bug 847081 + + + + +Mozilla Bug 847081 +

+ + + +
+
+
+ + diff --git a/dom/security/test/csp/test_sandbox.html b/dom/security/test/csp/test_sandbox.html new file mode 100644 index 0000000000..9fa123eadf --- /dev/null +++ b/dom/security/test/csp/test_sandbox.html @@ -0,0 +1,249 @@ + + + + + Tests for bugs 886164 and 671389 + + + + +

+
+
+ + + + diff --git a/dom/security/test/csp/test_sandbox_allow_scripts.html b/dom/security/test/csp/test_sandbox_allow_scripts.html new file mode 100644 index 0000000000..68544a5178 --- /dev/null +++ b/dom/security/test/csp/test_sandbox_allow_scripts.html @@ -0,0 +1,31 @@ + + + + Bug 1396320: Fix CSP sandbox regression for allow-scripts + + + + + + + + diff --git a/dom/security/test/csp/test_scheme_relative_sources.html b/dom/security/test/csp/test_scheme_relative_sources.html new file mode 100644 index 0000000000..3de3d98d69 --- /dev/null +++ b/dom/security/test/csp/test_scheme_relative_sources.html @@ -0,0 +1,91 @@ + + + + Bug 921493 - CSP: test allowlisting of scheme-relative sources + + + + + + + + + + diff --git a/dom/security/test/csp/test_script_template.html b/dom/security/test/csp/test_script_template.html new file mode 100644 index 0000000000..a71ebfe960 --- /dev/null +++ b/dom/security/test/csp/test_script_template.html @@ -0,0 +1,60 @@ + + + + Bug 1548385 - CSP: Test script template + + + + + + + + + diff --git a/dom/security/test/csp/test_security_policy_violation_event.html b/dom/security/test/csp/test_security_policy_violation_event.html new file mode 100644 index 0000000000..0d5cfade9c --- /dev/null +++ b/dom/security/test/csp/test_security_policy_violation_event.html @@ -0,0 +1,15 @@ + + + + + + diff --git a/dom/security/test/csp/test_self_none_as_hostname_confusion.html b/dom/security/test/csp/test_self_none_as_hostname_confusion.html new file mode 100644 index 0000000000..50627711ff --- /dev/null +++ b/dom/security/test/csp/test_self_none_as_hostname_confusion.html @@ -0,0 +1,55 @@ + + + + + + Test for Bug 587377 + + + + +Mozilla Bug 587377 +

+ + + +
+
+
+
+ + diff --git a/dom/security/test/csp/test_sendbeacon.html b/dom/security/test/csp/test_sendbeacon.html new file mode 100644 index 0000000000..3b0df34c05 --- /dev/null +++ b/dom/security/test/csp/test_sendbeacon.html @@ -0,0 +1,34 @@ + + + + + Bug 1234813 - sendBeacon should not throw if blocked by Content Policy + + + + + +

+ + + + + diff --git a/dom/security/test/csp/test_service_worker.html b/dom/security/test/csp/test_service_worker.html new file mode 100644 index 0000000000..dc3b3b43d2 --- /dev/null +++ b/dom/security/test/csp/test_service_worker.html @@ -0,0 +1,62 @@ + + + + Bug 1208559 - ServiceWorker registration not governed by CSP + + + + + + + + + + diff --git a/dom/security/test/csp/test_strict_dynamic.html b/dom/security/test/csp/test_strict_dynamic.html new file mode 100644 index 0000000000..f894e6d447 --- /dev/null +++ b/dom/security/test/csp/test_strict_dynamic.html @@ -0,0 +1,133 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + + + + + + + + + diff --git a/dom/security/test/csp/test_strict_dynamic_default_src.html b/dom/security/test/csp/test_strict_dynamic_default_src.html new file mode 100644 index 0000000000..53eb899ab2 --- /dev/null +++ b/dom/security/test/csp/test_strict_dynamic_default_src.html @@ -0,0 +1,136 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + + + + + + + + + diff --git a/dom/security/test/csp/test_strict_dynamic_parser_inserted.html b/dom/security/test/csp/test_strict_dynamic_parser_inserted.html new file mode 100644 index 0000000000..63d2c5a256 --- /dev/null +++ b/dom/security/test/csp/test_strict_dynamic_parser_inserted.html @@ -0,0 +1,94 @@ + + + + Bug 1299483 - CSP: Implement 'strict-dynamic' + + + + + + + + + + diff --git a/dom/security/test/csp/test_subframe_run_js_if_allowed.html b/dom/security/test/csp/test_subframe_run_js_if_allowed.html new file mode 100644 index 0000000000..fbf5a885cd --- /dev/null +++ b/dom/security/test/csp/test_subframe_run_js_if_allowed.html @@ -0,0 +1,33 @@ + + + + + Test for Bug 702439 + + + + + + + + diff --git a/dom/security/test/csp/test_svg_inline_style.html b/dom/security/test/csp/test_svg_inline_style.html new file mode 100644 index 0000000000..c05ca20467 --- /dev/null +++ b/dom/security/test/csp/test_svg_inline_style.html @@ -0,0 +1,135 @@ + + + + Bug 1262842: Test CSP inline style within svg image + + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/test_uir_top_nav.html b/dom/security/test/csp/test_uir_top_nav.html new file mode 100644 index 0000000000..57005ba6f9 --- /dev/null +++ b/dom/security/test/csp/test_uir_top_nav.html @@ -0,0 +1,53 @@ + + + + Bug 1391011: Test uir for toplevel navigations + + + + + + + + + diff --git a/dom/security/test/csp/test_uir_windowwatcher.html b/dom/security/test/csp/test_uir_windowwatcher.html new file mode 100644 index 0000000000..f16b3c93a6 --- /dev/null +++ b/dom/security/test/csp/test_uir_windowwatcher.html @@ -0,0 +1,31 @@ + + + + + Bug 1529893 - Test upgrade-insecure-requests for opening window through nsWindowWatcher + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure.html b/dom/security/test/csp/test_upgrade_insecure.html new file mode 100644 index 0000000000..b0dcdeefd4 --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure.html @@ -0,0 +1,192 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_cors.html b/dom/security/test/csp/test_upgrade_insecure_cors.html new file mode 100644 index 0000000000..3ed53d8108 --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_cors.html @@ -0,0 +1,86 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html b/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html new file mode 100644 index 0000000000..dc6039ec35 --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_docwrite_iframe.html @@ -0,0 +1,54 @@ + + + + + Bug 1273430 - Test CSP upgrade-insecure-requests for doc.write(iframe) + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_loopback.html b/dom/security/test/csp/test_upgrade_insecure_loopback.html new file mode 100644 index 0000000000..f72f95215e --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_loopback.html @@ -0,0 +1,91 @@ + + + + + Bug 1447784 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation.html b/dom/security/test/csp/test_upgrade_insecure_navigation.html new file mode 100644 index 0000000000..5694deb15a --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_navigation.html @@ -0,0 +1,105 @@ + + + + Bug 1271173 - Missing spec on Upgrade Insecure Requests(Navigational Upgrades) + + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html b/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html new file mode 100644 index 0000000000..af25577cbb --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_navigation_redirect.html @@ -0,0 +1,67 @@ + + + + Bug 1422284 - Upgrade insecure requests should only apply to top-level same-origin redirects + + + + + + + + + + diff --git a/dom/security/test/csp/test_upgrade_insecure_reporting.html b/dom/security/test/csp/test_upgrade_insecure_reporting.html new file mode 100644 index 0000000000..4966b8627e --- /dev/null +++ b/dom/security/test/csp/test_upgrade_insecure_reporting.html @@ -0,0 +1,69 @@ + + + + + Bug 1139297 - Implement CSP upgrade-insecure-requests directive + + + + + + + + + + diff --git a/dom/security/test/csp/test_websocket_localhost.html b/dom/security/test/csp/test_websocket_localhost.html new file mode 100644 index 0000000000..6bcc93fceb --- /dev/null +++ b/dom/security/test/csp/test_websocket_localhost.html @@ -0,0 +1,40 @@ + + + + + Bug 1729897: Allow unsecure websocket from localhost page with CSP: upgrade-insecure + + + + + + + + + + diff --git a/dom/security/test/csp/test_websocket_self.html b/dom/security/test/csp/test_websocket_self.html new file mode 100644 index 0000000000..3eae83bfbf --- /dev/null +++ b/dom/security/test/csp/test_websocket_self.html @@ -0,0 +1,61 @@ + + + + + Bug 1345615: Allow websocket schemes when using 'self' in CSP + + + + + + + + + + + diff --git a/dom/security/test/csp/test_win_open_blocked.html b/dom/security/test/csp/test_win_open_blocked.html new file mode 100644 index 0000000000..1335c9d272 --- /dev/null +++ b/dom/security/test/csp/test_win_open_blocked.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + diff --git a/dom/security/test/csp/test_worker_src.html b/dom/security/test/csp/test_worker_src.html new file mode 100644 index 0000000000..5aa8f7bc56 --- /dev/null +++ b/dom/security/test/csp/test_worker_src.html @@ -0,0 +1,105 @@ + + + + + Bug 1302667 - Test worker-src + + + + + + + + + diff --git a/dom/security/test/csp/test_xslt_inherits_csp.html b/dom/security/test/csp/test_xslt_inherits_csp.html new file mode 100644 index 0000000000..90e8372db1 --- /dev/null +++ b/dom/security/test/csp/test_xslt_inherits_csp.html @@ -0,0 +1,33 @@ + + + + + Bug 1597645: Make sure XSLT inherits the CSP r=ckerschb + + + + + + + + + + diff --git a/dom/security/test/csp/worker.sjs b/dom/security/test/csp/worker.sjs new file mode 100644 index 0000000000..e85df3382a --- /dev/null +++ b/dom/security/test/csp/worker.sjs @@ -0,0 +1,114 @@ +Components.utils.importGlobalProperties(["URLSearchParams"]); + +const SJS = "http://mochi.test:8888/tests/dom/security/test/csp/worker.sjs"; + +function createFetchWorker(url) { + return `fetch("${url}");`; +} + +function createXHRWorker(url) { + return ` + try { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "${url}"); + xhr.send(); + } catch(ex) {} + `; +} + +function createImportScriptsWorker(url) { + return ` + try { + importScripts("${url}"); + } catch(ex) {} + `; +} + +function createChildWorkerURL(params) { + let url = SJS + "?" + params.toString(); + return `new Worker("${url}");`; +} + +function createChildWorkerBlob(params) { + let url = SJS + "?" + params.toString(); + return ` + try { + var xhr = new XMLHttpRequest(); + xhr.open("GET", "${url}"); + xhr.responseType = "blob"; + xhr.send(); + xhr.onload = () => { + new Worker(URL.createObjectURL(xhr.response));}; + } catch(ex) {} + `; +} + +function handleRequest(request, response) { + let params = new URLSearchParams(request.queryString); + + let id = params.get("id"); + let base = unescape(params.get("base")); + let child = params.has("child") ? params.get("child") : ""; + + //avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "application/javascript"); + + // Deliver the CSP policy encoded in the URL + if (params.has("csp")) { + response.setHeader( + "Content-Security-Policy", + unescape(params.get("csp")), + false + ); + } + + if (child) { + let childCsp = params.has("childCsp") ? params.get("childCsp") : ""; + params.delete("csp"); + params.delete("child"); + params.delete("childCsp"); + params.append("csp", childCsp); + + switch (child) { + case "blob": + response.write(createChildWorkerBlob(params)); + break; + + case "url": + response.write(createChildWorkerURL(params)); + break; + + default: + response.setStatusLine(request.httpVersion, 400, "Bad request"); + break; + } + + return; + } + + if (params.has("action")) { + switch (params.get("action")) { + case "fetch": + response.write(createFetchWorker(base + "?id=" + id)); + break; + + case "xhr": + response.write(createXHRWorker(base + "?id=" + id)); + break; + + case "importScripts": + response.write(createImportScriptsWorker(base + "?id=" + id)); + break; + + default: + response.setStatusLine(request.httpVersion, 400, "Bad request"); + break; + } + + return; + } + + response.write("I don't know action "); + return; +} diff --git a/dom/security/test/csp/worker_helper.js b/dom/security/test/csp/worker_helper.js new file mode 100644 index 0000000000..3cadec9ea1 --- /dev/null +++ b/dom/security/test/csp/worker_helper.js @@ -0,0 +1,91 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var _tests = []; +function addTest(test) { + _tests.push(test); +} + +function addAsyncTest(fn) { + _tests.push(() => fn().catch(ok.bind(null, false))); +} + +function runNextTest() { + if (!_tests.length) { + SimpleTest.finish(); + return; + } + const fn = _tests.shift(); + try { + fn(); + } catch (ex) { + info( + "Test function " + + (fn.name ? "'" + fn.name + "' " : "") + + "threw an exception: " + + ex + ); + } +} + +/** + * Helper to perform an XHR then blob response to create worker + */ +function doXHRGetBlob(uri) { + return new Promise(resolve => { + const xhr = new XMLHttpRequest(); + xhr.open("GET", uri); + xhr.responseType = "blob"; + xhr.addEventListener("load", function () { + is( + xhr.status, + 200, + "doXHRGetBlob load uri='" + uri + "' status=" + xhr.status + ); + resolve(xhr.response); + }); + xhr.send(); + }); +} + +function removeObserver(observer) { + SpecialPowers.removeObserver(observer, "specialpowers-http-notify-request"); + SpecialPowers.removeObserver(observer, "csp-on-violate-policy"); +} + +/** + * Helper to perform an assert to check if the request should be blocked or + * allowed by CSP + */ +function assertCSPBlock(url, shouldBlock) { + return new Promise((resolve, reject) => { + let observer = { + observe(subject, topic, data) { + if (topic === "specialpowers-http-notify-request") { + if (data == url) { + is(shouldBlock, false, "Should allow request uri='" + url); + removeObserver(observer); + resolve(); + } + } + + if (topic === "csp-on-violate-policy") { + let asciiSpec = SpecialPowers.getPrivilegedProps( + SpecialPowers.do_QueryInterface(subject, "nsIURI"), + "asciiSpec" + ); + if (asciiSpec == url) { + is(shouldBlock, true, "Should block request uri='" + url); + removeObserver(observer); + resolve(); + } + } + }, + }; + + SpecialPowers.addObserver(observer, "csp-on-violate-policy"); + SpecialPowers.addObserver(observer, "specialpowers-http-notify-request"); + }); +} diff --git a/dom/security/test/general/browser.ini b/dom/security/test/general/browser.ini new file mode 100644 index 0000000000..bdbaf86b03 --- /dev/null +++ b/dom/security/test/general/browser.ini @@ -0,0 +1,55 @@ +[DEFAULT] +[browser_test_toplevel_data_navigations.js] +skip-if = (verify && debug && (os == 'mac')) || (debug && (os == 'mac' || os == 'linux')) # Bug 1403815 +support-files = + file_toplevel_data_navigations.sjs + file_toplevel_data_meta_redirect.html +[browser_test_data_download.js] +support-files = + file_data_download.html +[browser_test_data_text_csv.js] +support-files = + file_data_text_csv.html +[browser_test_view_image_data_navigation.js] +support-files = + file_view_image_data_navigation.html + file_view_bg_image_data_navigation.html +[browser_test_assert_systemprincipal_documents.js] +skip-if = !nightly_build +support-files = + file_assert_systemprincipal_documents.html + file_assert_systemprincipal_documents_iframe.html +[browser_test_referrer_loadInOtherProcess.js] +[browser_test_framing_error_pages.js] +support-files = + file_framing_error_pages_csp.html + file_framing_error_pages_xfo.html + file_framing_error_pages.sjs +[browser_test_xfo_embed_object.js] +support-files = + file_framing_xfo_embed.html + file_framing_xfo_object.html + file_framing_xfo_embed_object.sjs +[browser_test_report_blocking.js] +support-files = + file_framing_error_pages_xfo.html + file_framing_error_pages_csp.html + file_framing_error_pages.sjs +[browser_same_site_cookies_bug1748693.js] +support-files = + file_same_site_cookies_bug1748693.sjs +[browser_file_nonscript.js] +support-files = + file_loads_nonscript.html + file_nonscript + file_nonscript.xyz + file_nonscript.html + file_nonscript.txt + file_nonscript.json + file_script.js +[browser_restrict_privileged_about_script.js] +# This test intentionally asserts when in debug builds. Let's rely on opt builds when in CI. +skip-if = debug +support-files = + file_about_child.html + file_1767581.js diff --git a/dom/security/test/general/browser_file_nonscript.js b/dom/security/test/general/browser_file_nonscript.js new file mode 100644 index 0000000000..95243c32a7 --- /dev/null +++ b/dom/security/test/general/browser_file_nonscript.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +add_task(async function test_fileurl_nonscript_load() { + await SpecialPowers.pushPrefEnv({ + set: [["security.block_fileuri_script_with_wrong_mime", true]], + }); + + let file = getChromeDir(getResolvedURI(gTestPath)); + file.append("file_loads_nonscript.html"); + let uriString = Services.io.newFileURI(file).spec; + + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, uriString); + registerCleanupFunction(async function () { + BrowserTestUtils.removeTab(tab); + }); + + let counter = await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + Cu.exportFunction(Assert.equal.bind(Assert), content.window, { + defineAs: "equal", + }); + content.window.postMessage("run", "*"); + + await new Promise(resolve => { + content.window.addEventListener("message", event => { + if (event.data === "done") { + resolve(); + } + }); + }); + + return content.window.wrappedJSObject.counter; + }); + + is(counter, 1, "Only one script should have run"); +}); diff --git a/dom/security/test/general/browser_restrict_privileged_about_script.js b/dom/security/test/general/browser_restrict_privileged_about_script.js new file mode 100644 index 0000000000..0baa6e3d4d --- /dev/null +++ b/dom/security/test/general/browser_restrict_privileged_about_script.js @@ -0,0 +1,70 @@ +"use strict"; + +const kChildPage = getRootDirectory(gTestPath) + "file_about_child.html"; + +const kAboutPagesRegistered = BrowserTestUtils.registerAboutPage( + registerCleanupFunction, + "test-about-privileged-with-scripts", + kChildPage, + Ci.nsIAboutModule.ALLOW_SCRIPT | + Ci.nsIAboutModule.URI_MUST_LOAD_IN_CHILD | + Ci.nsIAboutModule.URI_CAN_LOAD_IN_PRIVILEGEDABOUT_PROCESS | + Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | + Ci.nsIAboutModule.IS_SECURE_CHROME_UI +); + +add_task(async function test_principal_click() { + await kAboutPagesRegistered; + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.skip_about_page_has_csp_assert", true]], + }); + await BrowserTestUtils.withNewTab( + "about:test-about-privileged-with-scripts", + async function (browser) { + // Wait for page to fully load + info("Waiting for tab to be loaded.."); + // let's look into the fully loaded about page + await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [], + async function () { + let channel = content.docShell.currentDocumentChannel; + is( + channel.originalURI.asciiSpec, + "about:test-about-privileged-with-scripts", + "sanity check - make sure we test the principal for the correct URI" + ); + + let triggeringPrincipal = channel.loadInfo.triggeringPrincipal; + ok( + triggeringPrincipal.isSystemPrincipal, + "loading about: from privileged page must have a triggering of System" + ); + + let contentPolicyType = channel.loadInfo.externalContentPolicyType; + is( + contentPolicyType, + Ci.nsIContentPolicy.TYPE_DOCUMENT, + "sanity check - loading a top level document" + ); + + let loadingPrincipal = channel.loadInfo.loadingPrincipal; + is( + loadingPrincipal, + null, + "sanity check - load of TYPE_DOCUMENT must have a null loadingPrincipal" + ); + ok( + !content.document.nodePrincipal.isSystemPrincipal, + "sanity check - loaded about page does not have the system principal" + ); + isnot( + content.testResult, + "fail-script-was-loaded", + "The script from https://example.com shouldn't work in an about: page." + ); + } + ); + } + ); +}); diff --git a/dom/security/test/general/browser_same_site_cookies_bug1748693.js b/dom/security/test/general/browser_same_site_cookies_bug1748693.js new file mode 100644 index 0000000000..da3c3d7762 --- /dev/null +++ b/dom/security/test/general/browser_same_site_cookies_bug1748693.js @@ -0,0 +1,51 @@ +"use strict"; + +const HTTPS_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const HTTP_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +function checkCookies(expectedCookies = {}) { + info(JSON.stringify(expectedCookies)); + return SpecialPowers.spawn( + gBrowser.selectedBrowser, + [expectedCookies], + async function (expectedCookies) { + let cookies = content.document.getElementById("msg").innerHTML; + info(cookies); + for (const [cookie, expected] of Object.entries(expectedCookies)) { + if (expected) { + ok(cookies.includes(cookie), `${cookie} should be sent`); + } else { + ok(!cookies.includes(cookie), `${cookie} should not be sent`); + } + } + } + ); +} + +add_task(async function bug1748693() { + waitForExplicitFinish(); + + let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + BrowserTestUtils.loadURIString( + gBrowser, + `${HTTPS_PATH}file_same_site_cookies_bug1748693.sjs?setcookies` + ); + await loaded; + + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + BrowserTestUtils.loadURIString( + gBrowser, + `${HTTP_PATH}file_same_site_cookies_bug1748693.sjs` + ); + await loaded; + + await checkCookies({ auth: true, auth_secure: false }); + + finish(); +}); diff --git a/dom/security/test/general/browser_test_assert_systemprincipal_documents.js b/dom/security/test/general/browser_test_assert_systemprincipal_documents.js new file mode 100644 index 0000000000..8804e85b2c --- /dev/null +++ b/dom/security/test/general/browser_test_assert_systemprincipal_documents.js @@ -0,0 +1,41 @@ +//"use strict" + +const kTestPath = getRootDirectory(gTestPath); +const kTestURI = kTestPath + "file_assert_systemprincipal_documents.html"; + +add_setup(async function () { + // We expect the assertion in function + // CheckSystemPrincipalLoads as defined in + // file dom/security/nsContentSecurityManager.cpp + SimpleTest.expectAssertions(1); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.disallow_non_local_systemprincipal_in_tests", true], + ["security.allow_unsafe_parent_loads", true], + ], + }); +}); + +add_task(async function open_test_iframe_in_tab() { + // This looks at the iframe (load type SUBDOCUMENT) + await BrowserTestUtils.withNewTab( + { gBrowser, url: kTestURI }, + async browser => { + await SpecialPowers.spawn(browser, [], async function () { + let outerPrincipal = content.document.nodePrincipal; + ok( + outerPrincipal.isSystemPrincipal, + "Sanity: Using SystemPrincipal for test file on chrome://" + ); + const iframeDoc = + content.document.getElementById("testframe").contentDocument; + is( + iframeDoc.body.innerHTML, + "", + "iframe with systemprincipal should be empty document" + ); + }); + } + ); +}); diff --git a/dom/security/test/general/browser_test_data_download.js b/dom/security/test/general/browser_test_data_download.js new file mode 100644 index 0000000000..a74126971f --- /dev/null +++ b/dom/security/test/general/browser_test_data_download.js @@ -0,0 +1,113 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); +const kTestURI = kTestPath + "file_data_download.html"; + +function addWindowListener(aURL) { + return new Promise(resolve => { + Services.wm.addListener({ + onOpenWindow(aXULWindow) { + info("window opened, waiting for focus"); + Services.wm.removeListener(this); + var domwindow = aXULWindow.docShell.domWindow; + waitForFocus(function () { + is( + domwindow.document.location.href, + aURL, + "should have seen the right window open" + ); + resolve(domwindow); + }, domwindow); + }, + onCloseWindow(aXULWindow) {}, + }); + }); +} + +function waitDelay(delay) { + return new Promise((resolve, reject) => { + /* eslint-disable mozilla/no-arbitrary-setTimeout */ + window.setTimeout(resolve, delay); + }); +} + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +add_task(async function test_with_downloads_pref_disabled() { + waitForExplicitFinish(); + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.data_uri.block_toplevel_data_uri_navigations", true], + ["browser.download.always_ask_before_handling_new_types", true], + ], + }); + let windowPromise = addWindowListener( + "chrome://mozapps/content/downloads/unknownContentType.xhtml" + ); + BrowserTestUtils.loadURIString(gBrowser, kTestURI); + let win = await windowPromise; + + is( + win.document.getElementById("location").value, + "data-foo.html", + "file name of download should match" + ); + + let mainWindowActivated = BrowserTestUtils.waitForEvent(window, "activate"); + await BrowserTestUtils.closeWindow(win); + await mainWindowActivated; +}); + +add_task(async function test_with_always_ask_pref_disabled() { + waitForExplicitFinish(); + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.data_uri.block_toplevel_data_uri_navigations", true], + ["browser.download.always_ask_before_handling_new_types", false], + ], + }); + let downloadsPanelPromise = promisePanelOpened(); + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + + BrowserTestUtils.loadURIString(gBrowser, kTestURI); + // wait until downloadsPanel opens before continuing with test + await downloadsPanelPromise; + let downloadList = await downloadsPromise; + + is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open."); + is( + downloadList._downloads.length, + 1, + "File should be successfully downloaded." + ); + + let [download] = downloadList._downloads; + is(download.contentType, "text/html", "File contentType should be correct."); + is( + download.source.url, + "data:text/html,data download", + "File name should be correct." + ); + + info("cleaning up downloads"); + try { + if (Services.appinfo.OS === "WINNT") { + // We need to make the file writable to delete it on Windows. + await IOUtils.setPermissions(download.target.path, 0o600); + } + await IOUtils.remove(download.target.path); + } catch (error) { + info("The file " + download.target.path + " is not removed, " + error); + } + + await downloadList.remove(download); + await download.finalize(); +}); diff --git a/dom/security/test/general/browser_test_data_text_csv.js b/dom/security/test/general/browser_test_data_text_csv.js new file mode 100644 index 0000000000..2c013a0d61 --- /dev/null +++ b/dom/security/test/general/browser_test_data_text_csv.js @@ -0,0 +1,108 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); +const kTestURI = kTestPath + "file_data_text_csv.html"; + +function addWindowListener(aURL, aCallback) { + return new Promise(resolve => { + Services.wm.addListener({ + onOpenWindow(aXULWindow) { + info("window opened, waiting for focus"); + Services.wm.removeListener(this); + var domwindow = aXULWindow.docShell.domWindow; + waitForFocus(function () { + is( + domwindow.document.location.href, + aURL, + "should have seen the right window open" + ); + resolve(domwindow); + }, domwindow); + }, + onCloseWindow(aXULWindow) {}, + }); + }); +} + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +add_task(async function test_with_pref_enabled() { + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.data_uri.block_toplevel_data_uri_navigations", true], + ["browser.download.always_ask_before_handling_new_types", true], + ], + }); + + let windowPromise = addWindowListener( + "chrome://mozapps/content/downloads/unknownContentType.xhtml" + ); + BrowserTestUtils.loadURIString(gBrowser, kTestURI); + let win = await windowPromise; + + let expectedValue = "Untitled.csv"; + is( + win.document.getElementById("location").value, + expectedValue, + "file name of download should match" + ); + let mainWindowActivated = BrowserTestUtils.waitForEvent(window, "activate"); + await BrowserTestUtils.closeWindow(win); + await mainWindowActivated; +}); + +add_task(async function test_with_pref_disabled() { + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.data_uri.block_toplevel_data_uri_navigations", true], + ["browser.download.always_ask_before_handling_new_types", false], + ], + }); + let downloadsPanelPromise = promisePanelOpened(); + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + let sourceURLBit = "text/csv;foo,bar,foobar"; + + info("Loading URI for pref enabled"); + BrowserTestUtils.loadURIString(gBrowser, kTestURI); + info("Waiting for downloads panel to open"); + await downloadsPanelPromise; + info("Getting downloads info after opening downloads panel"); + let downloadList = await downloadsPromise; + + is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open."); + is( + downloadList._downloads.length, + 1, + "File should be successfully downloaded." + ); + + let [download] = downloadList._downloads; + is(download.contentType, "text/csv", "File contentType should be correct."); + is( + download.source.url, + `data:${sourceURLBit}`, + "File name should be correct." + ); + + info("Cleaning up downloads"); + try { + if (Services.appinfo.OS === "WINNT") { + // We need to make the file writable to delete it on Windows. + await IOUtils.setPermissions(download.target.path, 0o600); + } + await IOUtils.remove(download.target.path); + } catch (ex) { + info("The file " + download.target.path + " is not removed, " + ex); + } + + await downloadList.remove(download); + await download.finalize(); +}); diff --git a/dom/security/test/general/browser_test_framing_error_pages.js b/dom/security/test/general/browser_test_framing_error_pages.js new file mode 100644 index 0000000000..16e67eb702 --- /dev/null +++ b/dom/security/test/general/browser_test_framing_error_pages.js @@ -0,0 +1,53 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const kTestXFrameOptionsURI = kTestPath + "file_framing_error_pages_xfo.html"; +const kTestXFrameOptionsURIFrame = + kTestPath + "file_framing_error_pages.sjs?xfo"; + +const kTestFrameAncestorsURI = kTestPath + "file_framing_error_pages_csp.html"; +const kTestFrameAncestorsURIFrame = + kTestPath + "file_framing_error_pages.sjs?csp"; + +add_task(async function open_test_xfo_error_page() { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + let loaded = BrowserTestUtils.browserLoaded( + browser, + true, + kTestXFrameOptionsURIFrame, + true + ); + BrowserTestUtils.loadURIString(browser, kTestXFrameOptionsURI); + await loaded; + + await SpecialPowers.spawn(browser, [], async function () { + const iframeDoc = + content.document.getElementById("testframe").contentDocument; + let errorPage = iframeDoc.body.innerHTML; + ok(errorPage.includes("csp-xfo-error-title"), "xfo error page correct"); + }); + }); +}); + +add_task(async function open_test_csp_frame_ancestor_error_page() { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + let loaded = BrowserTestUtils.browserLoaded( + browser, + true, + kTestFrameAncestorsURIFrame, + true + ); + BrowserTestUtils.loadURIString(browser, kTestFrameAncestorsURI); + await loaded; + + await SpecialPowers.spawn(browser, [], async function () { + const iframeDoc = + content.document.getElementById("testframe").contentDocument; + let errorPage = iframeDoc.body.innerHTML; + ok(errorPage.includes("csp-xfo-error-title"), "csp error page correct"); + }); + }); +}); diff --git a/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js b/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js new file mode 100644 index 0000000000..7da60b727d --- /dev/null +++ b/dom/security/test/general/browser_test_referrer_loadInOtherProcess.js @@ -0,0 +1,156 @@ +const TEST_PAGE = + "https://example.org/browser/browser/base/content/test/general/dummy_page.html"; +const TEST_REFERRER = "http://mochi.test:8888/"; + +const ReferrerInfo = Components.Constructor( + "@mozilla.org/referrer-info;1", + "nsIReferrerInfo", + "init" +); + +let referrerInfo = new ReferrerInfo( + Ci.nsIReferrerInfo.ORIGIN, + true, + Services.io.newURI(TEST_REFERRER) +); +let deReferrerInfo = E10SUtils.serializeReferrerInfo(referrerInfo); + +var checkResult = async function (isRemote, browserKey, uri) { + is( + gBrowser.selectedBrowser.isRemoteBrowser, + isRemote, + "isRemoteBrowser should be correct" + ); + + is( + gBrowser.selectedBrowser.permanentKey, + browserKey, + "browser.permanentKey should be correct" + ); + + if (SpecialPowers.Services.appinfo.sessionHistoryInParent) { + let sessionHistory = + gBrowser.selectedBrowser.browsingContext.sessionHistory; + let entry = sessionHistory.getEntryAtIndex(sessionHistory.count - 1); + let args = { uri, referrerInfo: deReferrerInfo, isRemote }; + Assert.equal(entry.URI.spec, args.uri, "Uri should be correct"); + + // Main process like about:mozilla does not trigger the real network request. + // So we don't store referrerInfo in sessionHistory in that case. + // Besides, the referrerInfo stored in sessionHistory was computed, we only + // check pre-computed things. + if (args.isRemote) { + let resultReferrerInfo = entry.referrerInfo; + let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo( + args.referrerInfo + ); + + Assert.equal( + resultReferrerInfo.originalReferrer.spec, + expectedReferrerInfo.originalReferrer.spec, + "originalReferrer should be correct" + ); + Assert.equal( + resultReferrerInfo.sendReferrer, + expectedReferrerInfo.sendReferrer, + "sendReferrer should be correct" + ); + Assert.equal( + resultReferrerInfo.referrerPolicy, + expectedReferrerInfo.referrerPolicy, + "referrerPolicy should be correct" + ); + } else { + Assert.equal(entry.referrerInfo, null, "ReferrerInfo should be correct"); + } + + return; + } + + await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [{ uri, referrerInfo: deReferrerInfo, isRemote }], + async function (args) { + let webNav = content.docShell.QueryInterface(Ci.nsIWebNavigation); + let sessionHistory = webNav.sessionHistory; + let entry = sessionHistory.legacySHistory.getEntryAtIndex( + sessionHistory.count - 1 + ); + + var { E10SUtils } = SpecialPowers.ChromeUtils.importESModule( + "resource://gre/modules/E10SUtils.sys.mjs" + ); + + Assert.equal(entry.URI.spec, args.uri, "Uri should be correct"); + + // Main process like about:mozilla does not trigger the real network request. + // So we don't store referrerInfo in sessionHistory in that case. + // Besides, the referrerInfo stored in sessionHistory was computed, we only + // check pre-computed things. + if (args.isRemote) { + let resultReferrerInfo = entry.referrerInfo; + let expectedReferrerInfo = E10SUtils.deserializeReferrerInfo( + args.referrerInfo + ); + + Assert.equal( + resultReferrerInfo.originalReferrer.spec, + expectedReferrerInfo.originalReferrer.spec, + "originalReferrer should be correct" + ); + Assert.equal( + resultReferrerInfo.sendReferrer, + expectedReferrerInfo.sendReferrer, + "sendReferrer should be correct" + ); + Assert.equal( + resultReferrerInfo.referrerPolicy, + expectedReferrerInfo.referrerPolicy, + "referrerPolicy should be correct" + ); + } else { + Assert.equal( + entry.referrerInfo, + null, + "ReferrerInfo should be correct" + ); + } + } + ); +}; +var waitForLoad = async function (uri) { + info("waitForLoad " + uri); + let loadURIOptions = { + triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), + referrerInfo, + }; + gBrowser.selectedBrowser.webNavigation.loadURI( + Services.io.newURI(uri), + loadURIOptions + ); + + await BrowserTestUtils.browserStopped(gBrowser, uri); +}; + +// Tests referrerInfo when navigating from a page in the remote process to main +// process and vice versa. +add_task(async function test_navigation() { + // Navigate from non remote to remote + gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:blank"); + let testURI = TEST_PAGE; + let { permanentKey } = gBrowser.selectedBrowser; + await waitForLoad(testURI); + await checkResult(true, permanentKey, testURI); + gBrowser.removeCurrentTab(); + + // Navigate from remote to non-remote + gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, TEST_PAGE); + // Wait for the non-blank page to finish loading + await BrowserTestUtils.browserStopped(gBrowser, TEST_PAGE); + testURI = "about:mozilla"; + permanentKey = gBrowser.selectedBrowser.permanentKey; + await waitForLoad(testURI); + await checkResult(false, permanentKey, testURI); + + gBrowser.removeCurrentTab(); +}); diff --git a/dom/security/test/general/browser_test_report_blocking.js b/dom/security/test/general/browser_test_report_blocking.js new file mode 100644 index 0000000000..4937a47c4f --- /dev/null +++ b/dom/security/test/general/browser_test_report_blocking.js @@ -0,0 +1,218 @@ +"use strict"; + +const { TelemetryArchiveTesting } = ChromeUtils.importESModule( + "resource://testing-common/TelemetryArchiveTesting.sys.mjs" +); + +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +const kTestXFrameOptionsURI = kTestPath + "file_framing_error_pages_xfo.html"; +const kTestCspURI = kTestPath + "file_framing_error_pages_csp.html"; +const kTestXFrameOptionsURIFrame = + kTestPath + "file_framing_error_pages.sjs?xfo"; +const kTestCspURIFrame = kTestPath + "file_framing_error_pages.sjs?csp"; + +const kTestExpectedPingXFO = [ + [["payload", "error_type"], "xfo"], + [["payload", "xfo_header"], "deny"], + [["payload", "csp_header"], ""], + [["payload", "frame_hostname"], "example.com"], + [["payload", "top_hostname"], "example.com"], + [ + ["payload", "frame_uri"], + "https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs", + ], + [ + ["payload", "top_uri"], + "https://example.com/browser/dom/security/test/general/file_framing_error_pages_xfo.html", + ], +]; + +const kTestExpectedPingCSP = [ + [["payload", "error_type"], "csp"], + [["payload", "xfo_header"], ""], + [["payload", "csp_header"], "'none'"], + [["payload", "frame_hostname"], "example.com"], + [["payload", "top_hostname"], "example.com"], + [ + ["payload", "frame_uri"], + "https://example.com/browser/dom/security/test/general/file_framing_error_pages.sjs", + ], + [ + ["payload", "top_uri"], + "https://example.com/browser/dom/security/test/general/file_framing_error_pages_csp.html", + ], +]; + +const TEST_CASES = [ + { + type: "xfo", + test_uri: kTestXFrameOptionsURI, + frame_uri: kTestXFrameOptionsURIFrame, + expected_ping: kTestExpectedPingXFO, + }, + { + type: "csp", + test_uri: kTestCspURI, + frame_uri: kTestCspURIFrame, + expected_ping: kTestExpectedPingCSP, + }, +]; + +add_setup(async function () { + Services.telemetry.setEventRecordingEnabled("security.ui.xfocsperror", true); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.xfocsp.errorReporting.enabled", true], + ["security.xfocsp.errorReporting.automatic", false], + ], + }); +}); + +add_task(async function testReportingCases() { + for (const test of TEST_CASES) { + await testReporting(test); + } +}); + +async function testReporting(test) { + // Clear telemetry event before testing. + Services.telemetry.clearEvents(); + + let telemetryChecker = new TelemetryArchiveTesting.Checker(); + await telemetryChecker.promiseInit(); + + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "about:blank" + ); + let browser = tab.linkedBrowser; + + let loaded = BrowserTestUtils.browserLoaded( + browser, + true, + test.frame_uri, + true + ); + BrowserTestUtils.loadURIString(browser, test.test_uri); + await loaded; + + let { type } = test; + + let frameBC = await SpecialPowers.spawn(browser, [], async _ => { + const iframe = content.document.getElementById("testframe"); + return iframe.browsingContext; + }); + + await SpecialPowers.spawn(frameBC, [type], async obj => { + // Wait until the reporting UI is visible. + await ContentTaskUtils.waitForCondition(() => { + let reportUI = content.document.getElementById("blockingErrorReporting"); + return ContentTaskUtils.is_visible(reportUI); + }); + + let reportCheckBox = content.document.getElementById( + "automaticallyReportBlockingInFuture" + ); + is( + reportCheckBox.checked, + false, + "The checkbox of the reporting ui should be not checked." + ); + + // Click on the checkbox. + await EventUtils.synthesizeMouseAtCenter(reportCheckBox, {}, content); + }); + BrowserTestUtils.removeTab(tab); + + // Open the error page again + tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + browser = tab.linkedBrowser; + + loaded = BrowserTestUtils.browserLoaded(browser, true, test.frame_uri, true); + BrowserTestUtils.loadURIString(browser, test.test_uri); + await loaded; + + frameBC = await SpecialPowers.spawn(browser, [], async _ => { + const iframe = content.document.getElementById("testframe"); + return iframe.browsingContext; + }); + + await SpecialPowers.spawn(frameBC, [], async _ => { + // Wait until the reporting UI is visible. + await ContentTaskUtils.waitForCondition(() => { + let reportUI = content.document.getElementById("blockingErrorReporting"); + return ContentTaskUtils.is_visible(reportUI); + }); + + let reportCheckBox = content.document.getElementById( + "automaticallyReportBlockingInFuture" + ); + is( + reportCheckBox.checked, + true, + "The checkbox of the reporting ui should be checked." + ); + + // Click on the checkbox again to disable the reporting. + await EventUtils.synthesizeMouseAtCenter(reportCheckBox, {}, content); + + is( + reportCheckBox.checked, + false, + "The checkbox of the reporting ui should be unchecked." + ); + }); + BrowserTestUtils.removeTab(tab); + + // Open the error page again to see if the reporting is disabled. + tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank"); + browser = tab.linkedBrowser; + + loaded = BrowserTestUtils.browserLoaded(browser, true, test.frame_uri, true); + BrowserTestUtils.loadURIString(browser, test.test_uri); + await loaded; + + frameBC = await SpecialPowers.spawn(browser, [], async _ => { + const iframe = content.document.getElementById("testframe"); + return iframe.browsingContext; + }); + + await SpecialPowers.spawn(frameBC, [], async _ => { + // Wait until the reporting UI is visible. + await ContentTaskUtils.waitForCondition(() => { + let reportUI = content.document.getElementById("blockingErrorReporting"); + return ContentTaskUtils.is_visible(reportUI); + }); + + let reportCheckBox = content.document.getElementById( + "automaticallyReportBlockingInFuture" + ); + is( + reportCheckBox.checked, + false, + "The checkbox of the reporting ui should be unchecked." + ); + }); + BrowserTestUtils.removeTab(tab); + + // Finally, check if the ping has been archived. + await new Promise(resolve => { + telemetryChecker + .promiseFindPing("xfocsp-error-report", test.expected_ping) + .then( + found => { + ok(found, "Telemetry ping submitted successfully"); + resolve(); + }, + err => { + ok(false, "Exception finding telemetry ping: " + err); + resolve(); + } + ); + }); +} diff --git a/dom/security/test/general/browser_test_toplevel_data_navigations.js b/dom/security/test/general/browser_test_toplevel_data_navigations.js new file mode 100644 index 0000000000..0e006f1fd2 --- /dev/null +++ b/dom/security/test/general/browser_test_toplevel_data_navigations.js @@ -0,0 +1,70 @@ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ + +"use strict"; + +const kDataBody = "toplevel navigation to data: URI allowed"; +const kDataURI = "data:text/html," + kDataBody + ""; +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); +const kRedirectURI = kTestPath + "file_toplevel_data_navigations.sjs"; +const kMetaRedirectURI = kTestPath + "file_toplevel_data_meta_redirect.html"; + +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 SpecialPowers.spawn( + gBrowser.selectedBrowser, + [{ kDataBody }], + async function ({ kDataBody }) { + // eslint-disable-line + is( + content.document.body.innerHTML, + kDataBody, + "data: URI navigation from system should be allowed" + ); + } + ); + }); +}); + +add_task(async function test_nav_data_uri_redirect() { + await SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + let tab = BrowserTestUtils.addTab(gBrowser, kRedirectURI); + registerCleanupFunction(async function () { + BrowserTestUtils.removeTab(tab); + }); + // wait to make sure data: URI did not load before checking that it got blocked + await new Promise(resolve => setTimeout(resolve, 500)); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + is( + content.document.body.innerHTML, + "", + "data: URI navigation after server redirect should be blocked" + ); + }); +}); + +add_task(async function test_nav_data_uri_meta_redirect() { + await SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + let tab = BrowserTestUtils.addTab(gBrowser, kMetaRedirectURI); + registerCleanupFunction(async function () { + BrowserTestUtils.removeTab(tab); + }); + // wait to make sure data: URI did not load before checking that it got blocked + await new Promise(resolve => setTimeout(resolve, 500)); + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () { + is( + content.document.body.innerHTML, + "", + "data: URI navigation after meta redirect should be blocked" + ); + }); +}); 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 new file mode 100644 index 0000000000..90aace1e3e --- /dev/null +++ b/dom/security/test/general/browser_test_view_image_data_navigation.js @@ -0,0 +1,71 @@ +"use strict"; + +add_task(async function test_principal_right_click_open_link_in_new_tab() { + await SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + + const TEST_PAGE = + getRootDirectory(gTestPath) + "file_view_image_data_navigation.html"; + + await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) { + let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true); + + // simulate right-click->view-image + BrowserTestUtils.waitForEvent(document, "popupshown", false, event => { + // These are operations that must be executed synchronously with the event. + document.getElementById("context-viewimage").doCommand(); + event.target.hidePopup(); + return true; + }); + BrowserTestUtils.synthesizeMouseAtCenter( + "#testimage", + { type: "contextmenu", button: 2 }, + gBrowser.selectedBrowser + ); + let tab = await loadPromise; + + let spec = tab.linkedBrowser.currentURI.spec; + ok( + spec.startsWith("data:image/svg+xml;"), + "data:image/svg navigation allowed through right-click view-image" + ); + + gBrowser.removeTab(tab); + }); +}); + +add_task(async function test_right_click_open_bg_image() { + await SpecialPowers.pushPrefEnv({ + set: [["security.data_uri.block_toplevel_data_uri_navigations", true]], + }); + + const TEST_PAGE = + getRootDirectory(gTestPath) + "file_view_bg_image_data_navigation.html"; + + await BrowserTestUtils.withNewTab(TEST_PAGE, async function (browser) { + let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, null, true); + + // simulate right-click->view-image + BrowserTestUtils.waitForEvent(document, "popupshown", false, event => { + // These are operations that must be executed synchronously with the event. + document.getElementById("context-viewimage").doCommand(); + event.target.hidePopup(); + return true; + }); + BrowserTestUtils.synthesizeMouseAtCenter( + "#testbody", + { type: "contextmenu", button: 2 }, + gBrowser.selectedBrowser + ); + let tab = await loadPromise; + + let spec = tab.linkedBrowser.currentURI.spec; + ok( + spec.startsWith("data:image/svg+xml;"), + "data:image/svg navigation allowed through right-click view-image with background image" + ); + + gBrowser.removeTab(tab); + }); +}); diff --git a/dom/security/test/general/browser_test_xfo_embed_object.js b/dom/security/test/general/browser_test_xfo_embed_object.js new file mode 100644 index 0000000000..e9aebbe630 --- /dev/null +++ b/dom/security/test/general/browser_test_xfo_embed_object.js @@ -0,0 +1,41 @@ +"use strict"; + +const kTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const kTestXFOEmbedURI = kTestPath + "file_framing_xfo_embed.html"; +const kTestXFOObjectURI = kTestPath + "file_framing_xfo_object.html"; + +const errorMessage = `The loading of “https://example.com/browser/dom/security/test/general/file_framing_xfo_embed_object.sjs” in a frame is denied by “X-Frame-Options“ directive set to “deny“`; + +let xfoBlocked = false; + +function onXFOMessage(msgObj) { + const message = msgObj.message; + + if (message.includes(errorMessage)) { + ok(true, "XFO error message logged"); + xfoBlocked = true; + } +} + +add_task(async function open_test_xfo_embed_blocked() { + xfoBlocked = false; + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + Services.console.registerListener(onXFOMessage); + BrowserTestUtils.loadURIString(browser, kTestXFOEmbedURI); + await BrowserTestUtils.waitForCondition(() => xfoBlocked); + Services.console.unregisterListener(onXFOMessage); + }); +}); + +add_task(async function open_test_xfo_object_blocked() { + xfoBlocked = false; + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + Services.console.registerListener(onXFOMessage); + BrowserTestUtils.loadURIString(browser, kTestXFOObjectURI); + await BrowserTestUtils.waitForCondition(() => xfoBlocked); + Services.console.unregisterListener(onXFOMessage); + }); +}); diff --git a/dom/security/test/general/bug1277803.html b/dom/security/test/general/bug1277803.html new file mode 100644 index 0000000000..c8033551a0 --- /dev/null +++ b/dom/security/test/general/bug1277803.html @@ -0,0 +1,11 @@ + + + + + + + +Nothing to see here... + + + diff --git a/dom/security/test/general/chrome.ini b/dom/security/test/general/chrome.ini new file mode 100644 index 0000000000..35d7e44d89 --- /dev/null +++ b/dom/security/test/general/chrome.ini @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = + favicon_bug1277803.ico + bug1277803.html + +[test_innerhtml_sanitizer.html] +[test_innerhtml_sanitizer.xhtml] +[test_bug1277803.xhtml] +skip-if = os == 'android' + verify + diff --git a/dom/security/test/general/closeWindow.sjs b/dom/security/test/general/closeWindow.sjs new file mode 100644 index 0000000000..996db36f6f --- /dev/null +++ b/dom/security/test/general/closeWindow.sjs @@ -0,0 +1,24 @@ +const BODY = ` + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString.includes("unset")) { + response.setHeader("Set-Cookie", "test=wow", true); + } + + if (request.queryString.includes("none")) { + response.setHeader("Set-Cookie", "test2=wow2; samesite=none", true); + } + + if (request.queryString.includes("lax")) { + response.setHeader("Set-Cookie", "test3=wow3; samesite=lax", true); + } + + response.write(BODY); +} diff --git a/dom/security/test/general/favicon_bug1277803.ico b/dom/security/test/general/favicon_bug1277803.ico new file mode 100644 index 0000000000..d44438903b Binary files /dev/null and b/dom/security/test/general/favicon_bug1277803.ico differ diff --git a/dom/security/test/general/file_1767581.js b/dom/security/test/general/file_1767581.js new file mode 100644 index 0000000000..259435b1e4 --- /dev/null +++ b/dom/security/test/general/file_1767581.js @@ -0,0 +1 @@ +window.testResult = "fail-script-was-loaded"; diff --git a/dom/security/test/general/file_about_child.html b/dom/security/test/general/file_about_child.html new file mode 100644 index 0000000000..d83e0e4d41 --- /dev/null +++ b/dom/security/test/general/file_about_child.html @@ -0,0 +1,11 @@ + + + + + Test for Bug 1767581 + + + + Just an about page that loads in the privileged about process! + + \ No newline at end of file diff --git a/dom/security/test/general/file_assert_systemprincipal_documents.html b/dom/security/test/general/file_assert_systemprincipal_documents.html new file mode 100644 index 0000000000..2d7ff4d253 --- /dev/null +++ b/dom/security/test/general/file_assert_systemprincipal_documents.html @@ -0,0 +1,11 @@ + + + + Bug 1543579: Block web documents loading into system land + + +

This page loads documents from the SystemPrincipal (which should be blocked)

+ + + + diff --git a/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html b/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html new file mode 100644 index 0000000000..704625a1da --- /dev/null +++ b/dom/security/test/general/file_assert_systemprincipal_documents_iframe.html @@ -0,0 +1,9 @@ + + + + Bug 1543579: Block web documents loading into system land + + +

This is the iframe that should not load.

+ + diff --git a/dom/security/test/general/file_block_script_wrong_mime_server.sjs b/dom/security/test/general/file_block_script_wrong_mime_server.sjs new file mode 100644 index 0000000000..0025bbfbe8 --- /dev/null +++ b/dom/security/test/general/file_block_script_wrong_mime_server.sjs @@ -0,0 +1,38 @@ +// Custom *.sjs specifically for the needs of: +// Bug 1288361 - Block scripts with wrong MIME type + +"use strict"; +Cu.importGlobalProperties(["URLSearchParams"]); + +const WORKER = ` + onmessage = function(event) { + postMessage("worker-loaded"); + };`; + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // Set MIME type + response.setHeader("Content-Type", query.get("mime"), false); + + // Deliver response + switch (query.get("type")) { + case "script": + response.write(""); + break; + case "worker": + response.write(WORKER); + break; + case "worker-import": + response.write( + `importScripts("file_block_script_wrong_mime_server.sjs?type=script&mime=${query.get( + "mime" + )}");` + ); + response.write(WORKER); + break; + } +} diff --git a/dom/security/test/general/file_block_subresource_redir_to_data.sjs b/dom/security/test/general/file_block_subresource_redir_to_data.sjs new file mode 100644 index 0000000000..1e312bc810 --- /dev/null +++ b/dom/security/test/general/file_block_subresource_redir_to_data.sjs @@ -0,0 +1,33 @@ +"use strict"; + +let SCRIPT_DATA = "alert('this alert should be blocked');"; +let WORKER_DATA = + "onmessage = function(event) { postMessage('worker-loaded'); }"; + +function handleRequest(request, response) { + const query = request.queryString; + + response.setHeader("Cache-Control", "no-cache", false); + response.setStatusLine("1.1", 302, "Found"); + + if (query === "script" || query === "modulescript") { + response.setHeader( + "Location", + "data:text/javascript," + escape(SCRIPT_DATA), + false + ); + return; + } + + if (query === "worker") { + response.setHeader( + "Location", + "data:text/javascript," + escape(WORKER_DATA), + false + ); + return; + } + + // we should never get here; just in case return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/general/file_block_toplevel_data_navigation.html b/dom/security/test/general/file_block_toplevel_data_navigation.html new file mode 100644 index 0000000000..d6e083a247 --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation.html @@ -0,0 +1,16 @@ + + + + + Toplevel data navigation + + +test1: clicking data: URI tries to navigate window
+ +click me + + + diff --git a/dom/security/test/general/file_block_toplevel_data_navigation2.html b/dom/security/test/general/file_block_toplevel_data_navigation2.html new file mode 100644 index 0000000000..957189ce07 --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation2.html @@ -0,0 +1,17 @@ + + + + + Toplevel data navigation + + +test2: data: URI in iframe tries to window.open(data:, _blank);
+ + + + diff --git a/dom/security/test/general/file_block_toplevel_data_navigation3.html b/dom/security/test/general/file_block_toplevel_data_navigation3.html new file mode 100644 index 0000000000..3743a72034 --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_navigation3.html @@ -0,0 +1,16 @@ + + + + + Toplevel data navigation + + +test3: performing data: URI navigation through win.loc.href
+ + + diff --git a/dom/security/test/general/file_block_toplevel_data_redirect.sjs b/dom/security/test/general/file_block_toplevel_data_redirect.sjs new file mode 100644 index 0000000000..c03ace5f23 --- /dev/null +++ b/dom/security/test/general/file_block_toplevel_data_redirect.sjs @@ -0,0 +1,13 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1394554 - Block toplevel data: URI navigations after redirect + +var DATA_URI = + "toplevel data: URI navigations after redirect should be blocked"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", "data:text/html," + escape(DATA_URI), false); +} diff --git a/dom/security/test/general/file_cache_splitting_isloaded.sjs b/dom/security/test/general/file_cache_splitting_isloaded.sjs new file mode 100644 index 0000000000..a40b9674e5 --- /dev/null +++ b/dom/security/test/general/file_cache_splitting_isloaded.sjs @@ -0,0 +1,35 @@ +/* + Helper Server - + Send a Request with ?queryResult - response will be the + queryString of the next request. + +*/ +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // save the object state of the initial request, which returns + // async once the server has processed the img request. + if (request.queryString.includes("wait")) { + response.processAsync(); + setObjectState("wait", response); + return; + } + + response.write(IMG_BYTES); + + // return the result + getObjectState("wait", function (queryResponse) { + if (!queryResponse) { + return; + } + queryResponse.write("1"); + queryResponse.finish(); + }); +} diff --git a/dom/security/test/general/file_cache_splitting_server.sjs b/dom/security/test/general/file_cache_splitting_server.sjs new file mode 100644 index 0000000000..da75986f74 --- /dev/null +++ b/dom/security/test/general/file_cache_splitting_server.sjs @@ -0,0 +1,27 @@ +function handleRequest(request, response) { + var receivedRequests = parseInt(getState("requests")); + if (isNaN(receivedRequests)) { + receivedRequests = 0; + } + if (request.queryString.includes("state")) { + response.write(receivedRequests); + return; + } + if (request.queryString.includes("flush")) { + setState("requests", "0"); + response.write("OK"); + return; + } + response.setHeader("Cache-Control", "max-age=999999"); // Force caching + response.setHeader("Content-Type", "text/css"); + receivedRequests = receivedRequests + 1; + setState("requests", "" + receivedRequests); + response.write(` + .test{ + color:red; + } + .test h1{ + font-size:200px; + } + `); +} diff --git a/dom/security/test/general/file_cache_splitting_window.html b/dom/security/test/general/file_cache_splitting_window.html new file mode 100644 index 0000000000..59a2ff2ca9 --- /dev/null +++ b/dom/security/test/general/file_cache_splitting_window.html @@ -0,0 +1,17 @@ + + + + + Document + + + +

HELLO WORLD!

+ + + + diff --git a/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs b/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs new file mode 100644 index 0000000000..9ee73ae3c4 --- /dev/null +++ b/dom/security/test/general/file_contentpolicytype_targeted_link_iframe.sjs @@ -0,0 +1,45 @@ +// custom *.sjs for Bug 1255240 + +const TEST_FRAME = ` + + + + + click me + + + + `; + +const INNER_FRAME = ` + + + + hello world! + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + var queryString = request.queryString; + + if (queryString === "testframe") { + response.write(TEST_FRAME); + return; + } + + if (queryString === "innerframe") { + response.write(INNER_FRAME); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/general/file_data_download.html b/dom/security/test/general/file_data_download.html new file mode 100644 index 0000000000..4cc92fe8f5 --- /dev/null +++ b/dom/security/test/general/file_data_download.html @@ -0,0 +1,14 @@ + + + + Test download attribute for data: URI + + + download data + + + diff --git a/dom/security/test/general/file_data_text_csv.html b/dom/security/test/general/file_data_text_csv.html new file mode 100644 index 0000000000..a9ac369d16 --- /dev/null +++ b/dom/security/test/general/file_data_text_csv.html @@ -0,0 +1,14 @@ + + + + Test open data:text/csv + + + test text/csv + + + diff --git a/dom/security/test/general/file_framing_error_pages.sjs b/dom/security/test/general/file_framing_error_pages.sjs new file mode 100644 index 0000000000..fb62a34bdb --- /dev/null +++ b/dom/security/test/general/file_framing_error_pages.sjs @@ -0,0 +1,27 @@ +"use strict"; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + let query = request.queryString; + if (query === "xfo") { + response.setHeader("x-frame-options", "deny", false); + response.write("xfo test loaded"); + return; + } + + if (query === "csp") { + response.setHeader( + "content-security-policy", + "frame-ancestors 'none'", + false + ); + response.write("csp test loaded"); + return; + } + + // we should never get here, but just in case + // return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/general/file_framing_error_pages_csp.html b/dom/security/test/general/file_framing_error_pages_csp.html new file mode 100644 index 0000000000..2764ed4aa6 --- /dev/null +++ b/dom/security/test/general/file_framing_error_pages_csp.html @@ -0,0 +1,7 @@ + + + +iframe should be blocked
+ + + diff --git a/dom/security/test/general/file_framing_error_pages_xfo.html b/dom/security/test/general/file_framing_error_pages_xfo.html new file mode 100644 index 0000000000..82dd1ee459 --- /dev/null +++ b/dom/security/test/general/file_framing_error_pages_xfo.html @@ -0,0 +1,7 @@ + + + +iframe should be blocked
+ + + diff --git a/dom/security/test/general/file_framing_xfo_embed.html b/dom/security/test/general/file_framing_xfo_embed.html new file mode 100644 index 0000000000..f5cc761b5b --- /dev/null +++ b/dom/security/test/general/file_framing_xfo_embed.html @@ -0,0 +1,7 @@ + + + + embed should be blocked
+ + + diff --git a/dom/security/test/general/file_framing_xfo_embed_object.sjs b/dom/security/test/general/file_framing_xfo_embed_object.sjs new file mode 100644 index 0000000000..56616b7930 --- /dev/null +++ b/dom/security/test/general/file_framing_xfo_embed_object.sjs @@ -0,0 +1,7 @@ +"use strict"; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("x-frame-options", "deny", false); + response.write("doc with x-frame-options: deny"); +} diff --git a/dom/security/test/general/file_framing_xfo_object.html b/dom/security/test/general/file_framing_xfo_object.html new file mode 100644 index 0000000000..c8480a2c42 --- /dev/null +++ b/dom/security/test/general/file_framing_xfo_object.html @@ -0,0 +1,7 @@ + + + + object should be blocked
+ + + diff --git a/dom/security/test/general/file_gpc_server.sjs b/dom/security/test/general/file_gpc_server.sjs new file mode 100644 index 0000000000..d0b14215b4 --- /dev/null +++ b/dom/security/test/general/file_gpc_server.sjs @@ -0,0 +1,14 @@ +"use strict"; + +function handleRequest(request, response) { + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Cache-Control", "no-cache", false); + + var gpc = request.hasHeader("Sec-GPC") ? request.getHeader("Sec-GPC") : ""; + + if (gpc === "1") { + response.write("true"); + } else { + response.write("false"); + } +} diff --git a/dom/security/test/general/file_loads_nonscript.html b/dom/security/test/general/file_loads_nonscript.html new file mode 100644 index 0000000000..f7692b8066 --- /dev/null +++ b/dom/security/test/general/file_loads_nonscript.html @@ -0,0 +1,49 @@ + + + + File that loads a non-script file-extension as script + + + + diff --git a/dom/security/test/general/file_meta_referrer_in_head.html b/dom/security/test/general/file_meta_referrer_in_head.html new file mode 100644 index 0000000000..9c4c4cd695 --- /dev/null +++ b/dom/security/test/general/file_meta_referrer_in_head.html @@ -0,0 +1,13 @@ + + + + + +Bug 1704473 - Remove head requirement for meta name=referrer + + + + + diff --git a/dom/security/test/general/file_meta_referrer_notin_head.html b/dom/security/test/general/file_meta_referrer_notin_head.html new file mode 100644 index 0000000000..55bd38e4c5 --- /dev/null +++ b/dom/security/test/general/file_meta_referrer_notin_head.html @@ -0,0 +1,14 @@ + + + + +Bug 1704473 - Remove head requirement for meta name=referrer + + + + + + + diff --git a/dom/security/test/general/file_nonscript b/dom/security/test/general/file_nonscript new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_nonscript @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_nonscript.html b/dom/security/test/general/file_nonscript.html new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_nonscript.html @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_nonscript.json b/dom/security/test/general/file_nonscript.json new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_nonscript.json @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_nonscript.txt b/dom/security/test/general/file_nonscript.txt new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_nonscript.txt @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_nonscript.xyz b/dom/security/test/general/file_nonscript.xyz new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_nonscript.xyz @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_nosniff_navigation.sjs b/dom/security/test/general/file_nosniff_navigation.sjs new file mode 100644 index 0000000000..20363ceb76 --- /dev/null +++ b/dom/security/test/general/file_nosniff_navigation.sjs @@ -0,0 +1,40 @@ +// Custom *.sjs file specifically for the needs of Bug 1286861 + +// small red image +const IMG = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +// https://stackoverflow.com/questions/17279712/what-is-the-smallest-possible-valid-pdf +const PDF = `%PDF-1.0 +1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>endobj +trailer<>`; + +function getSniffableContent(type) { + switch (type) { + case "xml": + return ``; + case "html": + return ` Test test `; + case "css": + return `*{ color: pink !important; }`; + case "json": + return `{ 'test':'yes' }`; + case "img": + return IMG; + case "pdf": + return PDF; + } + return "Basic UTF-8 Text"; +} + +function handleRequest(request, response) { + Cu.importGlobalProperties(["URLSearchParams"]); + let query = new URLSearchParams(request.queryString); + + // avoid confusing cache behaviors (XXXX no sure what this means?) + response.setHeader("X-Content-Type-Options", "nosniff"); // Disable Sniffing + response.setHeader("Content-Type", query.get("mime")); + response.write(getSniffableContent(query.get("content"))); +} diff --git a/dom/security/test/general/file_nosniff_testserver.sjs b/dom/security/test/general/file_nosniff_testserver.sjs new file mode 100644 index 0000000000..fd35d8ad4f --- /dev/null +++ b/dom/security/test/general/file_nosniff_testserver.sjs @@ -0,0 +1,61 @@ +"use strict"; +Cu.importGlobalProperties(["URLSearchParams"]); + +const SCRIPT = "var foo = 24;"; +const CSS = "body { background-color: green; }"; + +// small red image +const IMG = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +function handleRequest(request, response) { + const query = new URLSearchParams(request.queryString); + + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // set the nosniff header + response.setHeader("X-Content-Type-Options", " NoSniFF , foo ", false); + + if (query.has("cssCorrectType")) { + response.setHeader("Content-Type", "teXt/cSs", false); + response.write(CSS); + return; + } + + if (query.has("cssWrongType")) { + response.setHeader("Content-Type", "text/html", false); + response.write(CSS); + return; + } + + if (query.has("scriptCorrectType")) { + response.setHeader("Content-Type", "appLIcation/jAvaScriPt;blah", false); + response.write(SCRIPT); + return; + } + + if (query.has("scriptWrongType")) { + response.setHeader("Content-Type", "text/html", false); + response.write(SCRIPT); + return; + } + + if (query.has("imgCorrectType")) { + response.setHeader("Content-Type", "iMaGe/pnG;blah", false); + response.write(IMG); + return; + } + + if (query.has("imgWrongType")) { + response.setHeader("Content-Type", "text/html", false); + response.write(IMG); + return; + } + + // we should never get here, but just in case + response.setHeader("Content-Type", "text/html", false); + response.write("do'h"); +} diff --git a/dom/security/test/general/file_same_site_cookies_about.sjs b/dom/security/test/general/file_same_site_cookies_about.sjs new file mode 100644 index 0000000000..421eb999be --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_about.sjs @@ -0,0 +1,99 @@ +// Custom *.sjs file specifically for the needs of Bug 1454721 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const IFRAME_INC = ``; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // using startsWith and discard the math random + if (request.queryString.startsWith("setSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=mySameSiteAboutCookie; samesite=strict", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + // navigation tests + if (request.queryString.includes("loadsrcdocframeNav")) { + let FRAME = ` + `; + response.write(FRAME); + return; + } + + if (request.queryString.includes("loadblankframeNav")) { + let FRAME = ` + `; + response.write(FRAME); + return; + } + + // inclusion tets + if (request.queryString.includes("loadsrcdocframeInc")) { + response.write(''); + return; + } + + if (request.queryString.includes("loadblankframeInc")) { + let FRAME = + ` + + + + + `); + } + + if (request.queryString.includes("inclusion")) { + const cookies = request.hasHeader("Cookie") + ? request.getHeader("Cookie") + : ""; + response.write(` + + + + + + + `); + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html b/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html new file mode 100644 index 0000000000..b3456f0b90 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_blob_iframe_inclusion.html @@ -0,0 +1,34 @@ + + + + + + diff --git a/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html b/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html new file mode 100644 index 0000000000..815c6a6bfc --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_blob_iframe_navigation.html @@ -0,0 +1,30 @@ + + + + + + diff --git a/dom/security/test/general/file_same_site_cookies_bug1748693.sjs b/dom/security/test/general/file_same_site_cookies_bug1748693.sjs new file mode 100644 index 0000000000..6890bafa17 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_bug1748693.sjs @@ -0,0 +1,31 @@ +const MESSAGE_PAGE = function (msg) { + return ` + + + +

${msg}

+ + +`; +}; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-store"); + response.setHeader("Content-Type", "text/html"); + + if (request.queryString.includes("setcookies")) { + response.setHeader( + "Set-Cookie", + "auth_secure=foo; SameSite=None; HttpOnly; Secure", + true + ); + response.setHeader("Set-Cookie", "auth=foo; HttpOnly;", true); + response.write(MESSAGE_PAGE(request.queryString)); + return; + } + + const cookies = request.hasHeader("Cookie") + ? request.getHeader("Cookie") + : ""; + response.write(MESSAGE_PAGE(cookies)); +} diff --git a/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs new file mode 100644 index 0000000000..9103941653 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_cross_origin_context.sjs @@ -0,0 +1,54 @@ +// Custom *.sjs file specifically for the needs of Bug 1452496 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const FRAME = ` + + + + Bug 1452496 - Do not allow same-site cookies in cross site context + + + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString.includes("setSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=strictSameSiteCookie; samesite=strict", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + if (request.queryString.includes("setRegularCookie")) { + response.setHeader("Set-Cookie", "myKey=regularCookie;", true); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + if (request.queryString.includes("loadFrame")) { + response.write(FRAME); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_from_script.sjs b/dom/security/test/general/file_same_site_cookies_from_script.sjs new file mode 100644 index 0000000000..0df217cf45 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_from_script.sjs @@ -0,0 +1,48 @@ +// Custom *.sjs file specifically for the needs of Bug 1452496 + +const SET_COOKIE_FRAME = ` + + + + Bug 1452496 - Do not allow same-site cookies in cross site context + + + + + `; + +const GET_COOKIE_FRAME = ` + + + + Bug 1452496 - Do not allow same-site cookies in cross site context + + + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString.includes("setSameSiteCookieUsingInlineScript")) { + response.write(SET_COOKIE_FRAME); + return; + } + + if (request.queryString.includes("getCookieFrame")) { + response.write(GET_COOKIE_FRAME); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_iframe.sjs b/dom/security/test/general/file_same_site_cookies_iframe.sjs new file mode 100644 index 0000000000..7b511257c3 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_iframe.sjs @@ -0,0 +1,99 @@ +// Custom *.sjs file specifically for the needs of Bug 1454027 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const NESTED_IFRAME_NAVIGATION = ` + + + + + + + `); +} diff --git a/dom/security/test/general/file_same_site_cookies_redirect.sjs b/dom/security/test/general/file_same_site_cookies_redirect.sjs new file mode 100644 index 0000000000..f7451fb504 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_redirect.sjs @@ -0,0 +1,103 @@ +// Custom *.sjs file specifically for the needs of Bug 1453814 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const FRAME = ` + + + + Bug 1453814 - Do not allow same-site cookies for cross origin redirect + + + + + `; + +const SAME_ORIGIN = "http://mochi.test:8888/"; +const CROSS_ORIGIN = "http://example.com/"; +const PATH = + "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs"; + +const FRAME_META_REFRESH_SAME = + ` + + + `; + +const FRAME_META_REFRESH_CROSS = + ` + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString === "setSameSiteCookie") { + response.setHeader( + "Set-Cookie", + "myKey=strictSameSiteCookie; samesite=strict", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + if (request.queryString === "sameToSameRedirect") { + let URL = SAME_ORIGIN + PATH + "?loadFrame"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", URL, false); + return; + } + + if (request.queryString === "sameToCrossRedirect") { + let URL = CROSS_ORIGIN + PATH + "?loadFrame"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", URL, false); + return; + } + + if (request.queryString === "crossToSameRedirect") { + let URL = SAME_ORIGIN + PATH + "?loadFrame"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", URL, false); + return; + } + + if (request.queryString === "sameToCrossRedirectMeta") { + response.write(FRAME_META_REFRESH_CROSS); + return; + } + + if (request.queryString === "crossToSameRedirectMeta") { + response.write(FRAME_META_REFRESH_SAME); + return; + } + + if (request.queryString === "loadFrame") { + response.write(FRAME); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_subrequest.sjs b/dom/security/test/general/file_same_site_cookies_subrequest.sjs new file mode 100644 index 0000000000..fdc81344ef --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_subrequest.sjs @@ -0,0 +1,82 @@ +// Custom *.sjs file specifically for the needs of Bug 1286861 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const FRAME = ` + + + + Bug 1286861 - Add support for same site cookies + + + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString.includes("setStrictSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=strictSameSiteCookie; samesite=strict", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + if (request.queryString.includes("setLaxSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=laxSameSiteCookie; samesite=lax", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + // save the object state of the initial request, which returns + // async once the server has processed the img request. + if (request.queryString.includes("queryresult")) { + response.processAsync(); + setObjectState("queryResult", response); + return; + } + + if (request.queryString.includes("loadFrame")) { + response.write(FRAME); + return; + } + + if (request.queryString.includes("checkCookie")) { + var cookie = "unitialized"; + if (request.hasHeader("Cookie")) { + cookie = request.getHeader("Cookie"); + } else { + cookie = "myKey=noCookie"; + } + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + + // return the result + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + queryResponse.write(cookie); + queryResponse.finish(); + }); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs new file mode 100644 index 0000000000..45b515a28b --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_toplevel_nav.sjs @@ -0,0 +1,96 @@ +// Custom *.sjs file specifically for the needs of Bug 1286861 + +// small red image +const IMG_BYTES = atob( + "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" + + "P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" +); + +const FRAME = ` + + + + Bug 1286861 - Add support for same site cookies + + + + + `; + +const WIN = ` + + + + just a dummy window + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString.includes("setStrictSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=strictSameSiteCookie; samesite=strict", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + if (request.queryString.includes("setLaxSameSiteCookie")) { + response.setHeader( + "Set-Cookie", + "myKey=laxSameSiteCookie; samesite=lax", + true + ); + response.setHeader("Content-Type", "image/png"); + response.write(IMG_BYTES); + return; + } + + // save the object state of the initial request, which returns + // async once the server has processed the img request. + if (request.queryString.includes("queryresult")) { + response.processAsync(); + setObjectState("queryResult", response); + return; + } + + if (request.queryString.includes("loadFrame")) { + response.write(FRAME); + return; + } + + if (request.queryString.includes("loadWin")) { + var cookie = "unitialized"; + if (request.hasHeader("Cookie")) { + cookie = request.getHeader("Cookie"); + } else { + cookie = "myKey=noCookie"; + } + response.write(WIN); + + // return the result + getObjectState("queryResult", function (queryResponse) { + if (!queryResponse) { + return; + } + queryResponse.write(cookie); + queryResponse.finish(); + }); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs b/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs new file mode 100644 index 0000000000..34dfe40e23 --- /dev/null +++ b/dom/security/test/general/file_same_site_cookies_toplevel_set_cookie.sjs @@ -0,0 +1,68 @@ +// Custom *.sjs file specifically for the needs of Bug 1454242 + +const WIN = ` + + + + + `; + +const DUMMY_WIN = ` + + + just a dummy window that sets a same-site=lax cookie + + + `; + +const FRAME = ` + + + + + `; + +const SAME_ORIGIN = "http://mochi.test:8888/"; +const CROSS_ORIGIN = "http://example.com/"; +const PATH = + "tests/dom/security/test/general/file_same_site_cookies_redirect.sjs"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.queryString === "loadWin") { + response.write(WIN); + return; + } + + if (request.queryString === "loadWinAndSetCookie") { + response.setHeader( + "Set-Cookie", + "myKey=laxSameSiteCookie; samesite=lax", + true + ); + response.write(DUMMY_WIN); + return; + } + + if (request.queryString === "checkCookie") { + response.write(FRAME); + return; + } + + // we should never get here, but just in case return something unexpected + response.write("D'oh"); +} diff --git a/dom/security/test/general/file_script.js b/dom/security/test/general/file_script.js new file mode 100644 index 0000000000..c339e45d5d --- /dev/null +++ b/dom/security/test/general/file_script.js @@ -0,0 +1 @@ +window.counter++; diff --git a/dom/security/test/general/file_toplevel_data_meta_redirect.html b/dom/security/test/general/file_toplevel_data_meta_redirect.html new file mode 100644 index 0000000000..e94a61ed48 --- /dev/null +++ b/dom/security/test/general/file_toplevel_data_meta_redirect.html @@ -0,0 +1,10 @@ + + + + + + +Meta Redirect to data: URI + + diff --git a/dom/security/test/general/file_toplevel_data_navigations.sjs b/dom/security/test/general/file_toplevel_data_navigations.sjs new file mode 100644 index 0000000000..57c4b527dd --- /dev/null +++ b/dom/security/test/general/file_toplevel_data_navigations.sjs @@ -0,0 +1,13 @@ +// Custom *.sjs file specifically for the needs of Bug: +// Bug 1394554 - Block toplevel data: URI navigations after redirect + +var DATA_URI = + "data:text/html,toplevel data: URI navigations after redirect should be blocked"; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", DATA_URI, false); +} diff --git a/dom/security/test/general/file_view_bg_image_data_navigation.html b/dom/security/test/general/file_view_bg_image_data_navigation.html new file mode 100644 index 0000000000..d9aa6ca8b6 --- /dev/null +++ b/dom/security/test/general/file_view_bg_image_data_navigation.html @@ -0,0 +1,16 @@ + + + + + Bug 1658244: Test navigation for right-click view-bg-image on data:image/svg + + + + This page has an inline SVG image as a background. + + diff --git a/dom/security/test/general/file_view_image_data_navigation.html b/dom/security/test/general/file_view_image_data_navigation.html new file mode 100644 index 0000000000..a3f9acfb4d --- /dev/null +++ b/dom/security/test/general/file_view_image_data_navigation.html @@ -0,0 +1,12 @@ + + + + + Bug 1407891: Test navigation for right-click view-image on data:image/svg + + + + + + + diff --git a/dom/security/test/general/file_xfo_error_page.sjs b/dom/security/test/general/file_xfo_error_page.sjs new file mode 100644 index 0000000000..b1fa33cbd4 --- /dev/null +++ b/dom/security/test/general/file_xfo_error_page.sjs @@ -0,0 +1,8 @@ +"use strict"; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + response.setHeader("x-frame-options", "deny", false); + response.write("xfo test loaded"); +} diff --git a/dom/security/test/general/mochitest.ini b/dom/security/test/general/mochitest.ini new file mode 100644 index 0000000000..ba67830706 --- /dev/null +++ b/dom/security/test/general/mochitest.ini @@ -0,0 +1,95 @@ +[DEFAULT] +support-files = + file_contentpolicytype_targeted_link_iframe.sjs + file_nosniff_testserver.sjs + file_nosniff_navigation.sjs + file_block_script_wrong_mime_server.sjs + file_block_toplevel_data_navigation.html + file_block_toplevel_data_navigation2.html + file_block_toplevel_data_navigation3.html + file_block_toplevel_data_redirect.sjs + file_block_subresource_redir_to_data.sjs + file_same_site_cookies_subrequest.sjs + file_same_site_cookies_toplevel_nav.sjs + file_same_site_cookies_cross_origin_context.sjs + file_same_site_cookies_from_script.sjs + file_same_site_cookies_redirect.sjs + file_same_site_cookies_toplevel_set_cookie.sjs + file_same_site_cookies_blob_iframe_navigation.html + file_same_site_cookies_blob_iframe_inclusion.html + file_same_site_cookies_iframe.sjs + file_same_site_cookies_about.sjs + file_cache_splitting_server.sjs + file_cache_splitting_isloaded.sjs + file_cache_splitting_window.html + window_nosniff_navigation.html + +[test_contentpolicytype_targeted_link_iframe.html] +skip-if = + http3 +[test_nosniff.html] +[test_cache_split.html] +skip-if = + http3 +[test_nosniff_navigation.html] +[test_block_script_wrong_mime.html] +[test_block_toplevel_data_navigation.html] +[test_block_toplevel_data_img_navigation.html] +[test_allow_opening_data_pdf.html] +skip-if = toolkit == 'android' # no pdf reader on Android +[test_allow_opening_data_json.html] +[test_block_subresource_redir_to_data.html] +[test_same_site_cookies_subrequest.html] +fail-if = xorigin # Cookies set incorrectly +skip-if = + http3 +[test_same_site_cookies_toplevel_nav.html] +fail-if = xorigin +skip-if = + http3 +[test_same_site_cookies_cross_origin_context.html] +skip-if = + http3 +[test_same_site_cookies_from_script.html] +fail-if = xorigin +skip-if = + http3 +[test_same_site_cookies_redirect.html] +fail-if = xorigin +skip-if = + http3 +[test_same_site_cookies_toplevel_set_cookie.html] +fail-if = xorigin # Cookies not set +skip-if = + http3 +[test_same_site_cookies_iframe.html] +fail-if = xorigin +skip-if = + http3 +[test_same_site_cookies_about.html] +fail-if = xorigin +skip-if = + http3 +[test_assert_about_page_no_csp.html] +skip-if = !debug +[test_same_site_cookies_laxByDefault.html] +skip-if = debug +support-files = closeWindow.sjs +[test_xfo_error_page.html] +support-files = file_xfo_error_page.sjs +skip-if = + http3 +[test_bug1450853.html] +skip-if = + http3 +[test_meta_referrer.html] +support-files = + file_meta_referrer_in_head.html + file_meta_referrer_notin_head.html +[test_bug1660452_http.html] +skip-if = + http3 +[test_bug1660452_https.html] +scheme = https +[test_gpc.html] +support-files = file_gpc_server.sjs diff --git a/dom/security/test/general/test_allow_opening_data_json.html b/dom/security/test/general/test_allow_opening_data_json.html new file mode 100644 index 0000000000..4b37931e1f --- /dev/null +++ b/dom/security/test/general/test_allow_opening_data_json.html @@ -0,0 +1,39 @@ + + + + + Bug 1403814: Allow toplevel data URI navigation data:application/json + + + + + + + diff --git a/dom/security/test/general/test_assert_about_page_no_csp.html b/dom/security/test/general/test_assert_about_page_no_csp.html new file mode 100644 index 0000000000..06be4ce460 --- /dev/null +++ b/dom/security/test/general/test_assert_about_page_no_csp.html @@ -0,0 +1,30 @@ + + + + Bug 1490977: Test Assertion if content privileged about: page has no CSP + + + + + + + + + diff --git a/dom/security/test/general/test_block_script_wrong_mime.html b/dom/security/test/general/test_block_script_wrong_mime.html new file mode 100644 index 0000000000..93a4b9d220 --- /dev/null +++ b/dom/security/test/general/test_block_script_wrong_mime.html @@ -0,0 +1,92 @@ + + + + Bug 1288361 - Block scripts with incorrect MIME type + + + + + + + + + diff --git a/dom/security/test/general/test_block_subresource_redir_to_data.html b/dom/security/test/general/test_block_subresource_redir_to_data.html new file mode 100644 index 0000000000..eafb6b5d83 --- /dev/null +++ b/dom/security/test/general/test_block_subresource_redir_to_data.html @@ -0,0 +1,68 @@ + + + + Bug 1428793: Block insecure redirects to data: URIs + + + + + + + + + + + diff --git a/dom/security/test/general/test_block_toplevel_data_img_navigation.html b/dom/security/test/general/test_block_toplevel_data_img_navigation.html new file mode 100644 index 0000000000..07e46b1f2f --- /dev/null +++ b/dom/security/test/general/test_block_toplevel_data_img_navigation.html @@ -0,0 +1,53 @@ + + + + + Bug 1396798: Do not block toplevel data: navigation to image (except svgs) + + + + + + + diff --git a/dom/security/test/general/test_block_toplevel_data_navigation.html b/dom/security/test/general/test_block_toplevel_data_navigation.html new file mode 100644 index 0000000000..bbadacb218 --- /dev/null +++ b/dom/security/test/general/test_block_toplevel_data_navigation.html @@ -0,0 +1,134 @@ + + + + + Bug 1331351 - Block top level window data: URI navigations + + + + + + + + diff --git a/dom/security/test/general/test_bug1277803.xhtml b/dom/security/test/general/test_bug1277803.xhtml new file mode 100644 index 0000000000..30cc82310b --- /dev/null +++ b/dom/security/test/general/test_bug1277803.xhtml @@ -0,0 +1,65 @@ + + + + + + + + + + diff --git a/dom/security/test/general/test_bug1450853.html b/dom/security/test/general/test_bug1450853.html new file mode 100644 index 0000000000..e6b61ecce0 --- /dev/null +++ b/dom/security/test/general/test_bug1450853.html @@ -0,0 +1,91 @@ + + + + + +Test for Cross-origin resouce status leak via MediaError + + + + + + + + + + + Mozilla Bug 1450853 + + + diff --git a/dom/security/test/general/test_bug1660452_http.html b/dom/security/test/general/test_bug1660452_http.html new file mode 100644 index 0000000000..3a6512da21 --- /dev/null +++ b/dom/security/test/general/test_bug1660452_http.html @@ -0,0 +1,39 @@ + + + +Bug 1660452: NullPrincipals need to know whether they were spun off of a Secure Context + + + + + + + + diff --git a/dom/security/test/general/test_bug1660452_https.html b/dom/security/test/general/test_bug1660452_https.html new file mode 100644 index 0000000000..1aed356a21 --- /dev/null +++ b/dom/security/test/general/test_bug1660452_https.html @@ -0,0 +1,39 @@ + + + +Bug 1660452: NullPrincipals need to know whether they were spun off of a Secure Context + + + + + + + + diff --git a/dom/security/test/general/test_cache_split.html b/dom/security/test/general/test_cache_split.html new file mode 100644 index 0000000000..f0fc056bce --- /dev/null +++ b/dom/security/test/general/test_cache_split.html @@ -0,0 +1,153 @@ + + + + + + Bug 1454721 - Add same-site cookie test for about:blank and about:srcdoc + + + + + + + + + + + diff --git a/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html new file mode 100644 index 0000000000..99620d06f9 --- /dev/null +++ b/dom/security/test/general/test_contentpolicytype_targeted_link_iframe.html @@ -0,0 +1,103 @@ + + + + + Bug 1255240 - Test content policy types within content policies for targeted links in iframes + + + + + + + + + + diff --git a/dom/security/test/general/test_gpc.html b/dom/security/test/general/test_gpc.html new file mode 100644 index 0000000000..506629554d --- /dev/null +++ b/dom/security/test/general/test_gpc.html @@ -0,0 +1,51 @@ + + + + Test for Global Privacy Control headers + + + + + + + diff --git a/dom/security/test/general/test_innerhtml_sanitizer.html b/dom/security/test/general/test_innerhtml_sanitizer.html new file mode 100644 index 0000000000..4a4e4efed1 --- /dev/null +++ b/dom/security/test/general/test_innerhtml_sanitizer.html @@ -0,0 +1,74 @@ + + + + + Test for Bug 1667113 + + + + +Mozilla Bug 1667113 +
+ + + diff --git a/dom/security/test/general/test_innerhtml_sanitizer.xhtml b/dom/security/test/general/test_innerhtml_sanitizer.xhtml new file mode 100644 index 0000000000..4d938bc23b --- /dev/null +++ b/dom/security/test/general/test_innerhtml_sanitizer.xhtml @@ -0,0 +1,73 @@ + + + + Test for Bug 1667113 + + + + +Mozilla Bug 1667113 +
+ + + diff --git a/dom/security/test/general/test_meta_referrer.html b/dom/security/test/general/test_meta_referrer.html new file mode 100644 index 0000000000..f5e8b649f4 --- /dev/null +++ b/dom/security/test/general/test_meta_referrer.html @@ -0,0 +1,55 @@ + + + + Bug 1704473 - Remove head requirement for meta name=referrer + + + + + + + + + + + diff --git a/dom/security/test/general/test_nosniff.html b/dom/security/test/general/test_nosniff.html new file mode 100644 index 0000000000..a22386aea0 --- /dev/null +++ b/dom/security/test/general/test_nosniff.html @@ -0,0 +1,88 @@ + + + + Bug 471020 - Add X-Content-Type-Options: nosniff support to Firefox + + + + + + + + + + + + + + + + + diff --git a/dom/security/test/general/test_nosniff_navigation.html b/dom/security/test/general/test_nosniff_navigation.html new file mode 100644 index 0000000000..6710f4f5b9 --- /dev/null +++ b/dom/security/test/general/test_nosniff_navigation.html @@ -0,0 +1,35 @@ + + + + + Bug 1428473 Support X-Content-Type-Options: nosniff when navigating + + + + + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_about.html b/dom/security/test/general/test_same_site_cookies_about.html new file mode 100644 index 0000000000..faf2caab9a --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_about.html @@ -0,0 +1,116 @@ + + + + Bug 1454721 - Add same-site cookie test for about:blank and about:srcdoc + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_cross_origin_context.html b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html new file mode 100644 index 0000000000..9294a3d030 --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_cross_origin_context.html @@ -0,0 +1,93 @@ + + + + Bug 1452496 - Do not allow same-site cookies in cross site context + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_from_script.html b/dom/security/test/general/test_same_site_cookies_from_script.html new file mode 100644 index 0000000000..74c38b6249 --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_from_script.html @@ -0,0 +1,86 @@ + + + + Bug 1452496 - Do not allow same-site cookies in cross site context + + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_iframe.html b/dom/security/test/general/test_same_site_cookies_iframe.html new file mode 100644 index 0000000000..45d5d5830a --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_iframe.html @@ -0,0 +1,168 @@ + + + + Bug 1454027 - Update SameSite cookie handling inside iframes + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_laxByDefault.html b/dom/security/test/general/test_same_site_cookies_laxByDefault.html new file mode 100644 index 0000000000..9fd0d0b704 --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_laxByDefault.html @@ -0,0 +1,85 @@ + + + + Bug 1551798 - SameSite=lax by default + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_redirect.html b/dom/security/test/general/test_same_site_cookies_redirect.html new file mode 100644 index 0000000000..59f98b2263 --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_redirect.html @@ -0,0 +1,101 @@ + + + + Bug 1453814 - Do not allow same-site cookies for cross origin redirect + + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_subrequest.html b/dom/security/test/general/test_same_site_cookies_subrequest.html new file mode 100644 index 0000000000..304dbafa9a --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_subrequest.html @@ -0,0 +1,113 @@ + + + + Bug 1286861 - Test same site cookies on subrequests + + + + + + + + + + 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 new file mode 100644 index 0000000000..aba825916b --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_toplevel_nav.html @@ -0,0 +1,117 @@ + + + + Bug 1286861 - Test same site cookies on top-level navigations + + + + + + + + + diff --git a/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html b/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html new file mode 100644 index 0000000000..cae2a6174e --- /dev/null +++ b/dom/security/test/general/test_same_site_cookies_toplevel_set_cookie.html @@ -0,0 +1,57 @@ + + + + Bug 1454242: Setting samesite cookie should not rely on CookieCommons::IsSameSiteForeign + + + + + + + + + + diff --git a/dom/security/test/general/test_xfo_error_page.html b/dom/security/test/general/test_xfo_error_page.html new file mode 100644 index 0000000000..218413b4f9 --- /dev/null +++ b/dom/security/test/general/test_xfo_error_page.html @@ -0,0 +1,35 @@ + + + + Bug 1626249: Ensure correct display of neterror page for XFO + + + + + + + + + diff --git a/dom/security/test/general/window_nosniff_navigation.html b/dom/security/test/general/window_nosniff_navigation.html new file mode 100644 index 0000000000..1287e451b1 --- /dev/null +++ b/dom/security/test/general/window_nosniff_navigation.html @@ -0,0 +1,96 @@ + + + + Bug 1428473 Support X-Content-Type-Options: nosniff when navigating + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dom/security/test/gtest/TestCSPParser.cpp b/dom/security/test/gtest/TestCSPParser.cpp new file mode 100644 index 0000000000..735a6c7502 --- /dev/null +++ b/dom/security/test/gtest/TestCSPParser.cpp @@ -0,0 +1,1155 @@ +/* -*- 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 "gtest/gtest.h" + +#include +#include + +#include "nsIContentSecurityPolicy.h" +#include "nsNetUtil.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/dom/nsCSPContext.h" +#include "mozilla/gtest/MozAssertions.h" +#include "nsComponentManagerUtils.h" +#include "nsIPrefBranch.h" +#include "nsIPrefService.h" +#include "nsStringFwd.h" + +/* + * Testing the parser is non trivial, especially since we can not call + * parser functionality directly in compiled code tests. + * All the tests (except the fuzzy tests at the end) follow the same schemata: + * a) create an nsIContentSecurityPolicy object + * b) set the selfURI in SetRequestContextWithPrincipal + * c) append one or more policies by calling AppendPolicy + * d) check if the policy count is correct by calling GetPolicyCount + * e) compare the result of the policy with the expected output + * using the struct PolicyTest; + * + * In general we test: + * a) policies that the parser should accept + * b) policies that the parser should reject + * c) policies that are randomly generated (fuzzy tests) + * + * Please note that fuzzy tests are *DISABLED* by default and shold only + * be run *OFFLINE* whenever code in nsCSPParser changes. + * To run fuzzy tests, flip RUN_OFFLINE_TESTS to 1. + * + */ + +#define RUN_OFFLINE_TESTS 0 + +/* + * Offline tests are separated in three different groups: + * * TestFuzzyPolicies - complete random ASCII input + * * TestFuzzyPoliciesIncDir - a directory name followed by random ASCII + * * TestFuzzyPoliciesIncDirLimASCII - a directory name followed by limited + * ASCII which represents more likely user input. + * + * We run each of this categories |kFuzzyRuns| times. + */ + +#if RUN_OFFLINE_TESTS +static const uint32_t kFuzzyRuns = 10000; +#endif + +// For fuzzy testing we actually do not care about the output, +// we just want to make sure that the parser can handle random +// input, therefore we use kFuzzyExpectedPolicyCount to return early. +static const uint32_t kFuzzyExpectedPolicyCount = 111; + +static const uint32_t kMaxPolicyLength = 96; + +struct PolicyTest { + char policy[kMaxPolicyLength]; + char expectedResult[kMaxPolicyLength]; +}; + +nsresult runTest( + uint32_t aExpectedPolicyCount, // this should be 0 for policies which + // should fail to parse + const char* aPolicy, const char* aExpectedResult) { + nsresult rv; + + // we init the csp with http://www.selfuri.com + nsCOMPtr selfURI; + rv = NS_NewURI(getter_AddRefs(selfURI), "http://www.selfuri.com"); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr selfURIPrincipal; + mozilla::OriginAttributes attrs; + selfURIPrincipal = + mozilla::BasePrincipal::CreateContentPrincipal(selfURI, attrs); + NS_ENSURE_TRUE(selfURIPrincipal, NS_ERROR_FAILURE); + + // create a CSP object + nsCOMPtr csp = + do_CreateInstance(NS_CSPCONTEXT_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + // for testing the parser we only need to set a principal which is needed + // to translate the keyword 'self' into an actual URI. + rv = + csp->SetRequestContextWithPrincipal(selfURIPrincipal, selfURI, u""_ns, 0); + NS_ENSURE_SUCCESS(rv, rv); + + // append a policy + nsString policyStr; + policyStr.AssignASCII(aPolicy); + rv = csp->AppendPolicy(policyStr, false, false); + NS_ENSURE_SUCCESS(rv, rv); + + // when executing fuzzy tests we do not care about the actual output + // of the parser, we just want to make sure that the parser is not crashing. + if (aExpectedPolicyCount == kFuzzyExpectedPolicyCount) { + return NS_OK; + } + + // verify that the expected number of policies exists + uint32_t actualPolicyCount; + rv = csp->GetPolicyCount(&actualPolicyCount); + NS_ENSURE_SUCCESS(rv, rv); + if (actualPolicyCount != aExpectedPolicyCount) { + EXPECT_TRUE(false) + << "Actual policy count not equal to expected policy count (" + << actualPolicyCount << " != " << aExpectedPolicyCount + << ") for policy: " << aPolicy; + return NS_ERROR_UNEXPECTED; + } + + // if the expected policy count is 0, we can return, because + // we can not compare any output anyway. Used when parsing + // errornous policies. + if (aExpectedPolicyCount == 0) { + return NS_OK; + } + + // compare the parsed policy against the expected result + nsString parsedPolicyStr; + // checking policy at index 0, which is the one what we appended. + rv = csp->GetPolicyString(0, parsedPolicyStr); + NS_ENSURE_SUCCESS(rv, rv); + + if (!NS_ConvertUTF16toUTF8(parsedPolicyStr).EqualsASCII(aExpectedResult)) { + EXPECT_TRUE(false) << "Actual policy does not match expected policy (" + << NS_ConvertUTF16toUTF8(parsedPolicyStr).get() + << " != " << aExpectedResult << ")"; + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +// ============================= run Tests ======================== + +nsresult runTestSuite(const PolicyTest* aPolicies, uint32_t aPolicyCount, + uint32_t aExpectedPolicyCount) { + nsresult rv; + nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); + bool navigateTo = false; + bool wasmUnsafeEval = false; + if (prefs) { + prefs->GetBoolPref("security.csp.enableNavigateTo", &navigateTo); + prefs->SetBoolPref("security.csp.enableNavigateTo", true); + prefs->GetBoolPref("security.csp.wasm-unsafe-eval.enabled", + &wasmUnsafeEval); + prefs->SetBoolPref("security.csp.wasm-unsafe-eval.enabled", true); + } + + for (uint32_t i = 0; i < aPolicyCount; i++) { + rv = runTest(aExpectedPolicyCount, aPolicies[i].policy, + aPolicies[i].expectedResult); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (prefs) { + prefs->SetBoolPref("security.csp.enableNavigateTo", navigateTo); + prefs->SetBoolPref("security.csp.wasm-unsafe-eval.enabled", wasmUnsafeEval); + } + + return NS_OK; +} + +// ============================= TestDirectives ======================== + +TEST(CSPParser, Directives) +{ + static const PolicyTest policies[] = { + // clang-format off + { "connect-src xn--mnchen-3ya.de", + "connect-src http://xn--mnchen-3ya.de"}, + { "default-src http://www.example.com", + "default-src http://www.example.com" }, + { "script-src http://www.example.com", + "script-src http://www.example.com" }, + { "object-src http://www.example.com", + "object-src http://www.example.com" }, + { "style-src http://www.example.com", + "style-src http://www.example.com" }, + { "img-src http://www.example.com", + "img-src http://www.example.com" }, + { "media-src http://www.example.com", + "media-src http://www.example.com" }, + { "frame-src http://www.example.com", + "frame-src http://www.example.com" }, + { "font-src http://www.example.com", + "font-src http://www.example.com" }, + { "connect-src http://www.example.com", + "connect-src http://www.example.com" }, + { "report-uri http://www.example.com", + "report-uri http://www.example.com/" }, + { "script-src 'nonce-correctscriptnonce'", + "script-src 'nonce-correctscriptnonce'" }, + { "script-src 'nonce-a'", + "script-src 'nonce-a'" }, + { "script-src 'sha256-a'", + "script-src 'sha256-a'" }, + { "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='", + "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }, + { "script-src 'nonce-foo' 'unsafe-inline' ", + "script-src 'nonce-foo' 'unsafe-inline'" }, + { "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https: ", + "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' https:" }, + { "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' 'report-sample' https: ", + "script-src 'nonce-foo' 'strict-dynamic' 'unsafe-inline' 'report-sample' https:" }, + { "default-src 'sha256-siVR8' 'strict-dynamic' 'unsafe-inline' https: ", + "default-src 'sha256-siVR8' 'unsafe-inline' https:" }, + { "worker-src https://example.com", + "worker-src https://example.com" }, + { "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com", + "worker-src http://worker.com; frame-src http://frame.com; child-src http://child.com" }, + { "navigate-to http://example.com", + "navigate-to http://example.com"}, + { "navigate-to 'unsafe-allow-redirects' http://example.com", + "navigate-to 'unsafe-allow-redirects' http://example.com"}, + { "script-src 'unsafe-allow-redirects' http://example.com", + "script-src http://example.com"}, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ============================= TestKeywords ======================== + +TEST(CSPParser, Keywords) +{ + static const PolicyTest policies[] = { + // clang-format off + { "script-src 'self'", + "script-src 'self'" }, + { "script-src 'unsafe-inline'", + "script-src 'unsafe-inline'" }, + { "script-src 'unsafe-eval'", + "script-src 'unsafe-eval'" }, + { "script-src 'unsafe-inline' 'unsafe-eval'", + "script-src 'unsafe-inline' 'unsafe-eval'" }, + { "script-src 'none'", + "script-src 'none'" }, + { "script-src 'wasm-unsafe-eval'", + "script-src 'wasm-unsafe-eval'" }, + { "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'", + "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'" }, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// =================== TestIgnoreUpperLowerCasePolicies ============== + +TEST(CSPParser, IgnoreUpperLowerCasePolicies) +{ + static const PolicyTest policies[] = { + // clang-format off + { "script-src 'SELF'", + "script-src 'self'" }, + { "sCriPt-src 'Unsafe-Inline'", + "script-src 'unsafe-inline'" }, + { "SCRIPT-src 'unsafe-eval'", + "script-src 'unsafe-eval'" }, + { "default-SRC 'unsafe-inline' 'unsafe-eval'", + "default-src 'unsafe-inline' 'unsafe-eval'" }, + { "script-src 'NoNe'", + "script-src 'none'" }, + { "img-sRc 'noNe'; scrIpt-src 'unsafe-EVAL' 'UNSAFE-inline'; deFAULT-src 'Self'", + "img-src 'none'; script-src 'unsafe-eval' 'unsafe-inline'; default-src 'self'" }, + { "default-src HTTP://www.example.com", + "default-src http://www.example.com" }, + { "default-src HTTP://WWW.EXAMPLE.COM", + "default-src http://www.example.com" }, + { "default-src HTTPS://*.example.COM", + "default-src https://*.example.com" }, + { "script-src 'none' test.com;", + "script-src http://test.com" }, + { "script-src 'NoNCE-correctscriptnonce'", + "script-src 'nonce-correctscriptnonce'" }, + { "script-src 'NoncE-NONCENEEDSTOBEUPPERCASE'", + "script-src 'nonce-NONCENEEDSTOBEUPPERCASE'" }, + { "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='", + "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" }, + { "upgrade-INSECURE-requests", + "upgrade-insecure-requests" }, + { "sanDBox alloW-foRMs", + "sandbox allow-forms"}, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ========================= TestPaths =============================== + +TEST(CSPParser, Paths) +{ + static const PolicyTest policies[] = { + // clang-format off + { "script-src http://www.example.com", + "script-src http://www.example.com" }, + { "script-src http://www.example.com/", + "script-src http://www.example.com/" }, + { "script-src http://www.example.com/path-1", + "script-src http://www.example.com/path-1" }, + { "script-src http://www.example.com/path-1/", + "script-src http://www.example.com/path-1/" }, + { "script-src http://www.example.com/path-1/path_2", + "script-src http://www.example.com/path-1/path_2" }, + { "script-src http://www.example.com/path-1/path_2/", + "script-src http://www.example.com/path-1/path_2/" }, + { "script-src http://www.example.com/path-1/path_2/file.js", + "script-src http://www.example.com/path-1/path_2/file.js" }, + { "script-src http://www.example.com/path-1/path_2/file_1.js", + "script-src http://www.example.com/path-1/path_2/file_1.js" }, + { "script-src http://www.example.com/path-1/path_2/file-2.js", + "script-src http://www.example.com/path-1/path_2/file-2.js" }, + { "script-src http://www.example.com/path-1/path_2/f.js", + "script-src http://www.example.com/path-1/path_2/f.js" }, + { "script-src http://www.example.com:88", + "script-src http://www.example.com:88" }, + { "script-src http://www.example.com:88/", + "script-src http://www.example.com:88/" }, + { "script-src http://www.example.com:88/path-1", + "script-src http://www.example.com:88/path-1" }, + { "script-src http://www.example.com:88/path-1/", + "script-src http://www.example.com:88/path-1/" }, + { "script-src http://www.example.com:88/path-1/path_2", + "script-src http://www.example.com:88/path-1/path_2" }, + { "script-src http://www.example.com:88/path-1/path_2/", + "script-src http://www.example.com:88/path-1/path_2/" }, + { "script-src http://www.example.com:88/path-1/path_2/file.js", + "script-src http://www.example.com:88/path-1/path_2/file.js" }, + { "script-src http://www.example.com:*", + "script-src http://www.example.com:*" }, + { "script-src http://www.example.com:*/", + "script-src http://www.example.com:*/" }, + { "script-src http://www.example.com:*/path-1", + "script-src http://www.example.com:*/path-1" }, + { "script-src http://www.example.com:*/path-1/", + "script-src http://www.example.com:*/path-1/" }, + { "script-src http://www.example.com:*/path-1/path_2", + "script-src http://www.example.com:*/path-1/path_2" }, + { "script-src http://www.example.com:*/path-1/path_2/", + "script-src http://www.example.com:*/path-1/path_2/" }, + { "script-src http://www.example.com:*/path-1/path_2/file.js", + "script-src http://www.example.com:*/path-1/path_2/file.js" }, + { "script-src http://www.example.com#foo", + "script-src http://www.example.com" }, + { "script-src http://www.example.com?foo=bar", + "script-src http://www.example.com" }, + { "script-src http://www.example.com:8888#foo", + "script-src http://www.example.com:8888" }, + { "script-src http://www.example.com:8888?foo", + "script-src http://www.example.com:8888" }, + { "script-src http://www.example.com/#foo", + "script-src http://www.example.com/" }, + { "script-src http://www.example.com/?foo", + "script-src http://www.example.com/" }, + { "script-src http://www.example.com/path-1/file.js#foo", + "script-src http://www.example.com/path-1/file.js" }, + { "script-src http://www.example.com/path-1/file.js?foo", + "script-src http://www.example.com/path-1/file.js" }, + { "script-src http://www.example.com/path-1/file.js?foo#bar", + "script-src http://www.example.com/path-1/file.js" }, + { "report-uri http://www.example.com/", + "report-uri http://www.example.com/" }, + { "report-uri http://www.example.com:8888/asdf", + "report-uri http://www.example.com:8888/asdf" }, + { "report-uri http://www.example.com:8888/path_1/path_2", + "report-uri http://www.example.com:8888/path_1/path_2" }, + { "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301", + "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301" }, + { "report-uri /examplepath", + "report-uri http://www.selfuri.com/examplepath" }, + { "connect-src http://www.example.com/foo%3Bsessionid=12%2C34", + "connect-src http://www.example.com/foo;sessionid=12,34" }, + { "connect-src http://www.example.com/foo%3bsessionid=12%2c34", + "connect-src http://www.example.com/foo;sessionid=12,34" }, + { "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@", + "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@" }, + { "script-src http://www.example.com:88/.js", + "script-src http://www.example.com:88/.js" }, + { "script-src https://foo.com/_abc/abc_/_/_a_b_c_", + "script-src https://foo.com/_abc/abc_/_/_a_b_c_" } + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ======================== TestSimplePolicies ======================= + +TEST(CSPParser, SimplePolicies) +{ + static const PolicyTest policies[] = { + // clang-format off + { "frame-src intent:", + "frame-src intent:" }, + { "frame-src intent://host.name", + "frame-src intent://host.name" }, + { "frame-src intent://my.host.link/", + "frame-src intent://my.host.link/" }, + { "default-src *", + "default-src *" }, + { "default-src https:", + "default-src https:" }, + { "default-src https://*", + "default-src https://*" }, + { "default-src *:*", + "default-src http://*:*" }, + { "default-src *:80", + "default-src http://*:80" }, + { "default-src http://*:80", + "default-src http://*:80" }, + { "default-src javascript:", + "default-src javascript:" }, + { "default-src data:", + "default-src data:" }, + { "script-src 'unsafe-eval' 'unsafe-inline' http://www.example.com", + "script-src 'unsafe-eval' 'unsafe-inline' http://www.example.com" }, + { "object-src 'self'", + "object-src 'self'" }, + { "style-src http://www.example.com 'self'", + "style-src http://www.example.com 'self'" }, + { "media-src http://www.example.com http://www.test.com", + "media-src http://www.example.com http://www.test.com" }, + { "connect-src http://www.test.com example.com *.other.com;", + "connect-src http://www.test.com http://example.com http://*.other.com"}, + { "connect-src example.com *.other.com", + "connect-src http://example.com http://*.other.com"}, + { "style-src *.other.com example.com", + "style-src http://*.other.com http://example.com"}, + { "default-src 'self'; img-src *;", + "default-src 'self'; img-src *" }, + { "object-src media1.example.com media2.example.com *.cdn.example.com;", + "object-src http://media1.example.com http://media2.example.com http://*.cdn.example.com" }, + { "script-src trustedscripts.example.com", + "script-src http://trustedscripts.example.com" }, + { "script-src 'self' ; default-src trustedscripts.example.com", + "script-src 'self'; default-src http://trustedscripts.example.com" }, + { "default-src 'none'; report-uri http://localhost:49938/test", + "default-src 'none'; report-uri http://localhost:49938/test" }, + { " ; default-src abc", + "default-src http://abc" }, + { " ; ; ; ; default-src abc ; ; ; ;", + "default-src http://abc" }, + { "script-src 'none' 'none' 'none';", + "script-src 'none'" }, + { "script-src http://www.example.com/path-1//", + "script-src http://www.example.com/path-1//" }, + { "script-src http://www.example.com/path-1//path_2", + "script-src http://www.example.com/path-1//path_2" }, + { "default-src 127.0.0.1", + "default-src http://127.0.0.1" }, + { "default-src 127.0.0.1:*", + "default-src http://127.0.0.1:*" }, + { "default-src -; ", + "default-src http://-" }, + { "script-src 1", + "script-src http://1" }, + { "upgrade-insecure-requests", + "upgrade-insecure-requests" }, + { "upgrade-insecure-requests https:", + "upgrade-insecure-requests" }, + { "sandbox allow-scripts allow-forms ", + "sandbox allow-scripts allow-forms" }, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// =================== TestPoliciesWithInvalidSrc ==================== + +TEST(CSPParser, PoliciesWithInvalidSrc) +{ + static const PolicyTest policies[] = { + // clang-format off + { "script-src 'self'; SCRIPT-SRC http://www.example.com", + "script-src 'self'" }, + { "script-src 'none' test.com; script-src example.com", + "script-src http://test.com" }, + { "default-src **", + "default-src 'none'" }, + { "default-src 'self", + "default-src 'none'" }, + { "default-src 'unsafe-inlin' ", + "default-src 'none'" }, + { "default-src */", + "default-src 'none'" }, + { "default-src", + "default-src 'none'" }, + { "default-src 'unsafe-inlin' ", + "default-src 'none'" }, + { "default-src :88", + "default-src 'none'" }, + { "script-src abc::::::88", + "script-src 'none'" }, + { "script-src *.*:*", + "script-src 'none'" }, + { "img-src *::88", + "img-src 'none'" }, + { "object-src http://localhost:", + "object-src 'none'" }, + { "script-src test..com", + "script-src 'none'" }, + { "script-src sub1.sub2.example+", + "script-src 'none'" }, + { "script-src http://www.example.com//", + "script-src 'none'" }, + { "script-src http://www.example.com:88path-1/", + "script-src 'none'" }, + { "script-src http://www.example.com:88//", + "script-src 'none'" }, + { "script-src http://www.example.com:88//path-1", + "script-src 'none'" }, + { "script-src http://www.example.com:88//path-1", + "script-src 'none'" }, + { "script-src http://www.example.com:88.js", + "script-src 'none'" }, + { "script-src http://www.example.com:*.js", + "script-src 'none'" }, + { "script-src http://www.example.com:*.", + "script-src 'none'" }, + { "script-src 'nonce-{invalid}'", + "script-src 'none'" }, + { "script-src 'sha256-{invalid}'", + "script-src 'none'" }, + { "script-src 'nonce-in$valid'", + "script-src 'none'" }, + { "script-src 'sha256-in$valid'", + "script-src 'none'" }, + { "script-src 'nonce-invalid==='", + "script-src 'none'" }, + { "script-src 'sha256-invalid==='", + "script-src 'none'" }, + { "script-src 'nonce-==='", + "script-src 'none'" }, + { "script-src 'sha256-==='", + "script-src 'none'" }, + { "script-src 'nonce-=='", + "script-src 'none'" }, + { "script-src 'sha256-=='", + "script-src 'none'" }, + { "script-src 'nonce-='", + "script-src 'none'" }, + { "script-src 'sha256-='", + "script-src 'none'" }, + { "script-src 'nonce-'", + "script-src 'none'" }, + { "script-src 'sha256-'", + "script-src 'none'" }, + { "connect-src http://www.example.com/foo%zz;", + "connect-src 'none'" }, + { "script-src https://foo.com/%$", + "script-src 'none'" }, + { "sandbox foo", + "sandbox"}, + // clang-format on + }; + + // amount of tests - 1, because the latest should be ignored. + uint32_t policyCount = (sizeof(policies) / sizeof(PolicyTest)) - 1; + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ============================= TestBadPolicies ======================= + +TEST(CSPParser, BadPolicies) +{ + static const PolicyTest policies[] = { + // clang-format off + { "script-sr 'self", "" }, + { "", "" }, + { "; ; ; ; ; ; ;", "" }, + { "defaut-src asdf", "" }, + { "default-src: aaa", "" }, + { "asdf http://test.com", ""}, + { "report-uri", ""}, + { "report-uri http://:foo", ""}, + { "require-sri-for", ""}, + { "require-sri-for style", ""}, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 0)); +} + +// ======================= TestGoodGeneratedPolicies ================= + +TEST(CSPParser, GoodGeneratedPolicies) +{ + static const PolicyTest policies[] = { + // clang-format off + { "default-src 'self'; img-src *", + "default-src 'self'; img-src *" }, + { "report-uri /policy", + "report-uri http://www.selfuri.com/policy"}, + { "img-src *", + "img-src *" }, + { "media-src foo.bar", + "media-src http://foo.bar" }, + { "frame-src *.bar", + "frame-src http://*.bar" }, + { "font-src com", + "font-src http://com" }, + { "connect-src f00b4r.com", + "connect-src http://f00b4r.com" }, + { "script-src *.a.b.c", + "script-src http://*.a.b.c" }, + { "object-src *.b.c", + "object-src http://*.b.c" }, + { "style-src a.b.c", + "style-src http://a.b.c" }, + { "img-src a.com", + "img-src http://a.com" }, + { "media-src http://abc.com", + "media-src http://abc.com" }, + { "frame-src a2-c.com", + "frame-src http://a2-c.com" }, + { "font-src https://a.com", + "font-src https://a.com" }, + { "connect-src *.a.com", + "connect-src http://*.a.com" }, + { "default-src a.com:23", + "default-src http://a.com:23" }, + { "script-src https://a.com:200", + "script-src https://a.com:200" }, + { "object-src data:", + "object-src data:" }, + { "style-src javascript:", + "style-src javascript:" }, + { "frame-src https://foobar.com:443", + "frame-src https://foobar.com:443" }, + { "font-src https://a.com:443", + "font-src https://a.com:443" }, + { "connect-src http://a.com:80", + "connect-src http://a.com:80" }, + { "default-src http://foobar.com", + "default-src http://foobar.com" }, + { "script-src https://foobar.com", + "script-src https://foobar.com" }, + { "style-src 'none'", + "style-src 'none'" }, + { "img-src foo.bar:21 https://ras.bar", + "img-src http://foo.bar:21 https://ras.bar" }, + { "media-src http://foo.bar:21 https://ras.bar:443", + "media-src http://foo.bar:21 https://ras.bar:443" }, + { "frame-src http://self.com:80", + "frame-src http://self.com:80" }, + { "font-src http://self.com", + "font-src http://self.com" }, + { "connect-src https://foo.com http://bar.com:88", + "connect-src https://foo.com http://bar.com:88" }, + { "default-src * https://bar.com 'none'", + "default-src * https://bar.com" }, + { "script-src *.foo.com", + "script-src http://*.foo.com" }, + { "object-src http://b.com", + "object-src http://b.com" }, + { "style-src http://bar.com:88", + "style-src http://bar.com:88" }, + { "img-src https://bar.com:88", + "img-src https://bar.com:88" }, + { "media-src http://bar.com:443", + "media-src http://bar.com:443" }, + { "frame-src https://foo.com:88", + "frame-src https://foo.com:88" }, + { "font-src http://foo.com", + "font-src http://foo.com" }, + { "connect-src http://x.com:23", + "connect-src http://x.com:23" }, + { "default-src http://barbaz.com", + "default-src http://barbaz.com" }, + { "script-src http://somerandom.foo.com", + "script-src http://somerandom.foo.com" }, + { "default-src *", + "default-src *" }, + { "style-src http://bar.com:22", + "style-src http://bar.com:22" }, + { "img-src https://foo.com:443", + "img-src https://foo.com:443" }, + { "script-src https://foo.com; ", + "script-src https://foo.com" }, + { "img-src bar.com:*", + "img-src http://bar.com:*" }, + { "font-src https://foo.com:400", + "font-src https://foo.com:400" }, + { "connect-src http://bar.com:400", + "connect-src http://bar.com:400" }, + { "default-src http://evil.com", + "default-src http://evil.com" }, + { "script-src https://evil.com:100", + "script-src https://evil.com:100" }, + { "default-src bar.com; script-src https://foo.com", + "default-src http://bar.com; script-src https://foo.com" }, + { "default-src 'self'; script-src 'self' https://*:*", + "default-src 'self'; script-src 'self' https://*:*" }, + { "img-src http://self.com:34", + "img-src http://self.com:34" }, + { "media-src http://subd.self.com:34", + "media-src http://subd.self.com:34" }, + { "default-src 'none'", + "default-src 'none'" }, + { "connect-src http://self", + "connect-src http://self" }, + { "default-src http://foo", + "default-src http://foo" }, + { "script-src http://foo:80", + "script-src http://foo:80" }, + { "object-src http://bar", + "object-src http://bar" }, + { "style-src http://three:80", + "style-src http://three:80" }, + { "img-src https://foo:400", + "img-src https://foo:400" }, + { "media-src https://self:34", + "media-src https://self:34" }, + { "frame-src https://bar", + "frame-src https://bar" }, + { "font-src http://three:81", + "font-src http://three:81" }, + { "connect-src https://three:81", + "connect-src https://three:81" }, + { "script-src http://self.com:80/foo", + "script-src http://self.com:80/foo" }, + { "object-src http://self.com/foo", + "object-src http://self.com/foo" }, + { "report-uri /report.py", + "report-uri http://www.selfuri.com/report.py"}, + { "img-src http://foo.org:34/report.py", + "img-src http://foo.org:34/report.py" }, + { "media-src foo/bar/report.py", + "media-src http://foo/bar/report.py" }, + { "report-uri /", + "report-uri http://www.selfuri.com/"}, + { "font-src https://self.com/report.py", + "font-src https://self.com/report.py" }, + { "connect-src https://foo.com/report.py", + "connect-src https://foo.com/report.py" }, + { "default-src *; report-uri http://www.reporturi.com/", + "default-src *; report-uri http://www.reporturi.com/" }, + { "default-src http://first.com", + "default-src http://first.com" }, + { "script-src http://second.com", + "script-src http://second.com" }, + { "object-src http://third.com", + "object-src http://third.com" }, + { "style-src https://foobar.com:4443", + "style-src https://foobar.com:4443" }, + { "img-src http://foobar.com:4443", + "img-src http://foobar.com:4443" }, + { "media-src bar.com", + "media-src http://bar.com" }, + { "frame-src http://bar.com", + "frame-src http://bar.com" }, + { "font-src http://self.com/", + "font-src http://self.com/" }, + { "script-src 'self'", + "script-src 'self'" }, + { "default-src http://self.com/foo.png", + "default-src http://self.com/foo.png" }, + { "script-src http://self.com/foo.js", + "script-src http://self.com/foo.js" }, + { "object-src http://bar.com/foo.js", + "object-src http://bar.com/foo.js" }, + { "style-src http://FOO.COM", + "style-src http://foo.com" }, + { "img-src HTTP", + "img-src http://http" }, + { "media-src http", + "media-src http://http" }, + { "frame-src 'SELF'", + "frame-src 'self'" }, + { "DEFAULT-src 'self';", + "default-src 'self'" }, + { "default-src 'self' http://FOO.COM", + "default-src 'self' http://foo.com" }, + { "default-src 'self' HTTP://foo.com", + "default-src 'self' http://foo.com" }, + { "default-src 'NONE'", + "default-src 'none'" }, + { "script-src policy-uri ", + "script-src http://policy-uri" }, + { "img-src 'self'; ", + "img-src 'self'" }, + { "frame-ancestors foo-bar.com", + "frame-ancestors http://foo-bar.com" }, + { "frame-ancestors http://a.com", + "frame-ancestors http://a.com" }, + { "frame-ancestors 'self'", + "frame-ancestors 'self'" }, + { "frame-ancestors http://self.com:88", + "frame-ancestors http://self.com:88" }, + { "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com", + "frame-ancestors http://a.b.c.d.e.f.g.h.i.j.k.l.x.com" }, + { "frame-ancestors https://self.com:34", + "frame-ancestors https://self.com:34" }, + { "frame-ancestors http://sampleuser:samplepass@example.com", + "frame-ancestors 'none'" }, + { "default-src 'none'; frame-ancestors 'self'", + "default-src 'none'; frame-ancestors 'self'" }, + { "frame-ancestors http://self:80", + "frame-ancestors http://self:80" }, + { "frame-ancestors http://self.com/bar", + "frame-ancestors http://self.com/bar" }, + { "default-src 'self'; frame-ancestors 'self'", + "default-src 'self'; frame-ancestors 'self'" }, + { "frame-ancestors http://bar.com/foo.png", + "frame-ancestors http://bar.com/foo.png" }, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ==================== TestBadGeneratedPolicies ==================== + +TEST(CSPParser, BadGeneratedPolicies) +{ + static const PolicyTest policies[] = { + // clang-format off + { "foo.*.bar", ""}, + { "foo!bar.com", ""}, + { "x.*.a.com", ""}, + { "a#2-c.com", ""}, + { "http://foo.com:bar.com:23", ""}, + { "f!oo.bar", ""}, + { "ht!ps://f-oo.bar", ""}, + { "https://f-oo.bar:3f", ""}, + { "**", ""}, + { "*a", ""}, + { "http://username:password@self.com/foo", ""}, + { "http://other:pass1@self.com/foo", ""}, + { "http://user1:pass1@self.com/foo", ""}, + { "http://username:password@self.com/bar", ""}, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 0)); +} + +// ============ TestGoodGeneratedPoliciesForPathHandling ============= + +TEST(CSPParser, GoodGeneratedPoliciesForPathHandling) +{ + // Once bug 808292 (Implement path-level host-source matching to CSP) + // lands we have to update the expected output to include the parsed path + + static const PolicyTest policies[] = { + // clang-format off + { "img-src http://test1.example.com", + "img-src http://test1.example.com" }, + { "img-src http://test1.example.com/", + "img-src http://test1.example.com/" }, + { "img-src http://test1.example.com/path-1", + "img-src http://test1.example.com/path-1" }, + { "img-src http://test1.example.com/path-1/", + "img-src http://test1.example.com/path-1/" }, + { "img-src http://test1.example.com/path-1/path_2/", + "img-src http://test1.example.com/path-1/path_2/" }, + { "img-src http://test1.example.com/path-1/path_2/file.js", + "img-src http://test1.example.com/path-1/path_2/file.js" }, + { "img-src http://test1.example.com/path-1/path_2/file_1.js", + "img-src http://test1.example.com/path-1/path_2/file_1.js" }, + { "img-src http://test1.example.com/path-1/path_2/file-2.js", + "img-src http://test1.example.com/path-1/path_2/file-2.js" }, + { "img-src http://test1.example.com/path-1/path_2/f.js", + "img-src http://test1.example.com/path-1/path_2/f.js" }, + { "img-src http://test1.example.com/path-1/path_2/f.oo.js", + "img-src http://test1.example.com/path-1/path_2/f.oo.js" }, + { "img-src test1.example.com", + "img-src http://test1.example.com" }, + { "img-src test1.example.com/", + "img-src http://test1.example.com/" }, + { "img-src test1.example.com/path-1", + "img-src http://test1.example.com/path-1" }, + { "img-src test1.example.com/path-1/", + "img-src http://test1.example.com/path-1/" }, + { "img-src test1.example.com/path-1/path_2/", + "img-src http://test1.example.com/path-1/path_2/" }, + { "img-src test1.example.com/path-1/path_2/file.js", + "img-src http://test1.example.com/path-1/path_2/file.js" }, + { "img-src test1.example.com/path-1/path_2/file_1.js", + "img-src http://test1.example.com/path-1/path_2/file_1.js" }, + { "img-src test1.example.com/path-1/path_2/file-2.js", + "img-src http://test1.example.com/path-1/path_2/file-2.js" }, + { "img-src test1.example.com/path-1/path_2/f.js", + "img-src http://test1.example.com/path-1/path_2/f.js" }, + { "img-src test1.example.com/path-1/path_2/f.oo.js", + "img-src http://test1.example.com/path-1/path_2/f.oo.js" }, + { "img-src *.example.com", + "img-src http://*.example.com" }, + { "img-src *.example.com/", + "img-src http://*.example.com/" }, + { "img-src *.example.com/path-1", + "img-src http://*.example.com/path-1" }, + { "img-src *.example.com/path-1/", + "img-src http://*.example.com/path-1/" }, + { "img-src *.example.com/path-1/path_2/", + "img-src http://*.example.com/path-1/path_2/" }, + { "img-src *.example.com/path-1/path_2/file.js", + "img-src http://*.example.com/path-1/path_2/file.js" }, + { "img-src *.example.com/path-1/path_2/file_1.js", + "img-src http://*.example.com/path-1/path_2/file_1.js" }, + { "img-src *.example.com/path-1/path_2/file-2.js", + "img-src http://*.example.com/path-1/path_2/file-2.js" }, + { "img-src *.example.com/path-1/path_2/f.js", + "img-src http://*.example.com/path-1/path_2/f.js" }, + { "img-src *.example.com/path-1/path_2/f.oo.js", + "img-src http://*.example.com/path-1/path_2/f.oo.js" }, + { "img-src test1.example.com:80", + "img-src http://test1.example.com:80" }, + { "img-src test1.example.com:80/", + "img-src http://test1.example.com:80/" }, + { "img-src test1.example.com:80/path-1", + "img-src http://test1.example.com:80/path-1" }, + { "img-src test1.example.com:80/path-1/", + "img-src http://test1.example.com:80/path-1/" }, + { "img-src test1.example.com:80/path-1/path_2", + "img-src http://test1.example.com:80/path-1/path_2" }, + { "img-src test1.example.com:80/path-1/path_2/", + "img-src http://test1.example.com:80/path-1/path_2/" }, + { "img-src test1.example.com:80/path-1/path_2/file.js", + "img-src http://test1.example.com:80/path-1/path_2/file.js" }, + { "img-src test1.example.com:80/path-1/path_2/f.ile.js", + "img-src http://test1.example.com:80/path-1/path_2/f.ile.js" }, + { "img-src test1.example.com:*", + "img-src http://test1.example.com:*" }, + { "img-src test1.example.com:*/", + "img-src http://test1.example.com:*/" }, + { "img-src test1.example.com:*/path-1", + "img-src http://test1.example.com:*/path-1" }, + { "img-src test1.example.com:*/path-1/", + "img-src http://test1.example.com:*/path-1/" }, + { "img-src test1.example.com:*/path-1/path_2", + "img-src http://test1.example.com:*/path-1/path_2" }, + { "img-src test1.example.com:*/path-1/path_2/", + "img-src http://test1.example.com:*/path-1/path_2/" }, + { "img-src test1.example.com:*/path-1/path_2/file.js", + "img-src http://test1.example.com:*/path-1/path_2/file.js" }, + { "img-src test1.example.com:*/path-1/path_2/f.ile.js", + "img-src http://test1.example.com:*/path-1/path_2/f.ile.js" }, + { "img-src http://test1.example.com/abc//", + "img-src http://test1.example.com/abc//" }, + { "img-src https://test1.example.com/abc/def//", + "img-src https://test1.example.com/abc/def//" }, + { "img-src https://test1.example.com/abc/def/ghi//", + "img-src https://test1.example.com/abc/def/ghi//" }, + { "img-src http://test1.example.com:80/abc//", + "img-src http://test1.example.com:80/abc//" }, + { "img-src https://test1.example.com:80/abc/def//", + "img-src https://test1.example.com:80/abc/def//" }, + { "img-src https://test1.example.com:80/abc/def/ghi//", + "img-src https://test1.example.com:80/abc/def/ghi//" }, + { "img-src https://test1.example.com/abc////////////def/", + "img-src https://test1.example.com/abc////////////def/" }, + { "img-src https://test1.example.com/abc////////////", + "img-src https://test1.example.com/abc////////////" }, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ============== TestBadGeneratedPoliciesForPathHandling ============ + +TEST(CSPParser, BadGeneratedPoliciesForPathHandling) +{ + static const PolicyTest policies[] = { + // clang-format off + { "img-src test1.example.com:88path-1/", + "img-src 'none'" }, + { "img-src test1.example.com:80.js", + "img-src 'none'" }, + { "img-src test1.example.com:*.js", + "img-src 'none'" }, + { "img-src test1.example.com:*.", + "img-src 'none'" }, + { "img-src http://test1.example.com//", + "img-src 'none'" }, + { "img-src http://test1.example.com:80//", + "img-src 'none'" }, + { "img-src http://test1.example.com:80abc", + "img-src 'none'" }, + // clang-format on + }; + + uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); + ASSERT_NS_SUCCEEDED(runTestSuite(policies, policyCount, 1)); +} + +// ======================== TestFuzzyPolicies ======================== + +// Use a policy, eliminate one character at a time, +// and feed it as input to the parser. + +TEST(CSPParser, ShorteningPolicies) +{ + char pol[] = + "default-src http://www.sub1.sub2.example.com:88/path1/path2/ " + "'unsafe-inline' 'none'"; + uint32_t len = static_cast(sizeof(pol)); + + PolicyTest testPol[1]; + memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char)); + + while (--len) { + memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char)); + memcpy(&testPol[0].policy, &pol, len * sizeof(char)); + ASSERT_TRUE( + NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount))); + } +} + +// ============================= TestFuzzyPolicies =================== + +// We generate kFuzzyRuns inputs by (pseudo) randomly picking from the 128 +// ASCII characters; feed them to the parser and verfy that the parser +// handles the input gracefully. +// +// Please note, that by using srand(0) we get deterministic results! + +#if RUN_OFFLINE_TESTS + +TEST(CSPParser, FuzzyPolicies) +{ + // init srand with 0 so we get same results + srand(0); + + PolicyTest testPol[1]; + memset(&testPol[0].policy, '\0', kMaxPolicyLength); + + for (uint32_t index = 0; index < kFuzzyRuns; index++) { + // randomly select the length of the next policy + uint32_t polLength = rand() % kMaxPolicyLength; + // reset memory of the policy string + memset(&testPol[0].policy, '\0', kMaxPolicyLength * sizeof(char)); + + for (uint32_t i = 0; i < polLength; i++) { + // fill the policy array with random ASCII chars + testPol[0].policy[i] = static_cast(rand() % 128); + } + ASSERT_TRUE( + NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount))); + } +} + +#endif + +// ======================= TestFuzzyPoliciesIncDir =================== + +// In a similar fashion as in TestFuzzyPolicies, we again (pseudo) randomly +// generate input for the parser, but this time also include a valid directive +// followed by the random input. + +#if RUN_OFFLINE_TESTS + +TEST(CSPParser, FuzzyPoliciesIncDir) +{ + // init srand with 0 so we get same results + srand(0); + + PolicyTest testPol[1]; + memset(&testPol[0].policy, '\0', kMaxPolicyLength); + + char defaultSrc[] = "default-src "; + int defaultSrcLen = sizeof(defaultSrc) - 1; + // copy default-src into the policy array + memcpy(&testPol[0].policy, &defaultSrc, (defaultSrcLen * sizeof(char))); + + for (uint32_t index = 0; index < kFuzzyRuns; index++) { + // randomly select the length of the next policy + uint32_t polLength = rand() % (kMaxPolicyLength - defaultSrcLen); + // reset memory of the policy string, but leave default-src. + memset((&(testPol[0].policy) + (defaultSrcLen * sizeof(char))), '\0', + (kMaxPolicyLength - defaultSrcLen) * sizeof(char)); + + // do not start at index 0 so we do not overwrite 'default-src' + for (uint32_t i = defaultSrcLen; i < polLength; i++) { + // fill the policy array with random ASCII chars + testPol[0].policy[i] = static_cast(rand() % 128); + } + ASSERT_TRUE( + NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount))); + } +} + +#endif + +// ====================== TestFuzzyPoliciesIncDirLimASCII ============ + +// Same as TestFuzzyPoliciesIncDir() but using limited ASCII, +// which represents more likely input. + +#if RUN_OFFLINE_TESTS + +TEST(CSPParser, FuzzyPoliciesIncDirLimASCII) +{ + char input[] = + "1234567890" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWZYZ" + "!@#^&*()-+_="; + + // init srand with 0 so we get same results + srand(0); + + PolicyTest testPol[1]; + memset(&testPol[0].policy, '\0', kMaxPolicyLength); + + char defaultSrc[] = "default-src "; + int defaultSrcLen = sizeof(defaultSrc) - 1; + // copy default-src into the policy array + memcpy(&testPol[0].policy, &defaultSrc, (defaultSrcLen * sizeof(char))); + + for (uint32_t index = 0; index < kFuzzyRuns; index++) { + // randomly select the length of the next policy + uint32_t polLength = rand() % (kMaxPolicyLength - defaultSrcLen); + // reset memory of the policy string, but leave default-src. + memset((&(testPol[0].policy) + (defaultSrcLen * sizeof(char))), '\0', + (kMaxPolicyLength - defaultSrcLen) * sizeof(char)); + + // do not start at index 0 so we do not overwrite 'default-src' + for (uint32_t i = defaultSrcLen; i < polLength; i++) { + // fill the policy array with chars from the pre-defined input + uint32_t inputIndex = rand() % sizeof(input); + testPol[0].policy[i] = input[inputIndex]; + } + ASSERT_TRUE( + NS_SUCCEEDED(runTestSuite(testPol, 1, kFuzzyExpectedPolicyCount))); + } +} +#endif diff --git a/dom/security/test/gtest/TestFilenameEvalParser.cpp b/dom/security/test/gtest/TestFilenameEvalParser.cpp new file mode 100644 index 0000000000..60683007ca --- /dev/null +++ b/dom/security/test/gtest/TestFilenameEvalParser.cpp @@ -0,0 +1,453 @@ +/* -*- 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 "gtest/gtest.h" + +#include +#include + +#include "nsContentSecurityUtils.h" +#include "nsStringFwd.h" + +#include "mozilla/ExtensionPolicyService.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/SimpleGlobalObject.h" +#include "mozilla/extensions/WebExtensionPolicy.h" + +static constexpr auto kChromeURI = "chromeuri"_ns; +static constexpr auto kResourceURI = "resourceuri"_ns; +static constexpr auto kBlobUri = "bloburi"_ns; +static constexpr auto kDataUri = "dataurl"_ns; +static constexpr auto kAboutUri = "abouturi"_ns; +static constexpr auto kSingleString = "singlestring"_ns; +static constexpr auto kMozillaExtensionFile = "mozillaextension_file"_ns; +static constexpr auto kExtensionURI = "extension_uri"_ns; +static constexpr auto kSuspectedUserChromeJS = "suspectedUserChromeJS"_ns; +#if defined(XP_WIN) +static constexpr auto kSanitizedWindowsURL = "sanitizedWindowsURL"_ns; +static constexpr auto kSanitizedWindowsPath = "sanitizedWindowsPath"_ns; +#endif +static constexpr auto kOther = "other"_ns; + +#define ASSERT_AND_PRINT(first, second, condition) \ + fprintf(stderr, "First: %s\n", first.get()); \ + fprintf(stderr, "Second: %s\n", NS_ConvertUTF16toUTF8(second).get()); \ + ASSERT_TRUE((condition)); +// Usage: ASSERT_AND_PRINT(ret.first, ret.second.value(), ... + +#define ASSERT_AND_PRINT_FIRST(first, condition) \ + fprintf(stderr, "First: %s\n", (first).get()); \ + ASSERT_TRUE((condition)); +// Usage: ASSERT_AND_PRINT_FIRST(ret.first, ... + +TEST(FilenameEvalParser, ResourceChrome) +{ + { + constexpr auto str = u"chrome://firegestures/content/browser.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kChromeURI && ret.second.isSome() && + ret.second.value() == str); + } + { + constexpr auto str = u"resource://firegestures/content/browser.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kResourceURI && ret.second.isSome() && + ret.second.value() == str); + } +} + +TEST(FilenameEvalParser, BlobData) +{ + { + constexpr auto str = u"blob://000-000"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kBlobUri && !ret.second.isSome()); + } + { + constexpr auto str = u"blob:000-000"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kBlobUri && !ret.second.isSome()); + } + { + constexpr auto str = u"data://blahblahblah"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kDataUri && !ret.second.isSome()); + } + { + constexpr auto str = u"data:blahblahblah"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kDataUri && !ret.second.isSome()); + } +} + +TEST(FilenameEvalParser, MozExtension) +{ + { // Test shield.mozilla.org replacing + constexpr auto str = + u"jar:file:///c:/users/bob/appdata/roaming/mozilla/firefox/profiles/" + u"foo/" + "extensions/federated-learning@shield.mozilla.org.xpi!/experiments/" + "study/api.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kMozillaExtensionFile && + ret.second.value() == + u"federated-learning@s!/experiments/study/api.js"_ns); + } + { // Test mozilla.org replacing + constexpr auto str = + u"jar:file:///c:/users/bob/appdata/roaming/mozilla/firefox/profiles/" + u"foo/" + "extensions/federated-learning@shigeld.mozilla.org.xpi!/experiments/" + "study/api.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE( + ret.first == kMozillaExtensionFile && + ret.second.value() == + nsLiteralString( + u"federated-learning@shigeld.m!/experiments/study/api.js")); + } + { // Test truncating + constexpr auto str = + u"jar:file:///c:/users/bob/appdata/roaming/mozilla/firefox/profiles/" + u"foo/" + "extensions/federated-learning@shigeld.mozilla.org.xpi!/experiments/" + "study/apiiiiiiiiiiiiiiiiiiiiiiiiiiiiii.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kMozillaExtensionFile && + ret.second.value() == + u"federated-learning@shigeld.m!/experiments/" + "study/apiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"_ns); + } +} + +TEST(FilenameEvalParser, UserChromeJS) +{ + { + constexpr auto str = u"firegestures/content/browser.uc.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSuspectedUserChromeJS && !ret.second.isSome()); + } + { + constexpr auto str = u"firegestures/content/browser.uc.js?"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSuspectedUserChromeJS && !ret.second.isSome()); + } + { + constexpr auto str = u"firegestures/content/browser.uc.js?243244224"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSuspectedUserChromeJS && !ret.second.isSome()); + } + { + constexpr auto str = + u"file:///b:/fxprofiles/mark/chrome/" + "addbookmarkherewithmiddleclick.uc.js?1558444389291"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSuspectedUserChromeJS && !ret.second.isSome()); + } +} + +TEST(FilenameEvalParser, SingleFile) +{ + { + constexpr auto str = u"browser.uc.js?2456"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSingleString && ret.second.isSome() && + ret.second.value() == str); + } + { + constexpr auto str = u"debugger"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kSingleString && ret.second.isSome() && + ret.second.value() == str); + } +} + +TEST(FilenameEvalParser, Other) +{ + { + constexpr auto str = u"firegestures--content"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); + } + { + constexpr auto str = u"gallop://thing/fire"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsURL && + ret.second.value() == u"gallop"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"gallop://fire"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsURL && + ret.second.value() == u"gallop"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"firegestures/content"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsPath && + ret.second.value() == u"content"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"firegestures\\content"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsPath && + ret.second.value() == u"content"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"/home/tom/files/thing"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsPath && + ret.second.value() == u"thing"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"file://c/uers/tom/file.txt"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsURL && + ret.second.value() == u"file://.../file.txt"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"c:/uers/tom/file.txt"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsPath && + ret.second.value() == u"file.txt"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"http://example.com/"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsURL && + ret.second.value() == u"http"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } + { + constexpr auto str = u"http://example.com/thing.html"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); +#if defined(XP_WIN) + ASSERT_TRUE(ret.first == kSanitizedWindowsURL && + ret.second.value() == u"http"_ns); +#else + ASSERT_TRUE(ret.first == kOther && !ret.second.isSome()); +#endif + } +} + +TEST(FilenameEvalParser, WebExtensionPathParser) +{ + { + // Set up an Extension and register it so we can test against it. + mozilla::dom::AutoJSAPI jsAPI; + ASSERT_TRUE(jsAPI.Init(xpc::PrivilegedJunkScope())); + JSContext* cx = jsAPI.cx(); + + mozilla::dom::GlobalObject go(cx, xpc::PrivilegedJunkScope()); + auto* wEI = new mozilla::extensions::WebExtensionInit(); + + JS::Rooted func( + cx, (JSObject*)JS_NewFunction(cx, (JSNative)1, 0, 0, "customMethodA")); + JS::Rooted tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx)); + wEI->mLocalizeCallback = new mozilla::dom::WebExtensionLocalizeCallback( + cx, func, tempGlobalRoot, nullptr); + + wEI->mAllowedOrigins = + mozilla::dom::OwningMatchPatternSetOrStringSequence(); + nsString* slotPtr = + wEI->mAllowedOrigins.SetAsStringSequence().AppendElement( + mozilla::fallible); + ASSERT_TRUE(slotPtr != nullptr); + nsString& slot = *slotPtr; + slot.Truncate(); + slot = u"http://example.com"_ns; + + wEI->mName = u"gtest Test Extension"_ns; + wEI->mId = u"gtesttestextension@mozilla.org"_ns; + wEI->mBaseURL = u"file://foo"_ns; + wEI->mMozExtensionHostname = "e37c3c08-beac-a04b-8032-c4f699a1a856"_ns; + + mozilla::ErrorResult eR; + RefPtr w = + mozilla::extensions::WebExtensionPolicy::Constructor(go, *wEI, eR); + w->SetActive(true, eR); + + constexpr auto str = + u"moz-extension://e37c3c08-beac-a04b-8032-c4f699a1a856/path/to/file.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, true); + + ASSERT_TRUE(ret.first == kExtensionURI && + ret.second.value() == + u"moz-extension://[gtesttestextension@mozilla.org: " + "gtest Test Extension]P=0/path/to/file.js"_ns); + + w->SetActive(false, eR); + + delete wEI; + } + { + // Set up an Extension and register it so we can test against it. + mozilla::dom::AutoJSAPI jsAPI; + ASSERT_TRUE(jsAPI.Init(xpc::PrivilegedJunkScope())); + JSContext* cx = jsAPI.cx(); + + mozilla::dom::GlobalObject go(cx, xpc::PrivilegedJunkScope()); + auto wEI = new mozilla::extensions::WebExtensionInit(); + + JS::Rooted func( + cx, (JSObject*)JS_NewFunction(cx, (JSNative)1, 0, 0, "customMethodA")); + JS::Rooted tempGlobalRoot(cx, JS::CurrentGlobalOrNull(cx)); + wEI->mLocalizeCallback = new mozilla::dom::WebExtensionLocalizeCallback( + cx, func, tempGlobalRoot, NULL); + + wEI->mAllowedOrigins = + mozilla::dom::OwningMatchPatternSetOrStringSequence(); + nsString* slotPtr = + wEI->mAllowedOrigins.SetAsStringSequence().AppendElement( + mozilla::fallible); + nsString& slot = *slotPtr; + slot.Truncate(); + slot = u"http://example.com"_ns; + + wEI->mName = u"gtest Test Extension"_ns; + wEI->mId = u"gtesttestextension@mozilla.org"_ns; + wEI->mBaseURL = u"file://foo"_ns; + wEI->mMozExtensionHostname = "e37c3c08-beac-a04b-8032-c4f699a1a856"_ns; + wEI->mIsPrivileged = true; + + mozilla::ErrorResult eR; + RefPtr w = + mozilla::extensions::WebExtensionPolicy::Constructor(go, *wEI, eR); + w->SetActive(true, eR); + + constexpr auto str = + u"moz-extension://e37c3c08-beac-a04b-8032-c4f699a1a856/path/to/file.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, true); + + ASSERT_TRUE(ret.first == kExtensionURI && + ret.second.value() == + u"moz-extension://[gtesttestextension@mozilla.org: " + "gtest Test Extension]P=1/path/to/file.js"_ns); + + w->SetActive(false, eR); + + delete wEI; + } + { + constexpr auto str = + u"moz-extension://e37c3c08-beac-a04b-8032-c4f699a1a856/path/to/file.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kExtensionURI && !ret.second.isSome()); + } + { + constexpr auto str = + u"moz-extension://e37c3c08-beac-a04b-8032-c4f699a1a856/file.js"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, true); + ASSERT_TRUE( + ret.first == kExtensionURI && + ret.second.value() == + nsLiteralString( + u"moz-extension://[failed finding addon by host]/file.js")); + } + { + constexpr auto str = + u"moz-extension://e37c3c08-beac-a04b-8032-c4f699a1a856/path/to/" + "file.js?querystringx=6"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, true); + ASSERT_TRUE(ret.first == kExtensionURI && + ret.second.value() == + u"moz-extension://[failed finding addon " + "by host]/path/to/file.js"_ns); + } +} + +TEST(FilenameEvalParser, AboutPageParser) +{ + { + constexpr auto str = u"about:about"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kAboutUri && + ret.second.value() == u"about:about"_ns); + } + { + constexpr auto str = u"about:about?hello"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kAboutUri && + ret.second.value() == u"about:about"_ns); + } + { + constexpr auto str = u"about:about#mom"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kAboutUri && + ret.second.value() == u"about:about"_ns); + } + { + constexpr auto str = u"about:about?hello=there#mom"_ns; + FilenameTypeAndDetails ret = + nsContentSecurityUtils::FilenameToFilenameType(str, false); + ASSERT_TRUE(ret.first == kAboutUri && + ret.second.value() == u"about:about"_ns); + } +} diff --git a/dom/security/test/gtest/TestSecureContext.cpp b/dom/security/test/gtest/TestSecureContext.cpp new file mode 100644 index 0000000000..dbfb4a63b6 --- /dev/null +++ b/dom/security/test/gtest/TestSecureContext.cpp @@ -0,0 +1,121 @@ +/* -*- 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 "gtest/gtest.h" + +#include +#include + +#include "nsContentSecurityManager.h" +#include "nsContentUtils.h" +#include "nsIPrincipal.h" +#include "nsScriptSecurityManager.h" +#include "mozilla/NullPrincipal.h" +#include "mozilla/Preferences.h" + +using namespace mozilla; + +static const uint32_t kURIMaxLength = 64; + +struct TestExpectations { + char uri[kURIMaxLength]; + bool expectedResult; +}; + +class MOZ_RAII AutoRestoreBoolPref final { + public: + AutoRestoreBoolPref(const char* aPref, bool aValue) : mPref(aPref) { + Preferences::GetBool(mPref, &mOldValue); + Preferences::SetBool(mPref, aValue); + } + + ~AutoRestoreBoolPref() { Preferences::SetBool(mPref, mOldValue); } + + private: + const char* mPref = nullptr; + bool mOldValue = false; +}; + +// ============================= TestDirectives ======================== + +TEST(SecureContext, IsOriginPotentiallyTrustworthyWithContentPrincipal) +{ + // boolean isOriginPotentiallyTrustworthy(in nsIPrincipal aPrincipal); + + AutoRestoreBoolPref savedPref("network.proxy.allow_hijacking_localhost", + false); + + static const TestExpectations uris[] = { + {"http://example.com/", false}, + {"https://example.com/", true}, + {"ws://example.com/", false}, + {"wss://example.com/", true}, + {"file:///xyzzy", true}, + {"about:config", false}, + {"http://localhost", true}, + {"http://localhost.localhost", true}, + {"http://a.b.c.d.e.localhost", true}, + {"http://xyzzy.localhost", true}, + {"http://127.0.0.1", true}, + {"http://127.0.0.2", true}, + {"http://127.1.0.1", true}, + {"http://128.0.0.1", false}, + {"http://[::1]", true}, + {"http://[::ffff:127.0.0.1]", false}, + {"http://[::ffff:127.0.0.2]", false}, + {"http://[::ffff:7f00:1]", false}, + {"http://[::ffff:7f00:2]", false}, + {"resource://xyzzy", true}, + {"moz-extension://xyzzy", true}, + {"data:data:text/plain;charset=utf-8;base64,eHl6enk=", false}, + {"blob://unique-id", false}, + {"mailto:foo@bar.com", false}, + {"moz-icon://example.com", false}, + {"javascript:42", false}, + }; + + uint32_t numExpectations = sizeof(uris) / sizeof(TestExpectations); + nsCOMPtr csManager = + do_GetService(NS_CONTENTSECURITYMANAGER_CONTRACTID); + ASSERT_TRUE(!!csManager); + + nsresult rv; + for (uint32_t i = 0; i < numExpectations; i++) { + nsCOMPtr prin; + nsAutoCString uri(uris[i].uri); + rv = nsScriptSecurityManager::GetScriptSecurityManager() + ->CreateContentPrincipalFromOrigin(uri, getter_AddRefs(prin)); + ASSERT_EQ(rv, NS_OK); + bool isPotentiallyTrustworthy = prin->GetIsOriginPotentiallyTrustworthy(); + ASSERT_EQ(isPotentiallyTrustworthy, uris[i].expectedResult) + << uris[i].uri << uris[i].expectedResult; + } +} + +TEST(SecureContext, IsOriginPotentiallyTrustworthyWithSystemPrincipal) +{ + RefPtr ssManager = + nsScriptSecurityManager::GetScriptSecurityManager(); + ASSERT_TRUE(!!ssManager); + nsCOMPtr sysPrin = nsContentUtils::GetSystemPrincipal(); + bool isPotentiallyTrustworthy = sysPrin->GetIsOriginPotentiallyTrustworthy(); + ASSERT_TRUE(isPotentiallyTrustworthy); +} + +TEST(SecureContext, IsOriginPotentiallyTrustworthyWithNullPrincipal) +{ + RefPtr ssManager = + nsScriptSecurityManager::GetScriptSecurityManager(); + ASSERT_TRUE(!!ssManager); + + RefPtr nullPrin = + NullPrincipal::CreateWithoutOriginAttributes(); + bool isPotentiallyTrustworthy; + nsresult rv = + nullPrin->GetIsOriginPotentiallyTrustworthy(&isPotentiallyTrustworthy); + ASSERT_EQ(rv, NS_OK); + ASSERT_TRUE(!isPotentiallyTrustworthy); +} diff --git a/dom/security/test/gtest/TestSmartCrashTrimmer.cpp b/dom/security/test/gtest/TestSmartCrashTrimmer.cpp new file mode 100644 index 0000000000..d2238c0d75 --- /dev/null +++ b/dom/security/test/gtest/TestSmartCrashTrimmer.cpp @@ -0,0 +1,44 @@ +/* -*- 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 "gtest/gtest.h" + +#include +#include +#include + +#include "nsContentSecurityUtils.h" +#include "nsTString.h" +#include "nsStringFwd.h" +#include "mozilla/Sprintf.h" + +#define ASSERT_STRCMP(first, second) ASSERT_TRUE(strcmp(first, second) == 0); + +#define ASSERT_STRCMP_AND_PRINT(first, second) \ + fprintf(stderr, "First: %s\n", first); \ + fprintf(stderr, "Second: %s\n", second); \ + fprintf(stderr, "strcmp = %i\n", strcmp(first, second)); \ + ASSERT_EQUAL(first, second); + +TEST(SmartCrashTrimmer, Test) +{ + static_assert(sPrintfCrashReasonSize == 1024); + { + auto ret = nsContentSecurityUtils::SmartFormatCrashString( + std::string(1025, '.').c_str()); + ASSERT_EQ(strlen(ret), 1023ul); + } + + { + auto ret = nsContentSecurityUtils::SmartFormatCrashString( + std::string(1025, '.').c_str(), std::string(1025, 'A').c_str(), + "Hello %s world %s!"); + char expected[1025]; + SprintfLiteral(expected, "Hello %s world AAAAAAAAAAAAAAAAAAAAAAAAA!", + std::string(984, '.').c_str()); + ASSERT_STRCMP(ret.get(), expected); + } +} diff --git a/dom/security/test/gtest/TestUnexpectedPrivilegedLoads.cpp b/dom/security/test/gtest/TestUnexpectedPrivilegedLoads.cpp new file mode 100644 index 0000000000..772e4bd353 --- /dev/null +++ b/dom/security/test/gtest/TestUnexpectedPrivilegedLoads.cpp @@ -0,0 +1,305 @@ +/* -*- 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 "core/TelemetryEvent.h" +#include "gtest/gtest.h" +#include "js/Array.h" // JS::GetArrayLength +#include "js/PropertyAndElement.h" // JS_GetElement, JS_GetProperty +#include "js/TypeDecls.h" +#include "mozilla/BasePrincipal.h" +#include "mozilla/Maybe.h" +#include "mozilla/RefPtr.h" +#include "mozilla/Telemetry.h" +#include "mozilla/Unused.h" +#include "TelemetryFixture.h" +#include "TelemetryTestHelpers.h" + +#include +#include +#include "nsContentSecurityManager.h" +#include "nsContentSecurityUtils.h" +#include "nsContentUtils.h" +#include "nsIContentPolicy.h" +#include "nsILoadInfo.h" +#include "nsNetUtil.h" +#include "nsStringFwd.h" + +using namespace mozilla; +using namespace TelemetryTestHelpers; + +extern Atomic sJSHacksChecked; +extern Atomic sJSHacksPresent; +extern Atomic sCSSHacksChecked; +extern Atomic sCSSHacksPresent; + +TEST_F(TelemetryTestFixture, UnexpectedPrivilegedLoadsTelemetryTest) { + // Disable JS/CSS Hacks Detection, which would consider this current profile + // as uninteresting for our measurements: + bool origJSHacksPresent = sJSHacksPresent; + bool origJSHacksChecked = sJSHacksChecked; + sJSHacksPresent = false; + sJSHacksChecked = true; + bool origCSSHacksPresent = sCSSHacksPresent; + bool origCSSHacksChecked = sCSSHacksChecked; + sCSSHacksPresent = false; + sCSSHacksChecked = true; + + struct testResults { + nsCString fileinfo; + nsCString extraValueContenttype; + nsCString extraValueRemotetype; + nsCString extraValueFiledetails; + nsCString extraValueRedirects; + }; + + struct testCasesAndResults { + nsCString urlstring; + nsContentPolicyType contentType; + nsCString remoteType; + testResults expected; + }; + + AutoJSContextWithGlobal cx(mCleanGlobal); + // Make sure we don't look at events from other tests. + Unused << mTelemetry->ClearEvents(); + + // required for telemetry lookups + constexpr auto category = "security"_ns; + constexpr auto method = "unexpectedload"_ns; + constexpr auto object = "systemprincipal"_ns; + constexpr auto extraKeyContenttype = "contenttype"_ns; + constexpr auto extraKeyRemotetype = "remotetype"_ns; + constexpr auto extraKeyFiledetails = "filedetails"_ns; + constexpr auto extraKeyRedirects = "redirects"_ns; + + // some cases from TestFilenameEvalParser + // no need to replicate all scenarios?! + testCasesAndResults myTestCases[] = { + {"chrome://firegestures/content/browser.js"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "web"_ns, + {"chromeuri"_ns, "TYPE_SCRIPT"_ns, "web"_ns, + "chrome://firegestures/content/browser.js"_ns, ""_ns}}, + {"resource://firegestures/content/browser.js"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "web"_ns, + {"resourceuri"_ns, "TYPE_SCRIPT"_ns, "web"_ns, + "resource://firegestures/content/browser.js"_ns, ""_ns}}, + {// test that we don't report blob details + // ..and test that we strip of URLs from remoteTypes + "blob://000-000"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "webIsolated=https://blob.example/"_ns, + {"bloburi"_ns, "TYPE_SCRIPT"_ns, "webIsolated"_ns, "unknown"_ns, ""_ns}}, + {// test for cases where finalURI is null, due to a broken nested URI + // .. like malformed moz-icon URLs + "moz-icon:blahblah"_ns, + nsContentPolicyType::TYPE_DOCUMENT, + "web"_ns, + {"other"_ns, "TYPE_DOCUMENT"_ns, "web"_ns, "unknown"_ns, ""_ns}}, + {// we dont report data urls + // ..and test that we strip of URLs from remoteTypes + "data://blahblahblah"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "webCOOP+COEP=https://data.example"_ns, + {"dataurl"_ns, "TYPE_SCRIPT"_ns, "webCOOP+COEP"_ns, "unknown"_ns, + ""_ns}}, + {// handle data URLs for webextension content scripts differently + // .. by noticing their annotation + "data:text/css;extension=style;charset=utf-8,/* some css here */"_ns, + nsContentPolicyType::TYPE_STYLESHEET, + "web"_ns, + {"dataurl-extension-contentstyle"_ns, "TYPE_STYLESHEET"_ns, "web"_ns, + "unknown"_ns, ""_ns}}, + {// we only report file URLs on windows, where we can easily sanitize + "file://c/users/tom/file.txt"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "web"_ns, + { +#if defined(XP_WIN) + "sanitizedWindowsURL"_ns, "TYPE_SCRIPT"_ns, "web"_ns, + "file://.../file.txt"_ns, ""_ns + +#else + "other"_ns, "TYPE_SCRIPT"_ns, "web"_ns, "unknown"_ns, ""_ns +#endif + }}, + {// test for one redirect + "moz-extension://abcdefab-1234-4321-0000-abcdefabcdef/js/assets.js"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "web"_ns, + {"extension_uri"_ns, "TYPE_SCRIPT"_ns, "web"_ns, + // the extension-id is made-up, so the extension will report failure + "moz-extension://[failed finding addon by host]/js/assets.js"_ns, + "https"_ns}}, + {// test for cases where finalURI is empty + ""_ns, + nsContentPolicyType::TYPE_STYLESHEET, + "web"_ns, + {"other"_ns, "TYPE_STYLESHEET"_ns, "web"_ns, "unknown"_ns, ""_ns}}, + {// test for cases where finalURI is null, due to the struct layout, we'll + // override the URL with nullptr in loop below. + "URLWillResultInNullPtr"_ns, + nsContentPolicyType::TYPE_SCRIPT, + "web"_ns, + {"other"_ns, "TYPE_SCRIPT"_ns, "web"_ns, "unknown"_ns, ""_ns}}, + }; + + int i = 0; + for (auto const& currentTest : myTestCases) { + nsresult rv; + nsCOMPtr uri; + + // special-casing for a case where the uri is null + if (!currentTest.urlstring.Equals("URLWillResultInNullPtr")) { + NS_NewURI(getter_AddRefs(uri), currentTest.urlstring); + } + + // We can't create channels for chrome: URLs unless they are in a chrome + // registry that maps them into the actual destination URL (usually + // file://). It seems that gtest don't have chrome manifest registered, so + // we'll use a mockChannel with a mockUri. + nsCOMPtr mockUri; + rv = NS_NewURI(getter_AddRefs(mockUri), "http://example.com"_ns); + ASSERT_EQ(rv, NS_OK) << "Could not create mockUri"; + nsCOMPtr mockChannel; + nsCOMPtr service = do_GetIOService(); + if (!service) { + ASSERT_TRUE(false) + << "Couldn't initialize IOService"; + } + rv = service->NewChannelFromURI( + mockUri, nullptr, nsContentUtils::GetSystemPrincipal(), + nsContentUtils::GetSystemPrincipal(), 0, currentTest.contentType, + getter_AddRefs(mockChannel)); + ASSERT_EQ(rv, NS_OK) << "Could not create a mock channel"; + nsCOMPtr mockLoadInfo = mockChannel->LoadInfo(); + + // We're adding a redirect entry for one specific test + if (currentTest.urlstring.EqualsASCII( + "moz-extension://abcdefab-1234-4321-0000-abcdefabcdef/js/" + "assets.js")) { + nsCOMPtr redirUri; + NS_NewURI(getter_AddRefs(redirUri), + "https://www.analytics.example/analytics.js"_ns); + nsCOMPtr redirPrincipal = + BasePrincipal::CreateContentPrincipal(redirUri, OriginAttributes()); + nsCOMPtr redirectChannel; + Unused << service->NewChannelFromURI(redirUri, nullptr, redirPrincipal, + nullptr, 0, currentTest.contentType, + getter_AddRefs(redirectChannel)); + + mockLoadInfo->AppendRedirectHistoryEntry(redirectChannel, false); + } + + // this will record the event + nsContentSecurityManager::MeasureUnexpectedPrivilegedLoads( + mockLoadInfo, uri, currentTest.remoteType); + + // let's inspect the recorded events + + JS::Rooted eventsSnapshot(cx.GetJSContext()); + GetEventSnapshot(cx.GetJSContext(), &eventsSnapshot); + + ASSERT_TRUE(EventPresent(cx.GetJSContext(), eventsSnapshot, category, + method, object)) + << "Test event with value and extra must be present."; + + // Convert eventsSnapshot into array/object + JSContext* aCx = cx.GetJSContext(); + JS::Rooted arrayObj(aCx, &eventsSnapshot.toObject()); + + JS::Rooted eventRecord(aCx); + ASSERT_TRUE(JS_GetElement(aCx, arrayObj, i++, &eventRecord)) + << "Must be able to get record."; // record is already undefined :-/ + + ASSERT_TRUE(!eventRecord.isUndefined()) + << "eventRecord should not be undefined"; + + JS::Rooted recordArray(aCx, &eventRecord.toObject()); + uint32_t recordLength; + ASSERT_TRUE(JS::GetArrayLength(aCx, recordArray, &recordLength)) + << "Event record array must have length."; + ASSERT_TRUE(recordLength == 6) + << "Event record must have 6 elements."; + + JS::Rooted str(aCx); + nsAutoJSString jsStr; + // The fileinfo string is at index 4 + ASSERT_TRUE(JS_GetElement(aCx, recordArray, 4, &str)) + << "Must be able to get value."; + ASSERT_TRUE(jsStr.init(aCx, str)) + << "Value must be able to be init'd to a jsstring."; + + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), + currentTest.expected.fileinfo.get()) + << "Reported fileinfo '" << NS_ConvertUTF16toUTF8(jsStr).get() + << " 'equals expected value: " << currentTest.expected.fileinfo.get(); + + // Extra is at index 5 + JS::Rooted obj(aCx); + ASSERT_TRUE(JS_GetElement(aCx, recordArray, 5, &obj)) + << "Must be able to get extra data"; + JS::Rooted extraObj(aCx, &obj.toObject()); + // looking at remotetype extra for content type + JS::Rooted extraValC(aCx); + ASSERT_TRUE( + JS_GetProperty(aCx, extraObj, extraKeyContenttype.get(), &extraValC)) + << "Must be able to get the extra key's value for contenttype"; + ASSERT_TRUE(jsStr.init(aCx, extraValC)) + << "Extra value contenttype must be able to be init'd to a jsstring."; + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), + currentTest.expected.extraValueContenttype.get()) + << "Reported value for extra contenttype '" + << NS_ConvertUTF16toUTF8(jsStr).get() + << "' should equals supplied value" + << currentTest.expected.extraValueContenttype.get(); + // and again for remote type + JS::Rooted extraValP(aCx); + ASSERT_TRUE( + JS_GetProperty(aCx, extraObj, extraKeyRemotetype.get(), &extraValP)) + << "Must be able to get the extra key's value for remotetype"; + ASSERT_TRUE(jsStr.init(aCx, extraValP)) + << "Extra value remotetype must be able to be init'd to a jsstring."; + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), + currentTest.expected.extraValueRemotetype.get()) + << "Reported value for extra remotetype '" + << NS_ConvertUTF16toUTF8(jsStr).get() + << "' should equals supplied value: " + << currentTest.expected.extraValueRemotetype.get(); + // repeating the same for filedetails extra + JS::Rooted extraValF(aCx); + ASSERT_TRUE( + JS_GetProperty(aCx, extraObj, extraKeyFiledetails.get(), &extraValF)) + << "Must be able to get the extra key's value for filedetails"; + ASSERT_TRUE(jsStr.init(aCx, extraValF)) + << "Extra value filedetails must be able to be init'd to a jsstring."; + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), + currentTest.expected.extraValueFiledetails.get()) + << "Reported value for extra filedetails '" + << NS_ConvertUTF16toUTF8(jsStr).get() << "'should equals supplied value" + << currentTest.expected.extraValueFiledetails.get(); + // checking the extraKeyRedirects match + JS::Rooted extraValRedirects(aCx); + ASSERT_TRUE(JS_GetProperty(aCx, extraObj, extraKeyRedirects.get(), + &extraValRedirects)) + << "Must be able to get the extra value for redirects"; + ASSERT_TRUE(jsStr.init(aCx, extraValRedirects)) + << "Extra value redirects must be able to be init'd to a jsstring"; + ASSERT_STREQ(NS_ConvertUTF16toUTF8(jsStr).get(), + currentTest.expected.extraValueRedirects.get()) + << "Reported value for extra redirect '" + << NS_ConvertUTF16toUTF8(jsStr).get() + << "' should equals supplied value: " + << currentTest.expected.extraValueRedirects.get(); + } + + // Re-store JS/CSS hacks detection state + sJSHacksPresent = origJSHacksPresent; + sJSHacksChecked = origJSHacksChecked; + sCSSHacksPresent = origCSSHacksPresent; + sCSSHacksChecked = origCSSHacksChecked; +} diff --git a/dom/security/test/gtest/moz.build b/dom/security/test/gtest/moz.build new file mode 100644 index 0000000000..c9ab4dcece --- /dev/null +++ b/dom/security/test/gtest/moz.build @@ -0,0 +1,25 @@ +# -*- 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/. + +UNIFIED_SOURCES += [ + "TestCSPParser.cpp", + "TestFilenameEvalParser.cpp", + "TestSecureContext.cpp", + "TestSmartCrashTrimmer.cpp", +] + +if CONFIG["OS_TARGET"] != "Android": + UNIFIED_SOURCES += [ + "TestUnexpectedPrivilegedLoads.cpp", + ] + +FINAL_LIBRARY = "xul-gtest" + +LOCAL_INCLUDES += [ + "/caps", + "/toolkit/components/telemetry/", + "/toolkit/components/telemetry/tests/gtest", +] diff --git a/dom/security/test/https-first/browser.ini b/dom/security/test/https-first/browser.ini new file mode 100644 index 0000000000..9e355423dc --- /dev/null +++ b/dom/security/test/https-first/browser.ini @@ -0,0 +1,35 @@ +[browser_httpsfirst.js] +support-files = + file_httpsfirst_timeout_server.sjs +[browser_httpsfirst_console_logging.js] +[browser_upgrade_onion.js] +[browser_mixed_content_console.js] +support-files = + file_mixed_content_console.html +[browser_downgrade_view_source.js] +support-files = file_downgrade_view_source.sjs +[browser_navigation.js] +support-files = file_navigation.html +[browser_httpsfirst_speculative_connect.js] +support-files = file_httpsfirst_speculative_connect.html +[browser_download_attribute.js] +support-files = file_download_attribute.html + file_download_attribute.sjs + +[browser_mixed_content_download.js] +skip-if = win10_2004 && debug # Bug 1723573 +support-files = + download_page.html + download_server.sjs +[browser_slow_download.js] +support-files = + file_slow_download.html + file_slow_download.sjs +[browser_downgrade_mixed_content_auto_upgrade_console.js] +support-files = + file_mixed_content_auto_upgrade.html + pass.png + test.ogv + test.wav +[browser_beforeunload_permit_http.js] +support-files = file_beforeunload_permit_http.html diff --git a/dom/security/test/https-first/browser_beforeunload_permit_http.js b/dom/security/test/https-first/browser_beforeunload_permit_http.js new file mode 100644 index 0000000000..dda5fbbba9 --- /dev/null +++ b/dom/security/test/https-first/browser_beforeunload_permit_http.js @@ -0,0 +1,208 @@ +"use strict"; + +const { PromptTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PromptTestUtils.sys.mjs" +); + +const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://nocert.example.com/" +); +/* + * Description of Tests: + * + * Test load page and reload: + * 1. Enable HTTPS-First and the pref to trigger beforeunload by user interaction + * 2. Open an HTTP site. HTTPS-First will try to upgrade it to https - but since it has no cert that try will fail + * 3. Then simulated user interaction and reload the page with a reload flag. + * 4. That should lead to a beforeUnload prompt that asks for users permission to perform reload. HTTPS-First should not try to upgrade the reload again + * + * Test Navigation: + * 1. Enable HTTPS-First and the pref to trigger beforeunload by user interaction + * 2. Open an http site. HTTPS-First will try to upgrade it to https - but since it has no cert for https that try will fail + * 3. Then simulated user interaction and navigate to another http page. Again HTTPS-First will try to upgrade to HTTPS + * 4. This attempted navigation leads to a prompt which askes for permission to leave page - accept it + * 5. Since the site is not using a valid HTTPS cert HTTPS-First will downgrade the request back to HTTP + * 6. User should NOT get asked again for permission to unload + * + * Test Session History Navigation: + * 1. Enable HTTPS-First and the pref to trigger beforeunload by user interaction + * 2. Open an http site. HTTPS-First will try to upgrade it to https - but since it has no cert for https that try will fail + * 3. Then navigate to another http page and simulated a user interaction. + * 4. Trigger a session history navigation by clicking the "back button". + * 5. This attempted navigation leads to a prompt which askes for permission to leave page - accept it + */ +add_setup(async function () { + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_first", true], + ["dom.require_user_interaction_for_beforeunload", true], + ], + }); +}); +const TESTS = [ + { + name: "Normal Reload (No flag)", + reloadFlag: Ci.nsIWebNavigation.LOAD_FLAGS_NONE, + }, + { + name: "Bypass Cache Reload", + reloadFlag: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE, + }, + { + name: "Bypass Proxy Reload", + reloadFlag: Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY, + }, + { + name: "Bypass Cache and Proxy Reload", + reloadFlag: + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE | + Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY, + }, +]; + +add_task(async function testReloadFlags() { + for (let index = 0; index < TESTS.length; index++) { + const testCase = TESTS[index]; + // The onbeforeunload dialog should appear + let dialogPromise = PromptTestUtils.waitForPrompt(null, { + modalType: Services.prompt.MODAL_TYPE_CONTENT, + promptType: "confirmEx", + }); + let reloadPromise = loadPageAndReload(testCase); + let dialog = await dialogPromise; + Assert.ok(true, "Showed the beforeunload dialog."); + await PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 0 }); + await reloadPromise; + } +}); + +add_task(async function testNavigation() { + // The onbeforeunload dialog should appear + let dialogPromise = PromptTestUtils.waitForPrompt(null, { + modalType: Services.prompt.MODAL_TYPE_CONTENT, + promptType: "confirmEx", + }); + + let openPagePromise = openPage(); + let dialog = await dialogPromise; + Assert.ok(true, "Showed the beforeunload dialog."); + await PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 0 }); + await openPagePromise; +}); + +add_task(async function testSessionHistoryNavigation() { + // The onbeforeunload dialog should appear + let dialogPromise = PromptTestUtils.waitForPrompt(null, { + modalType: Services.prompt.MODAL_TYPE_CONTENT, + promptType: "confirmEx", + }); + + let openPagePromise = loadPagesAndUseBackButton(); + let dialog = await dialogPromise; + Assert.ok(true, "Showed the beforeunload dialog."); + await PromptTestUtils.handlePrompt(dialog, { buttonNumClick: 0 }); + await openPagePromise; +}); + +async function openPage() { + // Open about:blank in a new tab + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async function (browser) { + // Load http page + BrowserTestUtils.loadURIString( + browser, + `${TEST_PATH_HTTP}file_beforeunload_permit_http.html` + ); + await BrowserTestUtils.browserLoaded(browser); + // Interact with page such that unload permit will be necessary + await BrowserTestUtils.synthesizeMouse("body", 2, 2, {}, browser); + let hasInteractedWith = await SpecialPowers.spawn( + browser, + [""], + function () { + return content.document.userHasInteracted; + } + ); + + is(true, hasInteractedWith, "Simulated successfully user interaction"); + // And then navigate away to another site which proves that user won't be asked twice to permit a reload (otherwise the test get timed out) + BrowserTestUtils.loadURIString( + browser, + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://self-signed.example.com/" + ); + await BrowserTestUtils.browserLoaded(browser); + Assert.ok(true, "Navigated successfully."); + } + ); +} + +async function loadPageAndReload(testCase) { + // Load initial site + // Open about:blank in a new tab + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async function (browser) { + BrowserTestUtils.loadURIString( + browser, + `${TEST_PATH_HTTP}file_beforeunload_permit_http.html` + ); + await BrowserTestUtils.browserLoaded(browser); + // Interact with page such that unload permit will be necessary + await BrowserTestUtils.synthesizeMouse("body", 2, 2, {}, browser); + + let hasInteractedWith = await SpecialPowers.spawn( + browser, + [""], + function () { + return content.document.userHasInteracted; + } + ); + is(true, hasInteractedWith, "Simulated successfully user interaction"); + BrowserReloadWithFlags(testCase.reloadFlag); + await BrowserTestUtils.browserLoaded(browser); + is(true, true, `reload with flag ${testCase.name} was successful`); + } + ); +} + +async function loadPagesAndUseBackButton() { + // Load initial site + // Open about:blank in a new tab + await BrowserTestUtils.withNewTab( + { gBrowser, url: "about:blank" }, + async function (browser) { + BrowserTestUtils.loadURIString( + browser, + `${TEST_PATH_HTTP}file_beforeunload_permit_http.html` + ); + await BrowserTestUtils.browserLoaded(browser); + + BrowserTestUtils.loadURIString( + browser, + `${TEST_PATH_HTTP}file_beforeunload_permit_http.html?getASessionHistoryEntry` + ); + await BrowserTestUtils.browserLoaded(browser); + // Interact with page such that unload permit will be necessary + await BrowserTestUtils.synthesizeMouse("body", 2, 2, {}, browser); + + let hasInteractedWith = await SpecialPowers.spawn( + browser, + [""], + function () { + return content.document.userHasInteracted; + } + ); + is(true, hasInteractedWith, "Simulated successfully user interaction"); + // Go back one site by clicking the back button + info("Clicking back button"); + let backButton = document.getElementById("back-button"); + backButton.click(); + await BrowserTestUtils.browserLoaded(browser); + is(true, true, `Got back successful`); + } + ); +} diff --git a/dom/security/test/https-first/browser_downgrade_mixed_content_auto_upgrade_console.js b/dom/security/test/https-first/browser_downgrade_mixed_content_auto_upgrade_console.js new file mode 100644 index 0000000000..2235d7392c --- /dev/null +++ b/dom/security/test/https-first/browser_downgrade_mixed_content_auto_upgrade_console.js @@ -0,0 +1,80 @@ +// Bug 1673574 - Improve Console logging for mixed content auto upgrading +"use strict"; + +const testPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://httpsfirst.com" +); + +let tests = [ + { + description: "Top-Level upgrade should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: ["Upgrading insecure request", "to use", "httpsfirst.com"], + }, + { + description: "Top-Level upgrade failure should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: [ + "Upgrading insecure request", + "failed", + "httpsfirst.com", + "Downgrading to", + ], + }, +]; + +const kTestURI = testPath + "file_mixed_content_auto_upgrade.html"; + +add_task(async function () { + // A longer timeout is necessary for this test than the plain mochitests + // due to opening a new tab with the web console. + requestLongerTimeout(4); + + // Enable ML2 and HTTPS-First Mode and register console-listener + await SpecialPowers.pushPrefEnv({ + set: [ + ["security.mixed_content.upgrade_display_content", true], + ["dom.security.https_first", true], + ], + }); + Services.console.registerListener(on_new_message); + // 1. Upgrade page to https:// + await BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, kTestURI); + + await BrowserTestUtils.waitForCondition(() => tests.length === 0); + + // Clean up + Services.console.unregisterListener(on_new_message); +}); + +function on_new_message(msgObj) { + const message = msgObj.message; + const logLevel = msgObj.logLevel; + + // The console message is: + // Should only show HTTPS-First messages + + if (message.includes("Mixed Content:")) { + ok( + !message.includes("Upgrading insecure display request"), + "msg included a mixed content upgrade" + ); + } + if (message.includes("HTTPS-First Mode:")) { + for (let i = 0; i < tests.length; i++) { + const testCase = tests[i]; + // Check if log-level matches + if (logLevel !== testCase.expectLogLevel) { + continue; + } + // Check if all substrings are included + if (testCase.expectIncludes.some(str => !message.includes(str))) { + continue; + } + ok(true, testCase.description); + tests.splice(i, 1); + break; + } + } +} diff --git a/dom/security/test/https-first/browser_downgrade_view_source.js b/dom/security/test/https-first/browser_downgrade_view_source.js new file mode 100644 index 0000000000..38ff468490 --- /dev/null +++ b/dom/security/test/https-first/browser_downgrade_view_source.js @@ -0,0 +1,81 @@ +// This test ensures that view-source:https falls back to view-source:http +"use strict"; + +const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +const TEST_PATH_HTTPS = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +async function runTest(desc, url, expectedURI, excpectedContent) { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + let loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); + BrowserTestUtils.loadURIString(browser, url); + await loaded; + + await SpecialPowers.spawn( + browser, + [desc, expectedURI, excpectedContent], + async function (desc, expectedURI, excpectedContent) { + let loadedURI = content.document.documentURI; + is(loadedURI, expectedURI, desc); + let loadedContent = content.document.body.textContent; + is(loadedContent, excpectedContent, desc); + } + ); + }); +} + +add_task(async function () { + requestLongerTimeout(2); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + + await runTest( + "URL with query 'downgrade' should be http:", + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade`, + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade`, + "view-source:http://" + ); + + await runTest( + "URL with query 'downgrade' should be http and leave query params untouched:", + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade&https://httpsfirst.com`, + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?downgrade&https://httpsfirst.com`, + "view-source:http://" + ); + + await runTest( + "URL with query 'upgrade' should be https:", + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?upgrade`, + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade`, + "view-source:https://" + ); + + await runTest( + "URL with query 'upgrade' should be https:", + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade`, + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade`, + "view-source:https://" + ); + + await runTest( + "URL with query 'upgrade' should be https and leave query params untouched:", + `view-source:${TEST_PATH_HTTP}/file_downgrade_view_source.sjs?upgrade&https://httpsfirst.com`, + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade&https://httpsfirst.com`, + "view-source:https://" + ); + + await runTest( + "URL with query 'upgrade' should be https and leave query params untouched:", + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade&https://httpsfirst.com`, + `view-source:${TEST_PATH_HTTPS}/file_downgrade_view_source.sjs?upgrade&https://httpsfirst.com`, + "view-source:https://" + ); +}); diff --git a/dom/security/test/https-first/browser_download_attribute.js b/dom/security/test/https-first/browser_download_attribute.js new file mode 100644 index 0000000000..81bd0d799a --- /dev/null +++ b/dom/security/test/https-first/browser_download_attribute.js @@ -0,0 +1,125 @@ +"use strict"; + +// Create a uri for an http site +//(in that case a site without cert such that https-first isn't upgrading it) +const insecureTestPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://nocert.example.com" +); +const insecureTestURI = insecureTestPath + "file_download_attribute.html"; + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +const CONSOLE_UPGRADE_TRY_MESSAGE = "Upgrading insecure request"; +const CONSOLE_ERROR_MESSAGE = "Downgrading to “http” again"; +const DOWNLOAD_PAGE_URL = + "nocert.example.com/browser/dom/security/test/https-first/file_download_attribute.html"; +const DOWNLOAD_LINK_URL = + "nocert.example.com/browser/dom/security/test/https-first/file_download_attribute.sjs"; + +// Verifys that https-first tried to upgrade the download +// - and that the upgrade attempt failed. +// We will receive 4 messages. Two for upgrading and downgrading +// the download page and another two for upgrading and downgrading +// the download. +let msgCounter = 0; +function shouldConsoleTryUpgradeAndError() { + // Waits until CONSOLE_ERROR_MESSAGE was logged. + // Checks if download was tried via http:// + return new Promise((resolve, reject) => { + function listener(msgObj) { + let text = msgObj.message; + // Verify upgrade messages + if ( + text.includes(CONSOLE_UPGRADE_TRY_MESSAGE) && + text.includes("http://") + ) { + if (msgCounter == 0) { + ok( + text.includes(DOWNLOAD_PAGE_URL), + "Tries to upgrade nocert example to https" + ); + } else { + ok( + text.includes(DOWNLOAD_LINK_URL), + "Tries to upgrade download to https" + ); + } + msgCounter++; + } + // Verify downgrade messages + if (text.includes(CONSOLE_ERROR_MESSAGE) && msgCounter > 0) { + if (msgCounter == 1) { + ok( + text.includes("https://" + DOWNLOAD_PAGE_URL), + "Downgrades nocert example to http" + ); + msgCounter++; + } else { + ok( + text.includes("https://" + DOWNLOAD_LINK_URL), + "Downgrades download to http" + ); + Services.console.unregisterListener(listener); + resolve(); + } + } + } + Services.console.registerListener(listener); + }); +} + +// Test https-first download of an html file from an http site. +// Test description: +// 1. https-first tries to upgrade site to https +// 2. upgrade fails because site has no certificate +// 3. https-first downgrades to http and starts download via http +// 4. Successfully completes download +add_task(async function test_with_downloads_pref_enabled() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + let checkPromise = shouldConsoleTryUpgradeAndError(); + let downloadsPanelPromise = promisePanelOpened(); + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + + BrowserTestUtils.loadURIString(gBrowser, insecureTestURI); + // wait for downloadsPanel to open before continuing with test + await downloadsPanelPromise; + let downloadList = await downloadsPromise; + await checkPromise; + is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open."); + is( + downloadList._downloads.length, + 1, + "File should be successfully downloaded." + ); + + let [download] = downloadList._downloads; + is(download.contentType, "text/html", "File contentType should be correct."); + // ensure https-first didn't upgrade the scheme. + is( + download.source.url, + insecureTestPath + "file_download_attribute.sjs", + "Scheme should be http." + ); + + info("cleaning up downloads"); + try { + if (Services.appinfo.OS === "WINNT") { + // We need to make the file writable to delete it on Windows. + await IOUtils.setPermissions(download.target.path, 0o600); + } + await IOUtils.remove(download.target.path); + } catch (error) { + info("The file " + download.target.path + " is not removed, " + error); + } + + await downloadList.remove(download); + await download.finalize(); +}); diff --git a/dom/security/test/https-first/browser_httpsfirst.js b/dom/security/test/https-first/browser_httpsfirst.js new file mode 100644 index 0000000000..a2f916a2f0 --- /dev/null +++ b/dom/security/test/https-first/browser_httpsfirst.js @@ -0,0 +1,74 @@ +"use strict"; + +const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +const TIMEOUT_PAGE_URI_HTTP = + TEST_PATH_HTTP + "file_httpsfirst_timeout_server.sjs"; + +async function runPrefTest(aURI, aDesc, aAssertURLStartsWith) { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + const loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); + BrowserTestUtils.loadURIString(browser, aURI); + await loaded; + + await ContentTask.spawn( + browser, + { aDesc, aAssertURLStartsWith }, + function ({ aDesc, aAssertURLStartsWith }) { + ok( + content.document.location.href.startsWith(aAssertURLStartsWith), + aDesc + ); + } + ); + }); +} + +add_task(async function () { + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", false]], + }); + + await runPrefTest( + "http://example.com", + "HTTPS-First disabled; Should not upgrade", + "http://" + ); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + + await runPrefTest( + "http://example.com", + "Should upgrade upgradeable website", + "https://" + ); + + await runPrefTest( + "http://httpsfirst.com", + "Should downgrade after error.", + "http://" + ); + + await runPrefTest( + "http://httpsfirst.com/?https://httpsfirst.com", + "Should downgrade after error and leave query params untouched.", + "http://httpsfirst.com/?https://httpsfirst.com" + ); + + await runPrefTest( + "http://domain.does.not.exist", + "Should not downgrade on dnsNotFound error.", + "https://" + ); + + await runPrefTest( + TIMEOUT_PAGE_URI_HTTP, + "Should downgrade after timeout.", + "http://" + ); +}); diff --git a/dom/security/test/https-first/browser_httpsfirst_console_logging.js b/dom/security/test/https-first/browser_httpsfirst_console_logging.js new file mode 100644 index 0000000000..55f114ced1 --- /dev/null +++ b/dom/security/test/https-first/browser_httpsfirst_console_logging.js @@ -0,0 +1,71 @@ +// Bug 1658924 - HTTPS-First Mode - Tests for console logging +// https://bugzilla.mozilla.org/show_bug.cgi?id=1658924 +// This test makes sure that the various console messages from the HTTPS-First +// mode get logged to the console. +"use strict"; + +// Test Cases +// description: Description of what the subtests expects. +// expectLogLevel: Expected log-level of a message. +// expectIncludes: Expected substrings the message should contain. +let tests = [ + { + description: "Top-Level upgrade should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: ["Upgrading insecure request", "to use", "httpsfirst.com"], + }, + { + description: "Top-Level upgrade failure should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: [ + "Upgrading insecure request", + "failed", + "httpsfirst.com", + "Downgrading to", + ], + }, +]; + +add_task(async function () { + // A longer timeout is necessary for this test than the plain mochitests + // due to opening a new tab with the web console. + requestLongerTimeout(4); + + // Enable HTTPS-First Mode and register console-listener + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + Services.console.registerListener(on_new_message); + // 1. Upgrade page to https:// + await BrowserTestUtils.loadURIString( + gBrowser.selectedBrowser, + "http://httpsfirst.com" + ); + + await BrowserTestUtils.waitForCondition(() => tests.length === 0); + + // Clean up + Services.console.unregisterListener(on_new_message); +}); + +function on_new_message(msgObj) { + const message = msgObj.message; + const logLevel = msgObj.logLevel; + + if (message.includes("HTTPS-First Mode:")) { + for (let i = 0; i < tests.length; i++) { + const testCase = tests[i]; + // Check if log-level matches + if (logLevel !== testCase.expectLogLevel) { + continue; + } + // Check if all substrings are included + if (testCase.expectIncludes.some(str => !message.includes(str))) { + continue; + } + ok(true, testCase.description); + tests.splice(i, 1); + break; + } + } +} diff --git a/dom/security/test/https-first/browser_httpsfirst_speculative_connect.js b/dom/security/test/https-first/browser_httpsfirst_speculative_connect.js new file mode 100644 index 0000000000..9bf02e797d --- /dev/null +++ b/dom/security/test/https-first/browser_httpsfirst_speculative_connect.js @@ -0,0 +1,69 @@ +"use strict"; + +const TEST_PATH_HTTP = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +let console_messages = [ + { + description: "Speculative Connection should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: [ + "Upgrading insecure speculative TCP connection", + "to use", + "example.com", + "file_httpsfirst_speculative_connect.html", + ], + }, + { + description: "Upgrade should get logged", + expectLogLevel: Ci.nsIConsoleMessage.warn, + expectIncludes: [ + "Upgrading insecure request", + "to use", + "example.com", + "file_httpsfirst_speculative_connect.html", + ], + }, +]; + +function on_new_console_messages(msgObj) { + const message = msgObj.message; + const logLevel = msgObj.logLevel; + + if (message.includes("HTTPS-First Mode:")) { + for (let i = 0; i < console_messages.length; i++) { + const testCase = console_messages[i]; + // Check if log-level matches + if (logLevel !== testCase.expectLogLevel) { + continue; + } + // Check if all substrings are included + if (testCase.expectIncludes.some(str => !message.includes(str))) { + continue; + } + ok(true, testCase.description); + console_messages.splice(i, 1); + break; + } + } +} + +add_task(async function () { + requestLongerTimeout(4); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + Services.console.registerListener(on_new_console_messages); + + await BrowserTestUtils.loadURIString( + gBrowser.selectedBrowser, + `${TEST_PATH_HTTP}file_httpsfirst_speculative_connect.html` + ); + + await BrowserTestUtils.waitForCondition(() => console_messages.length === 0); + + Services.console.unregisterListener(on_new_console_messages); +}); diff --git a/dom/security/test/https-first/browser_mixed_content_console.js b/dom/security/test/https-first/browser_mixed_content_console.js new file mode 100644 index 0000000000..0b93850ff7 --- /dev/null +++ b/dom/security/test/https-first/browser_mixed_content_console.js @@ -0,0 +1,104 @@ +// Bug 1713593: HTTPS-First: Add test for mixed content blocker. +"use strict"; + +const testPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "http://example.com" +); + +const UPGRADE_DISPLAY_CONTENT = + "security.mixed_content.upgrade_display_content"; + +let threeMessagesArrived = 0; +let messageImageSeen = false; + +const kTestURI = testPath + "file_mixed_content_console.html"; + +add_task(async function () { + // A longer timeout is necessary for this test than the plain mochitests + // due to opening a new tab with the web console. + requestLongerTimeout(4); + + // Enable HTTPS-First Mode and register console-listener + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + Services.console.registerListener(on_console_message); + BrowserTestUtils.loadURIString(gBrowser.selectedBrowser, kTestURI); + + await BrowserTestUtils.waitForCondition(() => threeMessagesArrived === 3); + + Services.console.unregisterListener(on_console_message); +}); + +function on_console_message(msgObj) { + const message = msgObj.message; + + // The first console message is: + // "HTTPS-First Mode: Upgrading insecure request + // ‘http://example.com/browser/dom/security/test/https-first/file_mixed_content_console.html’ to use ‘https’" + if (message.includes("HTTPS-First Mode: Upgrading insecure request")) { + ok(message.includes("Upgrading insecure request"), "request got upgraded"); + ok( + message.includes( + "“http://example.com/browser/dom/security/test/https-first/file_mixed_content_console.html” to use “https”." + ), + "correct top-level request" + ); + threeMessagesArrived++; + } + // If security.mixed_content.upgrade_display_content is enabled: + // The second console message is about upgrading the insecure image + else if ( + Services.prefs.getBoolPref(UPGRADE_DISPLAY_CONTENT) && + message.includes("Mixed Content: Upgrading") + ) { + ok( + message.includes("insecure display request"), + "display content got load" + ); + ok( + message.includes( + "‘http://example.com/browser/dom/security/test/https-first/auto_upgrading_identity.png’ to use ‘https’" + ), + "img loaded secure" + ); + threeMessagesArrived++; + messageImageSeen = true; + } + // Else: + // The second console message is about blocking the image: + // Message: "Loading mixed (insecure) display content + // “http://example.com/browser/dom/security/test/https-first/auto_upgrading_identity.png” on a secure page". + // Since the message is send twice, prevent reading the image message two times + else if (message.includes("Loading mixed") && !messageImageSeen) { + ok( + message.includes("Loading mixed (insecure) display content"), + "display content got load" + ); + ok( + message.includes( + "“http://example.com/browser/dom/security/test/https-first/auto_upgrading_identity.png” on a secure page" + ), + "img loaded insecure" + ); + threeMessagesArrived++; + messageImageSeen = true; + } + // The third message is: + // "Blocked loading mixed active content + // "http://example.com/browser/dom/security/test/https-first/barfoo"" + else if (message.includes("Blocked loading")) { + ok( + message.includes("Blocked loading mixed active content"), + "script got blocked" + ); + ok( + message.includes( + "http://example.com/browser/dom/security/test/https-first/barfoo" + ), + "the right script got blocked" + ); + threeMessagesArrived++; + } +} diff --git a/dom/security/test/https-first/browser_mixed_content_download.js b/dom/security/test/https-first/browser_mixed_content_download.js new file mode 100644 index 0000000000..09ea64cea8 --- /dev/null +++ b/dom/security/test/https-first/browser_mixed_content_download.js @@ -0,0 +1,156 @@ +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); + +let SECURE_BASE_URL = + getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "https://example.com/" + ) + "download_page.html"; + +/** + * Waits until a download is triggered. + * It waits until a prompt is shown, + * saves and then accepts the dialog. + * @returns {Promise} Resolved once done. + */ + +function shouldTriggerDownload() { + 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("save"); + actionRadio.click(); + button.disabled = false; + dialog.acceptDialog(); + resolve(); + } else { + reject(); + } + }, win); + }, + }); + }); +} + +const CONSOLE_UPGRADE_MESSAGE = "Upgrading insecure request"; +const CONSOLE_DOWNGRADE_MESSAGE = "Downgrading to “http” again."; +const DOWNLOAD_URL = + "example.com/browser/dom/security/test/https-first/download_server.sjs"; +// Verifies that https-first tries to upgrade download, +// falls back since download is not available via https +let msgCounter = 0; +function shouldConsoleError() { + return new Promise((resolve, reject) => { + function listener(msgObj) { + let text = msgObj.message; + if (text.includes(CONSOLE_UPGRADE_MESSAGE) && msgCounter == 0) { + ok( + text.includes("http://" + DOWNLOAD_URL), + "Https-first tries to upgrade download to https" + ); + msgCounter++; + } + if (text.includes(CONSOLE_DOWNGRADE_MESSAGE) && msgCounter == 1) { + ok( + text.includes("https://" + DOWNLOAD_URL), + "Https-first downgrades download to http." + ); + resolve(); + Services.console.unregisterListener(listener); + } + } + 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); + } + } +} + +async function runTest(url, link, checkFunction, description) { + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_first", true], + ["browser.download.always_ask_before_handling_new_types", true], + ], + }); + requestLongerTimeout(2); + await resetDownloads(); + + let tab = BrowserTestUtils.addTab(gBrowser, url); + gBrowser.selectedTab = tab; + + let browser = gBrowser.getBrowserForTab(tab); + await BrowserTestUtils.browserLoaded(browser); + is( + gBrowser.currentURI.schemeIs("https"), + true, + "Scheme of opened tab should be https" + ); + 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); +} + +//Test description: +// 1. Open "https://example.com" +// 2. From "https://example.com" download something, but that download is only available via http. +// 3. Https-first tries to upgrade the download. +// 4. Upgrading fails - so http-first downgrade download to http. + +add_task(async function test_mixed_download() { + await runTest( + SECURE_BASE_URL, + "insecure", + () => Promise.all([shouldTriggerDownload(), shouldConsoleError()]), + "Secure -> Insecure should Error" + ); + // remove downloaded file + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + let downloadList = await downloadsPromise; + let [download] = downloadList._downloads; + await downloadList.remove(download); +}); diff --git a/dom/security/test/https-first/browser_navigation.js b/dom/security/test/https-first/browser_navigation.js new file mode 100644 index 0000000000..b8e81f76bb --- /dev/null +++ b/dom/security/test/https-first/browser_navigation.js @@ -0,0 +1,97 @@ +"use strict"; + +const REQUEST_URL = + "http://httpsfirst.com/browser/dom/security/test/https-first/"; + +async function promiseGetHistoryIndex(browser) { + if (!SpecialPowers.Services.appinfo.sessionHistoryInParent) { + return SpecialPowers.spawn(browser, [], function () { + let shistory = + docShell.browsingContext.childSessionHistory.legacySHistory; + return shistory.index; + }); + } + + let shistory = browser.browsingContext.sessionHistory; + return shistory.index; +} + +async function testNavigations() { + // Load initial site + + let url1 = REQUEST_URL + "file_navigation.html?foo1"; + let url2 = REQUEST_URL + "file_navigation.html?foo2"; + let url3 = REQUEST_URL + "file_navigation.html?foo3"; + + let loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + BrowserTestUtils.loadURIString(gBrowser, url1); + await loaded; + + // Load another site + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [url2], + async url => (content.location.href = url) + ); + await loaded; + + // Load another site + loaded = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); + await SpecialPowers.spawn( + gBrowser.selectedBrowser, + [url3], + async url => (content.location.href = url) + ); + await loaded; + is( + await promiseGetHistoryIndex(gBrowser.selectedBrowser), + 2, + "correct session history index after load 3" + ); + + // Go back one site by clicking the back button + info("Clicking back button"); + loaded = BrowserTestUtils.waitForLocationChange(gBrowser, url2); + let backButton = document.getElementById("back-button"); + backButton.click(); + await loaded; + is( + await promiseGetHistoryIndex(gBrowser.selectedBrowser), + 1, + "correct session history index after going back for the first time" + ); + + // Go back again + info("Clicking back button again"); + loaded = BrowserTestUtils.waitForLocationChange(gBrowser, url1); + backButton.click(); + await loaded; + is( + await promiseGetHistoryIndex(gBrowser.selectedBrowser), + 0, + "correct session history index after going back for the second time" + ); +} + +add_task(async function () { + waitForExplicitFinish(); + + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + + await testNavigations(); + + // If fission is enabled we also want to test the navigations with the bfcache + // in the parent. + if (SpecialPowers.getBoolPref("fission.autostart")) { + await SpecialPowers.pushPrefEnv({ + set: [["fission.bfcacheInParent", true]], + }); + + await testNavigations(); + } + + finish(); +}); diff --git a/dom/security/test/https-first/browser_slow_download.js b/dom/security/test/https-first/browser_slow_download.js new file mode 100644 index 0000000000..82d7a99b07 --- /dev/null +++ b/dom/security/test/https-first/browser_slow_download.js @@ -0,0 +1,158 @@ +"use strict"; + +XPCOMUtils.defineLazyModuleGetters(this, { + BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm", +}); +// Create a uri for an https site +const testPath = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); +const TEST_URI = testPath + "file_slow_download.html"; +const EXPECTED_DOWNLOAD_URL = + "example.com/browser/dom/security/test/https-first/file_slow_download.sjs"; + +// Since the server send the complete download file after 3 seconds we need an longer timeout +requestLongerTimeout(4); + +function promisePanelOpened() { + if (DownloadsPanel.panel && DownloadsPanel.panel.state == "open") { + return Promise.resolve(); + } + return BrowserTestUtils.waitForEvent(DownloadsPanel.panel, "popupshown"); +} + +/** + * Waits for a download to finish, in case it has not finished already. + * + * @param aDownload + * The Download object to wait upon. + * + * @return {Promise} + * @resolves When the download has finished successfully. + * @rejects JavaScript exception if the download failed. + */ +function promiseDownloadStopped(aDownload) { + if (!aDownload.stopped) { + // The download is in progress, wait for the current attempt to finish and + // report any errors that may occur. + return aDownload.start(); + } + + if (aDownload.succeeded) { + return Promise.resolve(); + } + + // The download failed or was canceled. + return Promise.reject(aDownload.error || new Error("Download canceled.")); +} + +// Verifys that no background request was send +let requestCounter = 0; +function examiner() { + SpecialPowers.addObserver(this, "specialpowers-http-notify-request"); +} + +examiner.prototype = { + observe(subject, topic, data) { + if (topic !== "specialpowers-http-notify-request") { + return; + } + // On Android we have other requests appear here as well. Let's make + // sure we only evaluate requests triggered by the test. + if ( + !data.startsWith("http://example.com") && + !data.startsWith("https://example.com") + ) { + return; + } + ++requestCounter; + if (requestCounter == 1) { + is(data, TEST_URI, "Download start page is https"); + return; + } + if (requestCounter == 2) { + // The specialpowers-http-notify-request fires before the internal redirect( /upgrade) to + // https happens. + is( + data, + "http://" + EXPECTED_DOWNLOAD_URL, + "First download request is http (internal)" + ); + return; + } + if (requestCounter == 3) { + is( + data, + "https://" + EXPECTED_DOWNLOAD_URL, + "Download got upgraded to https" + ); + return; + } + ok(false, "we should never get here, but just in case"); + }, + remove() { + SpecialPowers.removeObserver(this, "specialpowers-http-notify-request"); + }, +}; + +// Test description: +// 1. Open https://example.com +// 2. Start download - location of download is http +// 3. https-first upgrades to https +// 4. Server send first part of download and after 3 seconds the rest +// 5. Complete download of text file +add_task(async function test_slow_download() { + await SpecialPowers.pushPrefEnv({ + set: [["dom.security.https_first", true]], + }); + + // remove all previous downloads + let downloadsList = await Downloads.getList(Downloads.PUBLIC); + await downloadsList.removeFinished(); + + // add observer to ensure that the background request gets canceled for the upgraded Download + this.examiner = new examiner(); + + let downloadsPanelPromise = promisePanelOpened(); + let downloadsPromise = Downloads.getList(Downloads.PUBLIC); + BrowserTestUtils.loadURIString(gBrowser, TEST_URI); + // wait for downloadsPanel to open before continuing with test + await downloadsPanelPromise; + let downloadList = await downloadsPromise; + is(DownloadsPanel.isPanelShowing, true, "DownloadsPanel should be open."); + is(downloadList._downloads.length, 1, "File should be downloaded."); + let [download] = downloadList._downloads; + // wait for download to finish (with success or error) + await promiseDownloadStopped(download); + is(download.contentType, "text/plain", "File contentType should be correct."); + // ensure https-first did upgrade the scheme. + is( + download.source.url, + "https://" + EXPECTED_DOWNLOAD_URL, + "Scheme should be https." + ); + // ensure that no background request was send + is( + requestCounter, + 3, + "three requests total (download page, download http, download https/ upgraded)" + ); + // ensure that downloaded is complete + is(download.target.size, 25, "Download size is correct"); + //clean up + this.examiner.remove(); + info("cleaning up downloads"); + try { + if (Services.appinfo.OS === "WINNT") { + // We need to make the file writable to delete it on Windows. + await IOUtils.setPermissions(download.target.path, 0o600); + } + await IOUtils.remove(download.target.path); + } catch (error) { + info("The file " + download.target.path + " is not removed, " + error); + } + + await downloadList.remove(download); + await download.finalize(); +}); diff --git a/dom/security/test/https-first/browser_upgrade_onion.js b/dom/security/test/https-first/browser_upgrade_onion.js new file mode 100644 index 0000000000..a6a6a85412 --- /dev/null +++ b/dom/security/test/https-first/browser_upgrade_onion.js @@ -0,0 +1,60 @@ +// This test ensures that various configurable upgrade exceptions work +"use strict"; + +async function runTest(desc, url, expectedURI) { + await BrowserTestUtils.withNewTab("about:blank", async function (browser) { + let loaded = BrowserTestUtils.browserLoaded(browser, false, null, true); + BrowserTestUtils.loadURIString(browser, url); + await loaded; + + await SpecialPowers.spawn( + browser, + [desc, expectedURI], + async function (desc, expectedURI) { + // XXX ckerschb: generally we use the documentURI, but our test infra + // can not handle .onion, hence we use the URI of the failed channel + // stored on the docshell to see if the scheme was upgraded to https. + let loadedURI = content.document.documentURI; + if (loadedURI.startsWith("about:neterror")) { + loadedURI = content.docShell.failedChannel.URI.spec; + } + is(loadedURI, expectedURI, desc); + } + ); + }); +} + +// by default local addresses and .onion should *not* get upgraded +add_task(async function () { + requestLongerTimeout(2); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_first", true], + ["dom.security.https_only_mode", false], + ["dom.security.https_only_mode.upgrade_local", false], + ["dom.security.https_only_mode.upgrade_onion", false], + ], + }); + + await runTest( + "Hosts ending with .onion should be be exempt from HTTPS-First upgrades by default", + "http://grocery.shopping.for.one.onion/", + "http://grocery.shopping.for.one.onion/" + ); + + await SpecialPowers.pushPrefEnv({ + set: [ + ["dom.security.https_first", true], + ["dom.security.https_only_mode", false], + ["dom.security.https_only_mode.upgrade_local", false], + ["dom.security.https_only_mode.upgrade_onion", true], + ], + }); + + await runTest( + "Hosts ending with .onion should get upgraded when 'dom.security.https_only_mode.upgrade_onion' is set to true", + "http://grocery.shopping.for.one.onion/", + "https://grocery.shopping.for.one.onion/" + ); +}); diff --git a/dom/security/test/https-first/download_page.html b/dom/security/test/https-first/download_page.html new file mode 100644 index 0000000000..a828ee07db --- /dev/null +++ b/dom/security/test/https-first/download_page.html @@ -0,0 +1,22 @@ + + + + Test mixed content download by https-first + + + hi + + + + diff --git a/dom/security/test/https-first/download_server.sjs b/dom/security/test/https-first/download_server.sjs new file mode 100644 index 0000000000..7af5722e7b --- /dev/null +++ b/dom/security/test/https-first/download_server.sjs @@ -0,0 +1,16 @@ +function handleRequest(request, response) { + // Only answer to http, in case request is in https let the reply time out. + if (request.scheme === "https") { + response.processAsync(); + return; + } + + response.setHeader("Cache-Control", "no-cache", false); + // Send some file, e.g. an image + response.setHeader( + "Content-Disposition", + "attachment; filename=some-file.png" + ); + response.setHeader("Content-Type", "image/png"); + response.write("Success!"); +} diff --git a/dom/security/test/https-first/file_bad_cert.sjs b/dom/security/test/https-first/file_bad_cert.sjs new file mode 100644 index 0000000000..1a8ae08a86 --- /dev/null +++ b/dom/security/test/https-first/file_bad_cert.sjs @@ -0,0 +1,34 @@ +const RESPONSE_SUCCESS = ` + + + send message, downgraded + + + `; + +const RESPONSE_UNEXPECTED = ` + + + send message, error + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + // if the received request is not http send an error + if (request.scheme === "http") { + response.write(RESPONSE_SUCCESS); + return; + } + // we should never get here; just in case, return something unexpected + response.write(RESPONSE_UNEXPECTED); +} diff --git a/dom/security/test/https-first/file_beforeunload_permit_http.html b/dom/security/test/https-first/file_beforeunload_permit_http.html new file mode 100644 index 0000000000..50459d6006 --- /dev/null +++ b/dom/security/test/https-first/file_beforeunload_permit_http.html @@ -0,0 +1,9 @@ + + + + + diff --git a/dom/security/test/https-first/file_break_endless_upgrade_downgrade_loop.sjs b/dom/security/test/https-first/file_break_endless_upgrade_downgrade_loop.sjs new file mode 100644 index 0000000000..eb64c59e97 --- /dev/null +++ b/dom/security/test/https-first/file_break_endless_upgrade_downgrade_loop.sjs @@ -0,0 +1,61 @@ +"use strict"; + +const REDIRECT_URI = + "http://example.com/tests/dom/security/test/https-first/file_break_endless_upgrade_downgrade_loop.sjs?verify"; +const DOWNGRADE_URI = + "http://example.com/tests/dom/security/test/https-first/file_downgrade_with_different_path.sjs"; +const RESPONSE_ERROR = "unexpected-query"; + +// An onload postmessage to window opener +const RESPONSE_HTTPS_SCHEME = ` + + + + + `; + +const RESPONSE_HTTP_SCHEME = ` + + + + + `; + +function handleRequest(request, response) { + response.setHeader("Cache-Control", "no-cache", false); + const query = request.queryString; + + if (query == "downgrade") { + // send same-origin downgrade from https: to http: with a different path. + // we don't consider it's an endless upgrade downgrade loop in this case. + response.setStatusLine(request.httpVersion, 302, "Found"); + response.setHeader("Location", DOWNGRADE_URI, false); + return; + } + + // handle the redirect case + if ((query >= 301 && query <= 303) || query == 307) { + // send same-origin downgrade from https: to http: again simluating + // and endless upgrade downgrade loop. + response.setStatusLine(request.httpVersion, query, "Found"); + response.setHeader("Location", REDIRECT_URI, false); + return; + } + + // Check if scheme is http:// or https:// + if (query == "verify") { + let response_content = + request.scheme === "https" ? RESPONSE_HTTPS_SCHEME : RESPONSE_HTTP_SCHEME; + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write(response_content); + return; + } + + // We should never get here, but just in case ... + response.setStatusLine(request.httpVersion, 500, "OK"); + response.write("unexepcted query"); +} diff --git a/dom/security/test/https-first/file_data_uri.html b/dom/security/test/https-first/file_data_uri.html new file mode 100644 index 0000000000..69133e5079 --- /dev/null +++ b/dom/security/test/https-first/file_data_uri.html @@ -0,0 +1,16 @@ + + + + + Bug 1709069: Test that Data URI which makes a top-level request gets updated in https-first + + + + + diff --git a/dom/security/test/https-first/file_downgrade_500_responses.sjs b/dom/security/test/https-first/file_downgrade_500_responses.sjs new file mode 100644 index 0000000000..b3cfbd79dd --- /dev/null +++ b/dom/security/test/https-first/file_downgrade_500_responses.sjs @@ -0,0 +1,70 @@ +// Custom *.sjs file specifically for the needs of Bug 1709552 +"use strict"; + +const RESPONSE_SUCCESS = ` + + + send message, downgraded + + + `; + +const RESPONSE_UNEXPECTED = ` + + + send message, error + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviour + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + let query = request.queryString; + // if the scheme is not https and it is the initial request + // then we rather fall through and display unexpected content + if (request.scheme === "https") { + if (query === "test1a") { + response.setStatusLine("1.1", 501, "Not Implemented"); + response.write("Not Implemented\n"); + return; + } + + if (query === "test2a") { + response.setStatusLine("1.1", 504, "Gateway Timeout"); + response.write("Gateway Timeout\n"); + return; + } + + if (query === "test3a") { + response.setStatusLine("1.1", 521, "Web Server Is Down"); + response.write("Web Server Is Down\n"); + return; + } + if (query === "test4a") { + response.setStatusLine("1.1", 530, "Railgun Error"); + response.write("Railgun Error\n"); + return; + } + if (query === "test5a") { + response.setStatusLine("1.1", 560, "Unauthorized"); + response.write("Unauthorized\n"); + return; + } + + // We should never arrive here, just in case send something unexpected + response.write(RESPONSE_UNEXPECTED); + return; + } + + // We should arrive here when the redirection was downraded successful + response.write(RESPONSE_SUCCESS); +} diff --git a/dom/security/test/https-first/file_downgrade_bad_responses.sjs b/dom/security/test/https-first/file_downgrade_bad_responses.sjs new file mode 100644 index 0000000000..1a6eea2dd1 --- /dev/null +++ b/dom/security/test/https-first/file_downgrade_bad_responses.sjs @@ -0,0 +1,73 @@ +// Custom *.sjs file specifically for the needs of Bug 1709552 +"use strict"; + +const RESPONSE_SUCCESS = ` + + + send message, downgraded + + + `; + +const RESPONSE_UNEXPECTED = ` + + + send message, error + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviour + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + let query = request.queryString; + // if the scheme is not https and it is the initial request + // then we rather fall through and display unexpected content + if (request.scheme === "https") { + if (query === "test1a") { + response.setStatusLine("1.1", 400, "Bad Request"); + response.write("Bad Request\n"); + return; + } + + if (query === "test2a") { + response.setStatusLine("1.1", 403, "Forbidden"); + response.write("Forbidden\n"); + return; + } + + if (query === "test3a") { + response.setStatusLine("1.1", 404, "Not Found"); + response.write("Not Found\n"); + return; + } + if (query === "test4a") { + response.setStatusLine("1.1", 416, "Requested Range Not Satisfiable"); + response.write("Requested Range Not Satisfiable\n"); + return; + } + if (query === "test5a") { + response.setStatusLine("1.1", 418, "I'm a teapot"); + response.write("I'm a teapot\n"); + return; + } + if (query == "test6a") { + // Simulating a timeout by processing the https request + response.processAsync(); + return; + } + + // We should never arrive here, just in case send something unexpected + response.write(RESPONSE_UNEXPECTED); + return; + } + + // We should arrive here when the redirection was downraded successful + response.write(RESPONSE_SUCCESS); +} diff --git a/dom/security/test/https-first/file_downgrade_request_upgrade_request.sjs b/dom/security/test/https-first/file_downgrade_request_upgrade_request.sjs new file mode 100644 index 0000000000..6004d57eaf --- /dev/null +++ b/dom/security/test/https-first/file_downgrade_request_upgrade_request.sjs @@ -0,0 +1,52 @@ +// Custom *.sjs file specifically for the needs of Bug 1706126 +"use strict"; +// subdomain of example.com +const REDIRECT_302 = + "http://www.redirect-example.com/tests/dom/security/test/https-first/file_downgrade_request_upgrade_request.sjs"; + +const RESPONSE_SUCCESS = ` + + + send message, upgraded + + + `; + +const RESPONSE_UNEXPECTED = ` + + + send message, error + + + `; + +function handleRequest(request, response) { + // avoid confusing cache behaviour + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + // if the scheme is https and it is the initial request time it out + if (request.scheme === "https" && request.host === "redirect-example.com") { + // Simulating a timeout by processing the https request + response.processAsync(); + return; + } + if (request.scheme === "http" && request.host === "redirect-example.com") { + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", REDIRECT_302, false); + return; + } + // if the request was sent to subdomain + if (request.host.startsWith("www.")) { + response.write(RESPONSE_SUCCESS); + return; + } + // We should never arrive here, just in case send 'error' + response.write(RESPONSE_UNEXPECTED); +} diff --git a/dom/security/test/https-first/file_downgrade_view_source.sjs b/dom/security/test/https-first/file_downgrade_view_source.sjs new file mode 100644 index 0000000000..c57dd0deb8 --- /dev/null +++ b/dom/security/test/https-first/file_downgrade_view_source.sjs @@ -0,0 +1,30 @@ +"use strict"; + +function handleRequest(request, response) { + // avoid confusing cache behaviour + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + let query = request.queryString.split("&"); + let scheme = request.scheme; + + if (scheme === "https") { + if (query.includes("downgrade")) { + response.setStatusLine("1.1", 400, "Bad Request"); + response.write("Bad Request\n"); + return; + } + if (query.includes("upgrade")) { + response.write("view-source:https://"); + return; + } + } + + if (scheme === "http" && query.includes("downgrade")) { + response.write("view-source:http://"); + return; + } + + // We should arrive here when the redirection was downraded successful + response.write("unexpected scheme and query given"); +} diff --git a/dom/security/test/https-first/file_downgrade_with_different_path.sjs b/dom/security/test/https-first/file_downgrade_with_different_path.sjs new file mode 100644 index 0000000000..7450313d98 --- /dev/null +++ b/dom/security/test/https-first/file_downgrade_with_different_path.sjs @@ -0,0 +1,27 @@ +"use strict"; + +// An onload postmessage to window opener +const RESPONSE_HTTPS_SCHEME = ` + + + + + `; + +const RESPONSE_HTTP_SCHEME = ` + + + + + `; + +function handleRequest(request, response) { + let response_content = + request.scheme === "https" ? RESPONSE_HTTPS_SCHEME : RESPONSE_HTTP_SCHEME; + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write(response_content); +} diff --git a/dom/security/test/https-first/file_download_attribute.html b/dom/security/test/https-first/file_download_attribute.html new file mode 100644 index 0000000000..453bf408b3 --- /dev/null +++ b/dom/security/test/https-first/file_download_attribute.html @@ -0,0 +1,14 @@ + + + + Test download attribute for http site + + + download by attribute + + + diff --git a/dom/security/test/https-first/file_download_attribute.sjs b/dom/security/test/https-first/file_download_attribute.sjs new file mode 100644 index 0000000000..8941da1a41 --- /dev/null +++ b/dom/security/test/https-first/file_download_attribute.sjs @@ -0,0 +1,12 @@ +function handleRequest(request, response) { + // Only answer to http, in case request is in https let the reply time out. + if (request.scheme === "https") { + response.processAsync(); + return; + } + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Disposition", "attachment; filename=some.html"); + response.setHeader("Content-Type", "text/html"); + response.write("success!"); +} diff --git a/dom/security/test/https-first/file_form_submission.sjs b/dom/security/test/https-first/file_form_submission.sjs new file mode 100644 index 0000000000..63b248d773 --- /dev/null +++ b/dom/security/test/https-first/file_form_submission.sjs @@ -0,0 +1,84 @@ +const CC = Components.Constructor; +const BinaryInputStream = CC( + "@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream" +); + +const RESPONSE_SUCCESS = ` + + + send message, downgraded + + + `; + +const POST_FORMULAR = ` + + +
+
+ + +
+
+ + + +`; + +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + let queryString = request.queryString; + if (request.scheme === "https" && queryString === "test=1") { + response.write(RESPONSE_SUCCESS); + return; + } + if ( + request.scheme === "https" && + (queryString === "test=2" || queryString === "test=4") + ) { + // time out request + response.processAsync(); + return; + } + if (request.scheme === "http" && queryString === "test=2") { + response.write(RESPONSE_SUCCESS); + return; + } + if (queryString === "test=3" || queryString === "test=4") { + // send post form + response.write(POST_FORMULAR); + return; + } + if (request.method == "POST") { + // extract form parameters + let body = new BinaryInputStream(request.bodyInputStream); + let avail; + let bytes = []; + while ((avail = body.available()) > 0) { + Array.prototype.push.apply(bytes, body.readByteArray(avail)); + } + let requestBodyContents = String.fromCharCode.apply(null, bytes); + + response.write(` + + + `); + + return; + } + // we should never get here; just in case, return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/https-first/file_fragment.html b/dom/security/test/https-first/file_fragment.html new file mode 100644 index 0000000000..5846d6d977 --- /dev/null +++ b/dom/security/test/https-first/file_fragment.html @@ -0,0 +1,43 @@ + + + + + Click me +
space
+ foo +
space
+ + diff --git a/dom/security/test/https-first/file_httpsfirst_speculative_connect.html b/dom/security/test/https-first/file_httpsfirst_speculative_connect.html new file mode 100644 index 0000000000..6542884191 --- /dev/null +++ b/dom/security/test/https-first/file_httpsfirst_speculative_connect.html @@ -0,0 +1 @@ +dummy file for speculative https-first upgrade test diff --git a/dom/security/test/https-first/file_httpsfirst_timeout_server.sjs b/dom/security/test/https-first/file_httpsfirst_timeout_server.sjs new file mode 100644 index 0000000000..81c4c0328b --- /dev/null +++ b/dom/security/test/https-first/file_httpsfirst_timeout_server.sjs @@ -0,0 +1,13 @@ +function handleRequest(request, response) { + // avoid confusing cache behaviors + response.setHeader("Cache-Control", "no-cache", false); + + if (request.scheme === "https") { + // Simulating a timeout by processing the https request + // async and *never* return anything! + response.processAsync(); + return; + } + // we should never get here; just in case, return something unexpected + response.write("do'h"); +} diff --git a/dom/security/test/https-first/file_mixed_content_auto_upgrade.html b/dom/security/test/https-first/file_mixed_content_auto_upgrade.html new file mode 100644 index 0000000000..7dda8909a5 --- /dev/null +++ b/dom/security/test/https-first/file_mixed_content_auto_upgrade.html @@ -0,0 +1,12 @@ + + + + Bug 1673574 - Improve Console logging for mixed content auto upgrading + + + + +