feat: secure password/passphrase input via getpass; interactive SSH auth menu (key/passphrase/password/temp-key); fix missing do_transfer call

This commit is contained in:
2026-05-22 23:42:52 +04:00
parent 4d6c7ef506
commit 6d6418c059
3 changed files with 18 additions and 4 deletions

View File

@@ -112,6 +112,19 @@ def prompt(text, default=None):
sys.exit(130) sys.exit(130)
def prompt_password(text):
"""Скрытый ввод пароля/passphrase. В pipe — обычный prompt с предупреждением."""
import getpass
try:
return getpass.getpass(f"{yellow('')} {text} ")
except EOFError:
print(f"{yellow('')} Ввод пароля в pipe не поддерживается скрытым режимом. Используем обычный ввод.")
return prompt(text)
except KeyboardInterrupt:
print(f"\n{yellow('')} Прервано пользователем (Ctrl+C)")
sys.exit(130)
def confirm(text, default="y"): def confirm(text, default="y"):
"""Да/нет с обработкой EOF. В pipe — возвращает default.""" """Да/нет с обработкой EOF. В pipe — возвращает default."""
yn = "Y/n" if default.lower() == "y" else "y/N" yn = "Y/n" if default.lower() == "y" else "y/N"

View File

@@ -10,7 +10,7 @@ import tarfile
import time import time
import sys import sys
from datetime import datetime from datetime import datetime
from core.color import header, subheader, success, warn, error as cerror, info, step, prompt, confirm, divider, log_cmd from core.color import header, subheader, success, warn, error as cerror, info, step, prompt, prompt_password, confirm, divider, log_cmd
from core import state from core import state
from core.runner import run from core.runner import run
from discover.docker import discover_docker, get_container_pid from discover.docker import discover_docker, get_container_pid
@@ -380,7 +380,7 @@ def do_transfer_offer():
state.set_stage("TRANSFER", target_host=host, target_user=user, target_port=port_int, ssh_key=key_path) state.set_stage("TRANSFER", target_host=host, target_user=user, target_port=port_int, ssh_key=key_path)
else: else:
# Нет SSH-ключа — спрашиваем пароль и пробуем sshpass # Нет SSH-ключа — спрашиваем пароль и пробуем sshpass
password = prompt(f"Введите пароль для {user}@{host} (или Enter для отмены)") password = prompt_password(f"Пароль для {user}@{host} (Enter для отмены)")
if not password: if not password:
state.set_error("ssh_key_setup", "", "Пароль не введён", suggestion="Запустите docker-migrate --resume или настройте SSH-ключ") state.set_error("ssh_key_setup", "", "Пароль не введён", suggestion="Запустите docker-migrate --resume или настройте SSH-ключ")
raise RuntimeError("Пароль не введён. Установите SSH-ключ или введите пароль.") raise RuntimeError("Пароль не введён. Установите SSH-ключ или введите пароль.")

View File

@@ -82,7 +82,7 @@ def test_keys_against_target(host, user, port, keys):
else: else:
# Проверим, не passphrase ли # Проверим, не passphrase ли
if "passphrase" in err.lower() or "password" in err.lower(): if "passphrase" in err.lower() or "password" in err.lower():
warn(f" ! Ключ '{label}' требует passphrase (зашифрован). Пропускаем (нужен ssh-agent).") warn(f" ! Ключ '{label}' требует passphrase (зашифрован). Можно ввести passphrase позже.")
else: else:
info(f" ✗ Ключ '{label}' не подходит ({err.strip()[:60]}).") info(f" ✗ Ключ '{label}' не подходит ({err.strip()[:60]}).")
return working return working
@@ -225,7 +225,8 @@ def pick_or_setup_ssh_key(host, user, port):
ok, _, err = check_ssh_connectivity(host, user, port, key_path=k["private"]) ok, _, err = check_ssh_connectivity(host, user, port, key_path=k["private"])
if not ok and ("passphrase" in err.lower() or "password" in err.lower()): if not ok and ("passphrase" in err.lower() or "password" in err.lower()):
if confirm(f"Ключ '{label}' зашифрован. Ввести passphrase и попробовать", default="y"): if confirm(f"Ключ '{label}' зашифрован. Ввести passphrase и попробовать", default="y"):
pw = prompt(f"Passphrase для {label} (ввод скрыт)") from core.color import prompt_password
pw = prompt_password(f"Passphrase для {label}")
if pw and try_key_with_passphrase(k["private"], pw): if pw and try_key_with_passphrase(k["private"], pw):
# После ssh-add ключ должен работать # После ssh-add ключ должен работать
ok2, _, _ = check_ssh_connectivity(host, user, port, key_path=k["private"]) ok2, _, _ = check_ssh_connectivity(host, user, port, key_path=k["private"])