mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-06-15 09:28:37 +00:00
fix: address five valid review findings; skip two
Fixed:
- march-madness/requirements.txt: Pillow>=10.3.0 (patches CVE-2024-28219;
10.3.0 is the actual fix version — reviewer cited 12.2.0 but that risks
breaking API changes without test coverage)
- wifi_monitor_daemon.py: add missing `import subprocess`; subprocess.run
and CalledProcessError would NameError at runtime on the NM restart path
- wifi_manager.py: validate ap_idle_timeout_minutes before arithmetic —
coerce to int, clamp 1–1440, fall back to 15 on bad config values
- wifi_manager.py: call _remove_nm_dnsmasq_captive_conf() on all three
rollback paths in _enable_ap_mode_nmcli_hotspot() and in the top-level
except block so stale dnsmasq drop-ins are never left behind
- api_v3.py: fix wrong_password prefix strip — removeprefix("wrong_password:")
then lstrip() handles both "wrong_password: msg" and "wrong_password:msg"
- plugins_manager.js: add .catch() to loadInstalledPlugins().then() to
surface failures instead of silently dropping unhandled rejections
Skipped:
- WiFiManager AP state persistence: architectural overhaul; _is_ap_mode_active()
already derives from live system state, not in-memory variables
- Absolute subprocess paths in api_v3.py: paths vary by distro (/usr/bin vs
/bin); web service has a normal PATH; sudoers already use resolved paths
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
requests>=2.28.0
|
requests>=2.28.0
|
||||||
Pillow>=10.2.0
|
Pillow>=10.3.0
|
||||||
pytz>=2022.1
|
pytz>=2022.1
|
||||||
numpy>=1.24.0
|
numpy>=1.24.0
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import sys
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import signal
|
import signal
|
||||||
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Add project root to path (parent of scripts/utils/)
|
# Add project root to path (parent of scripts/utils/)
|
||||||
|
|||||||
@@ -2074,6 +2074,7 @@ class WiFiManager:
|
|||||||
if up_result.returncode != 0:
|
if up_result.returncode != 0:
|
||||||
error_msg = up_result.stderr.strip() or up_result.stdout.strip()
|
error_msg = up_result.stderr.strip() or up_result.stdout.strip()
|
||||||
logger.error(f"Failed to bring up AP connection: {error_msg}")
|
logger.error(f"Failed to bring up AP connection: {error_msg}")
|
||||||
|
self._remove_nm_dnsmasq_captive_conf()
|
||||||
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
||||||
capture_output=True, timeout=10)
|
capture_output=True, timeout=10)
|
||||||
self._show_led_message("AP mode failed", duration=5)
|
self._show_led_message("AP mode failed", duration=5)
|
||||||
@@ -2085,6 +2086,7 @@ class WiFiManager:
|
|||||||
# need to add the iptables port-redirect rules for the captive portal.
|
# need to add the iptables port-redirect rules for the captive portal.
|
||||||
if not self._setup_iptables_redirect():
|
if not self._setup_iptables_redirect():
|
||||||
logger.error("Captive-portal redirect setup failed; rolling back AP profile")
|
logger.error("Captive-portal redirect setup failed; rolling back AP profile")
|
||||||
|
self._remove_nm_dnsmasq_captive_conf()
|
||||||
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
|
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
|
||||||
capture_output=True, timeout=10)
|
capture_output=True, timeout=10)
|
||||||
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
||||||
@@ -2102,6 +2104,7 @@ class WiFiManager:
|
|||||||
else:
|
else:
|
||||||
logger.error("AP mode started but not verified by status check — rolling back")
|
logger.error("AP mode started but not verified by status check — rolling back")
|
||||||
self._teardown_iptables_redirect()
|
self._teardown_iptables_redirect()
|
||||||
|
self._remove_nm_dnsmasq_captive_conf()
|
||||||
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
|
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
|
||||||
capture_output=True, timeout=10)
|
capture_output=True, timeout=10)
|
||||||
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
||||||
@@ -2111,6 +2114,7 @@ class WiFiManager:
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error starting AP mode with nmcli: {e}")
|
logger.error(f"Error starting AP mode with nmcli: {e}")
|
||||||
|
self._remove_nm_dnsmasq_captive_conf()
|
||||||
self._show_led_message("Setup mode error", duration=5)
|
self._show_led_message("Setup mode error", duration=5)
|
||||||
return False, str(e)
|
return False, str(e)
|
||||||
|
|
||||||
@@ -2498,7 +2502,10 @@ address=/detectportal.firefox.com/192.168.4.1
|
|||||||
# Idle-timeout check: disable AP if no client has connected within the window.
|
# Idle-timeout check: disable AP if no client has connected within the window.
|
||||||
# Only applies when AP is active and we haven't just decided to enable/disable it.
|
# Only applies when AP is active and we haven't just decided to enable/disable it.
|
||||||
if ap_active and self._ap_enabled_at is not None:
|
if ap_active and self._ap_enabled_at is not None:
|
||||||
idle_timeout_min = self.config.get("ap_idle_timeout_minutes", 15)
|
try:
|
||||||
|
idle_timeout_min = max(1, min(1440, int(self.config.get("ap_idle_timeout_minutes", 15))))
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
idle_timeout_min = 15
|
||||||
elapsed = time.time() - self._ap_enabled_at
|
elapsed = time.time() - self._ap_enabled_at
|
||||||
if elapsed > idle_timeout_min * 60 and not self._has_ap_clients():
|
if elapsed > idle_timeout_min * 60 and not self._has_ap_clients():
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|||||||
@@ -7135,7 +7135,7 @@ def connect_wifi():
|
|||||||
# Propagate structured error type so the captive portal UI can show
|
# Propagate structured error type so the captive portal UI can show
|
||||||
# "Wrong password — try again" instead of a generic failure message.
|
# "Wrong password — try again" instead of a generic failure message.
|
||||||
error_type = "wrong_password" if (message or "").startswith("wrong_password:") else "connection_failed"
|
error_type = "wrong_password" if (message or "").startswith("wrong_password:") else "connection_failed"
|
||||||
clean_message = (message or "").removeprefix("wrong_password: ") or "Failed to connect to network"
|
clean_message = (message or "").removeprefix("wrong_password:").lstrip() or "Failed to connect to network"
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'message': clean_message,
|
'message': clean_message,
|
||||||
|
|||||||
@@ -1227,6 +1227,8 @@ function initializePlugins() {
|
|||||||
// searchPluginStore renders Installed/Reinstall badges against it.
|
// searchPluginStore renders Installed/Reinstall badges against it.
|
||||||
loadInstalledPlugins().then(() => {
|
loadInstalledPlugins().then(() => {
|
||||||
searchPluginStore(!isReswapWarm);
|
searchPluginStore(!isReswapWarm);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('[PluginStore] loadInstalledPlugins failed:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup search functionality (with guard against duplicate listeners)
|
// Setup search functionality (with guard against duplicate listeners)
|
||||||
|
|||||||
Reference in New Issue
Block a user