feat(stammbaum): parse + sanitise URL pan/zoom params (#692)
Degrade Infinity/NaN/overflow per axis and clamp zoom into bounds so a crafted ?cx/?cy/?z shared link cannot blank the SVG (Nora's review). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { clampZoom, MIN_ZOOM, MAX_ZOOM } from './panZoom';
|
||||
import {
|
||||
clampZoom,
|
||||
parsePanZoomParams,
|
||||
DEFAULT_VIEW,
|
||||
DEFAULT_ZOOM,
|
||||
MIN_ZOOM,
|
||||
MAX_ZOOM
|
||||
} from './panZoom';
|
||||
|
||||
describe('clampZoom', () => {
|
||||
it('returns the value unchanged when within range', () => {
|
||||
@@ -24,3 +31,31 @@ describe('clampZoom', () => {
|
||||
expect(MAX_ZOOM).toBe(3.0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parsePanZoomParams', () => {
|
||||
it('parses well-formed cx/cy/z params', () => {
|
||||
expect(parsePanZoomParams({ cx: '120', cy: '-40', z: '1.5' })).toEqual({
|
||||
x: 120,
|
||||
y: -40,
|
||||
z: 1.5
|
||||
});
|
||||
});
|
||||
|
||||
it('falls back to DEFAULT_VIEW when params are absent', () => {
|
||||
expect(parsePanZoomParams({})).toEqual(DEFAULT_VIEW);
|
||||
expect(DEFAULT_VIEW).toEqual({ x: 0, y: 0, z: DEFAULT_ZOOM });
|
||||
});
|
||||
|
||||
it('rejects Infinity and NaN, degrading each axis to its default (Nora #692)', () => {
|
||||
expect(parsePanZoomParams({ z: 'Infinity' }).z).toBe(DEFAULT_ZOOM);
|
||||
expect(parsePanZoomParams({ z: 'NaN' }).z).toBe(DEFAULT_ZOOM);
|
||||
expect(parsePanZoomParams({ cx: 'NaN', cy: 'Infinity' })).toEqual(DEFAULT_VIEW);
|
||||
expect(parsePanZoomParams({ cx: '1e500' }).x).toBe(0);
|
||||
});
|
||||
|
||||
it('clamps an out-of-range zoom into the supported bounds', () => {
|
||||
expect(parsePanZoomParams({ z: '99' }).z).toBe(MAX_ZOOM);
|
||||
expect(parsePanZoomParams({ z: '0.01' }).z).toBe(MIN_ZOOM);
|
||||
expect(parsePanZoomParams({ z: '-3' }).z).toBe(MIN_ZOOM);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user