1use std::rc::Rc;
6
7use dom_struct::dom_struct;
8use js::rust::HandleValue;
9use strum_macros::AsRefStr;
10
11use crate::dom::bindings::callback::ExceptionHandling;
12use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyBinding::TrustedTypePolicyMethods;
13use crate::dom::bindings::codegen::Bindings::TrustedTypePolicyFactoryBinding::{
14 CreateHTMLCallback, CreateScriptCallback, CreateScriptURLCallback, TrustedTypePolicyOptions,
15};
16use crate::dom::bindings::codegen::UnionTypes::TrustedHTMLOrTrustedScriptOrTrustedScriptURLOrString as TrustedTypeOrString;
17use crate::dom::bindings::error::Error::Type;
18use crate::dom::bindings::error::Fallible;
19use crate::dom::bindings::reflector::{DomGlobal, DomObject, Reflector, reflect_dom_object};
20use crate::dom::bindings::root::DomRoot;
21use crate::dom::bindings::str::DOMString;
22use crate::dom::globalscope::GlobalScope;
23use crate::dom::trustedhtml::TrustedHTML;
24use crate::dom::trustedscript::TrustedScript;
25use crate::dom::trustedscripturl::TrustedScriptURL;
26use crate::script_runtime::{CanGc, JSContext};
27
28#[dom_struct]
29pub struct TrustedTypePolicy {
30 reflector_: Reflector,
31
32 name: String,
33
34 #[ignore_malloc_size_of = "Rc has unclear ownership"]
35 create_html: Option<Rc<CreateHTMLCallback>>,
36 #[ignore_malloc_size_of = "Rc has unclear ownership"]
37 create_script: Option<Rc<CreateScriptCallback>>,
38 #[ignore_malloc_size_of = "Rc has unclear ownership"]
39 create_script_url: Option<Rc<CreateScriptURLCallback>>,
40}
41
42#[derive(AsRefStr, Clone)]
43pub(crate) enum TrustedType {
44 TrustedHTML,
45 TrustedScript,
46 TrustedScriptURL,
47}
48
49impl TrustedType {
50 pub(crate) fn matches_idl_trusted_type(&self, idl_trusted_type: &TrustedTypeOrString) -> bool {
51 match self {
52 TrustedType::TrustedHTML => {
53 matches!(idl_trusted_type, TrustedTypeOrString::TrustedHTML(_))
54 },
55 TrustedType::TrustedScript => {
56 matches!(idl_trusted_type, TrustedTypeOrString::TrustedScript(_))
57 },
58 TrustedType::TrustedScriptURL => {
59 matches!(idl_trusted_type, TrustedTypeOrString::TrustedScriptURL(_))
60 },
61 }
62 }
63}
64
65impl TrustedTypePolicy {
66 fn new_inherited(name: String, options: &TrustedTypePolicyOptions) -> Self {
67 Self {
68 reflector_: Reflector::new(),
69 name,
70 create_html: options.createHTML.clone(),
71 create_script: options.createScript.clone(),
72 create_script_url: options.createScriptURL.clone(),
73 }
74 }
75
76 #[cfg_attr(crown, allow(crown::unrooted_must_root))]
77 pub(crate) fn new(
78 name: String,
79 options: &TrustedTypePolicyOptions,
80 global: &GlobalScope,
81 can_gc: CanGc,
82 ) -> DomRoot<Self> {
83 reflect_dom_object(Box::new(Self::new_inherited(name, options)), global, can_gc)
84 }
85
86 fn check_callback_if_missing(throw_if_missing: bool) -> Fallible<Option<DOMString>> {
88 if throw_if_missing {
90 Err(Type("Cannot find type".to_owned()))
91 } else {
92 Ok(None)
94 }
95 }
96
97 pub(crate) fn get_trusted_type_policy_value(
99 &self,
100 expected_type: TrustedType,
101 input: DOMString,
102 arguments: Vec<HandleValue>,
103 throw_if_missing: bool,
104 can_gc: CanGc,
105 ) -> Fallible<Option<DOMString>> {
106 match expected_type {
108 TrustedType::TrustedHTML => match &self.create_html {
109 None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
111 Some(callback) => {
113 callback.Call__(input, arguments, ExceptionHandling::Rethrow, can_gc)
117 },
118 },
119 TrustedType::TrustedScript => match &self.create_script {
120 None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
122 Some(callback) => {
124 callback.Call__(input, arguments, ExceptionHandling::Rethrow, can_gc)
128 },
129 },
130 TrustedType::TrustedScriptURL => match &self.create_script_url {
131 None => TrustedTypePolicy::check_callback_if_missing(throw_if_missing),
133 Some(callback) => {
135 callback
139 .Call__(input, arguments, ExceptionHandling::Rethrow, can_gc)
140 .map(|result| result.map(|str| DOMString::from(str.as_ref())))
141 },
142 },
143 }
144 }
145
146 fn create_trusted_type<R, TrustedTypeCallback>(
158 &self,
159 expected_type: TrustedType,
160 input: DOMString,
161 arguments: Vec<HandleValue>,
162 trusted_type_creation_callback: TrustedTypeCallback,
163 can_gc: CanGc,
164 ) -> Fallible<DomRoot<R>>
165 where
166 R: DomObject,
167 TrustedTypeCallback: FnOnce(DOMString) -> DomRoot<R>,
168 {
169 let policy_value =
172 self.get_trusted_type_policy_value(expected_type, input, arguments, true, can_gc);
173 match policy_value {
174 Err(error) => Err(error),
176 Ok(policy_value) => {
177 let data_string = match policy_value {
179 Some(value) => value,
180 None => DOMString::new(),
182 };
183 Ok(trusted_type_creation_callback(data_string))
186 },
187 }
188 }
189}
190
191impl TrustedTypePolicyMethods<crate::DomTypeHolder> for TrustedTypePolicy {
192 fn Name(&self) -> DOMString {
194 DOMString::from(&*self.name)
195 }
196 fn CreateHTML(
198 &self,
199 _cx: JSContext,
200 input: DOMString,
201 arguments: Vec<HandleValue>,
202 can_gc: CanGc,
203 ) -> Fallible<DomRoot<TrustedHTML>> {
204 self.create_trusted_type(
205 TrustedType::TrustedHTML,
206 input,
207 arguments,
208 |data_string| TrustedHTML::new(data_string, &self.global(), can_gc),
209 can_gc,
210 )
211 }
212 fn CreateScript(
214 &self,
215 _cx: JSContext,
216 input: DOMString,
217 arguments: Vec<HandleValue>,
218 can_gc: CanGc,
219 ) -> Fallible<DomRoot<TrustedScript>> {
220 self.create_trusted_type(
221 TrustedType::TrustedScript,
222 input,
223 arguments,
224 |data_string| TrustedScript::new(data_string, &self.global(), can_gc),
225 can_gc,
226 )
227 }
228 fn CreateScriptURL(
230 &self,
231 _cx: JSContext,
232 input: DOMString,
233 arguments: Vec<HandleValue>,
234 can_gc: CanGc,
235 ) -> Fallible<DomRoot<TrustedScriptURL>> {
236 self.create_trusted_type(
237 TrustedType::TrustedScriptURL,
238 input,
239 arguments,
240 |data_string| TrustedScriptURL::new(data_string, &self.global(), can_gc),
241 can_gc,
242 )
243 }
244}