mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(share): reject inherited style keys during restore
This commit is contained in:
1 parent
de2138e84c
commit
d49877ad2e
6 files changed
+50
-2
No files matched your search
@@ -1,5 +1,10 @@
|
|||||||
# God's Eye View Current State
|
# God's Eye View Current State
|
||||||
|
|
||||||
|
Share links and structured views accept only own keys in their style registries.
|
||||||
|
Inherited names such as `constructor` and `__proto__` fall back to the existing
|
||||||
|
normal/null defaults without interrupting other restored fields. Programmatic
|
||||||
|
visual-style calls ignore unknown or non-string values before mutating state.
|
||||||
|
|
||||||
Shared distance checks use `src/geoDistance.js` with `{ lat, lon }` points and
|
Shared distance checks use `src/geoDistance.js` with `{ lat, lon }` points and
|
||||||
the IUGG mean spherical Earth radius, 6371.0088 km. `greatCircleKm` is
|
the IUGG mean spherical Earth radius, 6371.0088 km. `greatCircleKm` is
|
||||||
canonical; `greatCircleMeters` is its exact metre conversion. Missing,
|
canonical; `greatCircleMeters` is its exact metre conversion. Missing,
|
||||||
|
|||||||
@@ -778,3 +778,20 @@ test('visual input listeners are revoked before asynchronous UI teardown', () =>
|
|||||||
assert.match(VisualSettings.prototype.stop.toString(), /this\._styleParameters\?\.destroy\(\)/);
|
assert.match(VisualSettings.prototype.stop.toString(), /this\._styleParameters\?\.destroy\(\)/);
|
||||||
assert.match(VisualSettings.prototype.stop.toString(), /this\._visualEffects\.stop\(\)/);
|
assert.match(VisualSettings.prototype.stop.toString(), /this\._visualEffects\.stop\(\)/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('share restore rejects inherited styles while continuing later fields', () => {
|
||||||
|
for (const style of ['constructor', '__proto__', 'toString', 'hasOwnProperty', 'unknown']) {
|
||||||
|
const restored = makeManager(`#lat=10&lon=20&style=${style}&cr=1`).parseInitialHash();
|
||||||
|
assert.equal(restored.style, 'normal');
|
||||||
|
assert.equal(restored.celestialRing, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('programmatic invalid styles are ignored before changing visual state', () => {
|
||||||
|
const target = { activeStyle: 'normal' };
|
||||||
|
for (const value of ['constructor', '__proto__', 'toString', 'hasOwnProperty', 'unknown', {}, null, () => {}]) {
|
||||||
|
assert.doesNotThrow(() => VisualSettings.prototype.setStyle.call(target, value));
|
||||||
|
assert.equal(target.activeStyle, 'normal');
|
||||||
|
}
|
||||||
|
});
|
||||||
+3
-1
@@ -175,7 +175,9 @@ export class ShareLinkManager {
|
|||||||
parseOr(params.get('dd'), 50),
|
parseOr(params.get('dd'), 50),
|
||||||
50,
|
50,
|
||||||
);
|
);
|
||||||
const style = URL_TO_STYLE[params.get('style')] || 'normal';
|
const style = Object.hasOwn(URL_TO_STYLE, params.get('style'))
|
||||||
|
? URL_TO_STYLE[params.get('style')]
|
||||||
|
: 'normal';
|
||||||
const decodedLayerState = decodeLayerStateParams(params);
|
const decodedLayerState = decodeLayerStateParams(params);
|
||||||
const state = {
|
const state = {
|
||||||
lat,
|
lat,
|
||||||
|
|||||||
@@ -1539,6 +1539,11 @@ export class VisualSettings {
|
|||||||
preserveCyberRestore = false,
|
preserveCyberRestore = false,
|
||||||
} = {},
|
} = {},
|
||||||
) {
|
) {
|
||||||
|
if (
|
||||||
|
typeof styleName !== 'string' ||
|
||||||
|
(styleName !== 'normal' && !Object.hasOwn(STYLES, styleName))
|
||||||
|
)
|
||||||
|
return;
|
||||||
const { setDetectionStyle } = this.services;
|
const { setDetectionStyle } = this.services;
|
||||||
if (!restore) this.shareLinkManager?.claimRestoreLane?.('visual');
|
if (!restore) this.shareLinkManager?.claimRestoreLane?.('visual');
|
||||||
if (this.hud.getVariant() === 'cyber') {
|
if (this.hud.getVariant() === 'cyber') {
|
||||||
|
|||||||
+3
-1
@@ -370,7 +370,9 @@ export function viewFromParams(params) {
|
|||||||
pitch_deg: number('pitch'),
|
pitch_deg: number('pitch'),
|
||||||
},
|
},
|
||||||
layers: state?.enabledLayerIds ?? [],
|
layers: state?.enabledLayerIds ?? [],
|
||||||
style: STYLES_BY_URL_NAME[params.get('style')] ?? null,
|
style: Object.hasOwn(STYLES_BY_URL_NAME, params.get('style'))
|
||||||
|
? STYLES_BY_URL_NAME[params.get('style')]
|
||||||
|
: null,
|
||||||
map: VIEW_MAPS.includes(map) ? map : null,
|
map: VIEW_MAPS.includes(map) ? map : null,
|
||||||
follow,
|
follow,
|
||||||
annotations: annotationsFromParams(params),
|
annotations: annotationsFromParams(params),
|
||||||
|
|||||||
@@ -126,3 +126,20 @@ test('annotations travel in the link, keeping only what the app draws', async ()
|
|||||||
// Too long for a link: the view keeps them, the link leaves them out.
|
// Too long for a link: the view keeps them, the link leaves them out.
|
||||||
assert.equal(viewToParams(many).has('an'), false);
|
assert.equal(viewToParams(many).has('an'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('inherited and unknown style keys do not corrupt a restored view', () => {
|
||||||
|
for (const style of [
|
||||||
|
'constructor',
|
||||||
|
'__proto__',
|
||||||
|
'toString',
|
||||||
|
'hasOwnProperty',
|
||||||
|
'unknown',
|
||||||
|
]) {
|
||||||
|
const view = viewFromParams(
|
||||||
|
new URLSearchParams({ lat: '10', lon: '20', style, map: 'osm' }),
|
||||||
|
);
|
||||||
|
assert.equal(view.style, null);
|
||||||
|
assert.equal(view.map, 'osm');
|
||||||
|
assert.equal(view.camera.lat, 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in new issue
Block a user