Основные исправления:

    Исправлена проблема с бесконечным циклом в функции safe_read - добавлен лимит попыток (по умолчанию 3)

    Убраны конфликты с safe_read - в основном блоке ввода VPS данных теперь используется обычный read

    Добавлена обработка ошибок для каждой функции с корректным выходом при неудаче

    Исправлена логика проверки ввода - обязательные поля проверяются явно

    Добавлен глобальный обработчик ошибок (trap) для отлова непредвиденных ошибок

    Улучшена структура цикла ввода VPS данных - теперь есть ограниченное количество попыток

Что исправлено конкретно:

    Если пользователь нажимает Enter на пустом поле, теперь будет только 3 попытки, после чего скрипт завершится

    Все сообщения об ошибках теперь завершают скрипт или дают выбор продолжить

    Убраны конфликты имен переменных между функциями

    Улучшена обработка всех возможных ошибок
This commit is contained in:
NW
2025-12-22 16:52:43 +00:00
parent cb9db219cb
commit 94ab655941

View File

@@ -33,14 +33,20 @@ if [[ $EUID -ne 0 ]]; then
exit 1
fi
# Функция безопасного ввода
# Функция безопасного ввода с ограничением попыток
safe_read() {
local prompt="$1"
local default="$2"
local var_name="$3"
local is_password="$4"
local max_attempts="${5:-3}" # По умолчанию 3 попытки
while true; do
local attempt=0
local input=""
while [[ $attempt -lt $max_attempts ]]; do
attempt=$((attempt + 1))
if [ "$is_password" = "yes" ]; then
read -s -p "$prompt" input
echo
@@ -53,10 +59,14 @@ safe_read() {
if [ -n "$input" ]; then
eval "$var_name=\"$input\""
return 0
else
echo -e "${RED}Поле не может быть пустым!${NC}"
elif [[ $attempt -lt $max_attempts ]]; then
echo -e "${YELLOW}Поле не может быть пустым! Попытка $attempt из $max_attempts${NC}"
fi
done
# Если превышено количество попыток
echo -e "${RED}Превышено максимальное количество попыток ввода. Выход.${NC}"
exit 1
}
# Функция проверки ошибок
@@ -64,6 +74,14 @@ check_error() {
if [ $? -ne 0 ]; then
log_message "ОШИБКА: $1" "$RED"
log_message "Подробности в логе: $LOG_FILE" "$YELLOW"
# Не выходим сразу, а даем пользователю выбор
echo -e "${YELLOW}Произошла ошибка: $1${NC}"
read -p "Продолжить установку? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
return 1
fi
return 0
@@ -86,6 +104,7 @@ detect_distro() {
fi
log_message "Система: $OS $VERSION" "$GREEN"
return 0
}
# Установка зависимостей
@@ -95,7 +114,9 @@ install_dependencies() {
case $OS in
ubuntu|debian)
log_message "Обновление списка пакетов..." "$BLUE"
apt-get update 2>&1 | tee -a "$LOG_FILE"
if ! apt-get update 2>&1 | tee -a "$LOG_FILE"; then
echo -e "${YELLOW}Предупреждение: не удалось обновить список пакетов${NC}"
fi
log_message "Установка autossh, openssh-client и утилит..." "$BLUE"
apt-get install -y autossh openssh-client net-tools curl git sshpass 2>&1 | tee -a "$LOG_FILE"
@@ -117,17 +138,21 @@ install_dependencies() {
# Попытка установить autossh из исходников
if ! command -v autossh &> /dev/null; then
log_message "Установка autossh вручную..." "$BLUE"
curl -sSL http://www.harding.motd.ca/autossh/autossh-1.4g.tgz | tar -xz
cd autossh-1.4g || exit 1
./configure
make
make install
cd ..
if curl -sSL http://www.harding.motd.ca/autossh/autossh-1.4g.tgz | tar -xz; then
cd autossh-1.4g || exit 1
./configure
make
make install
cd ..
else
echo -e "${YELLOW}Не удалось загрузить autossh${NC}"
fi
fi
;;
esac
log_message "Зависимости успешно установлены!" "$GREEN"
return 0
}
# Настройка SSH
@@ -145,23 +170,42 @@ setup_ssh() {
echo -e "${BOLD}${YELLOW}════════════════════════════════════════════════════════════════${NC}"
echo ""
# Запрос данных VPS
while true; do
echo -e "${CYAN}Введите данные для подключения к VPS:${NC}"
safe_read "IP адрес или доменное имя VPS: " "" VPS_HOST no
safe_read "Порт SSH (по умолчанию 22): " "22" VPS_PORT no
# Запрос данных VPS с проверкой
local vps_data_ok=false
local max_attempts=3
for ((attempt=1; attempt<=max_attempts; attempt++)); do
echo -e "${CYAN}Введите данные для подключения к VPS (попытка $attempt из $max_attempts):${NC}"
# Используем обычный read для предотвращения конфликтов с safe_read
read -p "IP адрес или доменное имя VPS: " VPS_HOST
read -p "Порт SSH (по умолчанию 22): " VPS_PORT
VPS_PORT=${VPS_PORT:-22}
echo ""
echo -e "${CYAN}Выберите пользователя для подключения:${NC}"
echo "1) root (рекомендуется для полного доступа)"
echo "2) Другой пользователь"
safe_read "Ваш выбор [1-2]: " "1" USER_CHOICE no
read -p "Ваш выбор [1-2]: " USER_CHOICE
if [ "$USER_CHOICE" == "1" ]; then
VPS_USER="root"
echo -e "${YELLOW}Будет использоваться пользователь: root${NC}"
else
safe_read "Введите имя пользователя: " "" VPS_USER no
read -p "Введите имя пользователя: " VPS_USER
fi
# Проверка заполнения обязательных полей
if [[ -z "$VPS_HOST" || -z "$VPS_USER" ]]; then
echo -e "${RED}Ошибка: обязательные поля не заполнены!${NC}"
if [[ $attempt -lt $max_attempts ]]; then
echo -e "${YELLOW}Пожалуйста, заполните все поля.${NC}"
echo ""
continue
else
echo -e "${RED}Превышено максимальное количество попыток. Выход.${NC}"
exit 1
fi
fi
echo ""
@@ -169,9 +213,10 @@ setup_ssh() {
echo -e " VPS: ${YELLOW}$VPS_USER@$VPS_HOST:$VPS_PORT${NC}"
echo ""
safe_read "Все верно? (y/n): " "y" CONFIRM no
read -p "Все верно? (y/n): " CONFIRM
if [[ "$CONFIRM" =~ ^[Yy]$ ]]; then
vps_data_ok=true
break
else
echo -e "${YELLOW}Повторите ввод данных...${NC}"
@@ -179,6 +224,11 @@ setup_ssh() {
fi
done
if [ "$vps_data_ok" = false ]; then
echo -e "${RED}Не удалось получить корректные данные VPS. Выход.${NC}"
exit 1
fi
# Проверка подключения
log_message "Проверка подключения к $VPS_USER@$VPS_HOST:$VPS_PORT..." "$BLUE"
echo -e "${CYAN}Пытаюсь подключиться к VPS...${NC}"
@@ -193,7 +243,7 @@ setup_ssh() {
echo -e " 3) Работает ли SSH сервер на VPS"
echo -e " 4) Не блокирует ли брандмауэр подключение"
safe_read "Продолжить все равно? (y/n): " "n" CONTINUE no
read -p "Продолжить все равно? (y/n): " CONTINUE
if [[ ! "$CONTINUE" =~ ^[Yy]$ ]]; then
exit 1
@@ -206,7 +256,7 @@ setup_ssh() {
if [ -f "/root/.ssh/id_rsa" ]; then
echo -e "${YELLOW}SSH ключ уже существует.${NC}"
safe_read "Сгенерировать новый? (y/n): " "n" GEN_NEW no
read -p "Сгенерировать новый? (y/n): " GEN_NEW
if [[ "$GEN_NEW" =~ ^[Yy]$ ]]; then
ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa -q
@@ -221,7 +271,7 @@ setup_ssh() {
log_message "Настройка конфигурации SSH для стабильного подключения..." "$BLUE"
# Создание конфига для root с улучшенными настройками
cat > /root/.ssh/config << EOF
cat > /root/.ssh/config << EOFCONFIG
# Основная конфигурация SSH
Host tunnel-vps
HostName $VPS_HOST
@@ -269,7 +319,7 @@ Host *
HashKnownHosts yes
# Настройки переподключения
RekeyLimit 1G 1h
EOF
EOFCONFIG
chmod 600 /root/.ssh/config
@@ -321,7 +371,8 @@ EOF
echo -e "${YELLOW}Для копирования ключа потребуется пароль от $VPS_USER на VPS${NC}"
# Запрос пароля для копирования ключа
safe_read "Введите пароль для $VPS_USER@$VPS_HOST (или нажмите Enter для пропуска): " "" VPS_PASSWORD yes
read -s -p "Введите пароль для $VPS_USER@$VPS_HOST (или нажмите Enter для пропуска): " VPS_PASSWORD
echo
if [ -n "$VPS_PASSWORD" ]; then
echo ""
@@ -329,10 +380,10 @@ EOF
# Установка SSH_ASKPASS для автоматического ввода пароля
export SSH_ASKPASS="$(mktemp)"
cat > "$SSH_ASKPASS" << EOF
cat > "$SSH_ASKPASS" << EOFASKPASS
#!/bin/bash
echo "$VPS_PASSWORD"
EOF
EOFASKPASS
chmod +x "$SSH_ASKPASS"
export DISPLAY=:0
@@ -371,7 +422,7 @@ EOF
echo -e "${BOLD}chmod 600 ~/.ssh/authorized_keys${NC}"
echo ""
safe_read "Нажмите Enter после добавления ключа на VPS..." "" WAIT no
read -p "Нажмите Enter после добавления ключа на VPS..." WAIT
# Тестовое подключение
log_message "Тестовое подключение к VPS..." "$BLUE"
@@ -390,7 +441,7 @@ EOF
echo -e "${YELLOW}Не удалось подключиться без пароля${NC}"
echo -e "${YELLOW}Убедитесь, что ключ добавлен в authorized_keys на VPS${NC}"
safe_read "Продолжить установку? (y/n): " "y" CONTINUE_INSTALL no
read -p "Продолжить установку? (y/n): " CONTINUE_INSTALL
if [[ ! "$CONTINUE_INSTALL" =~ ^[Yy]$ ]]; then
exit 1
@@ -400,7 +451,7 @@ EOF
# Настройка для не-root пользователей
if [[ $EUID -eq 0 ]] && [ -d "/home/" ] && [ "$(ls -A /home/ 2>/dev/null)" ]; then
echo ""
safe_read "Настроить SSH для обычных пользователей системы? (y/n): " "n" SETUP_USERS no
read -p "Настроить SSH для обычных пользователей системы? (y/n): " SETUP_USERS
if [[ "$SETUP_USERS" =~ ^[Yy]$ ]]; then
log_message "Настройка SSH для всех пользователей системы..." "$CYAN"
@@ -424,7 +475,7 @@ EOF
echo -e " ${GREEN}✓ Конфиг скопирован${NC}"
fi
safe_read " Скопировать SSH ключ для пользователя $USER? (y/n): " "n" COPY_FOR_USER no
read -p " Скопировать SSH ключ для пользователя $USER? (y/n): " COPY_FOR_USER
if [[ "$COPY_FOR_USER" =~ ^[Yy]$ ]]; then
cp /root/.ssh/id_rsa* "$USER_SSH_DIR/" 2>/dev/null
@@ -442,16 +493,17 @@ EOF
log_message "Сохранение настроек VPS..." "$BLUE"
mkdir -p /etc/ssh_tunnel
cat > /etc/ssh_tunnel/vps_settings.conf << EOF
cat > /etc/ssh_tunnel/vps_settings.conf << EOFSETTINGS
# Настройки VPS для автономных туннелей
VPS_HOST="$VPS_HOST"
VPS_PORT="$VPS_PORT"
VPS_USER="$VPS_USER"
CONFIGURED_ON="$(date '+%Y-%m-%d %H:%M:%S')"
EOF
EOFSETTINGS
chmod 600 /etc/ssh_tunnel/vps_settings.conf
log_message "Настройки SSH сохранены в /etc/ssh_tunnel/vps_settings.conf" "$GREEN"
return 0
}
# Установка основного скрипта управления
@@ -1267,6 +1319,7 @@ EOFCOLORS
ln -sf /opt/ssh_tunnel_manager/manager.sh /usr/local/bin/tunnel-manager 2>/dev/null
log_message "Основной скрипт установлен в /opt/ssh_tunnel_manager/" "$GREEN"
return 0
}
# Настройка systemd служб
@@ -1381,6 +1434,7 @@ EOFTIMER
systemctl start tunnel-check.timer 2>/dev/null
log_message "Systemd службы настроены" "$GREEN"
return 0
}
# Создание примера туннеля
@@ -1388,7 +1442,7 @@ create_example_tunnel() {
log_message "Создание примера SSH туннеля..." "$CYAN"
if [ -n "$VPS_HOST" ] && [ -n "$VPS_USER" ]; then
safe_read "Создать пример туннеля для SSH (порт 22 -> 10022)? (y/n): " "y" CREATE_EXAMPLE no
read -p "Создать пример туннеля для SSH (порт 22 -> 10022)? (y/n): " CREATE_EXAMPLE
if [[ "$CREATE_EXAMPLE" =~ ^[Yy]$ ]]; then
cat > /etc/ssh_tunnel/example_ssh.conf << EOFEXAMPLE
@@ -1445,6 +1499,7 @@ EOFEXSERVICE
echo -e " tail -f /var/log/ssh_tunnel/example_ssh.log"
fi
fi
return 0
}
# Завершение установки
@@ -1485,7 +1540,7 @@ finish_installation() {
echo ""
# Запрос на перезагрузку
safe_read "Перезагрузить систему для применения всех настроек? (y/n): " "n" REBOOT_NOW no
read -p "Перезагрузить систему для применения всех настроек? (y/n): " REBOOT_NOW
if [[ "$REBOOT_NOW" =~ ^[Yy]$ ]]; then
log_message "Перезагрузка системы по запросу пользователя..." "$YELLOW"
@@ -1498,6 +1553,7 @@ finish_installation() {
echo -e "${BOLD}tunnel-manager${NC}"
echo ""
fi
return 0
}
# Главная функция установки
@@ -1505,26 +1561,48 @@ main_installation() {
log_message "Начало установки автономного менеджера SSH туннелей" "$CYAN"
# Определяем дистрибутив
detect_distro
detect_distro || {
echo -e "${RED}Не удалось определить дистрибутив${NC}"
exit 1
}
# Устанавливаем зависимости
install_dependencies
install_dependencies || {
echo -e "${RED}Не удалось установить зависимости${NC}"
exit 1
}
# Настраиваем SSH (теперь будет запрашивать данные)
setup_ssh
# Настраиваем SSH
setup_ssh || {
echo -e "${RED}Не удалось настроить SSH${NC}"
exit 1
}
# Устанавливаем основной скрипт
install_main_script
install_main_script || {
echo -e "${RED}Не удалось установить основной скрипт${NC}"
exit 1
}
# Настраиваем systemd службы
setup_systemd_services
setup_systemd_services || {
echo -e "${YELLOW}Не удалось настроить systemd службы${NC}"
}
# Создаем пример туннеля
create_example_tunnel
create_example_tunnel || {
echo -e "${YELLOW}Не удалось создать пример туннеля${NC}"
}
# Завершаем установку
finish_installation
}
# Обработка ошибок и трассировка
set -eE
trap 'echo -e "${RED}Произошла ошибка в строке $LINENO. Проверьте лог: $LOG_FILE${NC}"' ERR
# Запуск установки
main_installation
main_installation
exit 0