mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
fix(terrain): reject out-of-range points at the proxy boundary
Rebased onto current main with review follow-ups folded in. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
0265ad4c19
commit
19fcc00b3e
5 files changed
+40
-1
No files matched your search
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
- Director timeline seeks cross the dateline along the short longitude arc.
|
- Director timeline seeks cross the dateline along the short longitude arc.
|
||||||
|
|
||||||
|
- The terrain proxy refuses out-of-range WGS84 coordinates before upstream resolution for every client.
|
||||||
|
|
||||||
- Treat explicitly current, complete empty vessel coverage as a successful update,
|
- Treat explicitly current, complete empty vessel coverage as a successful update,
|
||||||
clearing obsolete contacts while retaining stale or incomplete snapshots.
|
clearing obsolete contacts while retaining stale or incomplete snapshots.
|
||||||
|
|
||||||
|
|||||||
@@ -1192,6 +1192,10 @@ The browser layers and their rendering remain in their existing modules.
|
|||||||
|
|
||||||
## Terrain height cache bound
|
## Terrain height cache bound
|
||||||
|
|
||||||
|
The terrain proxy parser rejects finite longitudes outside [-180, 180] and
|
||||||
|
latitudes outside [-90, 90] for every client before upstream resolution. One
|
||||||
|
out-of-range point rejects the whole batch; inclusive WGS84 bounds remain valid.
|
||||||
|
|
||||||
The client terrain-height resolver's in-memory cache is bounded at 20 000
|
The client terrain-height resolver's in-memory cache is bounded at 20 000
|
||||||
entries (`DEFAULT_MAX_CACHE_ENTRIES`, overridable per instance through
|
entries (`DEFAULT_MAX_CACHE_ENTRIES`, overridable per instance through
|
||||||
`createTerrainHeights({ maxCacheEntries })`). Coordinate rounding makes repeated
|
`createTerrainHeights({ maxCacheEntries })`). Coordinate rounding makes repeated
|
||||||
|
|||||||
@@ -35,7 +35,13 @@ export function parseTerrainPoints(raw) {
|
|||||||
if (parts.length !== 2) return null;
|
if (parts.length !== 2) return null;
|
||||||
const lon = Number(parts[0]);
|
const lon = Number(parts[0]);
|
||||||
const lat = Number(parts[1]);
|
const lat = Number(parts[1]);
|
||||||
if (!Number.isFinite(lon) || !Number.isFinite(lat)) return null;
|
if (
|
||||||
|
!Number.isFinite(lon) ||
|
||||||
|
!Number.isFinite(lat) ||
|
||||||
|
Math.abs(lon) > 180 ||
|
||||||
|
Math.abs(lat) > 90
|
||||||
|
)
|
||||||
|
return null;
|
||||||
points.push([lon, lat]);
|
points.push([lon, lat]);
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { test } from 'node:test';
|
import { test } from 'node:test';
|
||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import {
|
import {
|
||||||
|
parseTerrainPoints,
|
||||||
fetchTerrainChunkWithRetry,
|
fetchTerrainChunkWithRetry,
|
||||||
resolveTerrainHeightRequest,
|
resolveTerrainHeightRequest,
|
||||||
terrainPointKey,
|
terrainPointKey,
|
||||||
@@ -227,3 +228,13 @@ test('malformed height objects remain refresh failures, not absent readings', as
|
|||||||
assert.equal(response.cacheChanged, false);
|
assert.equal(response.cacheChanged, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('terrain parser rejects out-of-range WGS84 points and accepts inclusive bounds', () => {
|
||||||
|
for (const value of ['181,0', '-181,0', '0,91', '0,-91', '1,2;0,91'])
|
||||||
|
assert.equal(parseTerrainPoints(value), null, value);
|
||||||
|
assert.deepEqual(parseTerrainPoints('-180,-90;180,90;0,0'), [
|
||||||
|
[-180, -90],
|
||||||
|
[180, 90],
|
||||||
|
[0, 0],
|
||||||
|
]);
|
||||||
|
});
|
||||||
@@ -2,6 +2,7 @@ import test from 'node:test';
|
|||||||
import assert from 'node:assert/strict';
|
import assert from 'node:assert/strict';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
import { parseTerrainPoints } from './data/terrainHeightsProxy.js';
|
||||||
import { readResponseTextCapped, coalesceProxyRequest } from './sources/httpBody.js';
|
import { readResponseTextCapped, coalesceProxyRequest } from './sources/httpBody.js';
|
||||||
|
|
||||||
const source = ['local.js', 'common/http.js', 'aircraft/enrichment.js', 'terrain.js', 'space/celestrak.js', 'space/launch-library.js', '../../src/data/spaceProviderRequests.js']
|
const source = ['local.js', 'common/http.js', 'aircraft/enrichment.js', 'terrain.js', 'space/celestrak.js', 'space/launch-library.js', '../../src/data/spaceProviderRequests.js']
|
||||||
@@ -172,3 +173,18 @@ test('ADSBDB retains validation and missing-aircraft semantics', async () => {
|
|||||||
assert.equal(absent.status, 200);
|
assert.equal(absent.status, 200);
|
||||||
assert.deepEqual(JSON.parse(absent.body), { found: false });
|
assert.deepEqual(JSON.parse(absent.body), { found: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (const preview of [false, true]) {
|
||||||
|
test(`terrain server rejects out-of-range points before upstream resolution in ${preview ? 'preview' : 'development'}`, async () => {
|
||||||
|
let calls = 0;
|
||||||
|
const app = fixture('terrainHeightsProxy', { parseTerrainPoints,
|
||||||
|
resolveTerrainHeightRequest: async () => { calls++; return { status: 200, body: { results: [] } }; },
|
||||||
|
}, preview);
|
||||||
|
for (const points of ['181,0', '-181,0', '0,91', '0,-91', '1,2;0,91']) {
|
||||||
|
assert.equal((await app.request('/?points=' + encodeURIComponent(points))).status, 400);
|
||||||
|
}
|
||||||
|
assert.equal(calls, 0);
|
||||||
|
assert.equal((await app.request('/?points=-180,-90;180,90')).status, 200);
|
||||||
|
assert.equal(calls, 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in new issue
Block a user