From 1e3170cc916cc1232d5c0639dc51f56692a6a8d3 Mon Sep 17 00:00:00 2001 From: Mohd Kaif Ansari <155880242+techykaif@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:59:57 +0530 Subject: [PATCH 1/2] fix(map): reject out-of-range share viewport values --- src/lib/share.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/lib/share.ts b/src/lib/share.ts index 98ac1d3..0ffa268 100644 --- a/src/lib/share.ts +++ b/src/lib/share.ts @@ -21,19 +21,22 @@ function parseList(raw: string | null, allowed: Set): string[] { .filter((value) => allowed.has(value)); } -function parseNumber(raw: string | null): number | null { +function parseNumber(raw: string | null, min?: number, max?: number): number | null { if (raw === null || raw.trim() === "") return null; const value = Number(raw); - return Number.isFinite(value) ? value : null; + if (!Number.isFinite(value)) return null; + if (min !== undefined && value < min) return null; + if (max !== undefined && value > max) return null; + return value; } /** Read filter, focused-pin, and viewport state out of a URL query string. */ export function parseMapState(search: string): MapShareState { const params = new URLSearchParams(search); const city = params.get("city")?.trim() || null; - const lat = parseNumber(params.get("lat")); - const lng = parseNumber(params.get("lng")); - const zoom = parseNumber(params.get("zoom")); + const lat = parseNumber(params.get("lat"), -90, 90); + const lng = parseNumber(params.get("lng"), -180, 180); + const zoom = parseNumber(params.get("zoom"), 0, 20); // A viewport only makes sense with both coordinates; otherwise ignore all three. const hasViewport = lat !== null && lng !== null; return { From 8cd6b06aac89729cdf1569d8af08fd249ab6e384 Mon Sep 17 00:00:00 2001 From: Mohd Kaif Ansari <155880242+techykaif@users.noreply.github.com> Date: Fri, 21 Aug 2026 23:00:08 +0530 Subject: [PATCH 2/2] test(map): cover share viewport bounds --- src/lib/share.test.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/lib/share.test.ts b/src/lib/share.test.ts index 3937dd3..ba5f54c 100644 --- a/src/lib/share.test.ts +++ b/src/lib/share.test.ts @@ -75,6 +75,30 @@ describe("mapStateToSearch / parseMapState round-trip", () => { expect(bogus.lng).toBeNull(); }); + it("rejects out-of-range viewport coordinates and zoom", () => { + expect(parseMapState("?lat=90&lng=180&zoom=20")).toMatchObject({ + lat: 90, + lng: 180, + zoom: 20, + }); + + expect(parseMapState("?lat=91&lng=180&zoom=20")).toMatchObject({ + lat: null, + lng: null, + zoom: null, + }); + expect(parseMapState("?lat=-90&lng=-181&zoom=20")).toMatchObject({ + lat: null, + lng: null, + zoom: null, + }); + expect(parseMapState("?lat=0&lng=0&zoom=21")).toMatchObject({ + lat: 0, + lng: 0, + zoom: null, + }); + }); + it("omits the zoom when it is null", () => { const search = mapStateToSearch({ ...emptyState, lat: 19.076, lng: 72.8777 }); expect(search).toBe("?lat=19.076&lng=72.8777");