mirror of
https://github.com/lexmount/moli.git
synced 2026-10-16 08:01:27 +00:00
refactor(geometry): validate DOMRect receivers through native bindings
This commit is contained in:
@@ -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::<webidl::UnrestrictedDouble>(
|
||||
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,
|
||||
|
||||
@@ -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/",
|
||||
"<!doctype html><body></body>",
|
||||
);
|
||||
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");
|
||||
}
|
||||
@@ -2204,3 +2204,4 @@ mod media_device_interfaces;
|
||||
|
||||
mod dom_rect_factory_descriptors;
|
||||
mod dom_rect_structured_clone;
|
||||
mod domrect_receiver_consolidation;
|
||||
|
||||
Reference in New Issue
Block a user