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:
@@ -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"
|
||||||
|
|||||||
@@ -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-ключ или введите пароль.")
|
||||||
|
|||||||
@@ -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"])
|
||||||
|
|||||||
Reference in New Issue
Block a user