v1.8.5: restore sudo auto-password + fix sudo SFTP operations

Terminal:
- Auto-detect [sudo] password prompts in interactive shell output
- Auto-send server password when sudo prompt detected
- Reset detection flag on new command (Enter key)

SSH client (SFTPSession):
- Fix exec_command() sudo password timing (0.1s delay for prompt)
- Fix listdir_attr_sudo() ls output parsing with proper maxsplit
- Handle filenames with spaces, symlinks, and varied ls formats

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-02-24 03:48:30 -05:00
parent 6144c17a96
commit f7c7fe731f
4 changed files with 43 additions and 15 deletions

View File

@@ -465,6 +465,8 @@ class SFTPSession:
full_cmd = cmd
stdin, stdout, stderr = self._client.exec_command(full_cmd, timeout=30)
if self.sudo_mode and user != "root" and password:
# Wait briefly for sudo prompt to appear before sending password
time.sleep(0.1)
stdin.write(password + "\n")
stdin.flush()
return stdout.read().decode("utf-8", errors="replace")
@@ -476,29 +478,35 @@ class SFTPSession:
for line in output.strip().splitlines():
if line.startswith("total "):
continue
parts = line.split(None, 7)
# With --time-style=+%s the columns are:
# perms links owner group size mtime name [-> target if symlink]
# Use maxsplit=8 to preserve spaces in filenames, giving us:
# [0=perms, 1=links, 2=owner, 3=group, 4=size, 5=mtime, 6=name...]
parts = line.split(None, 8)
if len(parts) < 7:
continue
perms = parts[0]
if perms.startswith("d") or perms.startswith("l") or perms.startswith("-"):
pass
else:
continue
size_str = parts[4]
mtime_str = parts[5]
# parts[6] may be time or name depending on format
# With --time-style=+%s: perms links owner group size epoch name
name = parts[6] if len(parts) == 7 else parts[7]
if name in (".", ".."):
if not (perms.startswith("d") or perms.startswith("l") or perms.startswith("-")):
continue
try:
size = int(size_str)
size = int(parts[4])
except ValueError:
size = 0
continue
try:
mtime = int(mtime_str)
mtime = int(parts[5])
except ValueError:
mtime = 0
continue
name = parts[6]
# Handle cases where name contains " -> " (symlinks) or has spaces
if len(parts) > 7:
# This means the filename itself contained spaces and was split
name = parts[6] + " " + parts[7]
# Strip symlink target (e.g. "name -> target")
name = name.split(" -> ")[0].strip()
if name in (".", ".."):
continue
mode = _parse_ls_perms(perms)
entry = _SudoFileAttr(name, size, mtime, mode)
results.append(entry)

View File

@@ -37,6 +37,10 @@ class TerminalTab(ctk.CTkFrame):
# Thread-safe data queue
self._data_queue: queue.Queue[bytes] = queue.Queue()
# Sudo auto-password detection
self._sudo_buffer = b"" # Buffer for detecting sudo prompts
self._sudo_sent = False # Prevent sending password twice for same prompt
def set_server(self, alias: str | None):
if alias == self._current_alias:
return
@@ -151,7 +155,20 @@ class TerminalTab(ctk.CTkFrame):
except queue.Empty:
pass
if chunks:
self._terminal.feed(b"".join(chunks))
combined = b"".join(chunks)
self._sudo_buffer += combined
# Keep only last 200 bytes for pattern matching
self._sudo_buffer = self._sudo_buffer[-200:]
if not self._sudo_sent:
buf_str = self._sudo_buffer.decode("utf-8", errors="replace").lower()
if "[sudo] password for" in buf_str or buf_str.rstrip().endswith("password:"):
server = self.store.get_server(self._current_alias)
if server and server.get("password"):
self._session.send(server["password"].encode() + b"\n")
self._sudo_sent = True
self._terminal.feed(combined)
def _on_disconnected(self):
"""Called from SSH read thread."""
@@ -189,6 +206,9 @@ class TerminalTab(ctk.CTkFrame):
session = self._session # local ref for thread safety
if session and session.connected:
session.send(data)
# Reset sudo sent flag when user sends a new command (detects \r or \n)
if b'\r' in data or b'\n' in data:
self._sudo_sent = False
elif self._current_alias and not self._intentional_disconnect and self._reconnect_count == 0:
# Session dead, no reconnect in progress — trigger one attempt
self._on_disconnected()

Binary file not shown.

View File

@@ -1,6 +1,6 @@
"""Version info for ServerManager."""
__version__ = "1.8.4"
__version__ = "1.8.5"
__app_name__ = "ServerManager"
__author__ = "aibot777"
__description__ = "Desktop GUI for managing remote servers"