Honor seeded Buildroot setup config

This commit is contained in:
Yellowcooln
2026-04-23 21:44:06 -04:00
parent 3208018c6d
commit aba0f5bd09
4 changed files with 41 additions and 8 deletions
+1
View File
@@ -776,6 +776,7 @@ security = repeater.setdefault("security", {})
radio = data.setdefault("radio", {})
repeater["node_name"] = node_name
repeater["setup_complete"] = True
security["admin_password"] = admin_password
security["jwt_secret"] = jwt_secret
+3
View File
@@ -6,6 +6,9 @@ repeater:
# Node name for logging and identification
node_name: "mesh-repeater-01"
# Set true once initial provisioning is complete so the web UI can skip /setup
setup_complete: false
# TX mode: forward | monitor | no_tx (default: forward)
# forward = repeat on; monitor = no repeat but companions/tenants can send; no_tx = all TX off
# mode: forward
+23 -6
View File
@@ -7,6 +7,7 @@ from pathlib import Path
from typing import Callable, Optional
import cherrypy
import yaml
from pymc_core.protocol import CryptoUtils
from repeater import __version__
@@ -196,6 +197,14 @@ class APIEndpoints:
def _is_cors_enabled(self):
return self.config.get("web", {}).get("cors_enabled", False)
def _load_live_config(self):
"""Prefer the on-disk config when checking first-boot/setup state."""
try:
with open(self._config_path, "r", encoding="utf-8") as f:
return yaml.safe_load(f) or {}
except Exception:
return self.config or {}
def _set_cors_headers(self):
if self._is_cors_enabled():
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
@@ -302,24 +311,27 @@ class APIEndpoints:
def needs_setup(self):
"""Check if the repeater needs initial setup configuration"""
try:
config = self.config
config = self._load_live_config()
# Check for default values that indicate first-time setup
node_name = config.get("repeater", {}).get("node_name", "")
repeater_config = config.get("repeater", {})
node_name = repeater_config.get("node_name", "")
has_default_name = node_name in ["mesh-repeater-01", ""]
admin_password = (
config.get("repeater", {}).get("security", {}).get("admin_password", "")
)
admin_password = repeater_config.get("security", {}).get("admin_password", "")
has_default_password = admin_password in ["admin123", ""]
setup_complete = bool(repeater_config.get("setup_complete", False))
needs_setup = has_default_name or has_default_password
needs_setup = (has_default_name or has_default_password) and not (
setup_complete and not has_default_name and not has_default_password
)
return {
"needs_setup": needs_setup,
"reasons": {
"default_name": has_default_name,
"default_password": has_default_password,
"setup_complete": setup_complete,
},
}
except Exception as e:
@@ -478,6 +490,7 @@ class APIEndpoints:
if "repeater" not in config_yaml:
config_yaml["repeater"] = {}
config_yaml["repeater"]["node_name"] = node_name
config_yaml["repeater"]["setup_complete"] = True
if "security" not in config_yaml["repeater"]:
config_yaml["repeater"]["security"] = {}
@@ -561,6 +574,10 @@ class APIEndpoints:
with open(self._config_path, "w") as f:
yaml.dump(config_yaml, f, default_flow_style=False, sort_keys=False)
# Keep in-memory config aligned until the restart lands.
self.config.clear()
self.config.update(config_yaml)
logger.info(
f"Setup wizard completed: node_name={node_name}, hardware={hardware_key}, freq={freq_mhz}MHz"
)
+14 -2
View File
@@ -3,6 +3,7 @@ Authentication endpoints for login and token management
"""
import cherrypy
import logging
import yaml
from .auth.middleware import require_auth
logger = logging.getLogger(__name__)
@@ -152,6 +153,16 @@ class AuthEndpoints:
self.jwt_handler = jwt_handler
self.token_manager = token_manager
self.config_manager = config_manager
def _load_live_config(self):
config_path = getattr(self.config_manager, "config_path", None)
if not config_path:
return self.config
try:
with open(config_path, "r", encoding="utf-8") as f:
return yaml.safe_load(f) or {}
except Exception:
return self.config
@cherrypy.expose
def login(self, **kwargs):
@@ -185,7 +196,8 @@ class AuthEndpoints:
# Validate credentials against config
# Check if username is 'admin' and password matches config
repeater_config = self.config.get('repeater', {})
live_config = self._load_live_config()
repeater_config = live_config.get('repeater', {})
security_config = repeater_config.get('security', {})
config_password = security_config.get('admin_password', '')
@@ -460,4 +472,4 @@ class AuthEndpoints:
return json.dumps({
'success': False,
'error': 'Failed to change password'
}).encode('utf-8')
}).encode('utf-8')