From ac13c913e3392f7c260aa69b5f01de189ffc8f03 Mon Sep 17 00:00:00 2001 From: D Stephenson Date: Tue, 18 Aug 2026 11:28:23 -0500 Subject: [PATCH] Add live Disable Telnet action to Web Access Control Adds a standalone DISABLE TELNET button (no enable counterpart, per requirement) alongside the existing HTTPS enable/disable toggle. Reuses the same target/concurrency controls and SSH push flow, backed by a new "disable_telnet" action mapped to "no ip telnet" on the switch. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01CLfUJoQTaUePx1m1d2v2j9 --- app.py | 12 +++++++++--- templates/index.html | 15 ++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/app.py b/app.py index 87de881..7383289 100644 --- a/app.py +++ b/app.py @@ -89,16 +89,22 @@ def api_web_access(): ip = data.get("ip", "").strip() username = data.get("username", "").strip() password = data.get("password", "").strip() - action = data.get("action", "") # "enable" or "disable" + action = data.get("action", "") # "enable", "disable", or "disable_telnet" + + commands = { + "enable": "ip http secure-server", + "disable": "no ip http secure-server", + "disable_telnet": "no ip telnet", + } if not ip or not username or not password: return jsonify({"ok": False, "error": "Missing IP or credentials"}), 400 - if action not in ("enable", "disable"): + if action not in commands: return jsonify({"ok": False, "error": "Invalid action"}), 400 print(f"[web-access] {action} {ip} user={username!r} pass_len={len(password)}", flush=True) - cmd = "ip http secure-server" if action == "enable" else "no ip http secure-server" + cmd = commands[action] try: sock = socket.create_connection((ip, 22), timeout=10) diff --git a/templates/index.html b/templates/index.html index 39fde19..326fe45 100644 --- a/templates/index.html +++ b/templates/index.html @@ -646,6 +646,11 @@ + +
Telnet Access
+ @@ -1253,6 +1258,7 @@ const waConcurrency = document.getElementById('wa-concurrency'); const waConcurVal = document.getElementById('wa-concurrency-val'); const btnWaEnable = document.getElementById('btn-wa-enable'); const btnWaDisable = document.getElementById('btn-wa-disable'); +const btnWaDisableTelnet = document.getElementById('btn-wa-disable-telnet'); waConcurrency.addEventListener('input', () => { waConcurVal.textContent = waConcurrency.value; @@ -1267,6 +1273,7 @@ function updateWaButtons() { const enabled = (target === 'selected') ? hasSelected : hasAny; btnWaEnable.disabled = !enabled; btnWaDisable.disabled = !enabled; + btnWaDisableTelnet.disabled = !enabled; } function getWaTargetSwitches() { @@ -1332,8 +1339,8 @@ function showWaResults(action, targetList) { document.getElementById('wa-results-panel').classList.add('active'); const badge = document.getElementById('wa-action-badge'); - badge.textContent = action.toUpperCase(); - badge.className = 'wa-action-badge ' + action; + badge.textContent = action.replace('_', ' ').toUpperCase(); + badge.className = 'wa-action-badge ' + (action === 'enable' ? 'enable' : 'disable'); const body = document.getElementById('wa-results-body'); body.innerHTML = ''; @@ -1366,6 +1373,7 @@ async function runWaOperation(action) { btnWaEnable.disabled = true; btnWaDisable.disabled = true; + btnWaDisableTelnet.disabled = true; const rows = showWaResults(action, targetList); let done = 0; @@ -1400,12 +1408,13 @@ async function runWaOperation(action) { } ); - showToast(`Web access ${action} complete — ${targetList.length} switches`, 'ok'); + showToast(`Web access ${action.replace('_', ' ')} complete — ${targetList.length} switches`, 'ok'); updateWaButtons(); } btnWaEnable.addEventListener('click', () => runWaOperation('enable')); btnWaDisable.addEventListener('click', () => runWaOperation('disable')); +btnWaDisableTelnet.addEventListener('click', () => runWaOperation('disable_telnet'));