diff --git a/backend/ais_proxy.js b/backend/ais_proxy.js index f03298f..62dbff1 100644 --- a/backend/ais_proxy.js +++ b/backend/ais_proxy.js @@ -1,7 +1,12 @@ const WebSocket = require('ws'); const args = process.argv.slice(2); -const API_KEY = args[0] || '75cc39af03c9cc23c90e8a7b3c3bc2b2a507c5fb'; +const API_KEY = args[0] || process.env.AIS_API_KEY; + +if (!API_KEY) { + console.error("FATAL: AIS_API_KEY is not set. WebSocket proxy cannot start."); + process.exit(1); +} const FILTER = [ // US Aircraft Carriers and major naval groups diff --git a/backend/services/api_settings.py b/backend/services/api_settings.py index b254bda..0c587ce 100644 --- a/backend/services/api_settings.py +++ b/backend/services/api_settings.py @@ -157,6 +157,15 @@ def get_api_keys(): def update_api_key(env_key: str, new_value: str) -> bool: """Update a single key in the .env file and in the current process env.""" + valid_keys = {api["env_key"] for api in API_REGISTRY if api.get("env_key")} + if env_key not in valid_keys: + return False + + if not isinstance(new_value, str): + return False + if "\n" in new_value or "\r" in new_value: + return False + if not ENV_PATH.exists(): return False diff --git a/backend/services/geopolitics.py b/backend/services/geopolitics.py index 57b41a0..d5a4f1b 100644 --- a/backend/services/geopolitics.py +++ b/backend/services/geopolitics.py @@ -285,12 +285,17 @@ def fetch_global_military_incidents(): headlines = [_url_to_headline(u) for u in urls] f["properties"]["_urls_list"] = urls f["properties"]["_headlines_list"] = headlines + import html # Keep html as fallback if urls: - links = [f'
{h}
' for u, h in zip(urls, headlines)] + links = [] + for u, h in zip(urls, headlines): + safe_url = u if u.startswith(('http://', 'https://')) else 'about:blank' + safe_h = html.escape(h) + links.append(f'
{safe_h}
') f["properties"]["html"] = ''.join(links) else: - f["properties"]["html"] = f["properties"]["name"] + f["properties"]["html"] = html.escape(f["properties"]["name"]) f.pop("_loc_key", None) logger.info(f"GDELT multi-file parsed: {len(features)} conflict locations from {successful} files")