Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ <h1>Pothole Dodger</h1>
</div>

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="js/sanitize.js"></script>
<script src="js/geocode.js"></script>
<script src="js/routing.js"></script>
<script src="js/hazards.js"></script>
Expand Down
6 changes: 3 additions & 3 deletions web/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function attachAutocomplete(inputEl) {

inputEl.addEventListener('input', function () {
clearTimeout(debounceTimer);
const query = inputEl.value.trim();
const query = sanitizeInput(inputEl.value);

if (query.length < 3) {
hideList();
Expand Down Expand Up @@ -72,8 +72,8 @@ document.addEventListener('DOMContentLoaded', function () {
}

async function run() {
const origin = document.getElementById('origin').value.trim();
const destination = document.getElementById('destination').value.trim();
const origin = sanitizeInput(document.getElementById('origin').value);
const destination = sanitizeInput(document.getElementById('destination').value);

if (!origin || !destination) {
setStatus('Please enter both an origin and destination.');
Expand Down
35 changes: 27 additions & 8 deletions web/js/hazards.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// hazards.js — loads hazard data and filters it to streets matching the route

const ABBR_MAP = [
const STREET_TYPE_ABBRS = [
[/\bSt\b/g, 'Street'],
[/\bAve\b/g, 'Avenue'],
[/\bBlvd\b/g, 'Boulevard'],
Expand All @@ -9,21 +9,40 @@ const ABBR_MAP = [
[/\bPkwy\b/g, 'Parkway'],
[/\bLn\b/g, 'Lane'],
[/\bCt\b/g, 'Court'],
[/\bW\b/g, 'West'],
[/\bE\b/g, 'East'],
[/\bN\b/g, 'North'],
[/\bS\b/g, 'South'],
];

const DIRECTIONAL_EXPAND = {
W: 'West',
E: 'East',
N: 'North',
S: 'South',
};

function normalizeStreet(str) {
let s = str;
for (const [pattern, replacement] of ABBR_MAP) {

// 1. Strip trailing ZIP code (5 digits, optionally preceded by comma and/or space)
s = s.replace(/[,\s]+\d{5}\s*$/, '');

// 2. Expand street type abbreviations
for (const [pattern, replacement] of STREET_TYPE_ABBRS) {
s = s.replace(pattern, replacement);
}
// Strip leading house numbers (including fractional like "8 1/2") but preserve
// street numbers that are part of the name (e.g. "1st Avenue")

// 3. Expand directionals at start of string (prefix directional)
s = s.replace(/^(W|E|N|S)\b\s*/, (_, d) => DIRECTIONAL_EXPAND[d] + ' ');

// 4. Expand directionals at end of string (suffix directional)
s = s.replace(/\s+(W|E|N|S)$/, (_, d) => ' ' + DIRECTIONAL_EXPAND[d]);

// 5. Strip leading house numbers (including fractional like "8 1/2")
s = s.replace(/^\d+(\s+\d+\/\d+)?\s+/, '');

// 6. Strip remaining punctuation
s = s.replace(/[^a-zA-Z0-9\s]/g, '');

// 7. Collapse whitespace and trim, lowercase
s = s.replace(/\s{2,}/g, ' ');
return s.trim().toLowerCase();
}

Expand Down
28 changes: 28 additions & 0 deletions web/js/sanitize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// sanitize.js — sanitizes raw user input before geocoding or internal matching

/**
* Sanitizes a raw user-supplied address string for use as a Nominatim query.
*
* - Trims leading/trailing whitespace
* - Collapses multiple spaces into one
* - Strips parenthetical context (e.g. "(near the park)")
* - Removes characters that break queries: # " ' . ; : ! ? @ ^ * [ ] { } | \ ~ ` = + < > % & _
* - Preserves commas (Nominatim field separators), hyphens (address ranges), slashes (fractions)
* - Does NOT expand abbreviations (leave that to normalizeStreet in hazards.js)
* - Does NOT strip ZIP codes (Nominatim handles them; strip only inside normalizeStreet)
* - Must never be called on coordinate (lat/lng) values
*
* @param {string} str Raw input string
* @returns {string} Sanitized string safe for Nominatim queries
*/
function sanitizeInput(str) {
if (typeof str !== 'string') return '';
let s = str;
// Remove parenthetical content
s = s.replace(/\([^)]*\)/g, '');
// Keep: letters, digits, spaces, commas, hyphens, forward slashes
s = s.replace(/[^a-zA-Z0-9\s,\-\/]/g, '');
// Collapse multiple spaces
s = s.replace(/\s{2,}/g, ' ');
return s.trim();
}
Loading