Skip to content

Commit

Permalink
Validate URL hash (#5241)
Browse files Browse the repository at this point in the history
* Validate hash location values

* Add tests for invalid hash locations

* Add changelog record

* Simplify validation code

* Rename loc to hash

* Split tests, create _isValidHash tests

* Rename to _hasValidHash

* Split isValidHash tests, pass hash as argument
  • Loading branch information
mattesCZ authored Dec 19, 2024
1 parent 6f10e5e commit 0bec4ef
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 15 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- Fix geometry artifacts when globe terrain is zoomed out too much ([#5232](https://github.com/maplibre/maplibre-gl-js/pull/5232))
- Fix center being incorrectly constrained when using globe ([#5186](https://github.com/maplibre/maplibre-gl-js/pull/5186))
- Fix atmosphere improperly blending into the background ([#5235](https://github.com/maplibre/maplibre-gl-js/pull/5235))
- Fix parsing wrong hash location ([#5131](https://github.com/maplibre/maplibre-gl-js/pull/5131))
- _...Add new stuff here..._

## 5.0.0-pre.10
Expand Down
53 changes: 49 additions & 4 deletions src/ui/hash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,6 @@ describe('hash', () => {
window.location.hash = '#4/wrongly/formed/hash';

expect(hash._onHashChange()).toBeFalsy();

window.location.hash = '#map=10/3.00/-1.00&foo=bar';

expect(hash._onHashChange()).toBeFalsy();
});

test('#_onHashChange empty', () => {
Expand Down Expand Up @@ -329,6 +325,55 @@ describe('hash', () => {
expect(window.location.hash).toBe('#baz&foo=bar');
});

describe('#_isValidHash', () => {
let hash: Hash

beforeEach(() => {
hash = createHash()
.addTo(map);
})

test('validate correct hash', () => {
window.location.hash = '#10/3.00/-1.00';

expect(hash._isValidHash(hash._getCurrentHash())).toBeTruthy();

window.location.hash = '#5/1.00/0.50/30/60';

expect(hash._isValidHash(hash._getCurrentHash())).toBeTruthy();
});

test('invalidate hash with string values', () => {
window.location.hash = '#4/wrongly/formed/hash';

expect(hash._isValidHash(hash._getCurrentHash())).toBeFalsy();
});

test('invalidate hash that is named, but should not be', () => {
window.location.hash = '#map=10/3.00/-1.00&foo=bar';

expect(hash._isValidHash(hash._getCurrentHash())).toBeFalsy();
});

test('invalidate hash, zoom greater than maxZoom', () => {
window.location.hash = '#24/3.00/-1.00';

expect(hash._isValidHash(hash._getCurrentHash())).toBeFalsy();
});

test('invalidate hash, latitude out of range', () => {
window.location.hash = '#10/100.00/-1.00';

expect(hash._isValidHash(hash._getCurrentHash())).toBeFalsy();
});

test('invalidate hash, pitch greater than maxPitch', () => {
window.location.hash = '#10/3.00/-1.00/30/90';

expect(hash._isValidHash(hash._getCurrentHash())).toBeFalsy();
});
});

test('initialize http://localhost/#', () => {
window.location.href = 'http://localhost/#';
createHash().addTo(map);
Expand Down
47 changes: 36 additions & 11 deletions src/ui/hash.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {throttle} from '../util/throttle';
import {LngLat} from '../geo/lng_lat';

import type {Map} from './map';

Expand Down Expand Up @@ -102,18 +103,21 @@ export class Hash {
};

_onHashChange = () => {
const loc = this._getCurrentHash();
if (loc.length >= 3 && !loc.some(v => isNaN(v))) {
const bearing = this._map.dragRotate.isEnabled() && this._map.touchZoomRotate.isEnabled() ? +(loc[3] || 0) : this._map.getBearing();
this._map.jumpTo({
center: [+loc[2], +loc[1]],
zoom: +loc[0],
bearing,
pitch: +(loc[4] || 0)
});
return true;
const hash = this._getCurrentHash();

if (!this._isValidHash(hash)) {
return false;
}
return false;

const bearing = this._map.dragRotate.isEnabled() && this._map.touchZoomRotate.isEnabled() ? +(hash[3] || 0) : this._map.getBearing();
this._map.jumpTo({
center: [+hash[2], +hash[1]],
zoom: +hash[0],
bearing,
pitch: +(hash[4] || 0)
});

return true;
};

_updateHashUnthrottled = () => {
Expand Down Expand Up @@ -150,4 +154,25 @@ export class Hash {
* Mobile Safari doesn't allow updating the hash more than 100 times per 30 seconds.
*/
_updateHash: () => ReturnType<typeof setTimeout> = throttle(this._updateHashUnthrottled, 30 * 1000 / 100);

_isValidHash(hash: number[]) {
if (hash.length < 3 || hash.some(isNaN)) {
return false;
}

// LngLat() throws error if latitude is out of range, and it's valid if it succeeds.
try {
new LngLat(+hash[2], +hash[1]);
} catch {
return false;
}

const zoom = +hash[0];
const bearing = +(hash[3] || 0);
const pitch = +(hash[4] || 0);

return zoom >= this._map.getMinZoom() && zoom <= this._map.getMaxZoom() &&
bearing >= 0 && bearing <= 180 &&
pitch >= this._map.getMinPitch() && pitch <= this._map.getMaxPitch();
};
}

0 comments on commit 0bec4ef

Please sign in to comment.