mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 12:16:01 +00:00
v2.2.1 hotfix: fix telemt download grep pattern (grep -iE), add QR cleanup, bump version to 2.2.1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
912
lib/common.sh
912
lib/common.sh
@@ -1,456 +1,456 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.2 — Общие утилиты
|
# GoTelegram v2.2 — Общие утилиты
|
||||||
# Цвета, логирование, спиннер, системные функции, совместимость с v1
|
# Цвета, логирование, спиннер, системные функции, совместимость с v1
|
||||||
|
|
||||||
# ── Версия ────────────────────────────────────────────────────────────────────
|
# ── Версия ────────────────────────────────────────────────────────────────────
|
||||||
GOTELEGRAM_VERSION="2.2.0"
|
GOTELEGRAM_VERSION="2.2.1"
|
||||||
GOTELEGRAM_NAME="GoTelegram"
|
GOTELEGRAM_NAME="GoTelegram"
|
||||||
|
|
||||||
# ── Пути ──────────────────────────────────────────────────────────────────────
|
# ── Пути ──────────────────────────────────────────────────────────────────────
|
||||||
GOTELEGRAM_DIR="/opt/gotelegram"
|
GOTELEGRAM_DIR="/opt/gotelegram"
|
||||||
GOTELEGRAM_CONFIG="$GOTELEGRAM_DIR/config.json"
|
GOTELEGRAM_CONFIG="$GOTELEGRAM_DIR/config.json"
|
||||||
TELEMT_CONFIG="/etc/telemt/config.toml"
|
TELEMT_CONFIG="/etc/telemt/config.toml"
|
||||||
TELEMT_BIN="/usr/local/bin/telemt"
|
TELEMT_BIN="/usr/local/bin/telemt"
|
||||||
TELEMT_SERVICE="telemt"
|
TELEMT_SERVICE="telemt"
|
||||||
NGINX_SITE_CONF="/etc/nginx/sites-available/gotelegram"
|
NGINX_SITE_CONF="/etc/nginx/sites-available/gotelegram"
|
||||||
NGINX_SITE_LINK="/etc/nginx/sites-enabled/gotelegram"
|
NGINX_SITE_LINK="/etc/nginx/sites-enabled/gotelegram"
|
||||||
WEBSITE_ROOT="/var/www/gotelegram-site"
|
WEBSITE_ROOT="/var/www/gotelegram-site"
|
||||||
BACKUP_DIR="$GOTELEGRAM_DIR/backups"
|
BACKUP_DIR="$GOTELEGRAM_DIR/backups"
|
||||||
LOG_FILE="/var/log/gotelegram.log"
|
LOG_FILE="/var/log/gotelegram.log"
|
||||||
BOT_DIR="/opt/gotelegram-bot"
|
BOT_DIR="/opt/gotelegram-bot"
|
||||||
|
|
||||||
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
||||||
V1_CONTAINER_NAME="mtproto-proxy"
|
V1_CONTAINER_NAME="mtproto-proxy"
|
||||||
V1_CONFIG_FILE="/opt/gotelegram-bot/proxy.json"
|
V1_CONFIG_FILE="/opt/gotelegram-bot/proxy.json"
|
||||||
V1_SERVICE_NAME="gotelegram-bot"
|
V1_SERVICE_NAME="gotelegram-bot"
|
||||||
|
|
||||||
# ── Цвета ────────────────────────────────────────────────────────────────────
|
# ── Цвета ────────────────────────────────────────────────────────────────────
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
CYAN='\033[0;36m'
|
CYAN='\033[0;36m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
MAGENTA='\033[0;35m'
|
MAGENTA='\033[0;35m'
|
||||||
BLUE='\033[0;34m'
|
BLUE='\033[0;34m'
|
||||||
WHITE='\033[1;37m'
|
WHITE='\033[1;37m'
|
||||||
BOLD='\033[1m'
|
BOLD='\033[1m'
|
||||||
DIM='\033[2m'
|
DIM='\033[2m'
|
||||||
NC='\033[0m'
|
NC='\033[0m'
|
||||||
|
|
||||||
# ── Логирование ──────────────────────────────────────────────────────────────
|
# ── Логирование ──────────────────────────────────────────────────────────────
|
||||||
log_info() { echo -e " ${CYAN}ℹ${NC} $*"; }
|
log_info() { echo -e " ${CYAN}ℹ${NC} $*"; }
|
||||||
log_success() { echo -e " ${GREEN}✓${NC} $*"; }
|
log_success() { echo -e " ${GREEN}✓${NC} $*"; }
|
||||||
log_warning() { echo -e " ${YELLOW}⚠${NC} $*"; }
|
log_warning() { echo -e " ${YELLOW}⚠${NC} $*"; }
|
||||||
log_error() { echo -e " ${RED}✗${NC} $*"; }
|
log_error() { echo -e " ${RED}✗${NC} $*"; }
|
||||||
log_step() { echo -e "\n${BOLD}${WHITE} $*${NC}"; }
|
log_step() { echo -e "\n${BOLD}${WHITE} $*${NC}"; }
|
||||||
log_dim() { echo -e " ${DIM}$*${NC}"; }
|
log_dim() { echo -e " ${DIM}$*${NC}"; }
|
||||||
|
|
||||||
log_to_file() {
|
log_to_file() {
|
||||||
local ts; ts=$(date '+%Y-%m-%d %H:%M:%S')
|
local ts; ts=$(date '+%Y-%m-%d %H:%M:%S')
|
||||||
echo "[$ts] $*" >> "$LOG_FILE" 2>/dev/null
|
echo "[$ts] $*" >> "$LOG_FILE" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Спиннер ──────────────────────────────────────────────────────────────────
|
# ── Спиннер ──────────────────────────────────────────────────────────────────
|
||||||
_spin_pid=""
|
_spin_pid=""
|
||||||
spinner_start() {
|
spinner_start() {
|
||||||
local msg="${1:-Подождите...}"
|
local msg="${1:-Подождите...}"
|
||||||
(
|
(
|
||||||
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
||||||
local i=0
|
local i=0
|
||||||
while true; do
|
while true; do
|
||||||
printf "\r ${CYAN}${frames[$i]}${NC} ${msg}" >&2
|
printf "\r ${CYAN}${frames[$i]}${NC} ${msg}" >&2
|
||||||
i=$(( (i+1) % ${#frames[@]} ))
|
i=$(( (i+1) % ${#frames[@]} ))
|
||||||
sleep 0.1
|
sleep 0.1
|
||||||
done
|
done
|
||||||
) &
|
) &
|
||||||
_spin_pid=$!
|
_spin_pid=$!
|
||||||
}
|
}
|
||||||
|
|
||||||
spinner_stop() {
|
spinner_stop() {
|
||||||
[ -n "$_spin_pid" ] && kill "$_spin_pid" 2>/dev/null && wait "$_spin_pid" 2>/dev/null
|
[ -n "$_spin_pid" ] && kill "$_spin_pid" 2>/dev/null && wait "$_spin_pid" 2>/dev/null
|
||||||
_spin_pid=""
|
_spin_pid=""
|
||||||
printf "\r\033[K" >&2
|
printf "\r\033[K" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Прогресс-бар ─────────────────────────────────────────────────────────────
|
# ── Прогресс-бар ─────────────────────────────────────────────────────────────
|
||||||
progress_bar() {
|
progress_bar() {
|
||||||
local current="$1" total="$2" label="${3:-}"
|
local current="$1" total="$2" label="${3:-}"
|
||||||
local pct=$(( current * 100 / total ))
|
local pct=$(( current * 100 / total ))
|
||||||
local filled=$(( pct / 2 ))
|
local filled=$(( pct / 2 ))
|
||||||
local empty=$(( 50 - filled ))
|
local empty=$(( 50 - filled ))
|
||||||
local bar=""
|
local bar=""
|
||||||
for ((i=0; i<filled; i++)); do bar+="█"; done
|
for ((i=0; i<filled; i++)); do bar+="█"; done
|
||||||
for ((i=0; i<empty; i++)); do bar+="░"; done
|
for ((i=0; i<empty; i++)); do bar+="░"; done
|
||||||
printf "\r ${GREEN}[${bar}]${NC} ${pct}%% ${label}" >&2
|
printf "\r ${GREEN}[${bar}]${NC} ${pct}%% ${label}" >&2
|
||||||
[ "$current" -eq "$total" ] && echo "" >&2
|
[ "$current" -eq "$total" ] && echo "" >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Выполнение с индикатором ─────────────────────────────────────────────────
|
# ── Выполнение с индикатором ─────────────────────────────────────────────────
|
||||||
run_with_spinner() {
|
run_with_spinner() {
|
||||||
local label="$1"; shift
|
local label="$1"; shift
|
||||||
local err_file="/tmp/.gotelegram_spinner_err_$$"
|
local err_file="/tmp/.gotelegram_spinner_err_$$"
|
||||||
spinner_start "$label"
|
spinner_start "$label"
|
||||||
"$@" >/dev/null 2>"$err_file"
|
"$@" >/dev/null 2>"$err_file"
|
||||||
local rc=$?
|
local rc=$?
|
||||||
spinner_stop
|
spinner_stop
|
||||||
if [ $rc -eq 0 ]; then
|
if [ $rc -eq 0 ]; then
|
||||||
log_success "$label"
|
log_success "$label"
|
||||||
else
|
else
|
||||||
log_error "$label ${RED}(ошибка, код: $rc)${NC}"
|
log_error "$label ${RED}(ошибка, код: $rc)${NC}"
|
||||||
if [ -s "$err_file" ]; then
|
if [ -s "$err_file" ]; then
|
||||||
log_dim " $(head -3 "$err_file")"
|
log_dim " $(head -3 "$err_file")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
rm -f "$err_file"
|
rm -f "$err_file"
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Баннер ───────────────────────────────────────────────────────────────────
|
# ── Баннер ───────────────────────────────────────────────────────────────────
|
||||||
show_banner() {
|
show_banner() {
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}╔══════════════════════════════════════════════════════════╗${NC}"
|
echo -e "${CYAN}╔══════════════════════════════════════════════════════════╗${NC}"
|
||||||
echo -e "${CYAN}║${NC} ${BOLD}${WHITE}🚀 GoTelegram v${GOTELEGRAM_VERSION}${NC} ${CYAN}║${NC}"
|
echo -e "${CYAN}║${NC} ${BOLD}${WHITE}🚀 GoTelegram v${GOTELEGRAM_VERSION}${NC} ${CYAN}║${NC}"
|
||||||
echo -e "${CYAN}║${NC} ${DIM}MTProxy на ядре telemt (Rust + Tokio)${NC} ${CYAN}║${NC}"
|
echo -e "${CYAN}║${NC} ${DIM}MTProxy на ядре telemt (Rust + Tokio)${NC} ${CYAN}║${NC}"
|
||||||
echo -e "${CYAN}║${NC} ${DIM}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC} ${CYAN}║${NC}"
|
echo -e "${CYAN}║${NC} ${DIM}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC} ${CYAN}║${NC}"
|
||||||
echo -e "${CYAN}╚══════════════════════════════════════════════════════════╝${NC}"
|
echo -e "${CYAN}╚══════════════════════════════════════════════════════════╝${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Благодарности ────────────────────────────────────────────────────────────
|
# ── Благодарности ────────────────────────────────────────────────────────────
|
||||||
show_credits() {
|
show_credits() {
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════╗${NC}"
|
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════╗${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${BOLD}Благодарности / Credits${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${BOLD}Благодарности / Credits${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}╟──────────────────────────────────────────────────────────╢${NC}"
|
echo -e "${MAGENTA}╟──────────────────────────────────────────────────────────╢${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${WHITE}telemt${NC} — MTProxy engine (Rust) ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${WHITE}telemt${NC} — MTProxy engine (Rust) ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${DIM}github.com/telemt/telemt${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${DIM}github.com/telemt/telemt${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${WHITE}HTML5 UP${NC} — адаптивные HTML/CSS шаблоны ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${WHITE}HTML5 UP${NC} — адаптивные HTML/CSS шаблоны ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${DIM}html5up.net • CC BY 3.0 • @ajlkn${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${DIM}html5up.net • CC BY 3.0 • @ajlkn${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${WHITE}learning-zone${NC} — 150+ HTML5 шаблонов ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${WHITE}learning-zone${NC} — 150+ HTML5 шаблонов ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${DIM}github.com/learning-zone/website-templates${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${DIM}github.com/learning-zone/website-templates${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${WHITE}Start Bootstrap${NC} — MIT лицензия ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${WHITE}Start Bootstrap${NC} — MIT лицензия ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}║${NC} ${DIM}startbootstrap.com${NC} ${MAGENTA}║${NC}"
|
echo -e "${MAGENTA}║${NC} ${DIM}startbootstrap.com${NC} ${MAGENTA}║${NC}"
|
||||||
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════╝${NC}"
|
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════╝${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Системные утилиты ────────────────────────────────────────────────────────
|
# ── Системные утилиты ────────────────────────────────────────────────────────
|
||||||
_valid_ip() {
|
_valid_ip() {
|
||||||
# Validate that each octet is 0-255
|
# Validate that each octet is 0-255
|
||||||
local ip="$1"
|
local ip="$1"
|
||||||
local IFS='.'
|
local IFS='.'
|
||||||
read -ra octets <<< "$ip"
|
read -ra octets <<< "$ip"
|
||||||
[ ${#octets[@]} -ne 4 ] && return 1
|
[ ${#octets[@]} -ne 4 ] && return 1
|
||||||
for octet in "${octets[@]}"; do
|
for octet in "${octets[@]}"; do
|
||||||
[[ "$octet" =~ ^[0-9]+$ ]] || return 1
|
[[ "$octet" =~ ^[0-9]+$ ]] || return 1
|
||||||
[ "$octet" -gt 255 ] && return 1
|
[ "$octet" -gt 255 ] && return 1
|
||||||
done
|
done
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
get_server_ip() {
|
get_server_ip() {
|
||||||
local ip raw
|
local ip raw
|
||||||
for url in "https://api.ipify.org" "https://icanhazip.com" "https://ifconfig.me"; do
|
for url in "https://api.ipify.org" "https://icanhazip.com" "https://ifconfig.me"; do
|
||||||
raw=$(curl -s -4 --max-time 5 "$url" 2>/dev/null)
|
raw=$(curl -s -4 --max-time 5 "$url" 2>/dev/null)
|
||||||
ip=$(echo "$raw" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
|
ip=$(echo "$raw" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' | head -1)
|
||||||
if [ -n "$ip" ] && _valid_ip "$ip"; then
|
if [ -n "$ip" ] && _valid_ip "$ip"; then
|
||||||
echo "$ip"
|
echo "$ip"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
echo "0.0.0.0"
|
echo "0.0.0.0"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
check_root() {
|
check_root() {
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$EUID" -ne 0 ]; then
|
||||||
log_error "Запустите скрипт с sudo / от root"
|
log_error "Запустите скрипт с sudo / от root"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_os() {
|
check_os() {
|
||||||
if [ ! -f /etc/os-release ]; then
|
if [ ! -f /etc/os-release ]; then
|
||||||
log_error "Не удалось определить ОС. Требуется Linux."
|
log_error "Не удалось определить ОС. Требуется Linux."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
# Validate os-release before sourcing (reject command injection: ;, backticks, $())
|
# Validate os-release before sourcing (reject command injection: ;, backticks, $())
|
||||||
if grep -qE '(;|`|\$\(|\$\{)' /etc/os-release 2>/dev/null; then
|
if grep -qE '(;|`|\$\(|\$\{)' /etc/os-release 2>/dev/null; then
|
||||||
log_warning "/etc/os-release содержит подозрительные строки, пропускаем"
|
log_warning "/etc/os-release содержит подозрительные строки, пропускаем"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
case "$ID" in
|
case "$ID" in
|
||||||
ubuntu|debian|centos|rocky|almalinux|fedora|rhel)
|
ubuntu|debian|centos|rocky|almalinux|fedora|rhel)
|
||||||
log_dim "ОС: $PRETTY_NAME"
|
log_dim "ОС: $PRETTY_NAME"
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
log_warning "ОС $ID может быть несовместима. Поддерживаются: Ubuntu, Debian, CentOS, Rocky."
|
log_warning "ОС $ID может быть несовместима. Поддерживаются: Ubuntu, Debian, CentOS, Rocky."
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
get_arch() {
|
get_arch() {
|
||||||
local arch
|
local arch
|
||||||
arch=$(uname -m)
|
arch=$(uname -m)
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
x86_64|amd64) echo "amd64" ;;
|
x86_64|amd64) echo "amd64" ;;
|
||||||
aarch64|arm64) echo "arm64" ;;
|
aarch64|arm64) echo "arm64" ;;
|
||||||
armv7*|armhf) echo "armv7" ;;
|
armv7*|armhf) echo "armv7" ;;
|
||||||
*) echo "$arch" ;;
|
*) echo "$arch" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
get_pkg_manager() {
|
get_pkg_manager() {
|
||||||
if command -v apt-get &>/dev/null; then echo "apt"
|
if command -v apt-get &>/dev/null; then echo "apt"
|
||||||
elif command -v dnf &>/dev/null; then echo "dnf"
|
elif command -v dnf &>/dev/null; then echo "dnf"
|
||||||
elif command -v yum &>/dev/null; then echo "yum"
|
elif command -v yum &>/dev/null; then echo "yum"
|
||||||
else echo "unknown"
|
else echo "unknown"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install_pkg() {
|
install_pkg() {
|
||||||
local pkg="$1"
|
local pkg="$1"
|
||||||
case "$(get_pkg_manager)" in
|
case "$(get_pkg_manager)" in
|
||||||
apt) apt-get install -y -qq "$pkg" ;;
|
apt) apt-get install -y -qq "$pkg" ;;
|
||||||
dnf) dnf install -y -q "$pkg" ;;
|
dnf) dnf install -y -q "$pkg" ;;
|
||||||
yum) yum install -y -q "$pkg" ;;
|
yum) yum install -y -q "$pkg" ;;
|
||||||
*) log_error "Неизвестный пакетный менеджер"; return 1 ;;
|
*) log_error "Неизвестный пакетный менеджер"; return 1 ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_deps() {
|
ensure_deps() {
|
||||||
local missing=()
|
local missing=()
|
||||||
for cmd in curl jq openssl git; do
|
for cmd in curl jq openssl git; do
|
||||||
if ! command -v "$cmd" &>/dev/null; then
|
if ! command -v "$cmd" &>/dev/null; then
|
||||||
missing+=("$cmd")
|
missing+=("$cmd")
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ ${#missing[@]} -gt 0 ]; then
|
if [ ${#missing[@]} -gt 0 ]; then
|
||||||
log_step "Установка зависимостей: ${missing[*]}"
|
log_step "Установка зависимостей: ${missing[*]}"
|
||||||
case "$(get_pkg_manager)" in
|
case "$(get_pkg_manager)" in
|
||||||
apt) apt-get update -qq && apt-get install -y -qq "${missing[@]}" ;;
|
apt) apt-get update -qq && apt-get install -y -qq "${missing[@]}" ;;
|
||||||
dnf) dnf install -y -q "${missing[@]}" ;;
|
dnf) dnf install -y -q "${missing[@]}" ;;
|
||||||
yum) yum install -y -q "${missing[@]}" ;;
|
yum) yum install -y -q "${missing[@]}" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
check_port() {
|
check_port() {
|
||||||
local port="$1"
|
local port="$1"
|
||||||
local line
|
local line
|
||||||
line=$(ss -tlnp 2>/dev/null | grep -E ":${port}\b" | head -1)
|
line=$(ss -tlnp 2>/dev/null | grep -E ":${port}\b" | head -1)
|
||||||
[ -z "$line" ] && line=$(netstat -tlnp 2>/dev/null | grep -E ":${port}\b" | head -1)
|
[ -z "$line" ] && line=$(netstat -tlnp 2>/dev/null | grep -E ":${port}\b" | head -1)
|
||||||
if [ -n "$line" ]; then
|
if [ -n "$line" ]; then
|
||||||
echo "$line"
|
echo "$line"
|
||||||
return 0 # порт занят
|
return 0 # порт занят
|
||||||
fi
|
fi
|
||||||
return 1 # свободен
|
return 1 # свободен
|
||||||
}
|
}
|
||||||
|
|
||||||
check_disk_space() {
|
check_disk_space() {
|
||||||
local min_mb="${1:-500}"
|
local min_mb="${1:-500}"
|
||||||
local avail_mb
|
local avail_mb
|
||||||
avail_mb=$(df -m / | awk 'NR==2 {print $4}')
|
avail_mb=$(df -m / | awk 'NR==2 {print $4}')
|
||||||
if [ "$avail_mb" -lt "$min_mb" ]; then
|
if [ "$avail_mb" -lt "$min_mb" ]; then
|
||||||
log_error "Мало места на диске: ${avail_mb}MB (нужно ${min_mb}MB+)"
|
log_error "Мало места на диске: ${avail_mb}MB (нужно ${min_mb}MB+)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Конфигурация GoTelegram (JSON) ──────────────────────────────────────────
|
# ── Конфигурация GoTelegram (JSON) ──────────────────────────────────────────
|
||||||
save_gotelegram_config() {
|
save_gotelegram_config() {
|
||||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
||||||
cat > "$GOTELEGRAM_CONFIG" << EOJSON
|
cat > "$GOTELEGRAM_CONFIG" << EOJSON
|
||||||
{
|
{
|
||||||
"version": "$GOTELEGRAM_VERSION",
|
"version": "$GOTELEGRAM_VERSION",
|
||||||
"engine": "${1:-telemt}",
|
"engine": "${1:-telemt}",
|
||||||
"mode": "${2:-quick}",
|
"mode": "${2:-quick}",
|
||||||
"port": ${3:-443},
|
"port": ${3:-443},
|
||||||
"secret": "${4:-}",
|
"secret": "${4:-}",
|
||||||
"mask_host": "${5:-google.com}",
|
"mask_host": "${5:-google.com}",
|
||||||
"domain": "${6:-}",
|
"domain": "${6:-}",
|
||||||
"template_id": "${7:-}",
|
"template_id": "${7:-}",
|
||||||
"installed_at": "$(date -Iseconds)",
|
"installed_at": "$(date -Iseconds)",
|
||||||
"updated_at": "$(date -Iseconds)"
|
"updated_at": "$(date -Iseconds)"
|
||||||
}
|
}
|
||||||
EOJSON
|
EOJSON
|
||||||
chmod 600 "$GOTELEGRAM_CONFIG"
|
chmod 600 "$GOTELEGRAM_CONFIG"
|
||||||
}
|
}
|
||||||
|
|
||||||
load_gotelegram_config() {
|
load_gotelegram_config() {
|
||||||
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ -f "$GOTELEGRAM_CONFIG" ]; then
|
||||||
cat "$GOTELEGRAM_CONFIG"
|
cat "$GOTELEGRAM_CONFIG"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
echo "{}"
|
echo "{}"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
config_get() {
|
config_get() {
|
||||||
local key="$1"
|
local key="$1"
|
||||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
||||||
log_dim "Конфиг не найден: $GOTELEGRAM_CONFIG" >&2
|
log_dim "Конфиг не найден: $GOTELEGRAM_CONFIG" >&2
|
||||||
return 2 # file missing
|
return 2 # file missing
|
||||||
fi
|
fi
|
||||||
local val
|
local val
|
||||||
val=$(jq -r ".$key // empty" "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
val=$(jq -r ".$key // empty" "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
log_dim "Ошибка чтения JSON: $GOTELEGRAM_CONFIG" >&2
|
log_dim "Ошибка чтения JSON: $GOTELEGRAM_CONFIG" >&2
|
||||||
return 3 # invalid JSON
|
return 3 # invalid JSON
|
||||||
fi
|
fi
|
||||||
if [ -z "$val" ]; then
|
if [ -z "$val" ]; then
|
||||||
return 1 # key missing or empty
|
return 1 # key missing or empty
|
||||||
fi
|
fi
|
||||||
echo "$val"
|
echo "$val"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
# ── V1 совместимость ─────────────────────────────────────────────────────────
|
||||||
detect_v1_installation() {
|
detect_v1_installation() {
|
||||||
# Проверяем наличие mtg Docker контейнера (v1)
|
# Проверяем наличие mtg Docker контейнера (v1)
|
||||||
if command -v docker &>/dev/null; then
|
if command -v docker &>/dev/null; then
|
||||||
if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${V1_CONTAINER_NAME}$"; then
|
if docker ps -a --format '{{.Names}}' 2>/dev/null | grep -q "^${V1_CONTAINER_NAME}$"; then
|
||||||
return 0 # v1 обнаружена
|
return 0 # v1 обнаружена
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# Проверяем наличие конфига v1
|
# Проверяем наличие конфига v1
|
||||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
get_v1_config() {
|
get_v1_config() {
|
||||||
# Извлекаем данные из работающего v1 контейнера
|
# Извлекаем данные из работающего v1 контейнера
|
||||||
if ! command -v docker &>/dev/null; then
|
if ! command -v docker &>/dev/null; then
|
||||||
echo "{}"
|
echo "{}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local running
|
local running
|
||||||
running=$(docker ps --format '{{.Names}}' 2>/dev/null | grep "^${V1_CONTAINER_NAME}$")
|
running=$(docker ps --format '{{.Names}}' 2>/dev/null | grep "^${V1_CONTAINER_NAME}$")
|
||||||
|
|
||||||
if [ -z "$running" ]; then
|
if [ -z "$running" ]; then
|
||||||
# Пробуем из сохранённого конфига
|
# Пробуем из сохранённого конфига
|
||||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||||
cat "$V1_CONFIG_FILE"
|
cat "$V1_CONFIG_FILE"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
echo "{}"
|
echo "{}"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Достаём из Docker
|
# Достаём из Docker
|
||||||
local cmd_str port secret ip
|
local cmd_str port secret ip
|
||||||
cmd_str=$(docker inspect "$V1_CONTAINER_NAME" --format='{{range .Config.Cmd}}{{.}} {{end}}' 2>/dev/null)
|
cmd_str=$(docker inspect "$V1_CONTAINER_NAME" --format='{{range .Config.Cmd}}{{.}} {{end}}' 2>/dev/null)
|
||||||
secret=$(echo "$cmd_str" | awk '{print $NF}')
|
secret=$(echo "$cmd_str" | awk '{print $NF}')
|
||||||
port=$(docker inspect "$V1_CONTAINER_NAME" --format='{{range $p,$c := .HostConfig.PortBindings}}{{(index $c 0).HostPort}}{{end}}' 2>/dev/null)
|
port=$(docker inspect "$V1_CONTAINER_NAME" --format='{{range $p,$c := .HostConfig.PortBindings}}{{(index $c 0).HostPort}}{{end}}' 2>/dev/null)
|
||||||
ip=$(get_server_ip)
|
ip=$(get_server_ip)
|
||||||
|
|
||||||
jq -n \
|
jq -n \
|
||||||
--arg secret "$secret" \
|
--arg secret "$secret" \
|
||||||
--arg port "${port:-443}" \
|
--arg port "${port:-443}" \
|
||||||
--arg ip "$ip" \
|
--arg ip "$ip" \
|
||||||
'{secret: $secret, port: ($port | tonumber), ip: $ip, engine: "mtg"}'
|
'{secret: $secret, port: ($port | tonumber), ip: $ip, engine: "mtg"}'
|
||||||
}
|
}
|
||||||
|
|
||||||
migrate_v1_to_v2() {
|
migrate_v1_to_v2() {
|
||||||
log_step "Миграция с v1 (mtg) на v2 (telemt)"
|
log_step "Миграция с v1 (mtg) на v2 (telemt)"
|
||||||
|
|
||||||
local v1_config
|
local v1_config
|
||||||
v1_config=$(get_v1_config)
|
v1_config=$(get_v1_config)
|
||||||
|
|
||||||
local old_port old_secret
|
local old_port old_secret
|
||||||
old_port=$(echo "$v1_config" | jq -r '.port // 443')
|
old_port=$(echo "$v1_config" | jq -r '.port // 443')
|
||||||
old_secret=$(echo "$v1_config" | jq -r '.secret // empty')
|
old_secret=$(echo "$v1_config" | jq -r '.secret // empty')
|
||||||
|
|
||||||
if [ -z "$old_secret" ]; then
|
if [ -z "$old_secret" ]; then
|
||||||
log_warning "Не удалось извлечь secret из v1. Будет создан новый."
|
log_warning "Не удалось извлечь secret из v1. Будет создан новый."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${WHITE}Найдена установка v1 (mtg):${NC}"
|
echo -e " ${WHITE}Найдена установка v1 (mtg):${NC}"
|
||||||
echo -e " Порт: ${CYAN}${old_port}${NC}"
|
echo -e " Порт: ${CYAN}${old_port}${NC}"
|
||||||
echo -e " Secret: ${CYAN}${old_secret:0:16}...${NC}"
|
echo -e " Secret: ${CYAN}${old_secret:0:16}...${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${YELLOW}Внимание:${NC} секрет mtg НЕ совместим с telemt напрямую."
|
echo -e " ${YELLOW}Внимание:${NC} секрет mtg НЕ совместим с telemt напрямую."
|
||||||
echo -e " Клиентам потребуется новая ссылка."
|
echo -e " Клиентам потребуется новая ссылка."
|
||||||
echo ""
|
echo ""
|
||||||
echo -ne " Остановить v1 контейнер и перейти на v2? [Y/n]: "
|
echo -ne " Остановить v1 контейнер и перейти на v2? [Y/n]: "
|
||||||
read -r ans
|
read -r ans
|
||||||
if [[ "$ans" =~ ^[Nn] ]]; then
|
if [[ "$ans" =~ ^[Nn] ]]; then
|
||||||
log_info "Миграция отменена. v1 оставлен без изменений."
|
log_info "Миграция отменена. v1 оставлен без изменений."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Останавливаем v1
|
# Останавливаем v1
|
||||||
log_info "Остановка v1 контейнера..."
|
log_info "Остановка v1 контейнера..."
|
||||||
docker stop "$V1_CONTAINER_NAME" 2>/dev/null
|
docker stop "$V1_CONTAINER_NAME" 2>/dev/null
|
||||||
docker rm "$V1_CONTAINER_NAME" 2>/dev/null
|
docker rm "$V1_CONTAINER_NAME" 2>/dev/null
|
||||||
|
|
||||||
# Бекапим v1 конфиг
|
# Бекапим v1 конфиг
|
||||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||||
mkdir -p "$GOTELEGRAM_DIR"
|
mkdir -p "$GOTELEGRAM_DIR"
|
||||||
cp "$V1_CONFIG_FILE" "$GOTELEGRAM_DIR/v1_backup_proxy.json" 2>/dev/null
|
cp "$V1_CONFIG_FILE" "$GOTELEGRAM_DIR/v1_backup_proxy.json" 2>/dev/null
|
||||||
log_success "Конфиг v1 сохранён в $GOTELEGRAM_DIR/v1_backup_proxy.json"
|
log_success "Конфиг v1 сохранён в $GOTELEGRAM_DIR/v1_backup_proxy.json"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_success "v1 остановлен. Порт $old_port освобождён."
|
log_success "v1 остановлен. Порт $old_port освобождён."
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Подтверждение ────────────────────────────────────────────────────────────
|
# ── Подтверждение ────────────────────────────────────────────────────────────
|
||||||
confirm() {
|
confirm() {
|
||||||
local msg="${1:-Продолжить?}"
|
local msg="${1:-Продолжить?}"
|
||||||
echo -ne " ${msg} [Y/n]: "
|
echo -ne " ${msg} [Y/n]: "
|
||||||
read -r ans
|
read -r ans
|
||||||
[[ ! "$ans" =~ ^[Nn] ]]
|
[[ ! "$ans" =~ ^[Nn] ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Выбор из списка ──────────────────────────────────────────────────────────
|
# ── Выбор из списка ──────────────────────────────────────────────────────────
|
||||||
select_option() {
|
select_option() {
|
||||||
local title="$1"
|
local title="$1"
|
||||||
shift
|
shift
|
||||||
local options=("$@")
|
local options=("$@")
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo -e " ${BOLD}${WHITE}${title}${NC}"
|
echo -e " ${BOLD}${WHITE}${title}${NC}"
|
||||||
echo -e " ${DIM}$(printf '─%.0s' {1..50})${NC}"
|
echo -e " ${DIM}$(printf '─%.0s' {1..50})${NC}"
|
||||||
local i=1
|
local i=1
|
||||||
for opt in "${options[@]}"; do
|
for opt in "${options[@]}"; do
|
||||||
echo -e " ${CYAN}${i})${NC} ${opt}"
|
echo -e " ${CYAN}${i})${NC} ${opt}"
|
||||||
((i++))
|
((i++))
|
||||||
done
|
done
|
||||||
echo -e " ${DIM}$(printf '─%.0s' {1..50})${NC}"
|
echo -e " ${DIM}$(printf '─%.0s' {1..50})${NC}"
|
||||||
echo -ne " ${WHITE}Выбор:${NC} "
|
echo -ne " ${WHITE}Выбор:${NC} "
|
||||||
read -r choice
|
read -r choice
|
||||||
echo "$choice"
|
echo "$choice"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Генерация случайного hex ─────────────────────────────────────────────────
|
# ── Генерация случайного hex ─────────────────────────────────────────────────
|
||||||
generate_hex() {
|
generate_hex() {
|
||||||
local len="${1:-32}"
|
local len="${1:-32}"
|
||||||
openssl rand -hex "$((len/2))" 2>/dev/null || head -c "$((len/2))" /dev/urandom | xxd -p | tr -d '\n'
|
openssl rand -hex "$((len/2))" 2>/dev/null || head -c "$((len/2))" /dev/urandom | xxd -p | tr -d '\n'
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Проверка домена ──────────────────────────────────────────────────────────
|
# ── Проверка домена ──────────────────────────────────────────────────────────
|
||||||
validate_domain() {
|
validate_domain() {
|
||||||
local domain="$1"
|
local domain="$1"
|
||||||
if echo "$domain" | grep -qE '^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'; then
|
if echo "$domain" | grep -qE '^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Init: создание директорий ────────────────────────────────────────────────
|
# ── Init: создание директорий ────────────────────────────────────────────────
|
||||||
init_dirs() {
|
init_dirs() {
|
||||||
mkdir -p "$GOTELEGRAM_DIR" "$BACKUP_DIR" /etc/telemt 2>/dev/null
|
mkdir -p "$GOTELEGRAM_DIR" "$BACKUP_DIR" /etc/telemt 2>/dev/null
|
||||||
touch "$LOG_FILE" 2>/dev/null
|
touch "$LOG_FILE" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|||||||
610
lib/telemt.sh
610
lib/telemt.sh
@@ -1,305 +1,305 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# GoTelegram v2.2 — Управление telemt binary
|
# GoTelegram v2.2 — Управление telemt binary
|
||||||
# Скачивание, обновление, запуск, остановка через systemd
|
# Скачивание, обновление, запуск, остановка через systemd
|
||||||
|
|
||||||
TELEMT_GITHUB="telemt/telemt"
|
TELEMT_GITHUB="telemt/telemt"
|
||||||
TELEMT_RELEASE_API="https://api.github.com/repos/${TELEMT_GITHUB}/releases/latest"
|
TELEMT_RELEASE_API="https://api.github.com/repos/${TELEMT_GITHUB}/releases/latest"
|
||||||
TELEMT_USER="telemt"
|
TELEMT_USER="telemt"
|
||||||
TELEMT_GROUP="telemt"
|
TELEMT_GROUP="telemt"
|
||||||
|
|
||||||
# ── Получение последней версии ───────────────────────────────────────────────
|
# ── Получение последней версии ───────────────────────────────────────────────
|
||||||
get_latest_telemt_version() {
|
get_latest_telemt_version() {
|
||||||
local resp
|
local resp
|
||||||
resp=$(curl -s --max-time 10 "$TELEMT_RELEASE_API" 2>/dev/null)
|
resp=$(curl -s --max-time 10 "$TELEMT_RELEASE_API" 2>/dev/null)
|
||||||
if [ $? -ne 0 ] || [ -z "$resp" ]; then
|
if [ $? -ne 0 ] || [ -z "$resp" ]; then
|
||||||
log_error "Не удалось получить информацию о релизах telemt"
|
log_error "Не удалось получить информацию о релизах telemt"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
echo "$resp" | jq -r '.tag_name // empty'
|
echo "$resp" | jq -r '.tag_name // empty'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_telemt_download_url() {
|
get_telemt_download_url() {
|
||||||
local arch
|
local arch
|
||||||
arch=$(get_arch)
|
arch=$(get_arch)
|
||||||
local resp
|
local resp
|
||||||
resp=$(curl -s --max-time 10 "$TELEMT_RELEASE_API" 2>/dev/null)
|
resp=$(curl -s --max-time 10 "$TELEMT_RELEASE_API" 2>/dev/null)
|
||||||
if [ -z "$resp" ]; then return 1; fi
|
if [ -z "$resp" ]; then return 1; fi
|
||||||
|
|
||||||
local pattern
|
local pattern
|
||||||
case "$arch" in
|
case "$arch" in
|
||||||
amd64) pattern="linux.*amd64\|linux.*x86_64" ;;
|
amd64) pattern="linux.*(amd64|x86_64)" ;;
|
||||||
arm64) pattern="linux.*arm64\|linux.*aarch64" ;;
|
arm64) pattern="linux.*(arm64|aarch64)" ;;
|
||||||
armv7) pattern="linux.*armv7\|linux.*arm" ;;
|
armv7) pattern="linux.*(armv7|arm)" ;;
|
||||||
*) pattern="linux.*${arch}" ;;
|
*) pattern="linux.*${arch}" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
echo "$resp" | jq -r ".assets[].browser_download_url" 2>/dev/null | grep -i "$pattern" | head -1
|
echo "$resp" | jq -r ".assets[].browser_download_url" 2>/dev/null | grep -iE "$pattern" | head -1
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Установленная версия ─────────────────────────────────────────────────────
|
# ── Установленная версия ─────────────────────────────────────────────────────
|
||||||
get_installed_telemt_version() {
|
get_installed_telemt_version() {
|
||||||
if [ -x "$TELEMT_BIN" ]; then
|
if [ -x "$TELEMT_BIN" ]; then
|
||||||
"$TELEMT_BIN" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1
|
"$TELEMT_BIN" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1
|
||||||
else
|
else
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
is_telemt_installed() {
|
is_telemt_installed() {
|
||||||
[ -x "$TELEMT_BIN" ]
|
[ -x "$TELEMT_BIN" ]
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Скачивание и установка ───────────────────────────────────────────────────
|
# ── Скачивание и установка ───────────────────────────────────────────────────
|
||||||
download_telemt() {
|
download_telemt() {
|
||||||
local url
|
local url
|
||||||
url=$(get_telemt_download_url)
|
url=$(get_telemt_download_url)
|
||||||
if [ -z "$url" ]; then
|
if [ -z "$url" ]; then
|
||||||
log_error "Не найден бинарник telemt для архитектуры $(get_arch)"
|
log_error "Не найден бинарник telemt для архитектуры $(get_arch)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local tmp_file="/tmp/telemt_download_$$"
|
local tmp_file="/tmp/telemt_download_$$"
|
||||||
log_info "Скачивание: $url"
|
log_info "Скачивание: $url"
|
||||||
|
|
||||||
if ! curl -L -s --max-time 120 -o "$tmp_file" "$url"; then
|
if ! curl -L -s --max-time 120 -o "$tmp_file" "$url"; then
|
||||||
log_error "Ошибка скачивания telemt"
|
log_error "Ошибка скачивания telemt"
|
||||||
rm -f "$tmp_file"
|
rm -f "$tmp_file"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Определяем тип файла и распаковываем
|
# Определяем тип файла и распаковываем
|
||||||
local mime
|
local mime
|
||||||
mime=$(file -b --mime-type "$tmp_file" 2>/dev/null)
|
mime=$(file -b --mime-type "$tmp_file" 2>/dev/null)
|
||||||
|
|
||||||
case "$mime" in
|
case "$mime" in
|
||||||
application/gzip|application/x-gzip)
|
application/gzip|application/x-gzip)
|
||||||
tar xzf "$tmp_file" -C /tmp/ 2>/dev/null
|
tar xzf "$tmp_file" -C /tmp/ 2>/dev/null
|
||||||
local extracted
|
local extracted
|
||||||
extracted=$(find /tmp -maxdepth 2 -name "telemt" -type f -newer "$tmp_file" 2>/dev/null | head -1)
|
extracted=$(find /tmp -maxdepth 2 -name "telemt" -type f -newer "$tmp_file" 2>/dev/null | head -1)
|
||||||
if [ -z "$extracted" ]; then
|
if [ -z "$extracted" ]; then
|
||||||
# Может быть просто gzip без tar
|
# Может быть просто gzip без tar
|
||||||
gunzip -c "$tmp_file" > /tmp/telemt_bin_$$ 2>/dev/null
|
gunzip -c "$tmp_file" > /tmp/telemt_bin_$$ 2>/dev/null
|
||||||
extracted="/tmp/telemt_bin_$$"
|
extracted="/tmp/telemt_bin_$$"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
application/x-tar)
|
application/x-tar)
|
||||||
tar xf "$tmp_file" -C /tmp/ 2>/dev/null
|
tar xf "$tmp_file" -C /tmp/ 2>/dev/null
|
||||||
extracted=$(find /tmp -maxdepth 2 -name "telemt" -type f -newer "$tmp_file" 2>/dev/null | head -1)
|
extracted=$(find /tmp -maxdepth 2 -name "telemt" -type f -newer "$tmp_file" 2>/dev/null | head -1)
|
||||||
;;
|
;;
|
||||||
application/zip)
|
application/zip)
|
||||||
unzip -o "$tmp_file" -d /tmp/telemt_extract_$$ 2>/dev/null
|
unzip -o "$tmp_file" -d /tmp/telemt_extract_$$ 2>/dev/null
|
||||||
extracted=$(find /tmp/telemt_extract_$$ -name "telemt" -type f 2>/dev/null | head -1)
|
extracted=$(find /tmp/telemt_extract_$$ -name "telemt" -type f 2>/dev/null | head -1)
|
||||||
;;
|
;;
|
||||||
application/octet-stream|application/x-executable)
|
application/octet-stream|application/x-executable)
|
||||||
# Уже бинарник
|
# Уже бинарник
|
||||||
extracted="$tmp_file"
|
extracted="$tmp_file"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
# Пробуем как бинарник
|
# Пробуем как бинарник
|
||||||
extracted="$tmp_file"
|
extracted="$tmp_file"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [ -z "$extracted" ] || [ ! -f "$extracted" ]; then
|
if [ -z "$extracted" ] || [ ! -f "$extracted" ]; then
|
||||||
log_error "Не удалось извлечь бинарник telemt"
|
log_error "Не удалось извлечь бинарник telemt"
|
||||||
rm -f "$tmp_file"
|
rm -f "$tmp_file"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Устанавливаем
|
# Устанавливаем
|
||||||
cp "$extracted" "$TELEMT_BIN"
|
cp "$extracted" "$TELEMT_BIN"
|
||||||
chmod 755 "$TELEMT_BIN"
|
chmod 755 "$TELEMT_BIN"
|
||||||
rm -f "$tmp_file"
|
rm -f "$tmp_file"
|
||||||
rm -rf /tmp/telemt_extract_$$ /tmp/telemt_bin_$$
|
rm -rf /tmp/telemt_extract_$$ /tmp/telemt_bin_$$
|
||||||
|
|
||||||
# Проверяем
|
# Проверяем
|
||||||
if "$TELEMT_BIN" --version &>/dev/null; then
|
if "$TELEMT_BIN" --version &>/dev/null; then
|
||||||
log_success "telemt $(get_installed_telemt_version) установлен в $TELEMT_BIN"
|
log_success "telemt $(get_installed_telemt_version) установлен в $TELEMT_BIN"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log_error "Бинарник telemt не запускается"
|
log_error "Бинарник telemt не запускается"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Системный пользователь ───────────────────────────────────────────────────
|
# ── Системный пользователь ───────────────────────────────────────────────────
|
||||||
create_telemt_user() {
|
create_telemt_user() {
|
||||||
if ! id "$TELEMT_USER" &>/dev/null; then
|
if ! id "$TELEMT_USER" &>/dev/null; then
|
||||||
useradd -r -s /usr/sbin/nologin -d /etc/telemt "$TELEMT_USER" 2>/dev/null
|
useradd -r -s /usr/sbin/nologin -d /etc/telemt "$TELEMT_USER" 2>/dev/null
|
||||||
log_dim "Создан системный пользователь: $TELEMT_USER"
|
log_dim "Создан системный пользователь: $TELEMT_USER"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Systemd сервис ───────────────────────────────────────────────────────────
|
# ── Systemd сервис ───────────────────────────────────────────────────────────
|
||||||
install_telemt_service() {
|
install_telemt_service() {
|
||||||
local config_path="${1:-$TELEMT_CONFIG}"
|
local config_path="${1:-$TELEMT_CONFIG}"
|
||||||
|
|
||||||
cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF
|
cat > "/etc/systemd/system/${TELEMT_SERVICE}.service" << EOF
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=GoTelegram MTProxy (telemt engine)
|
Description=GoTelegram MTProxy (telemt engine)
|
||||||
Documentation=https://github.com/telemt/telemt
|
Documentation=https://github.com/telemt/telemt
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
User=root
|
User=root
|
||||||
ExecStart=$TELEMT_BIN run $config_path
|
ExecStart=$TELEMT_BIN run $config_path
|
||||||
Restart=always
|
Restart=always
|
||||||
RestartSec=5
|
RestartSec=5
|
||||||
LimitNOFILE=65535
|
LimitNOFILE=65535
|
||||||
|
|
||||||
# Безопасность
|
# Безопасность
|
||||||
NoNewPrivileges=true
|
NoNewPrivileges=true
|
||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=true
|
ProtectHome=true
|
||||||
ReadWritePaths=/etc/telemt /var/log
|
ReadWritePaths=/etc/telemt /var/log
|
||||||
PrivateTmp=true
|
PrivateTmp=true
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
log_success "Systemd сервис $TELEMT_SERVICE создан"
|
log_success "Systemd сервис $TELEMT_SERVICE создан"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Управление сервисом ──────────────────────────────────────────────────────
|
# ── Управление сервисом ──────────────────────────────────────────────────────
|
||||||
start_telemt() {
|
start_telemt() {
|
||||||
systemctl start "$TELEMT_SERVICE" 2>/dev/null
|
systemctl start "$TELEMT_SERVICE" 2>/dev/null
|
||||||
sleep 2
|
sleep 2
|
||||||
if systemctl is-active --quiet "$TELEMT_SERVICE"; then
|
if systemctl is-active --quiet "$TELEMT_SERVICE"; then
|
||||||
log_success "telemt запущен"
|
log_success "telemt запущен"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log_error "telemt не запустился"
|
log_error "telemt не запустился"
|
||||||
journalctl -u "$TELEMT_SERVICE" --no-pager -n 10 2>/dev/null
|
journalctl -u "$TELEMT_SERVICE" --no-pager -n 10 2>/dev/null
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_telemt() {
|
stop_telemt() {
|
||||||
if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||||
systemctl stop "$TELEMT_SERVICE"
|
systemctl stop "$TELEMT_SERVICE"
|
||||||
log_success "telemt остановлен"
|
log_success "telemt остановлен"
|
||||||
else
|
else
|
||||||
log_dim "telemt уже остановлен"
|
log_dim "telemt уже остановлен"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
restart_telemt() {
|
restart_telemt() {
|
||||||
systemctl restart "$TELEMT_SERVICE" 2>/dev/null
|
systemctl restart "$TELEMT_SERVICE" 2>/dev/null
|
||||||
sleep 2
|
sleep 2
|
||||||
if systemctl is-active --quiet "$TELEMT_SERVICE"; then
|
if systemctl is-active --quiet "$TELEMT_SERVICE"; then
|
||||||
log_success "telemt перезапущен"
|
log_success "telemt перезапущен"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log_error "telemt не перезапустился"
|
log_error "telemt не перезапустился"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_telemt() {
|
enable_telemt() {
|
||||||
systemctl enable "$TELEMT_SERVICE" 2>/dev/null
|
systemctl enable "$TELEMT_SERVICE" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
telemt_status() {
|
telemt_status() {
|
||||||
if ! is_telemt_installed; then
|
if ! is_telemt_installed; then
|
||||||
echo "not_installed"
|
echo "not_installed"
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
if systemctl is-active --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||||
echo "running"
|
echo "running"
|
||||||
elif systemctl is-enabled --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
elif systemctl is-enabled --quiet "$TELEMT_SERVICE" 2>/dev/null; then
|
||||||
echo "stopped"
|
echo "stopped"
|
||||||
else
|
else
|
||||||
echo "disabled"
|
echo "disabled"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
telemt_logs() {
|
telemt_logs() {
|
||||||
local lines="${1:-40}"
|
local lines="${1:-40}"
|
||||||
journalctl -u "$TELEMT_SERVICE" --no-pager -n "$lines" 2>/dev/null
|
journalctl -u "$TELEMT_SERVICE" --no-pager -n "$lines" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
telemt_uptime() {
|
telemt_uptime() {
|
||||||
local started
|
local started
|
||||||
started=$(systemctl show "$TELEMT_SERVICE" --property=ActiveEnterTimestamp --value 2>/dev/null)
|
started=$(systemctl show "$TELEMT_SERVICE" --property=ActiveEnterTimestamp --value 2>/dev/null)
|
||||||
if [ -n "$started" ] && [ "$started" != "" ]; then
|
if [ -n "$started" ] && [ "$started" != "" ]; then
|
||||||
echo "$started"
|
echo "$started"
|
||||||
else
|
else
|
||||||
echo "N/A"
|
echo "N/A"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Обновление ───────────────────────────────────────────────────────────────
|
# ── Обновление ───────────────────────────────────────────────────────────────
|
||||||
check_telemt_update() {
|
check_telemt_update() {
|
||||||
local current latest
|
local current latest
|
||||||
current=$(get_installed_telemt_version)
|
current=$(get_installed_telemt_version)
|
||||||
latest=$(get_latest_telemt_version)
|
latest=$(get_latest_telemt_version)
|
||||||
|
|
||||||
if [ -z "$current" ] || [ -z "$latest" ]; then
|
if [ -z "$current" ] || [ -z "$latest" ]; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$current" != "$latest" ]; then
|
if [ "$current" != "$latest" ]; then
|
||||||
echo "$latest"
|
echo "$latest"
|
||||||
return 0 # есть обновление
|
return 0 # есть обновление
|
||||||
fi
|
fi
|
||||||
return 1 # актуально
|
return 1 # актуально
|
||||||
}
|
}
|
||||||
|
|
||||||
update_telemt() {
|
update_telemt() {
|
||||||
local latest
|
local latest
|
||||||
latest=$(check_telemt_update)
|
latest=$(check_telemt_update)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
log_info "telemt уже последней версии ($(get_installed_telemt_version))"
|
log_info "telemt уже последней версии ($(get_installed_telemt_version))"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log_info "Доступно обновление: $(get_installed_telemt_version) → $latest"
|
log_info "Доступно обновление: $(get_installed_telemt_version) → $latest"
|
||||||
if ! confirm "Обновить telemt?"; then
|
if ! confirm "Обновить telemt?"; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
stop_telemt
|
stop_telemt
|
||||||
if download_telemt; then
|
if download_telemt; then
|
||||||
start_telemt
|
start_telemt
|
||||||
log_success "telemt обновлён до $latest"
|
log_success "telemt обновлён до $latest"
|
||||||
else
|
else
|
||||||
start_telemt # запускаем старую версию обратно
|
start_telemt # запускаем старую версию обратно
|
||||||
log_error "Обновление не удалось"
|
log_error "Обновление не удалось"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Полная установка telemt ──────────────────────────────────────────────────
|
# ── Полная установка telemt ──────────────────────────────────────────────────
|
||||||
install_telemt_full() {
|
install_telemt_full() {
|
||||||
log_step "Установка telemt"
|
log_step "Установка telemt"
|
||||||
|
|
||||||
# Создаём директории
|
# Создаём директории
|
||||||
mkdir -p /etc/telemt
|
mkdir -p /etc/telemt
|
||||||
|
|
||||||
# Скачиваем бинарник
|
# Скачиваем бинарник
|
||||||
run_with_spinner "Скачивание telemt" download_telemt || return 1
|
run_with_spinner "Скачивание telemt" download_telemt || return 1
|
||||||
|
|
||||||
# Устанавливаем systemd сервис
|
# Устанавливаем systemd сервис
|
||||||
install_telemt_service
|
install_telemt_service
|
||||||
|
|
||||||
# Включаем автозапуск
|
# Включаем автозапуск
|
||||||
enable_telemt
|
enable_telemt
|
||||||
|
|
||||||
log_success "telemt готов к работе"
|
log_success "telemt готов к работе"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Удаление telemt ──────────────────────────────────────────────────────────
|
# ── Удаление telemt ──────────────────────────────────────────────────────────
|
||||||
remove_telemt() {
|
remove_telemt() {
|
||||||
stop_telemt
|
stop_telemt
|
||||||
systemctl disable "$TELEMT_SERVICE" 2>/dev/null
|
systemctl disable "$TELEMT_SERVICE" 2>/dev/null
|
||||||
rm -f "/etc/systemd/system/${TELEMT_SERVICE}.service"
|
rm -f "/etc/systemd/system/${TELEMT_SERVICE}.service"
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
rm -f "$TELEMT_BIN"
|
rm -f "$TELEMT_BIN"
|
||||||
rm -rf /etc/telemt
|
rm -rf /etc/telemt
|
||||||
log_success "telemt полностью удалён"
|
log_success "telemt полностью удалён"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user