mirror of https://github.com/telemt/telemt.git
Update install.sh - Add interactive domain prompt, EN/RU support, and script optimizations
This commit is contained in:
parent
23156a840d
commit
b4a3ad9aad
482
install.sh
482
install.sh
|
|
@ -21,47 +21,212 @@ PORT_PROVIDED=0
|
||||||
SECRET_PROVIDED=0
|
SECRET_PROVIDED=0
|
||||||
AD_TAG_PROVIDED=0
|
AD_TAG_PROVIDED=0
|
||||||
DOMAIN_PROVIDED=0
|
DOMAIN_PROVIDED=0
|
||||||
|
LANG_PROVIDED=0
|
||||||
|
|
||||||
ACTION="install"
|
ACTION="install"
|
||||||
TARGET_VERSION="${VERSION:-latest}"
|
TARGET_VERSION="${VERSION:-latest}"
|
||||||
|
LANG_CHOICE="en"
|
||||||
|
|
||||||
|
set_language() {
|
||||||
|
case "$1" in
|
||||||
|
ru)
|
||||||
|
L_ERR_DOMAIN_REQ="требует аргумент (домен)."
|
||||||
|
L_ERR_PORT_REQ="требует аргумент (порт)."
|
||||||
|
L_ERR_PORT_NUM="Порт должен быть числом."
|
||||||
|
L_ERR_PORT_RANGE="Порт должен быть от 1 до 65535."
|
||||||
|
L_ERR_SECRET_REQ="требует аргумент (секрет)."
|
||||||
|
L_ERR_SECRET_HEX="Секрет должен содержать только HEX символы."
|
||||||
|
L_ERR_SECRET_LEN="Секрет должен состоять ровно из 32 символов."
|
||||||
|
L_ERR_ADTAG_REQ="требует аргумент (ad_tag)."
|
||||||
|
L_ERR_UNKNOWN_OPT="Неизвестная опция:"
|
||||||
|
L_WARN_EXTRA_ARG="Игнорируется лишний аргумент:"
|
||||||
|
L_ERR_REQ_ARG="требует аргумент (1, 2, en или ru)."
|
||||||
|
L_ERR_EMPTY_VAR="не может быть пустым."
|
||||||
|
L_ERR_INV_VER="Недопустимые символы в версии."
|
||||||
|
L_ERR_INV_BIN="Недопустимые символы в BIN_NAME."
|
||||||
|
L_ERR_ROOT="Для работы скрипта требуются права root или sudo."
|
||||||
|
L_ERR_SUDO_TTY="sudo требует пароль, но терминал (TTY) не обнаружен."
|
||||||
|
L_ERR_DIR_CHECK="Ошибка: конфиг является директорией."
|
||||||
|
L_ERR_CMD_NOT_FOUND="Необходимая команда не найдена:"
|
||||||
|
L_ERR_NO_DL_TOOL="Не установлен curl или wget."
|
||||||
|
L_ERR_NO_CP_TOOL="Необходима утилита cp или install."
|
||||||
|
L_WARN_NO_NET_TOOL="Утилиты сети не найдены. Проверка порта пропущена."
|
||||||
|
L_INFO_PORT_IGNORE="Порт занят текущим процессом телеметрии. Игнорируем."
|
||||||
|
L_ERR_PORT_IN_USE="Порт уже занят другим процессом:"
|
||||||
|
L_ERR_PORT_FREE="Освободите порт или укажите другой и попробуйте снова."
|
||||||
|
L_ERR_UNSUP_ARCH="Неподдерживаемая архитектура:"
|
||||||
|
L_ERR_CREATE_GRP="Не удалось создать группу"
|
||||||
|
L_ERR_CREATE_USR="Не удалось создать пользователя"
|
||||||
|
L_ERR_MKDIR="Не удалось создать директории"
|
||||||
|
L_ERR_INSTALL_DIR="не является директорией."
|
||||||
|
L_ERR_BIN_INSTALL="Не удалось установить бинарный файл"
|
||||||
|
L_ERR_BIN_COPY="Не удалось скопировать бинарный файл"
|
||||||
|
L_ERR_BIN_EXEC="Бинарный файл не исполняемый."
|
||||||
|
L_ERR_GEN_SEC="Не удалось сгенерировать секрет."
|
||||||
|
L_INFO_CONF_EXISTS="Конфиг уже существует. Обновление параметров..."
|
||||||
|
L_INFO_UPD_PORT="Обновлен порт:"
|
||||||
|
L_INFO_UPD_SEC="Обновлен секрет для пользователя 'hello'"
|
||||||
|
L_INFO_UPD_DOM="Обновлен tls_domain:"
|
||||||
|
L_INFO_UPD_TAG="Обновлен ad_tag"
|
||||||
|
L_ERR_CONF_INST="Не удалось установить конфиг"
|
||||||
|
L_INFO_CONF_OK="Конфиг успешно создан."
|
||||||
|
L_INFO_CONF_SEC="Настроен секрет для пользователя 'hello':"
|
||||||
|
L_WARN_SVC_FAIL="Не удалось запустить службу"
|
||||||
|
L_INFO_MANUAL_START="Менеджер служб не найден. Запустите вручную:"
|
||||||
|
L_INFO_UNINST_START="Начинается удаление"
|
||||||
|
L_U_STAGE_1=">>> Этап 1: Остановка служб"
|
||||||
|
L_U_STAGE_2=">>> Этап 2: Удаление конфигурации службы"
|
||||||
|
L_U_STAGE_3=">>> Этап 3: Завершение процессов пользователя"
|
||||||
|
L_U_STAGE_4=">>> Этап 4: Удаление бинарного файла"
|
||||||
|
L_U_STAGE_5=">>> Этап 5: Полная очистка (конфиг, данные, пользователь)"
|
||||||
|
L_INFO_KEEP_CONF="Примечание: Конфигурация сохранена. Используйте 'purge' для очистки."
|
||||||
|
L_INFO_I_START="Начинается установка"
|
||||||
|
L_I_STAGE_1=">>> Этап 1: Проверка окружения и зависимостей"
|
||||||
|
L_I_STAGE_1_5=">>> Этап 1.5: Интерактивная настройка"
|
||||||
|
L_I_PROMPT_DOM="\nПожалуйста, укажите домен TLS\nНажмите Enter, чтобы оставить по умолчанию [%s]: "
|
||||||
|
L_WARN_NO_TTY="Интерактивный режим недоступен (нет TTY). Используется:"
|
||||||
|
L_I_STAGE_2=">>> Этап 2: Загрузка архива"
|
||||||
|
L_ERR_TMP_DIR="Не удалось создать временную директорию"
|
||||||
|
L_ERR_TMP_INV="Временная директория недействительна"
|
||||||
|
L_INFO_FALLBACK="Сборка x86_64-v3 не найдена, откат к стандартной x86_64..."
|
||||||
|
L_ERR_DL_FAIL="Ошибка загрузки архива"
|
||||||
|
L_I_STAGE_3=">>> Этап 3: Распаковка архива"
|
||||||
|
L_ERR_EXTRACT="Ошибка распаковки архива."
|
||||||
|
L_ERR_BIN_NOT_FOUND="Бинарный файл не найден в архиве"
|
||||||
|
L_I_STAGE_4=">>> Этап 4: Настройка окружения (Юзер, Группа, Папки)"
|
||||||
|
L_I_STAGE_5=">>> Этап 5: Установка бинарного файла"
|
||||||
|
L_I_STAGE_6=">>> Этап 6: Генерация/Обновление конфигурации"
|
||||||
|
L_I_STAGE_7=">>> Этап 7: Установка и запуск службы"
|
||||||
|
L_OUT_WARN_H="УСТАНОВКА ЗАВЕРШЕНА С ПРЕДУПРЕЖДЕНИЯМИ"
|
||||||
|
L_OUT_WARN_D="Служба установлена, но не запустилась.\nПожалуйста, проверьте логи.\n"
|
||||||
|
L_OUT_SUCC_H="УСТАНОВКА УСПЕШНО ЗАВЕРШЕНА"
|
||||||
|
L_OUT_UNINST_H="УДАЛЕНИЕ ЗАВЕРШЕНО"
|
||||||
|
L_OUT_LINK="Ваша ссылка для подключения к Telegram Proxy:\n"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
L_ERR_DOMAIN_REQ="requires a domain argument."
|
||||||
|
L_ERR_PORT_REQ="requires a port argument."
|
||||||
|
L_ERR_PORT_NUM="Port must be a valid number."
|
||||||
|
L_ERR_PORT_RANGE="Port must be between 1 and 65535."
|
||||||
|
L_ERR_SECRET_REQ="requires a secret argument."
|
||||||
|
L_ERR_SECRET_HEX="Secret must contain only hex characters."
|
||||||
|
L_ERR_SECRET_LEN="Secret must be exactly 32 chars."
|
||||||
|
L_ERR_ADTAG_REQ="requires an ad_tag argument."
|
||||||
|
L_ERR_UNKNOWN_OPT="Unknown option:"
|
||||||
|
L_WARN_EXTRA_ARG="Ignoring extra argument:"
|
||||||
|
L_ERR_REQ_ARG="requires an argument (1, 2, en, ru)."
|
||||||
|
L_ERR_EMPTY_VAR="cannot be empty."
|
||||||
|
L_ERR_INV_VER="Invalid characters in version."
|
||||||
|
L_ERR_INV_BIN="Invalid characters in BIN_NAME."
|
||||||
|
L_ERR_ROOT="This script requires root or sudo."
|
||||||
|
L_ERR_SUDO_TTY="sudo requires a password, but no TTY detected."
|
||||||
|
L_ERR_DIR_CHECK="Safety check failed: Config is a directory."
|
||||||
|
L_ERR_CMD_NOT_FOUND="Required command not found:"
|
||||||
|
L_ERR_NO_DL_TOOL="Neither curl nor wget is installed."
|
||||||
|
L_ERR_NO_CP_TOOL="Need cp or install."
|
||||||
|
L_WARN_NO_NET_TOOL="Network tools not found. Skipping port check."
|
||||||
|
L_INFO_PORT_IGNORE="Port is in use by telemt. Ignoring as it will be restarted."
|
||||||
|
L_ERR_PORT_IN_USE="Port is already in use by another process:"
|
||||||
|
L_ERR_PORT_FREE="Please free the port or change it and try again."
|
||||||
|
L_ERR_UNSUP_ARCH="Unsupported architecture:"
|
||||||
|
L_ERR_CREATE_GRP="Cannot create group"
|
||||||
|
L_ERR_CREATE_USR="Cannot create user"
|
||||||
|
L_ERR_MKDIR="Failed to create directories"
|
||||||
|
L_ERR_INSTALL_DIR="is not a directory."
|
||||||
|
L_ERR_BIN_INSTALL="Failed to install binary"
|
||||||
|
L_ERR_BIN_COPY="Failed to copy binary"
|
||||||
|
L_ERR_BIN_EXEC="Binary not executable."
|
||||||
|
L_ERR_GEN_SEC="Failed to generate secret."
|
||||||
|
L_INFO_CONF_EXISTS="Config already exists. Updating parameters..."
|
||||||
|
L_INFO_UPD_PORT="Updated port:"
|
||||||
|
L_INFO_UPD_SEC="Updated secret for user 'hello'"
|
||||||
|
L_INFO_UPD_DOM="Updated tls_domain:"
|
||||||
|
L_INFO_UPD_TAG="Updated ad_tag"
|
||||||
|
L_ERR_CONF_INST="Failed to install config"
|
||||||
|
L_INFO_CONF_OK="Config created successfully."
|
||||||
|
L_INFO_CONF_SEC="Configured secret for user 'hello':"
|
||||||
|
L_WARN_SVC_FAIL="Failed to start service"
|
||||||
|
L_INFO_MANUAL_START="Service manager not found. Start manually:"
|
||||||
|
L_INFO_UNINST_START="Starting uninstallation of"
|
||||||
|
L_U_STAGE_1=">>> Stage 1: Stopping services"
|
||||||
|
L_U_STAGE_2=">>> Stage 2: Removing service configuration"
|
||||||
|
L_U_STAGE_3=">>> Stage 3: Terminating user processes"
|
||||||
|
L_U_STAGE_4=">>> Stage 4: Removing binary"
|
||||||
|
L_U_STAGE_5=">>> Stage 5: Purging configuration, data, and user"
|
||||||
|
L_INFO_KEEP_CONF="Note: Configuration kept. Run with 'purge' to remove completely."
|
||||||
|
L_INFO_I_START="Starting installation of"
|
||||||
|
L_I_STAGE_1=">>> Stage 1: Verifying environment and dependencies"
|
||||||
|
L_I_STAGE_1_5=">>> Stage 1.5: Interactive Setup"
|
||||||
|
L_I_PROMPT_DOM="\nPlease specify the TLS Domain\nPress Enter to keep default [%s]: "
|
||||||
|
L_WARN_NO_TTY="Interactive mode unavailable (no TTY). Using:"
|
||||||
|
L_I_STAGE_2=">>> Stage 2: Downloading archive"
|
||||||
|
L_ERR_TMP_DIR="Temp directory creation failed"
|
||||||
|
L_ERR_TMP_INV="Temp directory is invalid or was not created"
|
||||||
|
L_INFO_FALLBACK="x86_64-v3 build not found, falling back to standard x86_64..."
|
||||||
|
L_ERR_DL_FAIL="Download failed"
|
||||||
|
L_I_STAGE_3=">>> Stage 3: Extracting archive"
|
||||||
|
L_ERR_EXTRACT="Extraction failed."
|
||||||
|
L_ERR_BIN_NOT_FOUND="Binary not found in archive"
|
||||||
|
L_I_STAGE_4=">>> Stage 4: Setting up environment (User, Group, Directories)"
|
||||||
|
L_I_STAGE_5=">>> Stage 5: Installing binary"
|
||||||
|
L_I_STAGE_6=">>> Stage 6: Generating/Updating configuration"
|
||||||
|
L_I_STAGE_7=">>> Stage 7: Installing and starting service"
|
||||||
|
L_OUT_WARN_H="INSTALLATION COMPLETED WITH WARNINGS"
|
||||||
|
L_OUT_WARN_D="The service was installed but failed to start.\nPlease check the logs to determine the issue.\n"
|
||||||
|
L_OUT_SUCC_H="INSTALLATION SUCCESS"
|
||||||
|
L_OUT_UNINST_H="UNINSTALLATION COMPLETE"
|
||||||
|
L_OUT_LINK="Your Telegram Proxy connection link:\n"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
set_language "$LANG_CHOICE"
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-h|--help) ACTION="help"; shift ;;
|
-h|--help) ACTION="help"; shift ;;
|
||||||
|
-l|--lang)
|
||||||
|
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||||
|
printf '[ERROR] %s %s\n' "$1" "$L_ERR_REQ_ARG" >&2; exit 1
|
||||||
|
fi
|
||||||
|
case "$2" in
|
||||||
|
ru|2) LANG_CHOICE="ru"; set_language "$LANG_CHOICE"; LANG_PROVIDED=1 ;;
|
||||||
|
en|1) LANG_CHOICE="en"; set_language "$LANG_CHOICE"; LANG_PROVIDED=1 ;;
|
||||||
|
*) printf '[ERROR] %s %s\n' "$1" "$L_ERR_REQ_ARG" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
shift 2 ;;
|
||||||
-d|--domain)
|
-d|--domain)
|
||||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||||
printf '[ERROR] %s requires a domain argument.\n' "$1" >&2
|
printf '[ERROR] %s %s\n' "$1" "$L_ERR_DOMAIN_REQ" >&2; exit 1
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
TLS_DOMAIN="$2"; DOMAIN_PROVIDED=1; shift 2 ;;
|
TLS_DOMAIN="$2"; DOMAIN_PROVIDED=1; shift 2 ;;
|
||||||
-p|--port)
|
-p|--port)
|
||||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||||
printf '[ERROR] %s requires a port argument.\n' "$1" >&2; exit 1
|
printf '[ERROR] %s %s\n' "$1" "$L_ERR_PORT_REQ" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
case "$2" in
|
case "$2" in
|
||||||
*[!0-9]*) printf '[ERROR] Port must be a valid number.\n' >&2; exit 1 ;;
|
*[!0-9]*) printf '[ERROR] %s\n' "$L_ERR_PORT_NUM" >&2; exit 1 ;;
|
||||||
esac
|
esac
|
||||||
port_num="$(printf '%s\n' "$2" | sed 's/^0*//')"
|
port_num="$(printf '%s\n' "$2" | sed 's/^0*//')"
|
||||||
[ -z "$port_num" ] && port_num="0"
|
[ -z "$port_num" ] && port_num="0"
|
||||||
if [ "${#port_num}" -gt 5 ] || [ "$port_num" -lt 1 ] || [ "$port_num" -gt 65535 ]; then
|
if [ "${#port_num}" -gt 5 ] || [ "$port_num" -lt 1 ] || [ "$port_num" -gt 65535 ]; then
|
||||||
printf '[ERROR] Port must be between 1 and 65535.\n' >&2; exit 1
|
printf '[ERROR] %s\n' "$L_ERR_PORT_RANGE" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
SERVER_PORT="$port_num"; PORT_PROVIDED=1; shift 2 ;;
|
SERVER_PORT="$port_num"; PORT_PROVIDED=1; shift 2 ;;
|
||||||
-s|--secret)
|
-s|--secret)
|
||||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||||
printf '[ERROR] %s requires a secret argument.\n' "$1" >&2; exit 1
|
printf '[ERROR] %s %s\n' "$1" "$L_ERR_SECRET_REQ" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
case "$2" in
|
case "$2" in
|
||||||
*[!0-9a-fA-F]*)
|
*[!0-9a-fA-F]*) printf '[ERROR] %s\n' "$L_ERR_SECRET_HEX" >&2; exit 1 ;;
|
||||||
printf '[ERROR] Secret must contain only hex characters.\n' >&2; exit 1 ;;
|
|
||||||
esac
|
esac
|
||||||
if [ "${#2}" -ne 32 ]; then
|
if [ "${#2}" -ne 32 ]; then
|
||||||
printf '[ERROR] Secret must be exactly 32 chars.\n' >&2; exit 1
|
printf '[ERROR] %s\n' "$L_ERR_SECRET_LEN" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
USER_SECRET="$2"; SECRET_PROVIDED=1; shift 2 ;;
|
USER_SECRET="$2"; SECRET_PROVIDED=1; shift 2 ;;
|
||||||
-a|--ad-tag|--ad_tag)
|
-a|--ad-tag|--ad_tag)
|
||||||
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
if [ "$#" -lt 2 ] || [ -z "$2" ]; then
|
||||||
printf '[ERROR] %s requires an ad_tag argument.\n' "$1" >&2; exit 1
|
printf '[ERROR] %s %s\n' "$1" "$L_ERR_ADTAG_REQ" >&2; exit 1
|
||||||
fi
|
fi
|
||||||
AD_TAG="$2"; AD_TAG_PROVIDED=1; shift 2 ;;
|
AD_TAG="$2"; AD_TAG_PROVIDED=1; shift 2 ;;
|
||||||
uninstall|--uninstall)
|
uninstall|--uninstall)
|
||||||
|
|
@ -69,14 +234,31 @@ while [ $# -gt 0 ]; do
|
||||||
shift ;;
|
shift ;;
|
||||||
purge|--purge) ACTION="purge"; shift ;;
|
purge|--purge) ACTION="purge"; shift ;;
|
||||||
install|--install) ACTION="install"; shift ;;
|
install|--install) ACTION="install"; shift ;;
|
||||||
-*) printf '[ERROR] Unknown option: %s\n' "$1" >&2; exit 1 ;;
|
-*) printf '[ERROR] %s %s\n' "$L_ERR_UNKNOWN_OPT" "$1" >&2; exit 1 ;;
|
||||||
*)
|
*)
|
||||||
if [ "$ACTION" = "install" ]; then TARGET_VERSION="$1"
|
if [ "$ACTION" = "install" ]; then TARGET_VERSION="$1"
|
||||||
else printf '[WARNING] Ignoring extra argument: %s\n' "$1" >&2; fi
|
else printf '[WARNING] %s %s\n' "$L_WARN_EXTRA_ARG" "$1" >&2; fi
|
||||||
shift ;;
|
shift ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ "$ACTION" != "help" ] && [ "$LANG_PROVIDED" -eq 0 ]; then
|
||||||
|
if [ -t 0 ] || [ -c /dev/tty ]; then
|
||||||
|
printf "\nSelect language / Выберите язык:\n"
|
||||||
|
printf " 1) English (default)\n"
|
||||||
|
printf " 2) Русский\n"
|
||||||
|
printf "Your choice / Ваш выбор [1/2]: "
|
||||||
|
read -r input_lang </dev/tty || input_lang=""
|
||||||
|
case "$input_lang" in
|
||||||
|
2) LANG_CHOICE="ru" ;;
|
||||||
|
*) LANG_CHOICE="en" ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
LANG_CHOICE="en"
|
||||||
|
fi
|
||||||
|
set_language "$LANG_CHOICE"
|
||||||
|
fi
|
||||||
|
|
||||||
say() {
|
say() {
|
||||||
if [ "$#" -eq 0 ] || [ -z "${1:-}" ]; then
|
if [ "$#" -eq 0 ] || [ -z "${1:-}" ]; then
|
||||||
printf '\n'
|
printf '\n'
|
||||||
|
|
@ -96,17 +278,33 @@ cleanup() {
|
||||||
trap cleanup EXIT INT TERM
|
trap cleanup EXIT INT TERM
|
||||||
|
|
||||||
show_help() {
|
show_help() {
|
||||||
say "Usage: $0 [ <version> | install | uninstall | purge ] [ options ]"
|
if [ "$LANG_CHOICE" = "ru" ]; then
|
||||||
say " <version> Install specific version (e.g. 3.3.15, default: latest)"
|
say "Использование: $0 [ <версия> | install | uninstall | purge ] [ опции ]"
|
||||||
say " install Install the latest version"
|
say " <версия> Установить конкретную версию (например, 3.3.15, по умолчанию: latest)"
|
||||||
say " uninstall Remove the binary and service"
|
say " install Установить последнюю версию"
|
||||||
say " purge Remove everything including configuration, data, and user"
|
say " uninstall Удалить бинарный файл и службу"
|
||||||
say ""
|
say " purge Полностью удалить вместе с конфигурацией, данными и пользователем"
|
||||||
say "Options:"
|
say ""
|
||||||
say " -d, --domain Set TLS domain (default: petrovich.ru)"
|
say "Опции:"
|
||||||
say " -p, --port Set server port (default: 443)"
|
say " -d, --domain Указать домен TLS (по умолчанию: petrovich.ru)"
|
||||||
say " -s, --secret Set specific user secret (32 hex characters)"
|
say " -p, --port Указать порт сервера (по умолчанию: 443)"
|
||||||
say " -a, --ad-tag Set ad_tag"
|
say " -s, --secret Указать секрет пользователя (32 hex символа)"
|
||||||
|
say " -a, --ad-tag Указать ad_tag"
|
||||||
|
say " -l, --lang Выбрать язык вывода (1/en или 2/ru)"
|
||||||
|
else
|
||||||
|
say "Usage: $0 [ <version> | install | uninstall | purge ] [ options ]"
|
||||||
|
say " <version> Install specific version (e.g. 3.3.15, default: latest)"
|
||||||
|
say " install Install the latest version"
|
||||||
|
say " uninstall Remove the binary and service"
|
||||||
|
say " purge Remove everything including configuration, data, and user"
|
||||||
|
say ""
|
||||||
|
say "Options:"
|
||||||
|
say " -d, --domain Set TLS domain (default: petrovich.ru)"
|
||||||
|
say " -p, --port Set server port (default: 443)"
|
||||||
|
say " -s, --secret Set specific user secret (32 hex characters)"
|
||||||
|
say " -a, --ad-tag Set ad_tag"
|
||||||
|
say " -l, --lang Set output language (1/en or 2/ru)"
|
||||||
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,17 +369,13 @@ is_config_exists() {
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_common() {
|
verify_common() {
|
||||||
[ -n "$BIN_NAME" ] || die "BIN_NAME cannot be empty."
|
[ -n "$BIN_NAME" ] || die "BIN_NAME $L_ERR_EMPTY_VAR"
|
||||||
[ -n "$INSTALL_DIR" ] || die "INSTALL_DIR cannot be empty."
|
[ -n "$INSTALL_DIR" ] || die "INSTALL_DIR $L_ERR_EMPTY_VAR"
|
||||||
[ -n "$CONFIG_DIR" ] || die "CONFIG_DIR cannot be empty."
|
[ -n "$CONFIG_DIR" ] || die "CONFIG_DIR $L_ERR_EMPTY_VAR"
|
||||||
[ -n "$CONFIG_FILE" ] || die "CONFIG_FILE cannot be empty."
|
[ -n "$CONFIG_FILE" ] || die "CONFIG_FILE $L_ERR_EMPTY_VAR"
|
||||||
|
|
||||||
case "${INSTALL_DIR}${CONFIG_DIR}${WORK_DIR}${CONFIG_FILE}" in
|
case "$TARGET_VERSION" in *[!a-zA-Z0-9_.-]*) die "$L_ERR_INV_VER" ;; esac
|
||||||
*[!a-zA-Z0-9_./-]*) die "Invalid characters in paths." ;;
|
case "$BIN_NAME" in *[!a-zA-Z0-9_-]*) die "$L_ERR_INV_BIN" ;; esac
|
||||||
esac
|
|
||||||
|
|
||||||
case "$TARGET_VERSION" in *[!a-zA-Z0-9_.-]*) die "Invalid characters in version." ;; esac
|
|
||||||
case "$BIN_NAME" in *[!a-zA-Z0-9_-]*) die "Invalid characters in BIN_NAME." ;; esac
|
|
||||||
|
|
||||||
INSTALL_DIR="$(get_realpath "$INSTALL_DIR")"
|
INSTALL_DIR="$(get_realpath "$INSTALL_DIR")"
|
||||||
CONFIG_DIR="$(get_realpath "$CONFIG_DIR")"
|
CONFIG_DIR="$(get_realpath "$CONFIG_DIR")"
|
||||||
|
|
@ -195,42 +389,42 @@ verify_common() {
|
||||||
if [ "$(id -u)" -eq 0 ]; then
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
SUDO=""
|
SUDO=""
|
||||||
else
|
else
|
||||||
command -v sudo >/dev/null 2>&1 || die "This script requires root or sudo."
|
command -v sudo >/dev/null 2>&1 || die "$L_ERR_ROOT"
|
||||||
SUDO="sudo"
|
SUDO="sudo"
|
||||||
if ! sudo -n true 2>/dev/null; then
|
if ! sudo -n true 2>/dev/null; then
|
||||||
if ! [ -t 0 ]; then
|
if ! [ -t 0 ]; then
|
||||||
die "sudo requires a password, but no TTY detected."
|
die "$L_ERR_SUDO_TTY"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$SUDO" ]; then
|
if [ -n "$SUDO" ]; then
|
||||||
if $SUDO sh -c '[ -d "$1" ]' _ "$CONFIG_FILE"; then
|
if $SUDO sh -c '[ -d "$1" ]' _ "$CONFIG_FILE"; then
|
||||||
die "Safety check failed: CONFIG_FILE '$CONFIG_FILE' is a directory."
|
die "$L_ERR_DIR_CHECK"
|
||||||
fi
|
fi
|
||||||
elif [ -d "$CONFIG_FILE" ]; then
|
elif [ -d "$CONFIG_FILE" ]; then
|
||||||
die "Safety check failed: CONFIG_FILE '$CONFIG_FILE' is a directory."
|
die "$L_ERR_DIR_CHECK"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for cmd in id uname awk grep find rm chown chmod mv mktemp mkdir tr dd sed ps head sleep cat tar gzip; do
|
for cmd in id uname awk grep find rm chown chmod mv mktemp mkdir tr dd sed ps head sleep cat tar gzip; do
|
||||||
command -v "$cmd" >/dev/null 2>&1 || die "Required command not found: $cmd"
|
command -v "$cmd" >/dev/null 2>&1 || die "$L_ERR_CMD_NOT_FOUND $cmd"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_install_deps() {
|
verify_install_deps() {
|
||||||
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || die "Neither curl nor wget is installed."
|
command -v curl >/dev/null 2>&1 || command -v wget >/dev/null 2>&1 || die "$L_ERR_NO_DL_TOOL"
|
||||||
command -v cp >/dev/null 2>&1 || command -v install >/dev/null 2>&1 || die "Need cp or install"
|
command -v cp >/dev/null 2>&1 || command -v install >/dev/null 2>&1 || die "$L_ERR_NO_CP_TOOL"
|
||||||
|
|
||||||
if ! command -v setcap >/dev/null 2>&1 || ! command -v conntrack >/dev/null 2>&1; then
|
if ! command -v setcap >/dev/null 2>&1; then
|
||||||
if command -v apk >/dev/null 2>&1; then
|
if command -v apk >/dev/null 2>&1; then
|
||||||
$SUDO apk add --no-cache libcap-utils libcap conntrack-tools >/dev/null 2>&1 || true
|
$SUDO apk add --no-cache libcap-utils libcap >/dev/null 2>&1 || true
|
||||||
elif command -v apt-get >/dev/null 2>&1; then
|
elif command -v apt-get >/dev/null 2>&1; then
|
||||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin conntrack >/dev/null 2>&1 || {
|
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin >/dev/null 2>&1 || {
|
||||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update -q >/dev/null 2>&1 || true
|
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get update -q >/dev/null 2>&1 || true
|
||||||
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin conntrack >/dev/null 2>&1 || true
|
$SUDO env DEBIAN_FRONTEND=noninteractive apt-get install -y -q libcap2-bin >/dev/null 2>&1 || true
|
||||||
}
|
}
|
||||||
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y -q libcap conntrack-tools >/dev/null 2>&1 || true
|
elif command -v dnf >/dev/null 2>&1; then $SUDO dnf install -y -q libcap >/dev/null 2>&1 || true
|
||||||
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y -q libcap conntrack-tools >/dev/null 2>&1 || true
|
elif command -v yum >/dev/null 2>&1; then $SUDO yum install -y -q libcap >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -245,17 +439,17 @@ check_port_availability() {
|
||||||
elif command -v lsof >/dev/null 2>&1; then
|
elif command -v lsof >/dev/null 2>&1; then
|
||||||
port_info=$($SUDO lsof -i :${SERVER_PORT} 2>/dev/null | grep LISTEN || true)
|
port_info=$($SUDO lsof -i :${SERVER_PORT} 2>/dev/null | grep LISTEN || true)
|
||||||
else
|
else
|
||||||
say "[WARNING] Network diagnostic tools (ss, netstat, lsof) not found. Skipping port check."
|
say "[WARNING] $L_WARN_NO_NET_TOOL"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$port_info" ]; then
|
if [ -n "$port_info" ]; then
|
||||||
if printf '%s\n' "$port_info" | grep -q "${BIN_NAME}"; then
|
if printf '%s\n' "$port_info" | grep -q "${BIN_NAME}"; then
|
||||||
say " -> Port ${SERVER_PORT} is in use by ${BIN_NAME}. Ignoring as it will be restarted."
|
say " -> $L_INFO_PORT_IGNORE"
|
||||||
else
|
else
|
||||||
say "[ERROR] Port ${SERVER_PORT} is already in use by another process:"
|
say "[ERROR] $L_ERR_PORT_IN_USE $SERVER_PORT:"
|
||||||
printf ' %s\n' "$port_info"
|
printf ' %s\n' "$port_info"
|
||||||
die "Please free the port ${SERVER_PORT} or change it and try again."
|
die "$L_ERR_PORT_FREE"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -271,7 +465,7 @@ detect_arch() {
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
aarch64|arm64) echo "aarch64" ;;
|
aarch64|arm64) echo "aarch64" ;;
|
||||||
*) die "Unsupported architecture: $sys_arch" ;;
|
*) die "$L_ERR_UNSUP_ARCH $sys_arch" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,7 +489,7 @@ ensure_user_group() {
|
||||||
if ! check_os_entity group telemt; then
|
if ! check_os_entity group telemt; then
|
||||||
if command -v groupadd >/dev/null 2>&1; then $SUDO groupadd -r telemt
|
if command -v groupadd >/dev/null 2>&1; then $SUDO groupadd -r telemt
|
||||||
elif command -v addgroup >/dev/null 2>&1; then $SUDO addgroup -S telemt
|
elif command -v addgroup >/dev/null 2>&1; then $SUDO addgroup -S telemt
|
||||||
else die "Cannot create group"; fi
|
else die "$L_ERR_CREATE_GRP" ; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! check_os_entity passwd telemt; then
|
if ! check_os_entity passwd telemt; then
|
||||||
|
|
@ -307,12 +501,12 @@ ensure_user_group() {
|
||||||
else
|
else
|
||||||
$SUDO adduser --system --home "$WORK_DIR" --shell "$nologin_bin" --no-create-home --ingroup telemt --disabled-password telemt
|
$SUDO adduser --system --home "$WORK_DIR" --shell "$nologin_bin" --no-create-home --ingroup telemt --disabled-password telemt
|
||||||
fi
|
fi
|
||||||
else die "Cannot create user"; fi
|
else die "$L_ERR_CREATE_USR"; fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_dirs() {
|
setup_dirs() {
|
||||||
$SUDO mkdir -p "$WORK_DIR" "$CONFIG_DIR" "$CONFIG_PARENT_DIR" || die "Failed to create directories"
|
$SUDO mkdir -p "$WORK_DIR" "$CONFIG_DIR" "$CONFIG_PARENT_DIR" || die "$L_ERR_MKDIR"
|
||||||
|
|
||||||
$SUDO chown telemt:telemt "$WORK_DIR" && $SUDO chmod 750 "$WORK_DIR"
|
$SUDO chown telemt:telemt "$WORK_DIR" && $SUDO chmod 750 "$WORK_DIR"
|
||||||
$SUDO chown telemt:telemt "$CONFIG_DIR" && $SUDO chmod 750 "$CONFIG_DIR"
|
$SUDO chown telemt:telemt "$CONFIG_DIR" && $SUDO chmod 750 "$CONFIG_DIR"
|
||||||
|
|
@ -334,20 +528,20 @@ stop_service() {
|
||||||
install_binary() {
|
install_binary() {
|
||||||
bin_src="$1"; bin_dst="$2"
|
bin_src="$1"; bin_dst="$2"
|
||||||
if [ -e "$INSTALL_DIR" ] && [ ! -d "$INSTALL_DIR" ]; then
|
if [ -e "$INSTALL_DIR" ] && [ ! -d "$INSTALL_DIR" ]; then
|
||||||
die "'$INSTALL_DIR' is not a directory."
|
die "'$INSTALL_DIR' $L_ERR_INSTALL_DIR"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$SUDO mkdir -p "$INSTALL_DIR" || die "Failed to create install directory"
|
$SUDO mkdir -p "$INSTALL_DIR" || die "$L_ERR_MKDIR"
|
||||||
|
|
||||||
$SUDO rm -f "$bin_dst" 2>/dev/null || true
|
$SUDO rm -f "$bin_dst" 2>/dev/null || true
|
||||||
|
|
||||||
if command -v install >/dev/null 2>&1; then
|
if command -v install >/dev/null 2>&1; then
|
||||||
$SUDO install -m 0755 "$bin_src" "$bin_dst" || die "Failed to install binary"
|
$SUDO install -m 0755 "$bin_src" "$bin_dst" || die "$L_ERR_BIN_INSTALL"
|
||||||
else
|
else
|
||||||
$SUDO cp "$bin_src" "$bin_dst" && $SUDO chmod 0755 "$bin_dst" || die "Failed to copy binary"
|
$SUDO cp "$bin_src" "$bin_dst" && $SUDO chmod 0755 "$bin_dst" || die "$L_ERR_BIN_COPY"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$SUDO sh -c '[ -x "$1" ]' _ "$bin_dst" || die "Binary not executable: $bin_dst"
|
$SUDO sh -c '[ -x "$1" ]' _ "$bin_dst" || die "$L_ERR_BIN_EXEC $bin_dst"
|
||||||
|
|
||||||
if command -v setcap >/dev/null 2>&1; then
|
if command -v setcap >/dev/null 2>&1; then
|
||||||
$SUDO setcap cap_net_bind_service,cap_net_admin=+ep "$bin_dst" 2>/dev/null || true
|
$SUDO setcap cap_net_bind_service,cap_net_admin=+ep "$bin_dst" 2>/dev/null || true
|
||||||
|
|
@ -404,40 +598,32 @@ EOF
|
||||||
|
|
||||||
install_config() {
|
install_config() {
|
||||||
if is_config_exists; then
|
if is_config_exists; then
|
||||||
say " -> Config already exists at $CONFIG_FILE. Updating parameters..."
|
say " -> $L_INFO_CONF_EXISTS"
|
||||||
|
|
||||||
tmp_conf="${TEMP_DIR}/config.tmp"
|
tmp_conf="${TEMP_DIR}/config.tmp"
|
||||||
$SUDO cat "$CONFIG_FILE" > "$tmp_conf"
|
$SUDO cat "$CONFIG_FILE" > "$tmp_conf"
|
||||||
|
|
||||||
escaped_domain="$(printf '%s\n' "$TLS_DOMAIN" | tr -d '[:cntrl:]' | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
escaped_domain="$(printf '%s\n' "$TLS_DOMAIN" | tr -d '[:cntrl:]' | sed 's/\\/\\\\/g; s/"/\\"/g')"
|
||||||
|
|
||||||
export AWK_PORT="$SERVER_PORT"
|
awk -v port="$SERVER_PORT" -v secret="$USER_SECRET" -v domain="$escaped_domain" -v ad_tag="$AD_TAG" \
|
||||||
export AWK_SECRET="$USER_SECRET"
|
-v flag_p="$PORT_PROVIDED" -v flag_s="$SECRET_PROVIDED" -v flag_d="$DOMAIN_PROVIDED" -v flag_a="$AD_TAG_PROVIDED" '
|
||||||
export AWK_DOMAIN="$escaped_domain"
|
|
||||||
export AWK_AD_TAG="$AD_TAG"
|
|
||||||
export AWK_FLAG_P="$PORT_PROVIDED"
|
|
||||||
export AWK_FLAG_S="$SECRET_PROVIDED"
|
|
||||||
export AWK_FLAG_D="$DOMAIN_PROVIDED"
|
|
||||||
export AWK_FLAG_A="$AD_TAG_PROVIDED"
|
|
||||||
|
|
||||||
awk '
|
|
||||||
BEGIN { ad_tag_handled = 0 }
|
BEGIN { ad_tag_handled = 0 }
|
||||||
|
|
||||||
ENVIRON["AWK_FLAG_P"] == "1" && /^[ \t]*port[ \t]*=/ { print "port = " ENVIRON["AWK_PORT"]; next }
|
flag_p == "1" && /^[ \t]*port[ \t]*=/ { print "port = " port; next }
|
||||||
ENVIRON["AWK_FLAG_S"] == "1" && /^[ \t]*hello[ \t]*=/ { print "hello = \"" ENVIRON["AWK_SECRET"] "\""; next }
|
flag_s == "1" && /^[ \t]*hello[ \t]*=/ { print "hello = \"" secret "\""; next }
|
||||||
ENVIRON["AWK_FLAG_D"] == "1" && /^[ \t]*tls_domain[ \t]*=/ { print "tls_domain = \"" ENVIRON["AWK_DOMAIN"] "\""; next }
|
flag_d == "1" && /^[ \t]*tls_domain[ \t]*=/ { print "tls_domain = \"" domain "\""; next }
|
||||||
|
|
||||||
ENVIRON["AWK_FLAG_A"] == "1" && /^[ \t]*ad_tag[ \t]*=/ {
|
flag_a == "1" && /^[ \t]*ad_tag[ \t]*=/ {
|
||||||
if (!ad_tag_handled) {
|
if (!ad_tag_handled) {
|
||||||
print "ad_tag = \"" ENVIRON["AWK_AD_TAG"] "\"";
|
print "ad_tag = \"" ad_tag "\"";
|
||||||
ad_tag_handled = 1;
|
ad_tag_handled = 1;
|
||||||
}
|
}
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
ENVIRON["AWK_FLAG_A"] == "1" && /^\[general\]/ {
|
flag_a == "1" && /^\[general\]/ {
|
||||||
print;
|
print;
|
||||||
if (!ad_tag_handled) {
|
if (!ad_tag_handled) {
|
||||||
print "ad_tag = \"" ENVIRON["AWK_AD_TAG"] "\"";
|
print "ad_tag = \"" ad_tag "\"";
|
||||||
ad_tag_handled = 1;
|
ad_tag_handled = 1;
|
||||||
}
|
}
|
||||||
next
|
next
|
||||||
|
|
@ -446,10 +632,10 @@ install_config() {
|
||||||
{ print }
|
{ print }
|
||||||
' "$tmp_conf" > "${tmp_conf}.new" && mv "${tmp_conf}.new" "$tmp_conf"
|
' "$tmp_conf" > "${tmp_conf}.new" && mv "${tmp_conf}.new" "$tmp_conf"
|
||||||
|
|
||||||
[ "$PORT_PROVIDED" -eq 1 ] && say " -> Updated port: $SERVER_PORT"
|
[ "$PORT_PROVIDED" -eq 1 ] && say " -> $L_INFO_UPD_PORT $SERVER_PORT"
|
||||||
[ "$SECRET_PROVIDED" -eq 1 ] && say " -> Updated secret for user 'hello'"
|
[ "$SECRET_PROVIDED" -eq 1 ] && say " -> $L_INFO_UPD_SEC"
|
||||||
[ "$DOMAIN_PROVIDED" -eq 1 ] && say " -> Updated tls_domain: $TLS_DOMAIN"
|
[ "$DOMAIN_PROVIDED" -eq 1 ] && say " -> $L_INFO_UPD_DOM $TLS_DOMAIN"
|
||||||
[ "$AD_TAG_PROVIDED" -eq 1 ] && say " -> Updated ad_tag"
|
[ "$AD_TAG_PROVIDED" -eq 1 ] && say " -> $L_INFO_UPD_TAG"
|
||||||
|
|
||||||
write_root "$CONFIG_FILE" < "$tmp_conf"
|
write_root "$CONFIG_FILE" < "$tmp_conf"
|
||||||
rm -f "$tmp_conf"
|
rm -f "$tmp_conf"
|
||||||
|
|
@ -457,14 +643,14 @@ install_config() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$USER_SECRET" ]; then
|
if [ -z "$USER_SECRET" ]; then
|
||||||
USER_SECRET="$(generate_secret)" || die "Failed to generate secret."
|
USER_SECRET="$(generate_secret)" || die "$L_ERR_GEN_SEC"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
generate_config_content "$USER_SECRET" "$AD_TAG" | write_root "$CONFIG_FILE" || die "Failed to install config"
|
generate_config_content "$USER_SECRET" "$AD_TAG" | write_root "$CONFIG_FILE" || die "$L_ERR_CONF_INST"
|
||||||
$SUDO chown root:telemt "$CONFIG_FILE" && $SUDO chmod 640 "$CONFIG_FILE"
|
$SUDO chown root:telemt "$CONFIG_FILE" && $SUDO chmod 640 "$CONFIG_FILE"
|
||||||
|
|
||||||
say " -> Config created successfully."
|
say " -> $L_INFO_CONF_OK"
|
||||||
say " -> Configured secret for user 'hello': $USER_SECRET"
|
say " -> $L_INFO_CONF_SEC $USER_SECRET"
|
||||||
}
|
}
|
||||||
|
|
||||||
generate_systemd_content() {
|
generate_systemd_content() {
|
||||||
|
|
@ -517,7 +703,7 @@ install_service() {
|
||||||
$SUDO systemctl enable "$SERVICE_NAME" || true
|
$SUDO systemctl enable "$SERVICE_NAME" || true
|
||||||
|
|
||||||
if ! $SUDO systemctl start "$SERVICE_NAME"; then
|
if ! $SUDO systemctl start "$SERVICE_NAME"; then
|
||||||
say "[WARNING] Failed to start service"
|
say "[WARNING] $L_WARN_SVC_FAIL"
|
||||||
SERVICE_START_FAILED=1
|
SERVICE_START_FAILED=1
|
||||||
fi
|
fi
|
||||||
elif [ "$svc" = "openrc" ]; then
|
elif [ "$svc" = "openrc" ]; then
|
||||||
|
|
@ -527,15 +713,15 @@ install_service() {
|
||||||
$SUDO rc-update add "$SERVICE_NAME" default 2>/dev/null || true
|
$SUDO rc-update add "$SERVICE_NAME" default 2>/dev/null || true
|
||||||
|
|
||||||
if ! $SUDO rc-service "$SERVICE_NAME" start 2>/dev/null; then
|
if ! $SUDO rc-service "$SERVICE_NAME" start 2>/dev/null; then
|
||||||
say "[WARNING] Failed to start service"
|
say "[WARNING] $L_WARN_SVC_FAIL"
|
||||||
SERVICE_START_FAILED=1
|
SERVICE_START_FAILED=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
cmd="\"${INSTALL_DIR}/${BIN_NAME}\" \"${CONFIG_FILE}\""
|
cmd="\"${INSTALL_DIR}/${BIN_NAME}\" \"${CONFIG_FILE}\""
|
||||||
if [ -n "$SUDO" ]; then
|
if [ -n "$SUDO" ]; then
|
||||||
say " -> Service manager not found. Start manually: sudo -u telemt $cmd"
|
say " -> $L_INFO_MANUAL_START sudo -u telemt $cmd"
|
||||||
else
|
else
|
||||||
say " -> Service manager not found. Start manually: su -s /bin/sh telemt -c '$cmd'"
|
say " -> $L_INFO_MANUAL_START su -s /bin/sh telemt -c '$cmd'"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -566,12 +752,12 @@ kill_user_procs() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall() {
|
uninstall() {
|
||||||
say "Starting uninstallation of $BIN_NAME..."
|
say "$L_INFO_UNINST_START $BIN_NAME..."
|
||||||
|
|
||||||
say ">>> Stage 1: Stopping services"
|
say "$L_U_STAGE_1"
|
||||||
stop_service
|
stop_service
|
||||||
|
|
||||||
say ">>> Stage 2: Removing service configuration"
|
say "$L_U_STAGE_2"
|
||||||
svc="$(get_svc_mgr)"
|
svc="$(get_svc_mgr)"
|
||||||
if [ "$svc" = "systemd" ]; then
|
if [ "$svc" = "systemd" ]; then
|
||||||
$SUDO systemctl disable "$SERVICE_NAME" 2>/dev/null || true
|
$SUDO systemctl disable "$SERVICE_NAME" 2>/dev/null || true
|
||||||
|
|
@ -582,28 +768,30 @@ uninstall() {
|
||||||
$SUDO rm -f "/etc/init.d/${SERVICE_NAME}"
|
$SUDO rm -f "/etc/init.d/${SERVICE_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say ">>> Stage 3: Terminating user processes"
|
say "$L_U_STAGE_3"
|
||||||
kill_user_procs
|
kill_user_procs
|
||||||
|
|
||||||
say ">>> Stage 4: Removing binary"
|
say "$L_U_STAGE_4"
|
||||||
$SUDO rm -f "${INSTALL_DIR}/${BIN_NAME}"
|
$SUDO rm -f "${INSTALL_DIR}/${BIN_NAME}"
|
||||||
|
|
||||||
if [ "$ACTION" = "purge" ]; then
|
if [ "$ACTION" = "purge" ]; then
|
||||||
say ">>> Stage 5: Purging configuration, data, and user"
|
say "$L_U_STAGE_5"
|
||||||
$SUDO rm -rf "$CONFIG_DIR" "$WORK_DIR"
|
$SUDO rm -rf "$CONFIG_DIR" "$WORK_DIR"
|
||||||
$SUDO rm -f "$CONFIG_FILE"
|
$SUDO rm -f "$CONFIG_FILE"
|
||||||
sleep 1
|
|
||||||
$SUDO userdel telemt 2>/dev/null || $SUDO deluser telemt 2>/dev/null || true
|
if check_os_entity passwd telemt; then
|
||||||
|
$SUDO userdel telemt 2>/dev/null || $SUDO deluser telemt 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
if check_os_entity group telemt; then
|
if check_os_entity group telemt; then
|
||||||
$SUDO groupdel telemt 2>/dev/null || $SUDO delgroup telemt 2>/dev/null || true
|
$SUDO groupdel telemt 2>/dev/null || $SUDO delgroup telemt 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
say "Note: Configuration and user kept. Run with 'purge' to remove completely."
|
say "$L_INFO_KEEP_CONF"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '\n====================================================================\n'
|
printf '\n====================================================================\n'
|
||||||
printf ' UNINSTALLATION COMPLETE\n'
|
printf ' %s\n' "$L_OUT_UNINST_H"
|
||||||
printf '====================================================================\n\n'
|
printf '====================================================================\n\n'
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
@ -612,21 +800,45 @@ case "$ACTION" in
|
||||||
help) show_help ;;
|
help) show_help ;;
|
||||||
uninstall|purge) verify_common; uninstall ;;
|
uninstall|purge) verify_common; uninstall ;;
|
||||||
install)
|
install)
|
||||||
say "Starting installation of $BIN_NAME (Version: $TARGET_VERSION)"
|
say "$L_INFO_I_START $BIN_NAME (Version: $TARGET_VERSION)"
|
||||||
|
|
||||||
say ">>> Stage 1: Verifying environment and dependencies"
|
say "$L_I_STAGE_1"
|
||||||
verify_common
|
verify_common
|
||||||
verify_install_deps
|
verify_install_deps
|
||||||
|
|
||||||
if is_config_exists && [ "$PORT_PROVIDED" -eq 0 ]; then
|
if is_config_exists; then
|
||||||
ext_port="$($SUDO awk -F'=' '/^[ \t]*port[ \t]*=/ {gsub(/[^0-9]/, "", $2); print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
ext_port="$($SUDO awk -F'=' '/^[ \t]*port[ \t]*=/ {gsub(/[^0-9]/, "", $2); print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
||||||
if [ -n "$ext_port" ]; then
|
if [ -n "$ext_port" ] && [ "$PORT_PROVIDED" -eq 0 ]; then
|
||||||
SERVER_PORT="$ext_port"
|
SERVER_PORT="$ext_port"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ext_secret="$($SUDO awk -F'"' '/^[ \t]*hello[ \t]*=/ {print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
||||||
|
if [ -n "$ext_secret" ] && [ "$SECRET_PROVIDED" -eq 0 ]; then
|
||||||
|
USER_SECRET="$ext_secret"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ext_domain="$($SUDO awk -F'"' '/^[ \t]*tls_domain[ \t]*=/ {print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
||||||
|
if [ -n "$ext_domain" ] && [ "$DOMAIN_PROVIDED" -eq 0 ]; then
|
||||||
|
TLS_DOMAIN="$ext_domain"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
check_port_availability
|
check_port_availability
|
||||||
|
|
||||||
|
if [ "$DOMAIN_PROVIDED" -eq 0 ]; then
|
||||||
|
say "$L_I_STAGE_1_5"
|
||||||
|
if [ -t 0 ] || [ -c /dev/tty ]; then
|
||||||
|
printf "$L_I_PROMPT_DOM" "$TLS_DOMAIN"
|
||||||
|
read -r input_domain </dev/tty || input_domain=""
|
||||||
|
if [ -n "$input_domain" ]; then
|
||||||
|
TLS_DOMAIN="$input_domain"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
say "[WARNING] $L_WARN_NO_TTY $TLS_DOMAIN"
|
||||||
|
fi
|
||||||
|
DOMAIN_PROVIDED=1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$TARGET_VERSION" != "latest" ]; then
|
if [ "$TARGET_VERSION" != "latest" ]; then
|
||||||
TARGET_VERSION="${TARGET_VERSION#v}"
|
TARGET_VERSION="${TARGET_VERSION#v}"
|
||||||
fi
|
fi
|
||||||
|
|
@ -640,15 +852,15 @@ case "$ACTION" in
|
||||||
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say ">>> Stage 2: Downloading archive"
|
say "$L_I_STAGE_2"
|
||||||
TEMP_DIR="$(mktemp -d)" || die "Temp directory creation failed"
|
TEMP_DIR="$(mktemp -d)" || die "$L_ERR_TMP_DIR"
|
||||||
if [ -z "$TEMP_DIR" ] || [ ! -d "$TEMP_DIR" ]; then
|
if [ -z "$TEMP_DIR" ] || [ ! -d "$TEMP_DIR" ]; then
|
||||||
die "Temp directory is invalid or was not created"
|
die "$L_ERR_TMP_INV"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! fetch_file "$DL_URL" "${TEMP_DIR}/${FILE_NAME}"; then
|
if ! fetch_file "$DL_URL" "${TEMP_DIR}/${FILE_NAME}"; then
|
||||||
if [ "$ARCH" = "x86_64-v3" ]; then
|
if [ "$ARCH" = "x86_64-v3" ]; then
|
||||||
say " -> x86_64-v3 build not found, falling back to standard x86_64..."
|
say " -> $L_INFO_FALLBACK"
|
||||||
ARCH="x86_64"
|
ARCH="x86_64"
|
||||||
FILE_NAME="${BIN_NAME}-${ARCH}-linux-${LIBC}.tar.gz"
|
FILE_NAME="${BIN_NAME}-${ARCH}-linux-${LIBC}.tar.gz"
|
||||||
if [ "$TARGET_VERSION" = "latest" ]; then
|
if [ "$TARGET_VERSION" = "latest" ]; then
|
||||||
|
|
@ -656,64 +868,58 @@ case "$ACTION" in
|
||||||
else
|
else
|
||||||
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
DL_URL="https://github.com/${REPO}/releases/download/${TARGET_VERSION}/${FILE_NAME}"
|
||||||
fi
|
fi
|
||||||
fetch_file "$DL_URL" "${TEMP_DIR}/${FILE_NAME}" || die "Download failed"
|
fetch_file "$DL_URL" "${TEMP_DIR}/${FILE_NAME}" || die "$L_ERR_DL_FAIL"
|
||||||
else
|
else
|
||||||
die "Download failed"
|
die "$L_ERR_DL_FAIL"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say ">>> Stage 3: Extracting archive"
|
say "$L_I_STAGE_3"
|
||||||
if ! gzip -dc "${TEMP_DIR}/${FILE_NAME}" | tar -xf - -C "$TEMP_DIR" 2>/dev/null; then
|
if ! gzip -dc "${TEMP_DIR}/${FILE_NAME}" | tar -xf - -C "$TEMP_DIR" 2>/dev/null; then
|
||||||
die "Extraction failed (downloaded archive might be invalid or 404)."
|
die "$L_ERR_EXTRACT"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
EXTRACTED_BIN="$(find "$TEMP_DIR" -type f -name "$BIN_NAME" -print 2>/dev/null | head -n 1 || true)"
|
EXTRACTED_BIN="$(find "$TEMP_DIR" -type f -name "$BIN_NAME" -print 2>/dev/null | head -n 1 || true)"
|
||||||
[ -n "$EXTRACTED_BIN" ] || die "Binary '$BIN_NAME' not found in archive"
|
[ -n "$EXTRACTED_BIN" ] || die "$L_ERR_BIN_NOT_FOUND"
|
||||||
|
|
||||||
say ">>> Stage 4: Setting up environment (User, Group, Directories)"
|
say "$L_I_STAGE_4"
|
||||||
ensure_user_group; setup_dirs; stop_service
|
ensure_user_group; setup_dirs; stop_service
|
||||||
|
|
||||||
say ">>> Stage 5: Installing binary"
|
say "$L_I_STAGE_5"
|
||||||
install_binary "$EXTRACTED_BIN" "${INSTALL_DIR}/${BIN_NAME}"
|
install_binary "$EXTRACTED_BIN" "${INSTALL_DIR}/${BIN_NAME}"
|
||||||
|
|
||||||
say ">>> Stage 6: Generating/Updating configuration"
|
say "$L_I_STAGE_6"
|
||||||
install_config
|
install_config
|
||||||
|
|
||||||
say ">>> Stage 7: Installing and starting service"
|
say "$L_I_STAGE_7"
|
||||||
install_service
|
install_service
|
||||||
|
|
||||||
if [ "${SERVICE_START_FAILED:-0}" -eq 1 ]; then
|
if [ "${SERVICE_START_FAILED:-0}" -eq 1 ]; then
|
||||||
printf '\n====================================================================\n'
|
printf '\n====================================================================\n'
|
||||||
printf ' INSTALLATION COMPLETED WITH WARNINGS\n'
|
printf ' %s\n' "$L_OUT_WARN_H"
|
||||||
printf '====================================================================\n\n'
|
printf '====================================================================\n\n'
|
||||||
printf 'The service was installed but failed to start automatically.\n'
|
printf '%b' "$L_OUT_WARN_D"
|
||||||
printf 'Please check the logs to determine the issue.\n\n'
|
|
||||||
else
|
else
|
||||||
printf '\n====================================================================\n'
|
printf '\n====================================================================\n'
|
||||||
printf ' INSTALLATION SUCCESS\n'
|
printf ' %s\n' "$L_OUT_SUCC_H"
|
||||||
printf '====================================================================\n\n'
|
printf '====================================================================\n\n'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
svc="$(get_svc_mgr)"
|
SERVER_IP=""
|
||||||
if [ "$svc" = "systemd" ]; then
|
if command -v curl >/dev/null 2>&1; then SERVER_IP="$(curl -s4 -m 3 ifconfig.me 2>/dev/null || curl -s4 -m 3 api.ipify.org 2>/dev/null || true)"
|
||||||
printf 'To check the status of your proxy service, run:\n'
|
elif command -v wget >/dev/null 2>&1; then SERVER_IP="$(wget -qO- -T 3 ifconfig.me 2>/dev/null || wget -qO- -T 3 api.ipify.org 2>/dev/null || true)"; fi
|
||||||
printf ' systemctl status %s\n\n' "$SERVICE_NAME"
|
[ -z "$SERVER_IP" ] && SERVER_IP="<YOUR_SERVER_IP>"
|
||||||
elif [ "$svc" = "openrc" ]; then
|
|
||||||
printf 'To check the status of your proxy service, run:\n'
|
|
||||||
printf ' rc-service %s status\n\n' "$SERVICE_NAME"
|
|
||||||
fi
|
|
||||||
|
|
||||||
API_LISTEN="$($SUDO awk -F'"' '/^[ \t]*listen[ \t]*=/ {print $2; exit}' "$CONFIG_FILE" 2>/dev/null || true)"
|
if command -v xxd >/dev/null 2>&1; then HEX_DOMAIN="$(printf '%s' "$TLS_DOMAIN" | xxd -p | tr -d '\n')"
|
||||||
API_LISTEN="${API_LISTEN:-127.0.0.1:9091}"
|
elif command -v hexdump >/dev/null 2>&1; then HEX_DOMAIN="$(printf '%s' "$TLS_DOMAIN" | hexdump -v -e '/1 "%02x"')"
|
||||||
|
elif command -v od >/dev/null 2>&1; then HEX_DOMAIN="$(printf '%s' "$TLS_DOMAIN" | od -A n -t x1 | tr -d ' \n')"
|
||||||
|
else HEX_DOMAIN=""; fi
|
||||||
|
|
||||||
printf 'To get your user connection links (for Telegram), run:\n'
|
CLIENT_SECRET="ee${USER_SECRET}${HEX_DOMAIN}"
|
||||||
if command -v jq >/dev/null 2>&1; then
|
|
||||||
printf ' curl -s http://%s/v1/users | jq -r '\''.data[]? | "User: \\(.username)\\n\\(.links.tls[0] // empty)\\n"'\''\n' "$API_LISTEN"
|
|
||||||
else
|
|
||||||
printf ' curl -s http://%s/v1/users\n' "$API_LISTEN"
|
|
||||||
printf ' (Tip: Install '\''jq'\'' for a much cleaner output)\n'
|
|
||||||
fi
|
|
||||||
|
|
||||||
printf '\n====================================================================\n'
|
printf '%b\n' "$L_OUT_LINK"
|
||||||
|
printf ' tg://proxy?server=%s&port=%s&secret=%s\n\n' "$SERVER_IP" "$SERVER_PORT" "$CLIENT_SECRET"
|
||||||
|
|
||||||
|
printf '====================================================================\n'
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue