mirror of
https://github.com/servo/servo.git
synced 2025-09-30 08:39:16 +01:00
Implement Trusted Type eval checks (#37834)
It implements the new codeForEvalGets callback to retrieve the value for a trusted script object. Additionally, it implements the new logic in can-compile-strings to call the policy factory if required. Note that parameter and argument checks aren't implemented yet, as they require updates to binding generation (see TODO in script_runtime). Part of #36258 Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
parent
4c05758ded
commit
82ca2b92cd
26 changed files with 159 additions and 345 deletions
|
@ -606,8 +606,7 @@ impl HTMLScriptElement {
|
|||
*self.script_text.borrow_mut() = TrustedScript::get_trusted_script_compliant_string(
|
||||
&self.owner_global(),
|
||||
self.Text(),
|
||||
"HTMLScriptElement",
|
||||
"text",
|
||||
"HTMLScriptElement text",
|
||||
can_gc,
|
||||
)?;
|
||||
}
|
||||
|
@ -1475,8 +1474,7 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
|
|||
let value = TrustedScript::get_trusted_script_compliant_string(
|
||||
&self.owner_global(),
|
||||
input,
|
||||
"HTMLScriptElement",
|
||||
"innerText",
|
||||
"HTMLScriptElement innerText",
|
||||
can_gc,
|
||||
)?;
|
||||
*self.script_text.borrow_mut() = value.clone();
|
||||
|
@ -1497,8 +1495,7 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
|
|||
let value = TrustedScript::get_trusted_script_compliant_string(
|
||||
&self.owner_global(),
|
||||
value,
|
||||
"HTMLScriptElement",
|
||||
"text",
|
||||
"HTMLScriptElement text",
|
||||
can_gc,
|
||||
)?;
|
||||
// Step 2: Set this's script text value to the given value.
|
||||
|
@ -1523,8 +1520,7 @@ impl HTMLScriptElementMethods<crate::DomTypeHolder> for HTMLScriptElement {
|
|||
let value = TrustedScript::get_trusted_script_compliant_string(
|
||||
&self.owner_global(),
|
||||
value.unwrap_or(TrustedScriptOrString::String(DOMString::from(""))),
|
||||
"HTMLScriptElement",
|
||||
"textContent",
|
||||
"HTMLScriptElement textContent",
|
||||
can_gc,
|
||||
)?;
|
||||
// Step 2: Set this's script text value to value.
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
use std::fmt;
|
||||
|
||||
use dom_struct::dom_struct;
|
||||
use js::jsapi::CompilationType;
|
||||
use js::rust::HandleValue;
|
||||
|
||||
use crate::dom::bindings::codegen::Bindings::TrustedScriptBinding::TrustedScriptMethods;
|
||||
use crate::dom::bindings::codegen::UnionTypes::TrustedScriptOrString;
|
||||
|
@ -11,10 +13,11 @@ use crate::dom::bindings::error::Fallible;
|
|||
use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::DomRoot;
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
use crate::dom::csp::CspReporting;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::trustedtypepolicy::TrustedType;
|
||||
use crate::dom::trustedtypepolicyfactory::TrustedTypePolicyFactory;
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::script_runtime::{CanGc, JSContext};
|
||||
|
||||
#[dom_struct]
|
||||
pub struct TrustedScript {
|
||||
|
@ -39,18 +42,16 @@ impl TrustedScript {
|
|||
pub(crate) fn get_trusted_script_compliant_string(
|
||||
global: &GlobalScope,
|
||||
value: TrustedScriptOrString,
|
||||
containing_class: &str,
|
||||
field: &str,
|
||||
sink: &str,
|
||||
can_gc: CanGc,
|
||||
) -> Fallible<DOMString> {
|
||||
match value {
|
||||
TrustedScriptOrString::String(value) => {
|
||||
let sink = format!("{} {}", containing_class, field);
|
||||
TrustedTypePolicyFactory::get_trusted_type_compliant_string(
|
||||
TrustedType::TrustedScript,
|
||||
global,
|
||||
value,
|
||||
&sink,
|
||||
sink,
|
||||
"'script'",
|
||||
can_gc,
|
||||
)
|
||||
|
@ -59,6 +60,83 @@ impl TrustedScript {
|
|||
TrustedScriptOrString::TrustedScript(trusted_script) => Ok(trusted_script.data.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn data(&self) -> DOMString {
|
||||
self.data.clone()
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/CSP/#can-compile-strings>
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn can_compile_string_with_trusted_type(
|
||||
cx: JSContext,
|
||||
global: &GlobalScope,
|
||||
code_string: DOMString,
|
||||
compilation_type: CompilationType,
|
||||
_parameter_strings: u8, //FIXME in bindings generation
|
||||
body_string: DOMString,
|
||||
_parameter_args: u8, //FIXME in bindings generation
|
||||
body_arg: HandleValue,
|
||||
can_gc: CanGc,
|
||||
) -> bool {
|
||||
// Step 2.1. Let compilationSink be "Function" if compilationType is "FUNCTION",
|
||||
// and "eval" otherwise.
|
||||
let compilation_sink = if compilation_type == CompilationType::Function {
|
||||
"Function"
|
||||
} else {
|
||||
"eval"
|
||||
};
|
||||
// Step 2.2. Let isTrusted be true if bodyArg implements TrustedScript,
|
||||
// and false otherwise.
|
||||
let is_trusted = match TrustedTypePolicyFactory::is_trusted_script(cx, body_arg) {
|
||||
// Step 2.3. If isTrusted is true then:
|
||||
Ok(trusted_script) => {
|
||||
// Step 2.3.1. If bodyString is not equal to bodyArg’s data, set isTrusted to false.
|
||||
body_string == trusted_script.data
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
// Step 2.4. If isTrusted is true, then:
|
||||
// Step 2.4.1. Assert: parameterArgs’ [list/size=] is equal to [parameterStrings]' size.
|
||||
// Step 2.4.2. For each index of the range 0 to |parameterArgs]' [list/size=]:
|
||||
// Step 2.4.2.1. Let arg be parameterArgs[index].
|
||||
// Step 2.4.2.2. If arg implements TrustedScript, then:
|
||||
// Step 2.4.2.2.1. if parameterStrings[index] is not equal to arg’s data,
|
||||
// set isTrusted to false.
|
||||
// Step 2.4.2.3. Otherwise, set isTrusted to false.
|
||||
// Step 2.5. Let sourceToValidate be a new TrustedScript object created in realm
|
||||
// whose data is set to codeString if isTrusted is true, and codeString otherwise.
|
||||
let source_string = if is_trusted {
|
||||
// We don't need to call the compliant string algorithm, as it would immediately
|
||||
// unroll the type as allowed by copying the data. This allows us to skip creating
|
||||
// the DOM object.
|
||||
code_string
|
||||
} else {
|
||||
// Step 2.6. Let sourceString be the result of executing the
|
||||
// Get Trusted Type compliant string algorithm, with TrustedScript, realm,
|
||||
// sourceToValidate, compilationSink, and 'script'.
|
||||
match TrustedScript::get_trusted_script_compliant_string(
|
||||
global,
|
||||
TrustedScriptOrString::String(code_string.clone()),
|
||||
compilation_sink,
|
||||
can_gc,
|
||||
) {
|
||||
// Step 2.7. If the algorithm throws an error, throw an EvalError.
|
||||
Err(_) => {
|
||||
return false;
|
||||
},
|
||||
Ok(source_string) => {
|
||||
// Step 2.8. If sourceString is not equal to codeString, throw an EvalError.
|
||||
if source_string != code_string {
|
||||
return false;
|
||||
}
|
||||
source_string
|
||||
},
|
||||
}
|
||||
};
|
||||
global
|
||||
.get_csp_list()
|
||||
.is_js_evaluation_allowed(global, &source_string)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TrustedScript {
|
||||
|
|
|
@ -12,7 +12,7 @@ use script_bindings::conversions::SafeToJSValConvertible;
|
|||
use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{
|
||||
TrustedTypePolicyFactoryMethods, TrustedTypePolicyOptions,
|
||||
};
|
||||
use crate::dom::bindings::conversions::root_from_object;
|
||||
use crate::dom::bindings::conversions::root_from_handlevalue;
|
||||
use crate::dom::bindings::error::{Error, Fallible};
|
||||
use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object};
|
||||
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
|
||||
|
@ -236,6 +236,15 @@ impl TrustedTypePolicyFactory {
|
|||
// Step 7: Assert: convertedInput is an instance of expectedType.
|
||||
// TODO(https://github.com/w3c/trusted-types/issues/566): Implement when spec is resolved
|
||||
}
|
||||
|
||||
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicyfactory-isscript>
|
||||
#[allow(unsafe_code)]
|
||||
pub(crate) fn is_trusted_script(
|
||||
cx: JSContext,
|
||||
value: HandleValue,
|
||||
) -> Result<DomRoot<TrustedScript>, ()> {
|
||||
unsafe { root_from_handlevalue::<TrustedScript>(value, *cx) }
|
||||
}
|
||||
}
|
||||
|
||||
impl TrustedTypePolicyFactoryMethods<crate::DomTypeHolder> for TrustedTypePolicyFactory {
|
||||
|
@ -251,29 +260,17 @@ impl TrustedTypePolicyFactoryMethods<crate::DomTypeHolder> for TrustedTypePolicy
|
|||
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicyfactory-ishtml>
|
||||
#[allow(unsafe_code)]
|
||||
fn IsHTML(&self, cx: JSContext, value: HandleValue) -> bool {
|
||||
if !value.get().is_object() {
|
||||
return false;
|
||||
}
|
||||
rooted!(in(*cx) let object = value.to_object());
|
||||
unsafe { root_from_object::<TrustedHTML>(object.get(), *cx).is_ok() }
|
||||
unsafe { root_from_handlevalue::<TrustedHTML>(value, *cx).is_ok() }
|
||||
}
|
||||
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicyfactory-isscript>
|
||||
#[allow(unsafe_code)]
|
||||
fn IsScript(&self, cx: JSContext, value: HandleValue) -> bool {
|
||||
if !value.get().is_object() {
|
||||
return false;
|
||||
}
|
||||
rooted!(in(*cx) let object = value.to_object());
|
||||
unsafe { root_from_object::<TrustedScript>(object.get(), *cx).is_ok() }
|
||||
TrustedTypePolicyFactory::is_trusted_script(cx, value).is_ok()
|
||||
}
|
||||
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicyfactory-isscripturl>
|
||||
#[allow(unsafe_code)]
|
||||
fn IsScriptURL(&self, cx: JSContext, value: HandleValue) -> bool {
|
||||
if !value.get().is_object() {
|
||||
return false;
|
||||
}
|
||||
rooted!(in(*cx) let object = value.to_object());
|
||||
unsafe { root_from_object::<TrustedScriptURL>(object.get(), *cx).is_ok() }
|
||||
unsafe { root_from_handlevalue::<TrustedScriptURL>(value, *cx).is_ok() }
|
||||
}
|
||||
/// <https://www.w3.org/TR/trusted-types/#dom-trustedtypepolicyfactory-emptyhtml>
|
||||
fn EmptyHTML(&self, can_gc: CanGc) -> DomRoot<TrustedHTML> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue