diff --git a/app/sovran_systemsos_web/server.py b/app/sovran_systemsos_web/server.py index f4de31c..5fbd526 100644 --- a/app/sovran_systemsos_web/server.py +++ b/app/sovran_systemsos_web/server.py @@ -929,9 +929,19 @@ class DomainSetRequest(BaseModel): ddns_url: str = "" +_SAFE_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]+$') + + +def _validate_safe_name(name: str) -> bool: + """Return True if name contains only safe path characters (no separators).""" + return bool(name) and _SAFE_NAME_RE.match(name) is not None + + @app.post("/api/domains/set") async def api_domains_set(req: DomainSetRequest): """Save a domain and optionally register a DDNS URL.""" + if not _validate_safe_name(req.domain_name): + raise HTTPException(status_code=400, detail="Invalid domain_name") os.makedirs(DOMAINS_DIR, exist_ok=True) domain_path = os.path.join(DOMAINS_DIR, req.domain_name) with open(domain_path, "w") as f: diff --git a/app/sovran_systemsos_web/static/app.js b/app/sovran_systemsos_web/static/app.js index 179c0ed..39f875f 100644 --- a/app/sovran_systemsos_web/static/app.js +++ b/app/sovran_systemsos_web/static/app.js @@ -930,9 +930,9 @@ function buildFeatureCard(feat) { var toggleLabel = card.querySelector(".feature-toggle"); toggle.addEventListener("change", function() { var newEnabled = toggle.checked; - // Revert visually until confirmed + // Revert visually to original state while confirmation/modal is pending toggle.checked = feat.enabled; - if (newEnabled) { toggleLabel.classList.remove("active"); } else { toggleLabel.classList.add("active"); } + if (feat.enabled) { toggleLabel.classList.add("active"); } else { toggleLabel.classList.remove("active"); } handleFeatureToggle(feat, newEnabled); });