diff --git a/moli-renderer-v8/src/context_bootstrap/dom_rect.rs b/moli-renderer-v8/src/context_bootstrap/dom_rect.rs index 62fce1344c..7f55585835 100644 --- a/moli-renderer-v8/src/context_bootstrap/dom_rect.rs +++ b/moli-renderer-v8/src/context_bootstrap/dom_rect.rs @@ -36,7 +36,7 @@ struct DomRectReadOnlyObjectDeclaration { } #[derive(WebApiFunctionTemplate)] -#[webapi(interface = web_api_interfaces::DOMRectReadOnly)] +#[webapi(interface = web_api_interfaces::DOMRectReadOnly, receiver)] struct DomRectReadOnlyPrototypeDeclaration { #[webapi( accessor_property, @@ -99,7 +99,7 @@ struct DomRectReadOnlyPrototypeDeclaration { } #[derive(WebApiFunctionTemplate)] -#[webapi(interface = web_api_interfaces::DOMRect)] +#[webapi(interface = web_api_interfaces::DOMRect, receiver)] struct DomRectPrototypeDeclaration { #[webapi( accessor_property, @@ -404,13 +404,9 @@ fn dom_rect_writable_getter_callback<'s>( rv.set_undefined(); return; }; - if !dom_rect_receiver_branded(scope, args.this()) { - throw_type_error(scope, "Illegal invocation"); - return; - } - rv.set( - get_private_value(scope, args.this(), slot).unwrap_or_else(|| v8::undefined(scope).into()), - ); + let receiver = moli_webapi_declare::web_api_object_target(scope, args.this()) + .expect("validated DOMRectReadOnly receiver"); + rv.set(get_private_value(scope, receiver, slot).unwrap_or_else(|| v8::undefined(scope).into())); } fn dom_rect_readonly_getter_callback<'s>( @@ -427,11 +423,9 @@ fn dom_rect_readonly_getter_callback<'s>( rv.set_undefined(); return; }; - if !dom_rect_receiver_branded(scope, args.this()) { - throw_type_error(scope, "Illegal invocation"); - return; - } - let value = dom_rect_readonly_attribute_value(scope, args.this(), attribute); + let receiver = moli_webapi_declare::web_api_object_target(scope, args.this()) + .expect("validated DOMRectReadOnly receiver"); + let value = dom_rect_readonly_attribute_value(scope, receiver, attribute); rv.set(v8::Number::new(scope, value).into()); } @@ -449,10 +443,8 @@ fn dom_rect_setter_callback<'s>( rv.set_undefined(); return; }; - if !dom_rect_receiver_branded(scope, args.this()) { - throw_type_error(scope, "Illegal invocation"); - return; - } + let receiver = moli_webapi_declare::web_api_object_target(scope, args.this()) + .expect("validated DOMRect receiver"); let value = match webidl::convert::( scope, args.get(0), @@ -464,12 +456,7 @@ fn dom_rect_setter_callback<'s>( return; } }; - set_private_value( - scope, - args.this(), - slot, - v8::Number::new(scope, value).into(), - ); + set_private_value(scope, receiver, slot, v8::Number::new(scope, value).into()); rv.set_undefined(); } @@ -478,11 +465,8 @@ fn dom_rect_to_json_callback<'s>( args: v8::FunctionCallbackArguments<'s>, mut rv: v8::ReturnValue<'_, v8::Value>, ) { - let this = args.this(); - if !dom_rect_receiver_branded(scope, this) { - throw_type_error(scope, "Illegal invocation"); - return; - } + let this = moli_webapi_declare::web_api_object_target(scope, args.this()) + .expect("validated DOMRectReadOnly receiver"); let declaration = DomRectJsonDeclaration { x: dom_rect_slot(this, scope, DOM_RECT_X_SLOT), y: dom_rect_slot(this, scope, DOM_RECT_Y_SLOT), @@ -554,20 +538,14 @@ fn dom_rect_slot<'s>( .unwrap_or(0.0) } -fn dom_rect_receiver_branded<'s>( - scope: &mut v8::PinScope<'s, '_>, - receiver: v8::Local<'s, v8::Object>, -) -> bool { - web_api_interfaces::DOMRectReadOnly::is_instance(scope, receiver) -} - pub(crate) fn dom_rect_clone_data<'s>( scope: &mut v8::PinScope<'s, '_>, object: v8::Local<'s, v8::Object>, ) -> Option<(bool, [f64; 4])> { - if !dom_rect_receiver_branded(scope, object) { + if !web_api_interfaces::DOMRectReadOnly::is_instance(scope, object) { return None; } + let object = moli_webapi_declare::web_api_object_target(scope, object)?; let mutable = web_api_interfaces::DOMRect::is_instance(scope, object); Some(( mutable, diff --git a/moli-renderer-v8/src/script_vm/tests/domrect_receiver_consolidation.rs b/moli-renderer-v8/src/script_vm/tests/domrect_receiver_consolidation.rs new file mode 100644 index 0000000000..8770fa196d --- /dev/null +++ b/moli-renderer-v8/src/script_vm/tests/domrect_receiver_consolidation.rs @@ -0,0 +1,37 @@ +use super::*; + +#[test] +fn domrect_native_receiver_checks_preserve_interface_and_callee_realm() { + let mut vm = new_parsed_test_vm( + "https://domrect_receiver_consolidation.test/", + "", + ); + assert_eq!(vm.eval(r#"(() => { + const child=document.body.appendChild(document.createElement('iframe')).contentWindow; + let conversions=0,traps=0; + const value={valueOf(){conversions++;return 7;}}; + for(const realm of [window,child]){ + const mutable=new realm.DOMRect(1,2,3,4),readonly=new realm.DOMRectReadOnly(1,2,3,4); + const revoked=Proxy.revocable(mutable,{});revoked.revoke(); + const invalid=[{},Object.create(mutable),Object.create(realm.DOMRect.prototype),new Proxy(mutable,{get(){traps++;throw Error('trap');}}),revoked.proxy]; + for(const name of ['x','y','width','height']){ + const getter=Object.getOwnPropertyDescriptor(realm.DOMRectReadOnly.prototype,name).get; + const setter=Object.getOwnPropertyDescriptor(realm.DOMRect.prototype,name).set; + for(const target of invalid){ + for(const invoke of [()=>getter.call(target),()=>setter.call(target,value)]){ + let caught;try{invoke();}catch(error){caught=error;} + if(!(caught instanceof realm.TypeError))throw Error(name+' receiver realm'); + } + } + let caught;try{setter.call(readonly,value);}catch(error){caught=error;} + if(!(caught instanceof realm.TypeError))throw Error('readonly accepted mutable setter'); + } + const foreign=realm===window?new child.DOMRect(5,6,7,8):new DOMRect(5,6,7,8); + const setter=Object.getOwnPropertyDescriptor(realm.DOMRect.prototype,'x').set; + setter.call(foreign,9);if(foreign.x!==9)throw Error('genuine foreign DOMRect'); + for(const target of invalid){let caught;try{realm.DOMRectReadOnly.prototype.toJSON.call(target);}catch(error){caught=error;}if(!(caught instanceof realm.TypeError))throw Error('toJSON receiver');} + } + if(conversions||traps)throw Error('receiver validation executed author code'); + return 'ok'; +})()"#).expect("native binding regression"), "ok"); +} diff --git a/moli-renderer-v8/src/script_vm/tests/mod.rs b/moli-renderer-v8/src/script_vm/tests/mod.rs index b316a3c297..e25a18e4b4 100644 --- a/moli-renderer-v8/src/script_vm/tests/mod.rs +++ b/moli-renderer-v8/src/script_vm/tests/mod.rs @@ -2204,3 +2204,4 @@ mod media_device_interfaces; mod dom_rect_factory_descriptors; mod dom_rect_structured_clone; +mod domrect_receiver_consolidation;