Commit e8e9916c authored by Mike West's avatar Mike West Committed by Commit Bot

Trusted Types: First stab at TrustedScriptURL.

koto@ added [`TrustedScriptURL`][1] to the explainer as a mechanism to
distinguish URLs that directly lead to script execution (e.g. via
assignment to `<script>`'s `src` attribute). This patch is a first pass
at an implementation, along with restrictions on `script.src` so we can
test it out.

[1]: https://github.com/mikewest/trusted-types/commit/834163e519b579e5566908cafcedb2efe24be6da

Bug: 739170
Change-Id: Ie784ff3992dbcf750521fd55710befe3ed26036c
Reviewed-on: https://chromium-review.googlesource.com/677390
Commit-Queue: Mike West <mkwst@chromium.org>
Reviewed-by: default avatarYoav Weiss <yoav@yoav.ws>
Cr-Commit-Position: refs/heads/master@{#504306}
parent fed2d25e
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./support/helper.js"></script>
<script>
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.safe);
assert_equals(url.toString(), URLS.safe);
}, "Basic processing: safe URL, unsafe construction.");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.javascript);
assert_equals(url.toString(), URLS.javascript);
}, "Basic processing: javascript URL, unsafe construction.");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.external);
assert_equals(url.toString(), URLS.external);
}, "Basic processing: external protocol URL, unsafe construction.");
</script>
<!DOCTYPE html>
<html>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./support/helper.js"></script>
<meta http-equiv="Content-Security-Policy" content="require-trusted-types">
</head>
<body>
<script>
// String assignments throw.
test(t => {
var s = document.createElement('script');
assert_throws(new TypeError(), _ => {
s.src = URLS.safe;
});
assert_equals('', s.src);
}, "'string'");
// TrustedURL assignments throw.
test(t => {
var url = TrustedURL.unsafelyCreate(URLS.safe);
var s = document.createElement('script');
assert_throws(new TypeError(), _ => {
s.src = url;
});
assert_equals('', s.src);
}, "TrustedURL(safe)");
// TrustedScriptURL assignments work.
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.safe);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
}, "TrustedScriptURL(safe)");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.javascript);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
}, "TrustedScriptURL(javascript)");
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.external);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
}, "TrustedScriptURL(external)");
</script>
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="./support/helper.js"></script>
<body>
<script>
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.safe);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
});
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.javascript);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
});
test(t => {
var url = TrustedScriptURL.unsafelyCreate(URLS.external);
var s = document.createElement('script');
s.src = url;
assert_equals(url + '', s.src);
});
</script>
...@@ -1158,6 +1158,11 @@ interface TrustedHTML ...@@ -1158,6 +1158,11 @@ interface TrustedHTML
attribute @@toStringTag attribute @@toStringTag
method constructor method constructor
method toString method toString
interface TrustedScriptURL
static method unsafelyCreate
attribute @@toStringTag
method constructor
method toString
interface TrustedURL interface TrustedURL
static method create static method create
static method unsafelyCreate static method unsafelyCreate
......
...@@ -1067,6 +1067,11 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -1067,6 +1067,11 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] attribute @@toStringTag [Worker] attribute @@toStringTag
[Worker] method constructor [Worker] method constructor
[Worker] method toString [Worker] method toString
[Worker] interface TrustedScriptURL
[Worker] static method unsafelyCreate
[Worker] attribute @@toStringTag
[Worker] method constructor
[Worker] method toString
[Worker] interface TrustedURL [Worker] interface TrustedURL
[Worker] static method create [Worker] static method create
[Worker] static method unsafelyCreate [Worker] static method unsafelyCreate
......
...@@ -7002,6 +7002,11 @@ interface TrustedHTML ...@@ -7002,6 +7002,11 @@ interface TrustedHTML
attribute @@toStringTag attribute @@toStringTag
method constructor method constructor
method toString method toString
interface TrustedScriptURL
static method unsafelyCreate
attribute @@toStringTag
method constructor
method toString
interface TrustedURL interface TrustedURL
static method create static method create
static method unsafelyCreate static method unsafelyCreate
......
...@@ -1067,6 +1067,11 @@ Starting worker: resources/global-interface-listing-worker.js ...@@ -1067,6 +1067,11 @@ Starting worker: resources/global-interface-listing-worker.js
[Worker] attribute @@toStringTag [Worker] attribute @@toStringTag
[Worker] method constructor [Worker] method constructor
[Worker] method toString [Worker] method toString
[Worker] interface TrustedScriptURL
[Worker] static method unsafelyCreate
[Worker] attribute @@toStringTag
[Worker] method constructor
[Worker] method toString
[Worker] interface TrustedURL [Worker] interface TrustedURL
[Worker] static method create [Worker] static method create
[Worker] static method unsafelyCreate [Worker] static method unsafelyCreate
......
...@@ -73,6 +73,8 @@ bindings_core_generated_union_type_files = [ ...@@ -73,6 +73,8 @@ bindings_core_generated_union_type_files = [
"$bindings_core_v8_output_dir/string_or_float.h", "$bindings_core_v8_output_dir/string_or_float.h",
"$bindings_core_v8_output_dir/string_or_trusted_html.cc", "$bindings_core_v8_output_dir/string_or_trusted_html.cc",
"$bindings_core_v8_output_dir/string_or_trusted_html.h", "$bindings_core_v8_output_dir/string_or_trusted_html.h",
"$bindings_core_v8_output_dir/string_or_trusted_script_url.cc",
"$bindings_core_v8_output_dir/string_or_trusted_script_url.h",
"$bindings_core_v8_output_dir/string_or_trusted_url.cc", "$bindings_core_v8_output_dir/string_or_trusted_url.cc",
"$bindings_core_v8_output_dir/string_or_trusted_url.h", "$bindings_core_v8_output_dir/string_or_trusted_url.h",
"$bindings_core_v8_output_dir/string_or_unrestricted_double_sequence.cc", "$bindings_core_v8_output_dir/string_or_unrestricted_double_sequence.cc",
......
...@@ -128,6 +128,7 @@ core_idl_files = ...@@ -128,6 +128,7 @@ core_idl_files =
"dom/events/Event.idl", "dom/events/Event.idl",
"dom/events/EventTarget.idl", "dom/events/EventTarget.idl",
"dom/trustedtypes/TrustedHTML.idl", "dom/trustedtypes/TrustedHTML.idl",
"dom/trustedtypes/TrustedScriptURL.idl",
"dom/trustedtypes/TrustedURL.idl", "dom/trustedtypes/TrustedURL.idl",
"editing/Selection.idl", "editing/Selection.idl",
"events/AnimationEvent.idl", "events/AnimationEvent.idl",
......
...@@ -337,6 +337,8 @@ blink_core_sources("dom") { ...@@ -337,6 +337,8 @@ blink_core_sources("dom") {
"events/WindowEventContext.h", "events/WindowEventContext.h",
"trustedtypes/TrustedHTML.cpp", "trustedtypes/TrustedHTML.cpp",
"trustedtypes/TrustedHTML.h", "trustedtypes/TrustedHTML.h",
"trustedtypes/TrustedScriptURL.cpp",
"trustedtypes/TrustedScriptURL.h",
"trustedtypes/TrustedURL.cpp", "trustedtypes/TrustedURL.cpp",
"trustedtypes/TrustedURL.h", "trustedtypes/TrustedURL.h",
] ]
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "bindings/core/v8/V8DOMActivityLogger.h" #include "bindings/core/v8/V8DOMActivityLogger.h"
#include "bindings/core/v8/scroll_into_view_options_or_boolean.h" #include "bindings/core/v8/scroll_into_view_options_or_boolean.h"
#include "bindings/core/v8/string_or_trusted_html.h" #include "bindings/core/v8/string_or_trusted_html.h"
#include "bindings/core/v8/string_or_trusted_script_url.h"
#include "core/CSSValueKeywords.h" #include "core/CSSValueKeywords.h"
#include "core/SVGNames.h" #include "core/SVGNames.h"
#include "core/XMLNames.h" #include "core/XMLNames.h"
...@@ -81,6 +82,7 @@ ...@@ -81,6 +82,7 @@
#include "core/dom/WhitespaceAttacher.h" #include "core/dom/WhitespaceAttacher.h"
#include "core/dom/events/EventDispatcher.h" #include "core/dom/events/EventDispatcher.h"
#include "core/dom/trustedtypes/TrustedHTML.h" #include "core/dom/trustedtypes/TrustedHTML.h"
#include "core/dom/trustedtypes/TrustedScriptURL.h"
#include "core/editing/EditingUtilities.h" #include "core/editing/EditingUtilities.h"
#include "core/editing/EphemeralRange.h" #include "core/editing/EphemeralRange.h"
#include "core/editing/FrameSelection.h" #include "core/editing/FrameSelection.h"
...@@ -1366,6 +1368,24 @@ void Element::SetSynchronizedLazyAttribute(const QualifiedName& name, ...@@ -1366,6 +1368,24 @@ void Element::SetSynchronizedLazyAttribute(const QualifiedName& name,
SetAttributeInternal(index, name, value, kInSynchronizationOfLazyAttribute); SetAttributeInternal(index, name, value, kInSynchronizationOfLazyAttribute);
} }
void Element::setAttribute(const QualifiedName& name,
const StringOrTrustedScriptURL& stringOrURL,
ExceptionState& exception_state) {
DCHECK(stringOrURL.isString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
if (stringOrURL.isString() && GetDocument().RequireTrustedTypes()) {
exception_state.ThrowTypeError(
"This document requires `TrustedScriptURL` assignment.");
return;
}
String valueString = stringOrURL.isString()
? stringOrURL.getAsString()
: stringOrURL.getAsTrustedScriptURL()->toString();
setAttribute(name, AtomicString(valueString));
}
ALWAYS_INLINE void Element::SetAttributeInternal( ALWAYS_INLINE void Element::SetAttributeInternal(
size_t index, size_t index,
const QualifiedName& name, const QualifiedName& name,
...@@ -3789,6 +3809,12 @@ KURL Element::GetURLAttribute(const QualifiedName& name) const { ...@@ -3789,6 +3809,12 @@ KURL Element::GetURLAttribute(const QualifiedName& name) const {
StripLeadingAndTrailingHTMLSpaces(getAttribute(name))); StripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
} }
void Element::GetURLAttribute(const QualifiedName& name,
StringOrTrustedScriptURL& result) const {
KURL url = GetURLAttribute(name);
result.setString(url.GetString());
}
KURL Element::GetNonEmptyURLAttribute(const QualifiedName& name) const { KURL Element::GetNonEmptyURLAttribute(const QualifiedName& name) const {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (GetElementData()) { if (GetElementData()) {
......
...@@ -74,6 +74,7 @@ class ShadowRoot; ...@@ -74,6 +74,7 @@ class ShadowRoot;
class ShadowRootInit; class ShadowRootInit;
class SpaceSplitString; class SpaceSplitString;
class StringOrTrustedHTML; class StringOrTrustedHTML;
class StringOrTrustedScriptURL;
class StylePropertySet; class StylePropertySet;
class StylePropertyMap; class StylePropertyMap;
class V0CustomElementDefinition; class V0CustomElementDefinition;
...@@ -197,6 +198,12 @@ class CORE_EXPORT Element : public ContainerNode { ...@@ -197,6 +198,12 @@ class CORE_EXPORT Element : public ContainerNode {
const AtomicString& value, const AtomicString& value,
ExceptionState&); ExceptionState&);
void setAttribute(const AtomicString& name, const AtomicString& value); void setAttribute(const AtomicString& name, const AtomicString& value);
// Trusted Type variant of the above.
void setAttribute(const QualifiedName&,
const StringOrTrustedScriptURL&,
ExceptionState&);
static bool ParseAttributeName(QualifiedName&, static bool ParseAttributeName(QualifiedName&,
const AtomicString& namespace_uri, const AtomicString& namespace_uri,
const AtomicString& qualified_name, const AtomicString& qualified_name,
...@@ -553,6 +560,8 @@ class CORE_EXPORT Element : public ContainerNode { ...@@ -553,6 +560,8 @@ class CORE_EXPORT Element : public ContainerNode {
KURL HrefURL() const; KURL HrefURL() const;
KURL GetURLAttribute(const QualifiedName&) const; KURL GetURLAttribute(const QualifiedName&) const;
void GetURLAttribute(const QualifiedName&, StringOrTrustedScriptURL&) const;
KURL GetNonEmptyURLAttribute(const QualifiedName&) const; KURL GetNonEmptyURLAttribute(const QualifiedName&) const;
virtual const AtomicString ImageSourceURL() const; virtual const AtomicString ImageSourceURL() const;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/dom/trustedtypes/TrustedScriptURL.h"
#include "core/dom/ExecutionContext.h"
#include "platform/bindings/ScriptState.h"
namespace blink {
TrustedScriptURL::TrustedScriptURL(const KURL& url) : url_(url) {}
TrustedScriptURL* TrustedScriptURL::unsafelyCreate(ScriptState* script_state,
const String& url) {
return TrustedScriptURL::Create(
ExecutionContext::From(script_state)->CompleteURL(url));
}
String TrustedScriptURL::toString() const {
return url_.GetString();
}
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TrustedScriptURL_h
#define TrustedScriptURL_h
#include "core/CoreExport.h"
#include "platform/bindings/ScriptWrappable.h"
#include "platform/heap/Handle.h"
#include "platform/weborigin/KURL.h"
#include "platform/wtf/text/WTFString.h"
namespace blink {
class ScriptState;
class CORE_EXPORT TrustedScriptURL final
: public GarbageCollectedFinalized<TrustedScriptURL>,
public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
static TrustedScriptURL* Create(const KURL& url) {
return new TrustedScriptURL(url);
}
// TrustedScriptURL.idl
String toString() const;
static TrustedScriptURL* unsafelyCreate(ScriptState*, const String& url);
DEFINE_INLINE_VIRTUAL_TRACE() {}
private:
TrustedScriptURL(const KURL&);
KURL url_;
};
} // namespace blink
#endif // TrustedScriptURL_h
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
typedef (DOMString or TrustedScriptURL) ScriptURLString;
[
Exposed=(Window,Worker),
RuntimeEnabled=TrustedDOMTypes
] interface TrustedScriptURL {
[CallWith=ScriptState] static TrustedScriptURL unsafelyCreate(DOMString url);
stringifier;
};
...@@ -23,7 +23,7 @@ class CORE_EXPORT TrustedURL final ...@@ -23,7 +23,7 @@ class CORE_EXPORT TrustedURL final
public: public:
static TrustedURL* Create(const KURL& url) { return new TrustedURL(url); } static TrustedURL* Create(const KURL& url) { return new TrustedURL(url); }
// CredentialsContainer.idl // TrustedURL.idl
String toString() const; String toString() const;
static TrustedURL* create(ScriptState*, const String& url); static TrustedURL* create(ScriptState*, const String& url);
static TrustedURL* unsafelyCreate(ScriptState*, const String& url); static TrustedURL* unsafelyCreate(ScriptState*, const String& url);
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
// https://html.spec.whatwg.org/#the-script-element // https://html.spec.whatwg.org/#the-script-element
interface HTMLScriptElement : HTMLElement { interface HTMLScriptElement : HTMLElement {
[CEReactions, Reflect, URL] attribute DOMString src; [CEReactions, Reflect, URL, RaisesException=Setter] attribute ScriptURLString src;
[CEReactions, Reflect] attribute DOMString type; [CEReactions, Reflect] attribute DOMString type;
[CEReactions, Reflect, RuntimeEnabled=ModuleScripts] attribute boolean noModule; [CEReactions, Reflect, RuntimeEnabled=ModuleScripts] attribute boolean noModule;
[CEReactions, Reflect] attribute DOMString charset; [CEReactions, Reflect] attribute DOMString charset;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment