bindings: Allow Guard to take multiple conditions, check for SecureContext in ConstructorEnabled (#33508)

* Update condition handling for exposing values

- Let Guard take a list of conditions
- Check for secure context condition when exposing constructor

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Update WPT expectations

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Python tidy

Signed-off-by: Daniel Adams <msub2official@gmail.com>

* Make interfaces test run in secure context

Signed-off-by: Daniel Adams <msub2official@gmail.com>

---------

Signed-off-by: Daniel Adams <msub2official@gmail.com>
This commit is contained in:
Daniel Adams 2024-09-21 09:50:05 +00:00 committed by GitHub
parent 24ad2a0526
commit 4e4b137eaa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 45 additions and 32 deletions

View file

@ -1545,15 +1545,20 @@ def MemberCondition(pref, func, exposed, secure):
assert func is None or isinstance(func, str)
assert exposed is None or isinstance(exposed, set)
assert func is None or pref is None or exposed is None or secure is None
conditions = []
if secure:
return 'Condition::SecureContext()'
conditions.append('Condition::SecureContext()')
if pref:
return f'Condition::Pref("{pref}")'
conditions.append(f'Condition::Pref("{pref}")')
if func:
return f'Condition::Func({func})'
conditions.append(f'Condition::Func({func})')
if exposed:
return [f"Condition::Exposed(InterfaceObjectMap::Globals::{camel_to_upper_snake(i)})" for i in exposed]
return "Condition::Satisfied"
conditions.extend([
f"Condition::Exposed(InterfaceObjectMap::Globals::{camel_to_upper_snake(i)})" for i in exposed
])
if len(conditions) == 0:
conditions.append("Condition::Satisfied")
return conditions
class PropertyDefiner:
@ -1639,13 +1644,10 @@ class PropertyDefiner:
currentSpecs.append(specTerminator)
joinedCurrentSpecs = ',\n'.join(currentSpecs)
specs.append(f"&[\n{joinedCurrentSpecs}]\n")
if isinstance(cond, list):
for i in cond:
prefableSpecs.append(
prefableTemplate % (i, f"{name}_specs", len(specs) - 1))
else:
prefableSpecs.append(
prefableTemplate % (cond, f"{name}_specs", len(specs) - 1))
conds = ','.join(cond) if isinstance(cond, list) else cond
prefableSpecs.append(
prefableTemplate % (f"&[{conds}]", f"{name}_specs", len(specs) - 1)
)
joinedSpecs = ',\n'.join(specs)
specsArray = (f"const {name}_specs: &[&[{specType}]] = &[\n"
@ -2815,6 +2817,15 @@ class CGConstructorEnabled(CGAbstractMethod):
assert isinstance(func, list) and len(func) == 1
conditions.append(f"{func[0]}(aCx, aObj)")
secure = iface.getExtendedAttribute("SecureContext")
if secure:
conditions.append("""
unsafe {
let in_realm_proof = AlreadyInRealm::assert_for_cx(aCx);
GlobalScope::from_context(*aCx, InRealm::Already(&in_realm_proof)).is_secure_context()
}
""")
return CGList((CGGeneric(cond) for cond in conditions), " &&\n")

View file

@ -13,23 +13,37 @@ use crate::dom::globalscope::GlobalScope;
use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_runtime::JSContext;
/// A container with a condition.
/// A container with a list of conditions.
pub struct Guard<T: Clone + Copy> {
condition: Condition,
conditions: &'static [Condition],
value: T,
}
impl<T: Clone + Copy> Guard<T> {
/// Construct a new guarded value.
pub const fn new(condition: Condition, value: T) -> Self {
Guard { condition, value }
pub const fn new(conditions: &'static [Condition], value: T) -> Self {
Guard { conditions, value }
}
/// Expose the value if the condition is satisfied.
/// Expose the value if the conditions are satisfied.
///
/// The passed handle is the object on which the value may be exposed.
pub fn expose(&self, cx: JSContext, obj: HandleObject, global: HandleObject) -> Option<T> {
if self.condition.is_satisfied(cx, obj, global) {
let mut exposed_on_global = false;
let conditions_satisfied = self.conditions.iter().all(|c| match c {
Condition::Satisfied => {
exposed_on_global = true;
true
},
// If there are multiple Exposed conditions, we just need one of them to be true
Condition::Exposed(globals) => {
exposed_on_global |= is_exposed_in(global, *globals);
true
},
_ => c.is_satisfied(cx, obj, global),
});
if conditions_satisfied && exposed_on_global {
Some(self.value)
} else {
None
@ -38,6 +52,7 @@ impl<T: Clone + Copy> Guard<T> {
}
/// A condition to expose things.
#[derive(Clone, Copy)]
pub enum Condition {
/// The condition is satisfied if the function returns true.
Func(fn(JSContext, HandleObject) -> bool),