From a3ec923c56732f813cadae28267dbc18a51bc4a9 Mon Sep 17 00:00:00 2001 From: Ian Renton Date: Sat, 1 Nov 2025 10:29:18 +0000 Subject: [PATCH] Improve add spot page warning and server-side validation. #71 --- server/webserver.py | 28 ++++++++++++++++++++++++---- views/webpage_add_spot.tpl | 7 +++++-- views/webpage_spots.tpl | 2 +- webassets/apidocs/openapi.yml | 2 +- webassets/css/style.css | 2 +- webassets/js/add-spot.js | 14 +++++++++++++- 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/server/webserver.py b/server/webserver.py index e617255..3a9029f 100644 --- a/server/webserver.py +++ b/server/webserver.py @@ -1,5 +1,6 @@ import json import logging +import re from datetime import datetime, timedelta from threading import Thread @@ -8,7 +9,8 @@ import pytz from bottle import run, request, response, template from core.config import MAX_SPOT_AGE, ALLOW_SPOTTING -from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS, SOFTWARE_VERSION +from core.constants import BANDS, ALL_MODES, MODE_TYPES, SIGS, CONTINENTS, SOFTWARE_VERSION, UNKNOWN_BAND +from core.lookup_helper import lookup_helper from core.prometheus_metrics_handler import page_requests_counter, get_metrics, api_requests_counter from data.spot import Spot @@ -138,13 +140,31 @@ class WebServer: json_spot = json.loads(post_data) spot = Spot(**json_spot) - # Reject if no timestamp or dx_call - if not spot.time or not spot.dx_call: + # Reject if no timestamp, frequency, dx_call or de_call + if not spot.time or not spot.dx_call or not spot.freq or not spot.de_call: response.content_type = 'application/json' response.status = 422 - return json.dumps("Error - 'time' and 'dx_call' must be provided as a minimum.", + return json.dumps("Error - 'time', 'dx_call', 'freq' and 'de_call' must be provided as a minimum.", default=serialize_everything) + # Reject invalid-looking callsigns + if not re.match(r"^[A-Za-z0-9/\-]*$", spot.dx_call): + response.content_type = 'application/json' + response.status = 422 + return json.dumps("Error - '" + spot.dx_call + "' does not look like a valid callsign.", + default=serialize_everything) + if not re.match(r"^[A-Za-z0-9/\-]*$", spot.de_call): + response.content_type = 'application/json' + response.status = 422 + return json.dumps("Error - '" + spot.de_call + "' does not look like a valid callsign.", + default=serialize_everything) + + # Reject if frequency not in a known band + if lookup_helper.infer_band_from_freq(spot.freq) == UNKNOWN_BAND: + response.content_type = 'application/json' + response.status = 422 + return json.dumps("Error - Frequency of " + str(spot.freq / 1000.0) + "kHz is not in a known band.", default=serialize_everything) + # infer missing data, and add it to our database. spot.source = "API" spot.icon = "desktop" diff --git a/views/webpage_add_spot.tpl b/views/webpage_add_spot.tpl index a53a768..8793409 100644 --- a/views/webpage_add_spot.tpl +++ b/views/webpage_add_spot.tpl @@ -1,7 +1,10 @@ % rebase('webpage_base.tpl') -