From 8f8f837cb70f263bd8e7f90eca18a167e782b5e0 Mon Sep 17 00:00:00 2001 From: accius Date: Tue, 3 Feb 2026 17:33:48 -0500 Subject: [PATCH 1/3] Update useWSJTX.js --- src/hooks/useWSJTX.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hooks/useWSJTX.js b/src/hooks/useWSJTX.js index 6523a77..eb3709a 100644 --- a/src/hooks/useWSJTX.js +++ b/src/hooks/useWSJTX.js @@ -14,20 +14,20 @@ const API_URL = '/api/wsjtx'; const DECODES_URL = '/api/wsjtx/decodes'; // Generate or retrieve persistent session ID +// NOTE: Kept short (8 chars) intentionally — long UUIDs in query strings +// trigger false positives in Bitdefender and similar security software function getSessionId() { const KEY = 'ohc-wsjtx-session'; + const generate = () => Math.random().toString(36).substring(2, 10); try { let id = localStorage.getItem(KEY); - if (id && id.length >= 16) return id; - // Generate a random ID - id = (typeof crypto !== 'undefined' && crypto.randomUUID) - ? crypto.randomUUID() - : Math.random().toString(36).substring(2) + Date.now().toString(36) + Math.random().toString(36).substring(2); + if (id && id.length >= 8) return id; + id = generate(); localStorage.setItem(KEY, id); return id; } catch { // Fallback for privacy browsers that block localStorage - return Math.random().toString(36).substring(2) + Date.now().toString(36) + Math.random().toString(36).substring(2); + return generate(); } } From ae5f89ffb38aea37b77747d6a71bd74117cd3e88 Mon Sep 17 00:00:00 2001 From: accius Date: Tue, 3 Feb 2026 17:37:05 -0500 Subject: [PATCH 2/3] Update setup-pi.sh --- scripts/setup-pi.sh | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/scripts/setup-pi.sh b/scripts/setup-pi.sh index d3ab463..ee79218 100644 --- a/scripts/setup-pi.sh +++ b/scripts/setup-pi.sh @@ -225,6 +225,9 @@ else CHROME_CMD="chromium-browser" fi +# Trap Ctrl+Q to exit kiosk cleanly +trap 'pkill -f "chromium.*kiosk"; exit 0' SIGTERM SIGINT + $CHROME_CMD \ --kiosk \ --noerrdialogs \ @@ -237,7 +240,17 @@ $CHROME_CMD \ --overscroll-history-navigation=0 \ --disable-pinch \ --incognito \ - http://localhost:3000 + http://localhost:3000 & + +CHROME_PID=$! + +echo "OpenHamClock kiosk running (PID: $CHROME_PID)" +echo "Exit methods:" +echo " - Alt+F4 (close Chromium)" +echo " - Ctrl+Alt+T (open terminal, then: pkill -f kiosk)" +echo " - SSH in and run: pkill -f kiosk.sh" + +wait $CHROME_PID EOF chmod +x "$INSTALL_DIR/kiosk.sh" @@ -339,7 +352,14 @@ print_summary() { if [ "$KIOSK_MODE" = true ]; then echo -e " ${GREEN}Kiosk Mode:${NC} Enabled" echo " OpenHamClock will auto-start on boot in fullscreen" - echo " To disable: rm ~/.config/autostart/openhamclock-kiosk.desktop" + echo "" + echo -e " ${YELLOW}Exit kiosk:${NC}" + echo " Alt+F4 Close Chromium" + echo " Ctrl+Alt+T Open terminal (then: pkill -f kiosk)" + echo " SSH: pkill -f kiosk.sh" + echo "" + echo -e " ${YELLOW}Disable auto-start:${NC}" + echo " rm ~/.config/autostart/openhamclock-kiosk.desktop" echo "" fi From 17709ff0ec9f2a4505bfaedfe111c098ebb99909 Mon Sep 17 00:00:00 2001 From: accius Date: Tue, 3 Feb 2026 17:43:24 -0500 Subject: [PATCH 3/3] dx proxy url --- .env.example | 7 +++++++ server.js | 4 ++-- src/hooks/useDXCluster.js | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index e3495bf..f23ac27 100644 --- a/.env.example +++ b/.env.example @@ -67,6 +67,13 @@ LAYOUT=modern # Only uncomment if you have your own proxy running # DXSPIDER_PROXY_URL=https://your-dxspider-proxy.com +# DX Cluster source: auto | proxy | hamqth | dxspider +# auto = tries proxy first, then HamQTH, then direct telnet +# proxy = use DX Spider Proxy (set DXSPIDER_PROXY_URL above) +# hamqth = HamQTH CSV feed (HTTP, works everywhere) +# dxspider = direct telnet to DX Spider nodes (works locally/Pi) +# DX_CLUSTER_SOURCE=auto + # OpenWeatherMap API key (for local weather display) # Get a free key at https://openweathermap.org/api # OPENWEATHER_API_KEY=your_api_key_here diff --git a/server.js b/server.js index e335222..c53244b 100644 --- a/server.js +++ b/server.js @@ -148,7 +148,7 @@ const CONFIG = { // DX Cluster settings spotRetentionMinutes: parseInt(process.env.SPOT_RETENTION_MINUTES) || jsonConfig.dxCluster?.spotRetentionMinutes || 30, - dxClusterSource: jsonConfig.dxCluster?.source || 'auto', + dxClusterSource: process.env.DX_CLUSTER_SOURCE || jsonConfig.dxCluster?.source || 'auto', // API keys (don't expose to frontend) _openWeatherApiKey: process.env.OPENWEATHER_API_KEY || '', @@ -983,7 +983,7 @@ let dxSpiderCache = { spots: [], timestamp: 0 }; const DXSPIDER_CACHE_TTL = 90000; // 90 seconds cache - reduces reconnection frequency app.get('/api/dxcluster/spots', async (req, res) => { - const source = (req.query.source || 'auto').toLowerCase(); + const source = (req.query.source || CONFIG.dxClusterSource || 'auto').toLowerCase(); // Helper function for HamQTH (HTTP-based, works everywhere) async function fetchHamQTH() { diff --git a/src/hooks/useDXCluster.js b/src/hooks/useDXCluster.js index 83a7303..571f1bb 100644 --- a/src/hooks/useDXCluster.js +++ b/src/hooks/useDXCluster.js @@ -89,7 +89,7 @@ export const useDXCluster = (source = 'auto', filters = {}) => { useEffect(() => { const fetchData = async () => { try { - const response = await fetch('/api/dxcluster/spots'); + const response = await fetch(`/api/dxcluster/spots?source=${encodeURIComponent(source)}`); if (response.ok) { const newSpots = await response.json();