diff --git a/moli-renderer-v8/src/context_bootstrap/exposed_interfaces/metadata.rs b/moli-renderer-v8/src/context_bootstrap/exposed_interfaces/metadata.rs index d47353d180..4590d24ed4 100644 --- a/moli-renderer-v8/src/context_bootstrap/exposed_interfaces/metadata.rs +++ b/moli-renderer-v8/src/context_bootstrap/exposed_interfaces/metadata.rs @@ -92,6 +92,12 @@ pub(in crate::context_bootstrap) const WORKER_SHARED_INTERFACE_NAMES: &[&str] = ]; const SECURE_CONTEXT_ONLY_INTERFACE_NAMES: &[&str] = &[ + "MIDIPort", + "MIDIAccess", + "MIDIInput", + "MIDIOutput", + "MIDIInputMap", + "MIDIOutputMap", "MediaDeviceInfo", "InputDeviceInfo", "DeviceMotionEvent", diff --git a/moli-renderer-v8/src/context_bootstrap/specs/registry.rs b/moli-renderer-v8/src/context_bootstrap/specs/registry.rs index 0f1d0f1aab..bde71cdce2 100644 --- a/moli-renderer-v8/src/context_bootstrap/specs/registry.rs +++ b/moli-renderer-v8/src/context_bootstrap/specs/registry.rs @@ -392,6 +392,30 @@ const CONSTRUCTOR_SPECS_BEFORE_STREAMS: &[ConstructorSpec] = &[ interface: web_api_interfaces::MessageChannel::DESCRIPTOR, kind: ConstructorKind::MessageChannel, }, + ConstructorSpec { + interface: web_api_interfaces::MIDIPort::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, + ConstructorSpec { + interface: web_api_interfaces::MIDIAccess::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, + ConstructorSpec { + interface: web_api_interfaces::MIDIInput::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, + ConstructorSpec { + interface: web_api_interfaces::MIDIOutput::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, + ConstructorSpec { + interface: web_api_interfaces::MIDIInputMap::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, + ConstructorSpec { + interface: web_api_interfaces::MIDIOutputMap::DESCRIPTOR, + kind: ConstructorKind::Illegal, + }, ConstructorSpec { interface: web_api_interfaces::MessagePort::DESCRIPTOR, kind: ConstructorKind::MessagePort, diff --git a/moli-renderer-v8/src/script_vm/tests/midi_owner_interfaces.rs b/moli-renderer-v8/src/script_vm/tests/midi_owner_interfaces.rs new file mode 100644 index 0000000000..fbbd3eadbc --- /dev/null +++ b/moli-renderer-v8/src/script_vm/tests/midi_owner_interfaces.rs @@ -0,0 +1,46 @@ +use super::*; + +#[test] +fn midi_owner_interfaces_preserve_native_inheritance_and_realm_contracts() { + for url in [ + "https://midi-owner-interfaces.test/", + "http://midi-owner-interfaces.test/", + "http://localhost/", + ] { + let mut vm = new_storage_page_task_executor_test_vm(url); + vm.eval("document.body.innerHTML = ''") + .unwrap(); + assert_eq!(vm.eval(r#"(() => { + const assert = (ok, message) => { if (!ok) throw Error(message); }; + const popup = open(); + assert(popup, 'popup test prerequisite'); + try { + const realms = [window, document.getElementById('child').contentWindow, popup]; + for (const w of realms) { + for (const [name, parentName] of [["MIDIPort","EventTarget"],["MIDIAccess","EventTarget"],["MIDIInput","MIDIPort"],["MIDIOutput","MIDIPort"],["MIDIInputMap","Object"],["MIDIOutputMap","Object"]]) { + if (true && !w.isSecureContext) { + assert(!(name in w), name + ' hidden in an insecure realm'); + continue; + } + const C = w[name], parent = w[parentName]; + assert(typeof C === 'function' && C.name === name && C.length === 0, name + ' interface object'); + const descriptor = Object.getOwnPropertyDescriptor(w, name); + assert(descriptor.writable && descriptor.configurable && !descriptor.enumerable, name + ' global descriptor'); + assert(Object.getPrototypeOf(C.prototype) === parent.prototype, name + ' prototype inheritance'); + assert(Object.getPrototypeOf(C) === (parentName === 'Object' ? w.Function.prototype : parent), name + ' interface inheritance'); + assert(C.prototype.constructor === C, name + ' prototype constructor'); + const tag = Object.getOwnPropertyDescriptor(C.prototype, Symbol.toStringTag); + assert(tag.value === name && !tag.writable && !tag.enumerable && tag.configurable, name + ' tag'); + for (const call of [() => C(), () => new C()]) { + let error; + try { call(); } catch (caught) { error = caught; } + assert(error instanceof w.TypeError, name + ' rejects direct construction in the callee realm'); + if (w !== window) assert(!(error instanceof TypeError), name + ' foreign error realm'); + } + } + } + return true; + } finally { popup.close(); } +})()"#).unwrap(), "true", "{url}"); + } +} diff --git a/moli-renderer-v8/src/script_vm/tests/mod.rs b/moli-renderer-v8/src/script_vm/tests/mod.rs index 0a8c70c352..9ea4785518 100644 --- a/moli-renderer-v8/src/script_vm/tests/mod.rs +++ b/moli-renderer-v8/src/script_vm/tests/mod.rs @@ -2152,6 +2152,7 @@ mod indexed_db; mod inspector_unwrap; mod lazy_storage; mod lazy_window_surfaces; +mod midi_owner_interfaces; mod mouse_snapshot; mod no_cors_header_fill; mod observer_callbacks; diff --git a/moli-renderer-v8/src/web_api_interfaces.rs b/moli-renderer-v8/src/web_api_interfaces.rs index 099e576fe7..a9171700cd 100644 --- a/moli-renderer-v8/src/web_api_interfaces.rs +++ b/moli-renderer-v8/src/web_api_interfaces.rs @@ -296,6 +296,12 @@ interfaces! { MediaQueryListEvent: Event; MediaSource: EventTarget; MemoryInfo; + MIDIPort: EventTarget; + MIDIAccess: EventTarget; + MIDIInput: MIDIPort; + MIDIOutput: MIDIPort; + MIDIInputMap; + MIDIOutputMap; MessageChannel; MessageEvent: Event; MessagePort: EventTarget;