mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-05-01 13:03:01 +00:00
fix: address three wifi_manager and one plugins_manager review findings
wifi_manager.py: - _create_hostapd_config: use _validate_ap_config() for ssid/channel instead of raw self.config values; strip newlines from SSID to prevent config-file injection via the generated hostapd.conf - _setup_iptables_redirect: check return codes of sysctl ip_forward enable and both iptables -A calls; on any failure log the error output, call _teardown_iptables_redirect() to restore state, and return False instead of silently succeeding - _enable_ap_mode_nmcli_hotspot: on AP verification failure roll back fully — tear down iptables redirect, delete the LEDMatrix-Setup-AP connection profile, clear the LED message — before returning False plugins_manager.js: - initializePlugins: chain searchPluginStore(!isReswapWarm) inside loadInstalledPlugins().then() so window.installedPlugins is populated before the store renders Installed/Reinstall badges (same pattern applied to refreshPlugins() in the previous commit) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -702,8 +702,14 @@ class WiFiManager:
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass # non-fatal; restore will fall back to "0"
|
pass # non-fatal; restore will fall back to "0"
|
||||||
|
|
||||||
subprocess.run(["sudo", "sysctl", "-w", "net.ipv4.ip_forward=1"],
|
sysctl_r = subprocess.run(
|
||||||
capture_output=True, timeout=5)
|
["sudo", "sysctl", "-w", "net.ipv4.ip_forward=1"],
|
||||||
|
capture_output=True, text=True, timeout=5
|
||||||
|
)
|
||||||
|
if sysctl_r.returncode != 0:
|
||||||
|
logger.error(f"Failed to enable ip_forward: {sysctl_r.stderr.strip()}")
|
||||||
|
self._teardown_iptables_redirect()
|
||||||
|
return False
|
||||||
|
|
||||||
# PREROUTING: redirect HTTP → Flask
|
# PREROUTING: redirect HTTP → Flask
|
||||||
if subprocess.run(
|
if subprocess.run(
|
||||||
@@ -712,12 +718,16 @@ class WiFiManager:
|
|||||||
"-j", "REDIRECT", "--to-port", "5000"],
|
"-j", "REDIRECT", "--to-port", "5000"],
|
||||||
capture_output=True, timeout=5
|
capture_output=True, timeout=5
|
||||||
).returncode != 0:
|
).returncode != 0:
|
||||||
subprocess.run(
|
add_r = subprocess.run(
|
||||||
["sudo", "iptables", "-t", "nat", "-A", "PREROUTING",
|
["sudo", "iptables", "-t", "nat", "-A", "PREROUTING",
|
||||||
"-i", self._wifi_interface, "-p", "tcp", "--dport", "80",
|
"-i", self._wifi_interface, "-p", "tcp", "--dport", "80",
|
||||||
"-j", "REDIRECT", "--to-port", "5000"],
|
"-j", "REDIRECT", "--to-port", "5000"],
|
||||||
capture_output=True, timeout=5
|
capture_output=True, text=True, timeout=5
|
||||||
)
|
)
|
||||||
|
if add_r.returncode != 0:
|
||||||
|
logger.error(f"Failed to add PREROUTING rule: {add_r.stderr.strip()}")
|
||||||
|
self._teardown_iptables_redirect()
|
||||||
|
return False
|
||||||
|
|
||||||
# INPUT: accept traffic on port 5000 (the post-redirect destination port)
|
# INPUT: accept traffic on port 5000 (the post-redirect destination port)
|
||||||
if subprocess.run(
|
if subprocess.run(
|
||||||
@@ -726,12 +736,16 @@ class WiFiManager:
|
|||||||
"-j", "ACCEPT"],
|
"-j", "ACCEPT"],
|
||||||
capture_output=True, timeout=5
|
capture_output=True, timeout=5
|
||||||
).returncode != 0:
|
).returncode != 0:
|
||||||
subprocess.run(
|
add_r = subprocess.run(
|
||||||
["sudo", "iptables", "-A", "INPUT",
|
["sudo", "iptables", "-A", "INPUT",
|
||||||
"-i", self._wifi_interface, "-p", "tcp", "--dport", "5000",
|
"-i", self._wifi_interface, "-p", "tcp", "--dport", "5000",
|
||||||
"-j", "ACCEPT"],
|
"-j", "ACCEPT"],
|
||||||
capture_output=True, timeout=5
|
capture_output=True, text=True, timeout=5
|
||||||
)
|
)
|
||||||
|
if add_r.returncode != 0:
|
||||||
|
logger.error(f"Failed to add INPUT rule: {add_r.stderr.strip()}")
|
||||||
|
self._teardown_iptables_redirect()
|
||||||
|
return False
|
||||||
|
|
||||||
logger.info("iptables: port 80→5000 redirect and INPUT accept-5000 rules added")
|
logger.info("iptables: port 80→5000 redirect and INPUT accept-5000 rules added")
|
||||||
return True
|
return True
|
||||||
@@ -1865,7 +1879,13 @@ class WiFiManager:
|
|||||||
self._show_led_message(f"WiFi Setup\n{ap_ssid}\nNo password\n{ip}:5000", duration=10)
|
self._show_led_message(f"WiFi Setup\n{ap_ssid}\nNo password\n{ip}:5000", duration=10)
|
||||||
return True, f"AP mode enabled (open network) - Access at {ip}:5000"
|
return True, f"AP mode enabled (open network) - Access at {ip}:5000"
|
||||||
else:
|
else:
|
||||||
logger.error("AP mode started but not verified by status check")
|
logger.error("AP mode started but not verified by status check — rolling back")
|
||||||
|
self._teardown_iptables_redirect()
|
||||||
|
subprocess.run(["nmcli", "connection", "down", "LEDMatrix-Setup-AP"],
|
||||||
|
capture_output=True, timeout=10)
|
||||||
|
subprocess.run(["nmcli", "connection", "delete", "LEDMatrix-Setup-AP"],
|
||||||
|
capture_output=True, timeout=10)
|
||||||
|
self._clear_led_message()
|
||||||
return False, "AP mode started but verification failed"
|
return False, "AP mode started but verification failed"
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2060,9 +2080,11 @@ class WiFiManager:
|
|||||||
try:
|
try:
|
||||||
config_dir = HOSTAPD_CONFIG_PATH.parent
|
config_dir = HOSTAPD_CONFIG_PATH.parent
|
||||||
config_dir.mkdir(parents=True, exist_ok=True)
|
config_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
ap_ssid = self.config.get("ap_ssid", DEFAULT_AP_SSID)
|
# Use validated values — strips invalid chars and ensures channel is an int.
|
||||||
ap_channel = self.config.get("ap_channel", DEFAULT_AP_CHANNEL)
|
# Also strip newlines from SSID to prevent config-file injection.
|
||||||
|
ap_ssid, ap_channel = self._validate_ap_config()
|
||||||
|
ap_ssid = ap_ssid.replace('\n', '').replace('\r', '')
|
||||||
|
|
||||||
# Open network configuration (no password) for easy setup access
|
# Open network configuration (no password) for easy setup access
|
||||||
config_content = f"""interface={self._wifi_interface}
|
config_content = f"""interface={self._wifi_interface}
|
||||||
|
|||||||
@@ -1223,8 +1223,11 @@ function initializePlugins() {
|
|||||||
// during a re-swap, fetch fresh data including GitHub commit/version info.
|
// during a re-swap, fetch fresh data including GitHub commit/version info.
|
||||||
const isReswapWarm = !!window.pluginManager._reswap && !storeCacheExpired();
|
const isReswapWarm = !!window.pluginManager._reswap && !storeCacheExpired();
|
||||||
window.pluginManager._reswap = false;
|
window.pluginManager._reswap = false;
|
||||||
loadInstalledPlugins();
|
// Await the installed-plugins fetch so window.installedPlugins is populated before
|
||||||
searchPluginStore(!isReswapWarm);
|
// searchPluginStore renders Installed/Reinstall badges against it.
|
||||||
|
loadInstalledPlugins().then(() => {
|
||||||
|
searchPluginStore(!isReswapWarm);
|
||||||
|
});
|
||||||
|
|
||||||
// Setup search functionality (with guard against duplicate listeners)
|
// Setup search functionality (with guard against duplicate listeners)
|
||||||
const searchInput = document.getElementById('plugin-search');
|
const searchInput = document.getElementById('plugin-search');
|
||||||
|
|||||||
Reference in New Issue
Block a user