mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-29 13:46:31 +00:00
LibWeb: Parse and propagate the iframe sandbox attribute
This commit is contained in:
parent
a5e2fd2e12
commit
40bb50ac60
Notes:
github-actions[bot]
2025-08-07 17:26:35 +00:00
Author: https://github.com/Lubrsi
Commit: 40bb50ac60
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5765
51 changed files with 1155 additions and 12 deletions
|
@ -555,6 +555,7 @@ set(SOURCES
|
|||
HTML/PromiseRejectionEvent.cpp
|
||||
HTML/RadioNodeList.cpp
|
||||
HTML/RenderingThread.cpp
|
||||
HTML/SandboxingFlagSet.cpp
|
||||
HTML/Scripting/Agent.cpp
|
||||
HTML/Scripting/ClassicScript.cpp
|
||||
HTML/Scripting/Environments.cpp
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/HTML/BrowsingContext.h>
|
||||
#include <LibWeb/HTML/BrowsingContextGroup.h>
|
||||
#include <LibWeb/HTML/HTMLDocument.h>
|
||||
#include <LibWeb/HTML/HTMLIFrameElement.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/HTML/SandboxingFlagSet.h>
|
||||
#include <LibWeb/HTML/Scripting/WindowEnvironmentSettingsObject.h>
|
||||
|
@ -487,11 +488,28 @@ bool BrowsingContext::is_familiar_with(BrowsingContext const& other) const
|
|||
return false;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsing-the-web.html#snapshotting-target-snapshot-params
|
||||
SandboxingFlagSet determine_the_creation_sandboxing_flags(BrowsingContext const&, GC::Ptr<DOM::Element>)
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#determining-the-creation-sandboxing-flags
|
||||
SandboxingFlagSet determine_the_creation_sandboxing_flags(BrowsingContext const& browsing_context, GC::Ptr<DOM::Element> embedder)
|
||||
{
|
||||
// FIXME: Populate this once we have the proper flag sets on BrowsingContext
|
||||
return {};
|
||||
// To determine the creation sandboxing flags for a browsing context browsing context, given null or an element
|
||||
// embedder, return the union of the flags that are present in the following sandboxing flag sets:
|
||||
SandboxingFlagSet sandboxing_flags {};
|
||||
|
||||
// - If embedder is null, then: the flags set on browsing context's popup sandboxing flag set.
|
||||
if (!embedder) {
|
||||
sandboxing_flags |= browsing_context.popup_sandboxing_flag_set();
|
||||
} else {
|
||||
// - If embedder is an element, then: the flags set on embedder's iframe sandboxing flag set.
|
||||
if (is<HTMLIFrameElement>(embedder.ptr())) {
|
||||
auto const& iframe_element = static_cast<HTMLIFrameElement const&>(*embedder);
|
||||
sandboxing_flags |= iframe_element.iframe_sandboxing_flag_set();
|
||||
}
|
||||
|
||||
// - If embedder is an element, then: the flags set on embedder's node document's active sandboxing flag set.
|
||||
sandboxing_flags |= embedder->document().active_sandboxing_flag_set();
|
||||
}
|
||||
|
||||
return sandboxing_flags;
|
||||
}
|
||||
|
||||
bool BrowsingContext::has_navigable_been_destroyed() const
|
||||
|
|
|
@ -53,6 +53,11 @@ void HTMLIFrameElement::attribute_changed(FlyString const& name, Optional<String
|
|||
{
|
||||
Base::attribute_changed(name, old_value, value, namespace_);
|
||||
|
||||
if (name == HTML::AttributeNames::sandbox) {
|
||||
if (m_sandbox)
|
||||
m_sandbox->associated_attribute_changed(value.value_or(String {}));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:process-the-iframe-attributes-2
|
||||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:process-the-iframe-attributes-3
|
||||
// Whenever an iframe element with a non-null content navigable has its srcdoc attribute set, changed, or removed,
|
||||
|
@ -62,6 +67,21 @@ void HTMLIFrameElement::attribute_changed(FlyString const& name, Optional<String
|
|||
if (m_content_navigable) {
|
||||
if (name == AttributeNames::srcdoc || (name == AttributeNames::src && !has_attribute(AttributeNames::srcdoc)))
|
||||
process_the_iframe_attributes();
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:iframe-sandboxing-flag-set-2
|
||||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#the-iframe-element:iframe-sandboxing-flag-set-3
|
||||
// When an iframe element's sandbox attribute is set or changed while it has a non-null content navigable, the
|
||||
// user agent must parse the sandboxing directive given the attribute's value and the iframe element's iframe
|
||||
// sandboxing flag set.
|
||||
// When an iframe element's sandbox attribute is removed while it has a non-null content navigable, the user
|
||||
// agent must empty the iframe element's iframe sandboxing flag set.
|
||||
if (name == AttributeNames::sandbox) {
|
||||
if (value.has_value()) {
|
||||
m_iframe_sandboxing_flag_set = parse_a_sandboxing_directive(value.value());
|
||||
} else {
|
||||
m_iframe_sandboxing_flag_set = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (name == HTML::AttributeNames::width || name == HTML::AttributeNames::height) {
|
||||
|
@ -89,8 +109,13 @@ void HTMLIFrameElement::post_connection()
|
|||
// The iframe HTML element post-connection steps, given insertedNode, are:
|
||||
// 1. Create a new child navigable for insertedNode.
|
||||
MUST(create_new_child_navigable(GC::create_function(realm().heap(), [this] {
|
||||
// FIXME: 2. If insertedNode has a sandbox attribute, then parse the sandboxing directive given the attribute's
|
||||
// value and insertedNode's iframe sandboxing flag set.
|
||||
// 2. If insertedNode has a sandbox attribute, then parse the sandboxing directive given the attribute's
|
||||
// value and insertedNode's iframe sandboxing flag set.
|
||||
if (has_attribute(AttributeNames::sandbox)) {
|
||||
auto sandbox_attribute = attribute(AttributeNames::sandbox);
|
||||
VERIFY(sandbox_attribute.has_value());
|
||||
m_iframe_sandboxing_flag_set = parse_a_sandboxing_directive(sandbox_attribute.value());
|
||||
}
|
||||
|
||||
// 3. Process the iframe attributes for insertedNode, with initialInsertion set to true.
|
||||
process_the_iframe_attributes(InitialInsertion::Yes);
|
||||
|
|
|
@ -33,6 +33,8 @@ public:
|
|||
|
||||
GC::Ref<DOM::DOMTokenList> sandbox();
|
||||
|
||||
SandboxingFlagSet iframe_sandboxing_flag_set() const { return m_iframe_sandboxing_flag_set; }
|
||||
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
private:
|
||||
|
@ -64,6 +66,9 @@ private:
|
|||
Optional<HighResolutionTime::DOMHighResTimeStamp> m_pending_resource_start_time = {};
|
||||
|
||||
GC::Ptr<DOM::DOMTokenList> m_sandbox;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#iframe-sandboxing-flag-set
|
||||
SandboxingFlagSet m_iframe_sandboxing_flag_set {};
|
||||
};
|
||||
|
||||
void run_iframe_load_event_steps(HTML::HTMLIFrameElement&);
|
||||
|
|
107
Libraries/LibWeb/HTML/SandboxingFlagSet.cpp
Normal file
107
Libraries/LibWeb/HTML/SandboxingFlagSet.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Luke Wilde <luke@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/HTML/SandboxingFlagSet.h>
|
||||
#include <LibWeb/Infra/CharacterTypes.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/browsers.html#parse-a-sandboxing-directive
|
||||
SandboxingFlagSet parse_a_sandboxing_directive(String const& input)
|
||||
{
|
||||
// 1. Split input on ASCII whitespace, to obtain tokens.
|
||||
auto lowercase_input = input.to_ascii_lowercase();
|
||||
auto tokens = lowercase_input.bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
|
||||
|
||||
// 2. Let output be empty.
|
||||
SandboxingFlagSet output {};
|
||||
|
||||
// 3. Add the following flags to output:
|
||||
// - The sandboxed navigation browsing context flag.
|
||||
output |= SandboxingFlagSet::SandboxedNavigation;
|
||||
|
||||
// - The sandboxed auxiliary navigation browsing context flag, unless tokens contains the allow-popups keyword.
|
||||
if (!tokens.contains_slow("allow-popups"sv))
|
||||
output |= SandboxingFlagSet::SandboxedAuxiliaryNavigation;
|
||||
|
||||
// - The sandboxed top-level navigation without user activation browsing context flag, unless tokens contains the
|
||||
// allow-top-navigation keyword.
|
||||
if (!tokens.contains_slow("allow-top-navigation"sv))
|
||||
output |= SandboxingFlagSet::SandboxedTopLevelNavigationWithoutUserActivation;
|
||||
|
||||
// - The sandboxed top-level navigation with user activation browsing context flag, unless tokens contains either
|
||||
// the allow-top-navigation-by-user-activation keyword or the allow-top-navigation keyword.
|
||||
// Spec Note: This means that if the allow-top-navigation is present, the allow-top-navigation-by-user-activation
|
||||
// keyword will have no effect. For this reason, specifying both is a document conformance error.
|
||||
if (!tokens.contains_slow("allow-top-navigation"sv) && !tokens.contains_slow("allow-top-navigation-by-user-activation"sv))
|
||||
output |= SandboxingFlagSet::SandboxedTopLevelNavigationWithUserActivation;
|
||||
|
||||
// - The sandboxed origin browsing context flag, unless the tokens contains the allow-same-origin keyword.
|
||||
// Spec Note: The allow-same-origin keyword is intended for two cases.
|
||||
//
|
||||
// First, it can be used to allow content from the same site to be sandboxed to disable scripting,
|
||||
// while still allowing access to the DOM of the sandboxed content.
|
||||
//
|
||||
// Second, it can be used to embed content from a third-party site, sandboxed to prevent that site from
|
||||
// opening popups, etc, without preventing the embedded page from communicating back to its originating
|
||||
// site, using the database APIs to store data, etc.
|
||||
if (!tokens.contains_slow("allow-same-origin"sv))
|
||||
output |= SandboxingFlagSet::SandboxedOrigin;
|
||||
|
||||
// - The sandboxed forms browsing context flag, unless tokens contains the allow-forms keyword.
|
||||
if (!tokens.contains_slow("allow-forms"sv))
|
||||
output |= SandboxingFlagSet::SandboxedForms;
|
||||
|
||||
// - The sandboxed pointer lock browsing context flag, unless tokens contains the allow-pointer-lock keyword.
|
||||
if (!tokens.contains_slow("allow-pointer-lock"sv))
|
||||
output |= SandboxingFlagSet::SandboxedPointerLock;
|
||||
|
||||
// - The sandboxed scripts browsing context flag, unless tokens contains the allow-scripts keyword.
|
||||
// - The sandboxed automatic features browsing context flag, unless tokens contains the allow-scripts keyword
|
||||
// (defined above).
|
||||
// Spec Note: This flag is relaxed by the same keyword as scripts, because when scripts are enabled these features
|
||||
// are trivially possible anyway, and it would be unfortunate to force authors to use script to do them
|
||||
// when sandboxed rather than allowing them to use the declarative features.
|
||||
if (!tokens.contains_slow("allow-scripts"sv)) {
|
||||
output |= SandboxingFlagSet::SandboxedScripts;
|
||||
output |= SandboxingFlagSet::SandboxedAutomaticFeatures;
|
||||
}
|
||||
|
||||
// - The sandboxed document.domain browsing context flag.
|
||||
output |= SandboxingFlagSet::SandboxedDocumentDomain;
|
||||
|
||||
// - The sandbox propagates to auxiliary browsing contexts flag, unless tokens contains the
|
||||
// allow-popups-to-escape-sandbox keyword.
|
||||
if (!tokens.contains_slow("allow-popups-to-escape-sandbox"sv))
|
||||
output |= SandboxingFlagSet::SandboxPropagatesToAuxiliaryBrowsingContexts;
|
||||
|
||||
// - The sandboxed modals flag, unless tokens contains the allow-modals keyword.
|
||||
if (!tokens.contains_slow("allow-modals"sv))
|
||||
output |= SandboxingFlagSet::SandboxedModals;
|
||||
|
||||
// - The sandboxed orientation lock browsing context flag, unless tokens contains the allow-orientation-lock
|
||||
// keyword.
|
||||
if (!tokens.contains_slow("allow-orientation-lock"sv))
|
||||
output |= SandboxingFlagSet::SandboxedOrientationLock;
|
||||
|
||||
// - The sandboxed presentation browsing context flag, unless tokens contains the allow-presentation keyword.
|
||||
if (!tokens.contains_slow("allow-presentation"sv))
|
||||
output |= SandboxingFlagSet::SandboxedPresentation;
|
||||
|
||||
// - The sandboxed downloads browsing context flag, unless tokens contains the allow-downloads keyword.
|
||||
if (!tokens.contains_slow("allow-downloads"sv))
|
||||
output |= SandboxingFlagSet::SandboxedDownloads;
|
||||
|
||||
// - The sandboxed custom protocols navigation browsing context flag, unless tokens contains either the
|
||||
// allow-top-navigation-to-custom-protocols keyword, the allow-popups keyword, or the allow-top-navigation
|
||||
// keyword.
|
||||
if (!tokens.contains_slow("allow-top-navigation-to-custom-protocols"sv) && !tokens.contains_slow("allow-popups"sv) && !tokens.contains_slow("allow-top-navigation"sv))
|
||||
output |= SandboxingFlagSet::SandboxedCustomProtocols;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/EnumBits.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
@ -35,4 +36,6 @@ enum class SandboxingFlagSet {
|
|||
AK_ENUM_BITWISE_OPERATORS(SandboxingFlagSet);
|
||||
inline bool is_empty(SandboxingFlagSet s) { return (to_underlying(s) & 0x1FFU) == 0; }
|
||||
|
||||
SandboxingFlagSet parse_a_sandboxing_directive(String const& input);
|
||||
|
||||
}
|
||||
|
|
|
@ -293,7 +293,9 @@ bool is_scripting_enabled(JS::Realm const& realm)
|
|||
if (!document.page().is_scripting_enabled())
|
||||
return false;
|
||||
|
||||
// FIXME: Either settings's global object is not a Window object, or settings's global object's associated Document's active sandboxing flag set does not have its sandboxed scripts browsing context flag set.
|
||||
// Either settings's global object is not a Window object, or settings's global object's associated Document's active sandboxing flag set does not have its sandboxed scripts browsing context flag set.
|
||||
if (has_flag(document.active_sandboxing_flag_set(), SandboxingFlagSet::SandboxedScripts))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>noscript parsing when sandbox disables scripting</title>
|
||||
<iframe srcdoc="PASS" sandbox></iframe>
|
||||
<iframe srcdoc="PASS" sandbox></iframe>
|
||||
<iframe srcdoc="P<b>AS</b>S" sandbox></iframe>
|
|
@ -0,0 +1,3 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<noscript>PASS</noscript>
|
|
@ -0,0 +1,7 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>noscript parsing when sandbox disables scripting</title>
|
||||
<link rel=match href=../../../../../expected/wpt-import//html/browsers/sandboxing/sandbox-parse-noscript-ref.html>
|
||||
<iframe srcdoc="<noscript>PASS</noscript>" sandbox></iframe>
|
||||
<iframe src="noscript-iframe.html" sandbox></iframe>
|
||||
<iframe srcdoc="<noscript>P<b>AS</b>S</noscript>" sandbox></iframe>
|
|
@ -320,3 +320,16 @@ Text/input/wpt-import/webaudio/the-audio-api/the-periodicwave-interface/periodic
|
|||
; https://github.com/LadybirdBrowser/ladybird/issues/5333
|
||||
Text/input/wpt-import/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect.html
|
||||
Text/input/wpt-import/webaudio/the-audio-api/the-audionode-interface/audionode-disconnect-audioparam.html
|
||||
|
||||
; Currently always timeout
|
||||
Text/input/wpt-import/html/browsers/sandboxing/inner-iframe.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-inherited-from-initiator-response.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-javascript-window-open.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-initial-empty-document-toward-same-origin.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-disallow-scripts-via-unsandboxed-popup.tentative.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-document-open.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-inherited-from-required-csp.html
|
||||
Text/input/wpt-import/html/browsers/sandboxing/sandbox-navigation-timing.tentative.html
|
||||
|
||||
; Not a ref test, but a subfile of the sandbox-parse-noscript ref test
|
||||
Ref/input/wpt-import/html/browsers/sandboxing/noscript-iframe.html
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail CORS with sandboxed iframe
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass DOM access in sandbox='allow-same-origin' iframe is allowed
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass Running script from sandbox='allow-scripts' iframe is allowed
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail window.open in sandbox iframe
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass Access to sandbox iframe is disallowed
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass Running script from sandbox iframe is disallowed
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail Using document.open() against a document from a different window must not mutate the other window's sandbox flags
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass Inherit sandbox flags from the initiator's frame
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: Timeout
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Timeout
|
||||
Timeout Inherit sandbox flags from the initiator's response
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: Timeout
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Timeout
|
||||
Timeout setting sandbox attribute should not affect current document in iframe
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass iframe with sandbox should load with new execution context
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail window.open('about:srcdoc') from sandboxed srcdoc doesn't crash.
|
|
@ -2,7 +2,6 @@ Harness status: OK
|
|||
|
||||
Found 2 tests
|
||||
|
||||
1 Pass
|
||||
1 Fail
|
||||
2 Pass
|
||||
Pass iframe 'sandbox' ASCII case insensitive, allow-same-orİgin
|
||||
Fail iframe 'sandbox' ASCII case insensitive, allow-ſcripts
|
||||
Pass iframe 'sandbox' ASCII case insensitive, allow-ſcripts
|
|
@ -2,5 +2,5 @@ Harness status: OK
|
|||
|
||||
Found 1 tests
|
||||
|
||||
1 Fail
|
||||
Fail When the scripting flag is disabled, a head start tag in "in head noscript" mode should be ignored
|
||||
1 Pass
|
||||
Pass When the scripting flag is disabled, a head start tag in "in head noscript" mode should be ignored
|
98
Tests/LibWeb/Text/input/wpt-import/common/utils.js
Normal file
98
Tests/LibWeb/Text/input/wpt-import/common/utils.js
Normal file
|
@ -0,0 +1,98 @@
|
|||
/**
|
||||
* Create an absolute URL from `options` and defaulting unspecified properties to `window.location`.
|
||||
* @param {Object} options - a `Location`-like object
|
||||
* @param {string} options.hostname
|
||||
* @param {string} options.subdomain - prepend subdomain to the hostname
|
||||
* @param {string} options.port
|
||||
* @param {string} options.path
|
||||
* @param {string} options.query
|
||||
* @param {string} options.hash
|
||||
* @returns {string}
|
||||
*/
|
||||
function make_absolute_url(options) {
|
||||
var loc = window.location;
|
||||
var protocol = get(options, "protocol", loc.protocol);
|
||||
if (protocol[protocol.length - 1] != ":") {
|
||||
protocol += ":";
|
||||
}
|
||||
|
||||
var hostname = get(options, "hostname", loc.hostname);
|
||||
|
||||
var subdomain = get(options, "subdomain");
|
||||
if (subdomain) {
|
||||
hostname = subdomain + "." + hostname;
|
||||
}
|
||||
|
||||
var port = get(options, "port", loc.port)
|
||||
var path = get(options, "path", loc.pathname);
|
||||
var query = get(options, "query", loc.search);
|
||||
var hash = get(options, "hash", loc.hash)
|
||||
|
||||
var url = protocol + "//" + hostname;
|
||||
if (port) {
|
||||
url += ":" + port;
|
||||
}
|
||||
|
||||
if (path[0] != "/") {
|
||||
url += "/";
|
||||
}
|
||||
url += path;
|
||||
if (query) {
|
||||
if (query[0] != "?") {
|
||||
url += "?";
|
||||
}
|
||||
url += query;
|
||||
}
|
||||
if (hash) {
|
||||
if (hash[0] != "#") {
|
||||
url += "#";
|
||||
}
|
||||
url += hash;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function get(obj, name, default_val) {
|
||||
if (obj.hasOwnProperty(name)) {
|
||||
return obj[name];
|
||||
}
|
||||
return default_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new UUID.
|
||||
* @returns {string}
|
||||
*/
|
||||
function token() {
|
||||
var uuid = [to_hex(rand_int(32), 8),
|
||||
to_hex(rand_int(16), 4),
|
||||
to_hex(0x4000 | rand_int(12), 4),
|
||||
to_hex(0x8000 | rand_int(14), 4),
|
||||
to_hex(rand_int(48), 12)].join("-")
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function rand_int(bits) {
|
||||
if (bits < 1 || bits > 53) {
|
||||
throw new TypeError();
|
||||
} else {
|
||||
if (bits >= 1 && bits <= 30) {
|
||||
return 0 | ((1 << bits) * Math.random());
|
||||
} else {
|
||||
var high = (0 | ((1 << (bits - 30)) * Math.random())) * (1 << 30);
|
||||
var low = 0 | ((1 << 30) * Math.random());
|
||||
return high + low;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function to_hex(x, length) {
|
||||
var rv = x.toString(16);
|
||||
while (rv.length < length) {
|
||||
rv = "0" + rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<iframe sandbox="allow-scripts" src="../resources/sandboxed-iframe.html"></iframe>
|
||||
<script>
|
||||
promise_test(async (t) => {
|
||||
const message = await new Promise((resolve) => {
|
||||
window.addEventListener('message', e => resolve(e.data));
|
||||
});
|
||||
assert_equals(message, 'PASS');
|
||||
}, 'CORS with sandboxed iframe');
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<script>
|
||||
async function no_cors_should_be_rejected() {
|
||||
let thrown = false;
|
||||
try {
|
||||
const resp = await fetch('top.txt');
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
if (!thrown) {
|
||||
throw Error('fetching "top.txt" should be rejected.');
|
||||
}
|
||||
}
|
||||
|
||||
async function null_origin_should_be_accepted() {
|
||||
const url = 'top.txt?pipe=header(access-control-allow-origin,null)|' +
|
||||
'header(cache-control,no-store)';
|
||||
const resp = await fetch(url);
|
||||
}
|
||||
|
||||
async function test() {
|
||||
try {
|
||||
await no_cors_should_be_rejected();
|
||||
await null_origin_should_be_accepted();
|
||||
parent.postMessage('PASS', '*');
|
||||
} catch (e) {
|
||||
parent.postMessage(e.message, '*');
|
||||
}
|
||||
}
|
||||
|
||||
test();
|
||||
</script>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
top.calledFromIframe();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="inner">foo</div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>DOM access in sandbox="allow-same-origin" iframe</title>
|
||||
<link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
|
||||
<link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>DOM access in sandbox="allow-same-origin" iframe</h1>
|
||||
<script type="text/javascript">
|
||||
var t = async_test("DOM access in sandbox='allow-same-origin' iframe is allowed")
|
||||
var called = 0;
|
||||
function calledFromIframe() {
|
||||
called++;
|
||||
}
|
||||
function loaded() {
|
||||
assert_equals(document.getElementById('sandboxedframe').contentWindow.document.getElementById('inner').innerHTML, 'foo');
|
||||
assert_equals(called, 0);
|
||||
t.done();
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe src="../../../html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox="allow-same-origin" id="sandboxedframe" onload="loaded();"></iframe>
|
||||
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Script execution in sandbox="allow-scripts" iframe</title>
|
||||
<link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
|
||||
<link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Script execution in sandbox="allow-scripts" iframe</h1>
|
||||
<script type="text/javascript">
|
||||
var t = async_test("Running script from sandbox='allow-scripts' iframe is allowed")
|
||||
var called = 0;
|
||||
function calledFromIframe() {
|
||||
called++;
|
||||
}
|
||||
function loaded() {
|
||||
assert_equals(called, 1);
|
||||
t.done();
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe src="../../../html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox="allow-scripts allow-same-origin" id="sandboxedframe" onload="loaded();"></iframe>
|
||||
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>window.open in sandbox iframe</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<script src="../../../common/utils.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
setup({single_test: true});
|
||||
// check that the popup's URL is not loaded
|
||||
const uuid = token();
|
||||
async function assert_popup_not_loaded() {
|
||||
const response = await fetch(`/fetch/api/resources/stash-take.py?key=${uuid}`);
|
||||
assert_equals(await response.json(), null); // is "loaded" if it loads
|
||||
}
|
||||
|
||||
// check for message from the iframe
|
||||
window.onmessage = e => {
|
||||
assert_equals(e.data, 'null', 'return value of window.open (stringified)');
|
||||
step_timeout(async () => {
|
||||
await assert_popup_not_loaded();
|
||||
done();
|
||||
}, 1000);
|
||||
};
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.sandbox = 'allow-scripts';
|
||||
iframe.srcdoc = `
|
||||
<script>
|
||||
let result;
|
||||
try {
|
||||
result = window.open('/fetch/api/resources/stash-put.py?key=${uuid}&value=loaded', '_blank');
|
||||
} catch(ex) {
|
||||
result = ex;
|
||||
}
|
||||
parent.postMessage(String(result), '*');
|
||||
<\/script>
|
||||
`;
|
||||
document.body.appendChild(iframe);
|
||||
</script>
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Access to sandbox iframe</title>
|
||||
<link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/#sandboxed-origin-browsing-context-flag">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/#integration-with-idl">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Access to sandbox iframe</h1>
|
||||
<script type="text/javascript">
|
||||
var t = async_test("Access to sandbox iframe is disallowed")
|
||||
var called = 0;
|
||||
function calledFromIframe() {
|
||||
called++;
|
||||
}
|
||||
function loaded() {
|
||||
t.step(() => {
|
||||
assert_throws_dom("SecurityError", () => {
|
||||
document.getElementById('sandboxedframe').contentWindow.document;
|
||||
});
|
||||
assert_equals(called, 0);
|
||||
t.done();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe src="../../../html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox id="sandboxedframe" onload="loaded();"></iframe>
|
||||
</body>
|
||||
|
||||
<div id="log"></div>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE html>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
async_test(t => {
|
||||
let i = document.createElement('iframe');
|
||||
i.sandbox = "allow-same-origin allow-popups allow-popups-to-escape-sandbox";
|
||||
i.srcdoc = `<a target='_blank' rel='opener'
|
||||
href="javascript:window.opener.top.postMessage('FAIL', '*');">Click me!</a>
|
||||
<a target='_blank' rel='opener'
|
||||
href="./resources/post-done-to-opener.html">Click me next!</a>`;
|
||||
|
||||
i.onload = _ => {
|
||||
// Since the frame is sandboxed, but allow-same-origin, we can reach into it to grab the
|
||||
// anchor element to click. We'll click the `javascript:` URL first, then pop up a new
|
||||
// window that posts `DONE`.
|
||||
//
|
||||
// TODO(mkwst): This feels like a race, but it's one that we consistently win when I'm
|
||||
// running the test locally 10,000 times. Good enough!™
|
||||
i.contentDocument.body.querySelectorAll('a')[0].click();
|
||||
i.contentDocument.body.querySelectorAll('a')[1].click();
|
||||
};
|
||||
document.body.appendChild(i);
|
||||
|
||||
window.addEventListener('message', t.step_func(e => {
|
||||
assert_not_equals(e.data, "FAIL");
|
||||
if (e.data == "DONE")
|
||||
t.done();
|
||||
}));
|
||||
}, "Sandboxed => unsandboxed popup");
|
||||
</script>
|
||||
</body>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Script execution in sandbox iframe</title>
|
||||
<link rel="author" title="Kinuko Yasuda" href="mailto:kinuko@chromium.org">
|
||||
<link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Script execution in sandbox iframe</h1>
|
||||
<script type="text/javascript">
|
||||
var t = async_test("Running script from sandbox iframe is disallowed")
|
||||
var called = 0;
|
||||
function calledFromIframe() {
|
||||
called++;
|
||||
}
|
||||
function loaded() {
|
||||
assert_equals(called, 0);
|
||||
t.done();
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe src="../../../html/browsers/sandboxing/inner-iframe.html" style="visibility:hidden;display:none" sandbox id="sandboxedframe" onload="loaded();"></iframe>
|
||||
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
|
||||
<div id=log></div>
|
||||
<script src="../../../html/browsers/sandboxing/sandbox-document-open-mutation.window.js"></script>
|
|
@ -0,0 +1,37 @@
|
|||
// Return whether the current context is sandboxed or not. The implementation do
|
||||
// not matter much, but might have to change over time depending on what side
|
||||
// effect sandbox flag have. Feel free to update as needed.
|
||||
const is_sandboxed = () => {
|
||||
try {
|
||||
document.domain = document.domain;
|
||||
return "not sandboxed";
|
||||
} catch (error) {
|
||||
return "sandboxed";
|
||||
}
|
||||
};
|
||||
|
||||
promise_test(async test => {
|
||||
const message = new Promise(r => window.addEventListener("message", r));
|
||||
|
||||
const iframe_unsandboxed = document.createElement("iframe");
|
||||
document.body.appendChild(iframe_unsandboxed);
|
||||
|
||||
const iframe_sandboxed = document.createElement("iframe");
|
||||
iframe_sandboxed.sandbox = "allow-same-origin allow-scripts";
|
||||
document.body.appendChild(iframe_sandboxed);
|
||||
|
||||
iframe_sandboxed.srcdoc = `
|
||||
<script>
|
||||
parent.frames[0].document.write(\`
|
||||
<script>
|
||||
const is_sandboxed = ${is_sandboxed};
|
||||
window.parent.postMessage(is_sandboxed(), '*');
|
||||
</scr\`+\`ipt>
|
||||
\`);
|
||||
parent.frames[0].document.close();
|
||||
</scr`+`ipt>
|
||||
`;
|
||||
assert_equals((await message).data, "not sandboxed");
|
||||
|
||||
}, "Using document.open() against a document from a different window must not" +
|
||||
" mutate the other window's sandbox flags");
|
|
@ -0,0 +1,50 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>
|
||||
Check sandbox-flags aren't lost after using document.open().
|
||||
</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
promise_test(async test => {
|
||||
let message = new Promise(resolve =>
|
||||
window.addEventListener("message", event => resolve(event.data))
|
||||
);
|
||||
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
||||
iframe.setAttribute("src", "./resources/document-open.html")
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
assert_equals(await message, "document-domain-is-disallowed");
|
||||
}, "document.open()");
|
||||
|
||||
promise_test(async test => {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
||||
iframe.setAttribute("src", "/common/blank.html");
|
||||
let loaded = new Promise(resolve => iframe.onload = resolve);
|
||||
document.body.appendChild(iframe);
|
||||
await loaded;
|
||||
|
||||
let message = new Promise(resolve =>
|
||||
window.addEventListener("message", event => resolve(event.data))
|
||||
);
|
||||
|
||||
iframe.contentDocument.write(`
|
||||
<script>
|
||||
try {
|
||||
document.domain = document.domain;
|
||||
parent.postMessage('document-domain-is-allowed', '*');
|
||||
} catch (error) {
|
||||
parent.postMessage('document-domain-is-disallowed', '*');
|
||||
}
|
||||
</sc`+`ript>
|
||||
`);
|
||||
|
||||
assert_equals(await message, "document-domain-is-disallowed");
|
||||
}, "other_document.open()");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,64 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Inherit sandbox flags from the initiator's frame</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
// Check sandbox flags are properly inherited when a document initiate a
|
||||
// navigation inside another frame that it doesn't own directly.
|
||||
|
||||
// This check the sandbox flags defined by the frame. See also the other test
|
||||
// about sandbox flags defined by the response (e.g. CSP sandbox):
|
||||
// => sandbox-inherited-from-initiators-response.html
|
||||
|
||||
// Return a promise, resolving when |element| triggers |event_name| event.
|
||||
let future = (element, event_name) => {
|
||||
return new Promise(resolve => {
|
||||
element.addEventListener(event_name, event => resolve(event))
|
||||
});
|
||||
};
|
||||
|
||||
promise_test(async test => {
|
||||
const iframe_1 = document.createElement("iframe");
|
||||
const iframe_2 = document.createElement("iframe");
|
||||
|
||||
iframe_1.id = "iframe_1";
|
||||
iframe_2.id = "iframe_2";
|
||||
|
||||
const iframe_1_script = encodeURI(`
|
||||
<script>
|
||||
try {
|
||||
document.domain = document.domain;
|
||||
parent.postMessage("not sandboxed", "*");
|
||||
} catch (exception) {
|
||||
parent.postMessage("sandboxed", "*");
|
||||
}
|
||||
</scr`+`ipt>
|
||||
`);
|
||||
|
||||
const iframe_2_script = `
|
||||
<script>
|
||||
const iframe_1 = parent.document.querySelector("#iframe_1");
|
||||
iframe_1.src = "data:text/html,${iframe_1_script}";
|
||||
</scr`+`ipt>
|
||||
`;
|
||||
|
||||
iframe_2.sandbox = "allow-scripts allow-same-origin";
|
||||
iframe_2.srcdoc = iframe_2_script;
|
||||
|
||||
// Insert |iframe_1|. It will load the initial empty document, with no sandbox
|
||||
// flags.
|
||||
const iframe_1_load_1 = future(iframe_1, "load");
|
||||
document.body.appendChild(iframe_1);
|
||||
await iframe_1_load_1;
|
||||
|
||||
// Insert |iframe_2|. It will load with sandbox flags. It will make |iframe_1|
|
||||
// to navigate toward a data-url, which should inherit the sandbox flags.
|
||||
const iframe_1_reply = future(window, "message");
|
||||
document.body.appendChild(iframe_2);
|
||||
const result = await iframe_1_reply;
|
||||
|
||||
assert_equals("sandboxed", result.data);
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Inherit sandbox flags from the initiator's response</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
// Check sandbox flags are properly inherited when a document initiate a
|
||||
// navigation inside another frame that it doesn't own directly.
|
||||
|
||||
// This check the sandbox flags defined by the response (e.g. CSP sandbox). See
|
||||
// also the other test about sandbox flags inherited from the frame.
|
||||
// => sandbox-inherited-from-initiators-frame.html
|
||||
|
||||
// Return a promise, resolving when |element| triggers |event_name| event.
|
||||
let future = (element, event_name) => {
|
||||
return new Promise(resolve => {
|
||||
element.addEventListener(event_name, event => resolve(event))
|
||||
});
|
||||
};
|
||||
|
||||
promise_test(async test => {
|
||||
const iframe_1 = document.createElement("iframe");
|
||||
const iframe_2 = document.createElement("iframe");
|
||||
|
||||
iframe_1.id = "iframe_1";
|
||||
iframe_2.id = "iframe_2";
|
||||
|
||||
iframe_2.src =
|
||||
"./resources/sandbox-inherited-from-initiator-response-helper.html";
|
||||
|
||||
// Insert |iframe_1|. It will load the initial empty document, with no sandbox
|
||||
// flags.
|
||||
const iframe_1_load_1 = future(iframe_1, "load");
|
||||
document.body.appendChild(iframe_1);
|
||||
await iframe_1_load_1;
|
||||
|
||||
// Insert |iframe_2|. It will load with sandbox flags. It will make |iframe_1|
|
||||
// to navigate toward a data-url, which should inherit the sandbox flags.
|
||||
const iframe_1_reply = future(window, "message");
|
||||
document.body.appendChild(iframe_2);
|
||||
const result = await iframe_1_reply;
|
||||
|
||||
assert_equals("sandboxed", result.data);
|
||||
})
|
||||
</script>
|
|
@ -0,0 +1,154 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>Inherit sandbox from CSP embedded enforcement</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<script src="../../../common/get-host-info.sub.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
// Check sandbox flags are properly defined when its parent requires them and
|
||||
// the child allows it.
|
||||
|
||||
const same_origin = get_host_info().HTTP_ORIGIN;
|
||||
const cross_origin = get_host_info().HTTP_REMOTE_ORIGIN;
|
||||
const check_sandbox_url =
|
||||
"/html/browsers/sandboxing/resources/check-sandbox-flags.html?pipe=";
|
||||
const allow_csp_from_star = "|header(Allow-CSP-From,*)";
|
||||
|
||||
// Return a promise, resolving when |element| triggers |event_name| event.
|
||||
const future = (element, event_name, source) => {
|
||||
return new Promise(resolve => {
|
||||
element.addEventListener(event_name, event => {
|
||||
if (!source || source.contentWindow == event.source)
|
||||
resolve(event)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
const check_sandbox_script = `
|
||||
<script>
|
||||
try {
|
||||
document.domain = document.domain;
|
||||
parent.postMessage("document-domain-is-allowed", "*");
|
||||
} catch (exception) {
|
||||
parent.postMessage("document-domain-is-disallowed", "*");
|
||||
}
|
||||
</scr`+`ipt>
|
||||
`;
|
||||
|
||||
const sandbox_policy = "sandbox allow-scripts allow-same-origin";
|
||||
|
||||
// Test using the modern async/await primitives are easier to read/write.
|
||||
// However they run sequentially, contrary to async_test. This is the parallel
|
||||
// version, to avoid timing out.
|
||||
let promise_test_parallel = (promise, description) => {
|
||||
async_test(test => {
|
||||
promise(test)
|
||||
.then(() => {test.done();})
|
||||
.catch(test.step_func(error => { throw error; }));
|
||||
}, description);
|
||||
};
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
|
||||
// The <iframe> immediately hosts the initial empty document after being
|
||||
// appended into the DOM. It will, as long as its 'src' isn't loaded. That's
|
||||
// why a page do not load is being used.
|
||||
iframe.src = "/fetch/api/resources/infinite-slow-response.py";
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
iframe.contentDocument.write(check_sandbox_script);
|
||||
const result = await iframe_reply;
|
||||
iframe.remove();
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "initial empty document");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.src = "data:text/html,dummy";
|
||||
|
||||
const iframe_load_1 = future(iframe, "load");
|
||||
document.body.appendChild(iframe);
|
||||
await iframe_load_1;
|
||||
|
||||
const iframe_load_2 = future(iframe, "load");
|
||||
iframe.csp = sandbox_policy;
|
||||
iframe.src = "about:blank";
|
||||
await iframe_load_2;
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
iframe.contentDocument.write(check_sandbox_script);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "about:blank");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
iframe.src =
|
||||
`data:text/html,${encodeURI(check_sandbox_script)}`;
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "data-url");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
iframe.srcdoc = check_sandbox_script;
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "srcdoc");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
|
||||
const blob = new Blob([check_sandbox_script], { type: "text/html" });
|
||||
|
||||
iframe.src = URL.createObjectURL(blob);
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "blob URL");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
iframe.src = same_origin + check_sandbox_url + allow_csp_from_star;
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "same-origin");
|
||||
|
||||
promise_test_parallel(async test => {
|
||||
const iframe = document.createElement("iframe");
|
||||
iframe.csp = sandbox_policy;
|
||||
iframe.src = cross_origin + check_sandbox_url + allow_csp_from_star;
|
||||
|
||||
const iframe_reply = future(window, "message", iframe);
|
||||
document.body.appendChild(iframe);
|
||||
const result = await iframe_reply;
|
||||
|
||||
assert_equals(result.data, "document-domain-is-disallowed");
|
||||
}, "cross-origin");
|
||||
|
||||
</script>
|
|
@ -0,0 +1,30 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>
|
||||
Check sandbox-flags inheritance in case of javascript window reuse.
|
||||
</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
promise_test(async test => {
|
||||
let message = new Promise(resolve =>
|
||||
window.addEventListener("message", event => resolve(event.data))
|
||||
);
|
||||
|
||||
// Create an initial empty document in the iframe, sandboxed. It will attempt
|
||||
// to load a slow page, but won't have time.
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin");
|
||||
iframe.src = "/fetch/api/resources/infinite-slow-response.py";
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
// Remove sandbox flags. This should apply to documents committed from
|
||||
// navigations started after this instruction.
|
||||
iframe.removeAttribute("sandbox");
|
||||
iframe.src = "./resources/check-sandbox-flags.html";
|
||||
|
||||
// The window is reused, but the new sandbox flags should be used.
|
||||
assert_equals(await message, "document-domain-is-allowed");
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>window.open in sandbox iframe</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<script src="../../../common/utils.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
promise_test(async test => {
|
||||
let message = new Promise(resolve => {
|
||||
window.addEventListener("message", event => resolve(event.data));
|
||||
});
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.sandbox = "allow-scripts allow-popups allow-same-origin";
|
||||
iframe.src = "./resources/sandbox-javascript-window-open.html";
|
||||
document.body.appendChild(iframe);
|
||||
assert_equals(await message, "disallow-document-domain");
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Sandbox Navigation Timing</title>
|
||||
<script src=../../../resources/testharness.js></script>
|
||||
<script src=../../../resources/testharnessreport.js></script>
|
||||
<html></html>
|
||||
<script>
|
||||
const sandboxUrl = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1) + 'sandbox-navigation-timing-iframe.tentative.html';
|
||||
async_test(t => {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.src = sandboxUrl;
|
||||
document.body.appendChild(iframe); // Navigation starts; value of sandbox flags locked on.
|
||||
// This should not affect the sandbox value used for both about:blank document
|
||||
// and the final document in iframe.
|
||||
iframe.sandbox = 'allow-scripts';
|
||||
const iframeAboutBlankDocument = iframe.contentDocument;
|
||||
|
||||
iframe.onload = t.step_func(() => {
|
||||
const iframeAboutBlankContents = iframeAboutBlankDocument.querySelectorAll('body');
|
||||
assert_equals(iframeAboutBlankContents[0].tagName, "BODY",
|
||||
"about:blank document's contents should still be accessible");
|
||||
|
||||
iframe.contentWindow.postMessage("is iframe sandboxed?", "*");
|
||||
});
|
||||
window.onmessage = t.step_func_done(e => {
|
||||
assert_equals(e.data.result, 'iframe not sandboxed');
|
||||
});
|
||||
}, 'setting sandbox attribute should not affect current document in iframe');
|
||||
</script>
|
|
@ -0,0 +1,39 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Reuse of iframe about:blank document execution context</title>
|
||||
<link rel="author" title="Dan Clark" href="mailto:daniec@microsoft.com">
|
||||
<link rel="help" href="http://www.w3.org/html/wg/drafts/html/master/browsers.html#sandboxing">
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Reuse of iframe about:blank document execution context in sandbox="allow-scripts" iframe</h1>
|
||||
<script type="text/javascript">
|
||||
async_test(t => {
|
||||
let iframe = document.createElement("iframe");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
let iframeAboutBlankDocument = iframe.contentDocument;
|
||||
assert_equals(iframeAboutBlankDocument.URL, "about:blank");
|
||||
|
||||
iframe.sandbox = "allow-scripts";
|
||||
iframe.src = './sandbox-new-execution-context-iframe.html';
|
||||
|
||||
iframe.onload = t.step_func_done(() => {
|
||||
assert_equals(iframe.contentDocument, null,
|
||||
"New document in sandboxed iframe should have opaque origin");
|
||||
|
||||
assert_equals(Object.getPrototypeOf(iframeAboutBlankDocument).changeFromSandboxedIframe, undefined,
|
||||
"Sandboxed iframe contents should not have been able to mess with type system of about:blank document");
|
||||
|
||||
let iframeAboutBlankContents = iframeAboutBlankDocument.querySelectorAll('body');
|
||||
assert_equals(iframeAboutBlankContents[0].tagName, "BODY",
|
||||
"about:blank document's contents should still be accessible");
|
||||
});
|
||||
},"iframe with sandbox should load with new execution context");
|
||||
</script>
|
||||
<div id="log"></div>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset=utf-8>
|
||||
<title>window.open("about:srcdoc") from a sandboxed iframe</title>
|
||||
<script src="../../../resources/testharness.js"></script>
|
||||
<script src="../../../resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
<script>
|
||||
// Check what happens when executing window.open("about:srcdoc") from a
|
||||
// sandboxed iframe. Srcdoc can't be loaded in the main frame. It should
|
||||
// result in an error page. The error page should be cross-origin with the
|
||||
// opener.
|
||||
//
|
||||
// This test covers an interesting edge case. A main frame should inherit
|
||||
// sandbox flags. However the document loaded is an internal error page. This
|
||||
// might trigger some assertions, especially if the implementation wrongly
|
||||
// applies the sandbox flags of the opener to the internal error page document.
|
||||
//
|
||||
// This test is mainly a coverage test. It passes if it doesn't crash.
|
||||
async_test(test => {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.sandbox = "allow-scripts allow-popups allow-same-origin";
|
||||
iframe.srcdoc = `
|
||||
<script>
|
||||
let w = window.open();
|
||||
onunload = () => w.close();
|
||||
|
||||
let notify = () => {
|
||||
try {
|
||||
w.origin; // Will fail after navigating to about:srcdoc.
|
||||
parent.postMessage("pending", "*");
|
||||
} catch (e) {
|
||||
parent.postMessage("done", "*");
|
||||
};
|
||||
};
|
||||
|
||||
addEventListener("message", notify);
|
||||
notify();
|
||||
|
||||
w.location = "about:srcdoc"; // Error page.
|
||||
</scr`+`ipt>
|
||||
`;
|
||||
|
||||
let closed = false;
|
||||
addEventListener("message", event => {
|
||||
closed = (event.data === "done");
|
||||
iframe.contentWindow.postMessage("ping","*");
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
test.step_wait_func_done(()=>closed);
|
||||
}, "window.open('about:srcdoc') from sandboxed srcdoc doesn't crash.");
|
||||
</script>
|
Loading…
Add table
Add a link
Reference in a new issue