fix(js): isolate bootstrap declarations
This commit is contained in:
1 parent
23a8a3111b
commit
6a55b63fa6
2 files changed
+65
-8
No files matched your search
Vendored
+9
@@ -1,4 +1,5 @@
|
||||
"use strict";
|
||||
(function () {
|
||||
|
||||
// Pre-declare all internal globals as non-enumerable so they are invisible
|
||||
// to Object.keys(window) / for-in enumeration. Must run before any var
|
||||
@@ -175,6 +176,12 @@ let _fpSeed = 0;
|
||||
// when SPAs dynamically insert multiple <script module> tags at once.
|
||||
let __dynScriptQueue = [];
|
||||
let __dynScriptBusy = false;
|
||||
Object.defineProperty(globalThis, '__obscura_hasPendingDynamicScripts', {
|
||||
value: function() { return __dynScriptBusy || __dynScriptQueue.length > 0; },
|
||||
writable: false,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
});
|
||||
function _decodeDataScriptUrl(url) {
|
||||
const comma = url.indexOf(',');
|
||||
if (!url.startsWith('data:') || comma < 5) {
|
||||
@@ -8959,3 +8966,5 @@ if (typeof Response !== 'undefined' && Response.prototype && !Response.prototype
|
||||
if (typeof val === 'function') { walk(val); }
|
||||
}
|
||||
})();
|
||||
|
||||
})();
|
||||
@@ -860,15 +860,14 @@ impl ObscuraJsRuntime {
|
||||
}
|
||||
|
||||
/// Whether the serialized dynamic-script queue is still fetching or
|
||||
/// evaluating a script. The queue variables are global lexicals rather
|
||||
/// than window properties, so page code cannot overwrite this state.
|
||||
/// evaluating a script. The queue stays private to the bootstrap closure;
|
||||
/// Rust reads it through a hidden status function so page declarations
|
||||
/// cannot collide with or overwrite the queue itself.
|
||||
pub fn has_pending_dynamic_scripts(&mut self) -> bool {
|
||||
self.evaluate(
|
||||
"typeof __dynScriptBusy !== 'undefined' && (__dynScriptBusy || __dynScriptQueue.length > 0)",
|
||||
)
|
||||
.ok()
|
||||
.and_then(|value| value.as_bool())
|
||||
.unwrap_or(false)
|
||||
self.evaluate("globalThis.__obscura_hasPendingDynamicScripts?.() === true")
|
||||
.ok()
|
||||
.and_then(|value| value.as_bool())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Arm a hard wall-clock backstop on synchronous V8 work. A page stuck in a
|
||||
@@ -2500,6 +2499,55 @@ mod tests {
|
||||
assert_eq!(result, serde_json::json!(["A", "B"]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn page_var_declarations_do_not_collide_with_dom_interfaces() {
|
||||
let mut rt = setup_runtime("<html><body></body></html>");
|
||||
|
||||
rt.execute_script(
|
||||
"legacy-node-guard",
|
||||
"if (!window.Node) { var Node = {}; } globalThis.__legacyNodeRan = true;",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
rt.evaluate("globalThis.__legacyNodeRan").unwrap(),
|
||||
serde_json::json!(true)
|
||||
);
|
||||
|
||||
rt.execute_script(
|
||||
"page-element",
|
||||
"var Element = function PageElement() {}; globalThis.__createdTag = document.createElement('div').tagName;",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
rt.evaluate("globalThis.__createdTag").unwrap(),
|
||||
serde_json::json!("DIV")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dynamic_script_status_bridge_is_hidden_and_idle() {
|
||||
let mut rt = setup_runtime("<html><body></body></html>");
|
||||
assert!(!rt.has_pending_dynamic_scripts());
|
||||
assert_eq!(
|
||||
rt.evaluate("typeof __dynScriptBusy").unwrap(),
|
||||
serde_json::json!("undefined")
|
||||
);
|
||||
assert_eq!(
|
||||
rt.evaluate(
|
||||
"Object.getOwnPropertyNames(globalThis).includes('__obscura_hasPendingDynamicScripts')"
|
||||
)
|
||||
.unwrap(),
|
||||
serde_json::json!(false)
|
||||
);
|
||||
assert_eq!(
|
||||
rt.evaluate(
|
||||
"Reflect.ownKeys(globalThis).includes('__obscura_hasPendingDynamicScripts')"
|
||||
)
|
||||
.unwrap(),
|
||||
serde_json::json!(false)
|
||||
);
|
||||
}
|
||||
|
||||
/// Regression test for #147: a TypeError in one script must not poison
|
||||
/// the runtime so that subsequent scripts (or DOM queries) collapse to
|
||||
/// empty. The reporter saw `--dump text` return 1 byte after offside.js
|
||||
|
||||
Reference in new issue
Block a user