diff --git a/moli-benchmark/wpt-cross-current/failed-cases.txt b/moli-benchmark/wpt-cross-current/failed-cases.txt index 42b3fa988..512039f10 100644 --- a/moli-benchmark/wpt-cross-current/failed-cases.txt +++ b/moli-benchmark/wpt-cross-current/failed-cases.txt @@ -2805,7 +2805,6 @@ fullscreen/api/element-request-fullscreen-active-document.html fullscreen/api/element-request-fullscreen-not-allowed.html fullscreen/api/historical.html fullscreen/api/promises-reject.html -geolocation/non-secure-contexts.http.html gyroscope/Gyroscope-supported-by-permissions-policy.html html/browsers/browsing-the-web/history-traversal/001.html html/browsers/browsing-the-web/history-traversal/PopStateEvent.html diff --git a/moli-benchmark/wpt-cross-current/passed-cases.txt b/moli-benchmark/wpt-cross-current/passed-cases.txt index af7942745..222e42b63 100644 --- a/moli-benchmark/wpt-cross-current/passed-cases.txt +++ b/moli-benchmark/wpt-cross-current/passed-cases.txt @@ -5054,6 +5054,7 @@ focus/iframe-focuses-parent-same-site.html focus/scroll-matches-focus.html fullscreen/api/document-fullscreen-enabled-active-document.html fullscreen/rendering/fullscreen-pseudo-class-support.html +geolocation/non-secure-contexts.http.html gyroscope/Gyroscope_insecure_context.html hr-time/clamped-time-origin.html hr-time/navigation-start-post-before-unload.html diff --git a/moli-protocol/src/conn/page_state/surfaces.rs b/moli-protocol/src/conn/page_state/surfaces.rs index 2dce1723c..85ce10035 100644 --- a/moli-protocol/src/conn/page_state/surfaces.rs +++ b/moli-protocol/src/conn/page_state/surfaces.rs @@ -448,6 +448,7 @@ impl BrowserContext { Object.defineProperty(obj, key, {{ configurable: true, get: getter }}); }} catch (_error) {{}} }}; + const geolocationOverrideEnabled = {geolocation_override_enabled}; const geolocationOverride = {geolocation_override}; const navigatorOnline = {navigator_online}; const maxTouchPoints = {max_touch_points}; @@ -467,7 +468,10 @@ impl BrowserContext { const geoState = globalThis.__moliGeolocationState || {{ nextWatchId: 1, watchers: new Map(), - object: null + object: null, + installed: false, + nativeHadOwnProperty: false, + nativeOwnDescriptor: null }}; globalThis.__moliGeolocationState = geoState; const previousOverrideKey = geoState.overrideKey || null; @@ -559,12 +563,37 @@ impl BrowserContext { }} }}; }} - if (previousOverrideKey !== null && previousOverrideKey !== geoState.overrideKey) {{ + if (geolocationOverrideEnabled && previousOverrideKey !== null && previousOverrideKey !== geoState.overrideKey) {{ for (const watcher of geoState.watchers.values()) {{ deliverGeolocation(watcher.success, watcher.error); }} }} - defineGetter(navigator, 'geolocation', () => geoState.object); + if (geolocationOverrideEnabled) {{ + if (!geoState.installed) {{ + geoState.nativeHadOwnProperty = Object.prototype.hasOwnProperty.call( + navigator, + 'geolocation' + ); + geoState.nativeOwnDescriptor = Object.getOwnPropertyDescriptor( + navigator, + 'geolocation' + ) || null; + }} + defineGetter(navigator, 'geolocation', () => geoState.object); + geoState.installed = true; + }} else if (geoState.installed) {{ + if (geoState.nativeHadOwnProperty && geoState.nativeOwnDescriptor) {{ + Object.defineProperty( + navigator, + 'geolocation', + geoState.nativeOwnDescriptor + ); + }} else {{ + delete navigator.geolocation; + }} + geoState.installed = false; + geoState.watchers.clear(); + }} }} catch (_error) {{}} defineGetter(navigator, 'onLine', () => currentNavigatorOnline()); defineGetter(navigator, 'maxTouchPoints', () => maxTouchPoints); @@ -584,6 +613,7 @@ impl BrowserContext { }} catch (_error) {{}} }} }})();", + geolocation_override_enabled = geolocation_override.is_some(), geolocation_override = geolocation_override .and_then(EmulatedGeolocationOverrideState::position) .map(|position| { diff --git a/moli-protocol/src/domains/emulation/tests.rs b/moli-protocol/src/domains/emulation/tests.rs index 87f4ce3b9..9c2d9132e 100644 --- a/moli-protocol/src/domains/emulation/tests.rs +++ b/moli-protocol/src/domains/emulation/tests.rs @@ -2396,6 +2396,94 @@ async fn evaluate_geolocation_once_for_session( ctx.take_response_by_id(id)["result"]["result"]["value"].clone() } +async fn evaluate_geolocation_surface_shape(ctx: &mut TestContext, id: u64) -> serde_json::Value { + ctx.process_and_wait_for_response_async(json!({ + "id": id, + "method": "Runtime.evaluate", + "sessionId": "SID-1", + "params": { + "awaitPromise": true, + "returnByValue": true, + "expression": r#" + new Promise((resolve) => { + const geolocation = navigator.geolocation; + const finish = (outcome) => resolve(JSON.stringify({ + outcome, + navigatorOwn: Object.prototype.hasOwnProperty.call( + navigator, + "geolocation" + ), + nativePrototype: + typeof Geolocation === "function" && + Object.getPrototypeOf(geolocation) === Geolocation.prototype + })); + geolocation.getCurrentPosition( + () => finish("success"), + (error) => finish(`error:${error.code}`) + ); + }) + "# + } + })) + .await; + let response = ctx.take_response_by_id(id); + let value = response["result"]["result"]["value"] + .as_str() + .expect("geolocation surface shape should be a JSON string"); + serde_json::from_str(value).expect("geolocation surface shape should be valid JSON") +} + +#[tokio::test(flavor = "multi_thread")] +async fn geolocation_override_only_shadows_native_surface_while_enabled() { + let mut ctx = TestContext::new(); + let mut bc = BrowserContext::new("BID-1".into()); + bc.set_active_target_id("TID-1"); + bc.attach_active_session("SID-1"); + install_session_page_for_emulation_test(&mut ctx, bc, "data:text/html,geo").await; + + assert_eq!( + evaluate_geolocation_surface_shape(&mut ctx, 101).await, + json!({ + "outcome": "error:1", + "navigatorOwn": false, + "nativePrototype": true, + }) + ); + + ctx.process_async(json!({ + "id": 102, + "method": "Emulation.setGeolocationOverride", + "sessionId": "SID-1", + "params": { "latitude": 1, "longitude": 2, "accuracy": 3 } + })) + .await; + ctx.expect_result(102, json!({}), Some("SID-1")); + assert_eq!( + evaluate_geolocation_surface_shape(&mut ctx, 103).await, + json!({ + "outcome": "success", + "navigatorOwn": true, + "nativePrototype": false, + }) + ); + + ctx.process_async(json!({ + "id": 104, + "method": "Emulation.clearGeolocationOverride", + "sessionId": "SID-1" + })) + .await; + ctx.expect_result(104, json!({}), Some("SID-1")); + assert_eq!( + evaluate_geolocation_surface_shape(&mut ctx, 105).await, + json!({ + "outcome": "error:1", + "navigatorOwn": false, + "nativePrototype": true, + }) + ); +} + #[tokio::test(flavor = "multi_thread")] async fn set_geolocation_override_updates_loaded_page_geolocation_surface() { let mut ctx = TestContext::new();