blob: b94320510853cd056eba2e8f2d6ca9eaa5bbf633 [file] [log] [blame]
// Copyright 2018 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 "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
#include "services/service_manager/public/cpp/connector.h"
#include "third_party/blink/public/mojom/reporting/reporting.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html_or_trusted_script_or_trusted_script_url_or_trusted_url.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script_url.h"
#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_script_url.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
namespace {
enum TrustedTypeViolationKind {
kAnyTrustedTypeAssignment,
kTrustedHTMLAssignment,
kTrustedScriptAssignment,
kTrustedURLAssignment,
kTrustedScriptURLAssignment,
kTrustedHTMLAssignmentAndDefaultPolicyFailed,
kTrustedScriptAssignmentAndDefaultPolicyFailed,
kTrustedURLAssignmentAndDefaultPolicyFailed,
kTrustedScriptURLAssignmentAndDefaultPolicyFailed,
};
const char* GetMessage(TrustedTypeViolationKind kind) {
switch (kind) {
case kAnyTrustedTypeAssignment:
return "This document requires any trusted type assignment.";
case kTrustedHTMLAssignment:
return "This document requires 'TrustedHTML' assignment.";
case kTrustedScriptAssignment:
return "This document requires 'TrustedScript' assignment.";
case kTrustedURLAssignment:
return "This document requires 'TrustedURL' assignment.";
case kTrustedScriptURLAssignment:
return "This document requires 'TrustedScriptURL' assignment.";
case kTrustedHTMLAssignmentAndDefaultPolicyFailed:
return "This document requires 'TrustedHTML' assignment and the "
"'default' policy failed to execute.";
case kTrustedScriptAssignmentAndDefaultPolicyFailed:
return "This document requires 'TrustedScript' assignment and the "
"'default' policy failed to execute.";
case kTrustedURLAssignmentAndDefaultPolicyFailed:
return "This document requires 'TrustedURL' assignment and the 'default' "
"policy failed to execute.";
case kTrustedScriptURLAssignmentAndDefaultPolicyFailed:
return "This document requires 'TrustedScriptURL' assignment and the "
"'default' policy failed to execute.";
}
NOTREACHED();
return "";
}
// Handle failure of a Trusted Type assignment.
//
// If trusted type assignment fails, we need to
// - report the violation via CSP
// - increment the appropriate counter,
// - raise a JavaScript exception (if enforced).
//
// Returns whether the failure should be enforced.
bool TrustedTypeFail(TrustedTypeViolationKind kind,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
if (!execution_context)
return true;
// Test case docs (Document::CreateForTest) might not have a window and hence
// no TrustedTypesPolicyFactory.
if (execution_context->GetTrustedTypes())
execution_context->GetTrustedTypes()->CountTrustedTypeAssignmentError();
const char* message = GetMessage(kind);
bool allow = execution_context->GetSecurityContext()
.GetContentSecurityPolicy()
->AllowTrustedTypeAssignmentFailure(message);
if (!allow) {
exception_state.ThrowTypeError(message);
}
return !allow;
}
bool RequireTrustedTypes(const ExecutionContext* execution_context) {
return execution_context &&
execution_context->GetSecurityContext().RequireTrustedTypes();
}
TrustedTypePolicy* GetDefaultPolicy(const ExecutionContext* execution_context) {
return execution_context->GetTrustedTypes()->getExposedPolicy("default");
}
} // namespace
String GetStringFromTrustedType(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_trusted_type,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_type.IsString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context));
DCHECK(!string_or_trusted_type.IsNull());
if (string_or_trusted_type.IsString() &&
RequireTrustedTypes(execution_context)) {
TrustedTypeFail(kAnyTrustedTypeAssignment, execution_context,
exception_state);
return g_empty_string;
}
if (string_or_trusted_type.IsTrustedHTML())
return string_or_trusted_type.GetAsTrustedHTML()->toString();
if (string_or_trusted_type.IsTrustedScript())
return string_or_trusted_type.GetAsTrustedScript()->toString();
if (string_or_trusted_type.IsTrustedScriptURL())
return string_or_trusted_type.GetAsTrustedScriptURL()->toString();
if (string_or_trusted_type.IsTrustedURL())
return string_or_trusted_type.GetAsTrustedURL()->toString();
return string_or_trusted_type.GetAsString();
}
String GetStringFromTrustedTypeWithoutCheck(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_trusted_type) {
if (string_or_trusted_type.IsTrustedHTML())
return string_or_trusted_type.GetAsTrustedHTML()->toString();
if (string_or_trusted_type.IsTrustedScript())
return string_or_trusted_type.GetAsTrustedScript()->toString();
if (string_or_trusted_type.IsTrustedScriptURL())
return string_or_trusted_type.GetAsTrustedScriptURL()->toString();
if (string_or_trusted_type.IsTrustedURL())
return string_or_trusted_type.GetAsTrustedURL()->toString();
if (string_or_trusted_type.IsString())
return string_or_trusted_type.GetAsString();
return g_empty_string;
}
String GetStringFromSpecificTrustedType(
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURLOrTrustedURL&
string_or_trusted_type,
SpecificTrustedType specific_trusted_type,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
switch (specific_trusted_type) {
case SpecificTrustedType::kTrustedHTML: {
StringOrTrustedHTML string_or_trusted_html =
string_or_trusted_type.IsTrustedHTML()
? StringOrTrustedHTML::FromTrustedHTML(
string_or_trusted_type.GetAsTrustedHTML())
: StringOrTrustedHTML::FromString(
GetStringFromTrustedTypeWithoutCheck(
string_or_trusted_type));
return GetStringFromTrustedHTML(string_or_trusted_html, execution_context,
exception_state);
}
case SpecificTrustedType::kTrustedScript: {
StringOrTrustedScript string_or_trusted_script =
string_or_trusted_type.IsTrustedScript()
? StringOrTrustedScript::FromTrustedScript(
string_or_trusted_type.GetAsTrustedScript())
: StringOrTrustedScript::FromString(
GetStringFromTrustedTypeWithoutCheck(
string_or_trusted_type));
return GetStringFromTrustedScript(string_or_trusted_script,
execution_context, exception_state);
}
case SpecificTrustedType::kTrustedScriptURL: {
StringOrTrustedScriptURL string_or_trusted_script_url =
string_or_trusted_type.IsTrustedScriptURL()
? StringOrTrustedScriptURL::FromTrustedScriptURL(
string_or_trusted_type.GetAsTrustedScriptURL())
: StringOrTrustedScriptURL::FromString(
GetStringFromTrustedTypeWithoutCheck(
string_or_trusted_type));
return GetStringFromTrustedScriptURL(string_or_trusted_script_url,
execution_context, exception_state);
}
case SpecificTrustedType::kTrustedURL: {
USVStringOrTrustedURL string_or_trusted_url =
string_or_trusted_type.IsTrustedURL()
? USVStringOrTrustedURL::FromTrustedURL(
string_or_trusted_type.GetAsTrustedURL())
: USVStringOrTrustedURL::FromUSVString(
GetStringFromTrustedTypeWithoutCheck(
string_or_trusted_type));
return GetStringFromTrustedURL(string_or_trusted_url, execution_context,
exception_state);
}
}
}
String GetStringFromTrustedHTML(StringOrTrustedHTML string_or_trusted_html,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_html.IsString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context));
DCHECK(!string_or_trusted_html.IsNull());
if (string_or_trusted_html.IsTrustedHTML()) {
return string_or_trusted_html.GetAsTrustedHTML()->toString();
}
return GetStringFromTrustedHTML(string_or_trusted_html.GetAsString(),
execution_context, exception_state);
}
String GetStringFromTrustedHTML(const String& string,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
bool require_trusted_type = RequireTrustedTypes(execution_context);
if (!require_trusted_type) {
return string;
}
TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context);
if (!default_policy) {
if (TrustedTypeFail(kTrustedHTMLAssignment, execution_context,
exception_state)) {
return g_empty_string;
}
return string;
}
TrustedHTML* result = default_policy->CreateHTML(
execution_context->GetIsolate(), string, exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
TrustedTypeFail(kTrustedHTMLAssignmentAndDefaultPolicyFailed,
execution_context, exception_state);
return g_empty_string;
}
return result->toString();
}
String GetStringFromTrustedScript(
StringOrTrustedScript string_or_trusted_script,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_script.IsString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context));
// To remain compatible with legacy behaviour, HTMLElement uses extended IDL
// attributes to allow for nullable union of (DOMString or TrustedScript).
// Thus, this method is required to handle the case where
// string_or_trusted_script.IsNull(), unlike the various similar methods in
// this file.
bool require_trusted_type = RequireTrustedTypes(execution_context);
if (!require_trusted_type) {
if (string_or_trusted_script.IsString()) {
return string_or_trusted_script.GetAsString();
}
if (string_or_trusted_script.IsNull()) {
return g_empty_string;
}
}
if (string_or_trusted_script.IsTrustedScript()) {
return string_or_trusted_script.GetAsTrustedScript()->toString();
}
DCHECK(require_trusted_type);
DCHECK(string_or_trusted_script.IsNull() ||
string_or_trusted_script.IsString());
TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context);
if (!default_policy) {
if (TrustedTypeFail(kTrustedScriptAssignment, execution_context,
exception_state)) {
return g_empty_string;
}
if (string_or_trusted_script.IsNull())
return g_empty_string;
return string_or_trusted_script.GetAsString();
}
const String& string_value_or_empty =
string_or_trusted_script.IsNull()
? g_empty_string
: string_or_trusted_script.GetAsString();
TrustedScript* result = default_policy->CreateScript(
execution_context->GetIsolate(), string_value_or_empty, exception_state);
DCHECK_EQ(!result, exception_state.HadException());
if (exception_state.HadException()) {
exception_state.ClearException();
TrustedTypeFail(kTrustedScriptAssignmentAndDefaultPolicyFailed,
execution_context, exception_state);
return g_empty_string;
}
return result->toString();
}
String GetStringFromTrustedScriptURL(
StringOrTrustedScriptURL string_or_trusted_script_url,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_script_url.IsString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context));
DCHECK(!string_or_trusted_script_url.IsNull());
bool require_trusted_type =
RequireTrustedTypes(execution_context) &&
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context);
if (!require_trusted_type && string_or_trusted_script_url.IsString()) {
return string_or_trusted_script_url.GetAsString();
}
if (string_or_trusted_script_url.IsTrustedScriptURL()) {
return string_or_trusted_script_url.GetAsTrustedScriptURL()->toString();
}
TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context);
if (!default_policy) {
if (TrustedTypeFail(kTrustedScriptURLAssignment, execution_context,
exception_state)) {
return g_empty_string;
}
return string_or_trusted_script_url.GetAsString();
}
TrustedScriptURL* result = default_policy->CreateScriptURL(
execution_context->GetIsolate(),
string_or_trusted_script_url.GetAsString(), exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
TrustedTypeFail(kTrustedScriptURLAssignmentAndDefaultPolicyFailed,
execution_context, exception_state);
return g_empty_string;
}
return result->toString();
}
String GetStringFromTrustedURL(USVStringOrTrustedURL string_or_trusted_url,
const ExecutionContext* execution_context,
ExceptionState& exception_state) {
DCHECK(string_or_trusted_url.IsUSVString() ||
RuntimeEnabledFeatures::TrustedDOMTypesEnabled(execution_context));
DCHECK(!string_or_trusted_url.IsNull());
bool require_trusted_type = RequireTrustedTypes(execution_context);
if (!require_trusted_type && string_or_trusted_url.IsUSVString()) {
return string_or_trusted_url.GetAsUSVString();
}
if (string_or_trusted_url.IsTrustedURL()) {
return string_or_trusted_url.GetAsTrustedURL()->toString();
}
TrustedTypePolicy* default_policy = GetDefaultPolicy(execution_context);
if (!default_policy) {
if (TrustedTypeFail(kTrustedURLAssignment, execution_context,
exception_state)) {
return g_empty_string;
}
return string_or_trusted_url.GetAsUSVString();
}
TrustedURL* result = default_policy->CreateURL(
execution_context->GetIsolate(), string_or_trusted_url.GetAsUSVString(),
exception_state);
if (exception_state.HadException()) {
exception_state.ClearException();
TrustedTypeFail(kTrustedURLAssignmentAndDefaultPolicyFailed,
execution_context, exception_state);
return g_empty_string;
}
return result->toString();
}
} // namespace blink