fix: Escapes location search results

Nominatim results were inserted via innerHTML and loaded as a JSONP script
with an unencoded query. Results are now fetched as JSON, the query is URL
encoded, text is escaped and coordinates must be numeric.
This commit is contained in:
Stefan Bethke 2026-11-15 11:36:49 +01:00
commit 6a64083175

View file

@ -37,15 +37,32 @@ function searchLocation(maxResults) {
searchLimit = 11; searchLimit = 11;
} }
var searchScript = document.createElement('script'); var searchUrl = 'https://nominatim.openstreetmap.org/search?q=' + encodeURIComponent(searchString)
searchScript.src = 'https://nominatim.openstreetmap.org/search.php?q=' + searchString + '&format=json&json_callback=parseResult&limit=' + searchLimit; + '&format=json&limit=' + encodeURIComponent(searchLimit);
document.body.appendChild(searchScript); fetch(searchUrl)
.then(function(response) { return response.json(); })
.then(parseResult)
.catch(function() { parseResult([]); });
} }
} }
// Escape a value for use in HTML text and in double-quoted attributes.
function escapeSearchHtml(value) {
return String(value)
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function parseResult(response) { function parseResult(response) {
var searchResultDivs = ''; var searchResultDivs = '';
if (!Array.isArray(response)) {
response = [];
}
if (response.length == searchLimit) { if (response.length == searchLimit) {
var lastResultIndex = searchLimit - 1; var lastResultIndex = searchLimit - 1;
var nextSearchLimit = searchLimit + 10; var nextSearchLimit = searchLimit + 10;
@ -67,10 +84,15 @@ function parseResult(response) {
// Show the current 10 search results. // Show the current 10 search results.
for (var i=searchLimit-11; i<lastResultIndex; i++) { for (var i=searchLimit-11; i<lastResultIndex; i++) {
searchResult = response[i]; searchResult = response[i];
var lat = Number(searchResult.lat);
var lon = Number(searchResult.lon);
if (!isFinite(lat) || !isFinite(lon)) {
continue;
}
searchResultDivs += searchResultDivs +=
'<div class="search-result" onClick="gotoLocation(' + searchResult.lat + ', ' + searchResult.lon + ');return false;">' + '<div class="search-result" onClick="gotoLocation(' + lat + ', ' + lon + ');return false;">' +
'<div class="text-medium">' + searchResult.class + ' / ' + searchResult.type + '</div>' + '<div class="text-medium">' + escapeSearchHtml(searchResult.class) + ' / ' + escapeSearchHtml(searchResult.type) + '</div>' +
'<div>' + searchResult.display_name + '</div>' + '<div>' + escapeSearchHtml(searchResult.display_name) + '</div>' +
'</div>'; '</div>';
} }