mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-20 00:46:03 +00:00
v2.4.0 — internationalization (EN/RU) + custom git templates
- i18n engine (lib/i18n.sh, lib/lang/en.sh, lib/lang/ru.sh)
- first-run language picker, persisted to .language + config.json
- install.sh, common.sh, backup.sh, templates_catalog.sh wired through t()/tf()
- backup.sh preserves .language marker and records language in metadata.json
- custom git template feature (first item in pro template picker)
* validates HTTPS URLs, rejects shell metachars
* 100MB size guard, 90s clone timeout
* auto-detects index.html in dist/public/build/_site/site/docs/out/www
- bot v2.4.0: i18n.py + lang/{en,ru}.json, /lang command, language toggle button
- bot: custom git template via text input with waiter gating
This commit is contained in:
160
lib/common.sh
160
lib/common.sh
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
# GoTelegram v2.3 — Общие утилиты
|
||||
# Цвета, логирование, спиннер, системные функции, совместимость с v1
|
||||
# GoTelegram v2.4 — common utilities
|
||||
# Colors, logging, spinner, system helpers, v1 compat, i18n-aware
|
||||
|
||||
# ── Версия ────────────────────────────────────────────────────────────────────
|
||||
GOTELEGRAM_VERSION="2.3.1"
|
||||
# ── Version ───────────────────────────────────────────────────────────────────
|
||||
GOTELEGRAM_VERSION="2.4.0"
|
||||
GOTELEGRAM_NAME="GoTelegram"
|
||||
|
||||
# ── Пути ──────────────────────────────────────────────────────────────────────
|
||||
@@ -49,10 +49,12 @@ log_to_file() {
|
||||
echo "[$ts] $*" >> "$LOG_FILE" 2>/dev/null
|
||||
}
|
||||
|
||||
# ── Спиннер ──────────────────────────────────────────────────────────────────
|
||||
# ── Spinner ──────────────────────────────────────────────────────────────────
|
||||
_spin_pid=""
|
||||
spinner_start() {
|
||||
local msg="${1:-Подождите...}"
|
||||
local default_msg
|
||||
default_msg=$(type t &>/dev/null && t wait || echo "Please wait...")
|
||||
local msg="${1:-$default_msg}"
|
||||
(
|
||||
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
||||
local i=0
|
||||
@@ -95,7 +97,9 @@ run_with_spinner() {
|
||||
if [ $rc -eq 0 ]; then
|
||||
log_success "$label"
|
||||
else
|
||||
log_error "$label ${RED}(ошибка, код: $rc)${NC}"
|
||||
local err_label
|
||||
err_label=$(type t &>/dev/null && t error || echo "error")
|
||||
log_error "$label ${RED}(${err_label}, code: $rc)${NC}"
|
||||
if [ -s "$err_file" ]; then
|
||||
log_dim " $(head -3 "$err_file")"
|
||||
fi
|
||||
@@ -104,35 +108,45 @@ run_with_spinner() {
|
||||
return $rc
|
||||
}
|
||||
|
||||
# ── Баннер ───────────────────────────────────────────────────────────────────
|
||||
# ── Banner ───────────────────────────────────────────────────────────────────
|
||||
show_banner() {
|
||||
local line
|
||||
line=$(printf '━%.0s' $(seq 1 60))
|
||||
echo ""
|
||||
echo -e "${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}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC} ${CYAN}║${NC}"
|
||||
echo -e "${CYAN}╚══════════════════════════════════════════════════════════╝${NC}"
|
||||
echo -e "${CYAN}${line}${NC}"
|
||||
if type tf &>/dev/null; then
|
||||
echo -e " ${BOLD}${WHITE}🚀 $(tf banner_title "$GOTELEGRAM_VERSION")${NC}"
|
||||
echo -e " ${DIM}$(t banner_subtitle)${NC}"
|
||||
echo -e " ${DIM}$(t banner_features)${NC}"
|
||||
else
|
||||
echo -e " ${BOLD}${WHITE}🚀 GoTelegram v${GOTELEGRAM_VERSION}${NC}"
|
||||
echo -e " ${DIM}MTProxy powered by telemt (Rust + Tokio)${NC}"
|
||||
echo -e " ${DIM}Anti-DPI • Fake TLS • TCP Splice • JA3/JA4${NC}"
|
||||
fi
|
||||
echo -e "${CYAN}${line}${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ── Благодарности ────────────────────────────────────────────────────────────
|
||||
# ── Credits ──────────────────────────────────────────────────────────────────
|
||||
show_credits() {
|
||||
local line
|
||||
line=$(printf '─%.0s' $(seq 1 60))
|
||||
echo ""
|
||||
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${MAGENTA}║${NC} ${BOLD}Благодарности / Credits${NC} ${MAGENTA}║${NC}"
|
||||
echo -e "${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} ${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} ${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} ${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}"
|
||||
echo -e "${MAGENTA}${line}${NC}"
|
||||
echo -e " ${BOLD}$(type t &>/dev/null && t credits_title || echo 'Credits')${NC}"
|
||||
echo -e "${MAGENTA}${line}${NC}"
|
||||
echo -e " ${WHITE}telemt${NC} — MTProxy engine (Rust)"
|
||||
echo -e " ${DIM}github.com/telemt/telemt${NC}"
|
||||
echo ""
|
||||
echo -e " ${WHITE}HTML5 UP${NC} — responsive HTML/CSS templates"
|
||||
echo -e " ${DIM}html5up.net • CC BY 3.0 • @ajlkn${NC}"
|
||||
echo ""
|
||||
echo -e " ${WHITE}learning-zone${NC} — 150+ HTML5 templates"
|
||||
echo -e " ${DIM}github.com/learning-zone/website-templates${NC}"
|
||||
echo ""
|
||||
echo -e " ${WHITE}Start Bootstrap${NC} — MIT license"
|
||||
echo -e " ${DIM}startbootstrap.com${NC}"
|
||||
echo -e "${MAGENTA}${line}${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
@@ -164,31 +178,41 @@ get_server_ip() {
|
||||
return 1
|
||||
}
|
||||
|
||||
_t_or() {
|
||||
# Helper: translate if i18n available, otherwise return fallback
|
||||
local key="$1" fallback="$2"
|
||||
if type t &>/dev/null; then
|
||||
t "$key"
|
||||
else
|
||||
echo "$fallback"
|
||||
fi
|
||||
}
|
||||
|
||||
check_root() {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
log_error "Запустите скрипт с sudo / от root"
|
||||
log_error "$(_t_or err_need_root 'Run the script with sudo / as root')"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_os() {
|
||||
if [ ! -f /etc/os-release ]; then
|
||||
log_error "Не удалось определить ОС. Требуется Linux."
|
||||
log_error "$(_t_or err_os_unknown 'Failed to detect OS. Linux is required.')"
|
||||
return 1
|
||||
fi
|
||||
# Validate os-release before sourcing (reject command injection: ;, backticks, $())
|
||||
if grep -qE '(;|`|\$\(|\$\{)' /etc/os-release 2>/dev/null; then
|
||||
log_warning "/etc/os-release содержит подозрительные строки, пропускаем"
|
||||
log_warning "/etc/os-release contains suspicious strings, skipping"
|
||||
return 0
|
||||
fi
|
||||
. /etc/os-release
|
||||
case "$ID" in
|
||||
ubuntu|debian|centos|rocky|almalinux|fedora|rhel)
|
||||
log_dim "ОС: $PRETTY_NAME"
|
||||
log_dim "OS: $PRETTY_NAME"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
log_warning "ОС $ID может быть несовместима. Поддерживаются: Ubuntu, Debian, CentOS, Rocky."
|
||||
log_warning "OS $ID may be incompatible. Supported: Ubuntu, Debian, CentOS, Rocky."
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
@@ -219,7 +243,7 @@ install_pkg() {
|
||||
apt) apt-get install -y -qq "$pkg" ;;
|
||||
dnf) dnf install -y -q "$pkg" ;;
|
||||
yum) yum install -y -q "$pkg" ;;
|
||||
*) log_error "Неизвестный пакетный менеджер"; return 1 ;;
|
||||
*) log_error "$(_t_or err_bad_pkg_mgr 'Unknown package manager')"; return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -231,7 +255,11 @@ ensure_deps() {
|
||||
fi
|
||||
done
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
log_step "Установка зависимостей: ${missing[*]}"
|
||||
if type tf &>/dev/null; then
|
||||
log_step "$(tf deps_installing "${missing[*]}")"
|
||||
else
|
||||
log_step "Installing dependencies: ${missing[*]}"
|
||||
fi
|
||||
case "$(get_pkg_manager)" in
|
||||
apt) apt-get update -qq && apt-get install -y -qq "${missing[@]}" ;;
|
||||
dnf) dnf install -y -q "${missing[@]}" ;;
|
||||
@@ -257,7 +285,11 @@ check_disk_space() {
|
||||
local avail_mb
|
||||
avail_mb=$(df -m / | awk 'NR==2 {print $4}')
|
||||
if [ "$avail_mb" -lt "$min_mb" ]; then
|
||||
log_error "Мало места на диске: ${avail_mb}MB (нужно ${min_mb}MB+)"
|
||||
if type tf &>/dev/null; then
|
||||
log_error "$(tf err_low_disk "$avail_mb" "$min_mb")"
|
||||
else
|
||||
log_error "Low disk space: ${avail_mb}MB (need ${min_mb}MB+)"
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
@@ -266,6 +298,8 @@ check_disk_space() {
|
||||
# ── Конфигурация GoTelegram (JSON) ──────────────────────────────────────────
|
||||
save_gotelegram_config() {
|
||||
mkdir -p "$(dirname "$GOTELEGRAM_CONFIG")"
|
||||
local cur_lang
|
||||
cur_lang=$(type get_language &>/dev/null && get_language || echo en)
|
||||
cat > "$GOTELEGRAM_CONFIG" << EOJSON
|
||||
{
|
||||
"version": "$GOTELEGRAM_VERSION",
|
||||
@@ -276,6 +310,7 @@ save_gotelegram_config() {
|
||||
"mask_host": "${5:-google.com}",
|
||||
"domain": "${6:-}",
|
||||
"template_id": "${7:-}",
|
||||
"language": "${cur_lang}",
|
||||
"installed_at": "$(date -Iseconds)",
|
||||
"updated_at": "$(date -Iseconds)"
|
||||
}
|
||||
@@ -295,13 +330,11 @@ load_gotelegram_config() {
|
||||
config_get() {
|
||||
local key="$1"
|
||||
if [ ! -f "$GOTELEGRAM_CONFIG" ]; then
|
||||
log_dim "Конфиг не найден: $GOTELEGRAM_CONFIG" >&2
|
||||
return 2 # file missing
|
||||
fi
|
||||
local val
|
||||
val=$(jq -r ".$key // empty" "$GOTELEGRAM_CONFIG" 2>/dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
log_dim "Ошибка чтения JSON: $GOTELEGRAM_CONFIG" >&2
|
||||
return 3 # invalid JSON
|
||||
fi
|
||||
if [ -z "$val" ]; then
|
||||
@@ -361,7 +394,7 @@ get_v1_config() {
|
||||
}
|
||||
|
||||
migrate_v1_to_v2() {
|
||||
log_step "Миграция с v1 (mtg) на v2 (telemt)"
|
||||
log_step "$(_t_or v1_migration_step 'Migrating from v1 (mtg) to v2 (telemt)')"
|
||||
|
||||
local v1_config
|
||||
v1_config=$(get_v1_config)
|
||||
@@ -371,44 +404,59 @@ migrate_v1_to_v2() {
|
||||
old_secret=$(echo "$v1_config" | jq -r '.secret // empty')
|
||||
|
||||
if [ -z "$old_secret" ]; then
|
||||
log_warning "Не удалось извлечь secret из v1. Будет создан новый."
|
||||
log_warning "Failed to extract secret from v1. A new one will be generated."
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e " ${WHITE}Найдена установка v1 (mtg):${NC}"
|
||||
echo -e " Порт: ${CYAN}${old_port}${NC}"
|
||||
echo -e " Secret: ${CYAN}${old_secret:0:16}...${NC}"
|
||||
echo -e " ${WHITE}$(_t_or v1_found_title 'Found v1 (mtg) installation:')${NC}"
|
||||
if type tf &>/dev/null; then
|
||||
echo -e " $(tf v1_port "$old_port")"
|
||||
echo -e " $(tf v1_secret "${old_secret:0:16}")"
|
||||
else
|
||||
echo -e " Port: ${CYAN}${old_port}${NC}"
|
||||
echo -e " Secret: ${CYAN}${old_secret:0:16}...${NC}"
|
||||
fi
|
||||
echo ""
|
||||
echo -e " ${YELLOW}Внимание:${NC} секрет mtg НЕ совместим с telemt напрямую."
|
||||
echo -e " Клиентам потребуется новая ссылка."
|
||||
echo -e " ${YELLOW}$(_t_or warning 'Warning'):${NC} $(_t_or v1_incompatible 'mtg secret is NOT directly compatible with telemt.')"
|
||||
echo -e " $(_t_or v1_new_link 'Clients will need a new link.')"
|
||||
echo ""
|
||||
echo -ne " Остановить v1 контейнер и перейти на v2? [Y/n]: "
|
||||
echo -ne " $(_t_or v1_stop_migrate 'Stop v1 container and migrate to v2? [Y/n]:') "
|
||||
read -r ans
|
||||
if [[ "$ans" =~ ^[Nn] ]]; then
|
||||
log_info "Миграция отменена. v1 оставлен без изменений."
|
||||
log_info "$(_t_or v1_migration_cancelled 'Migration cancelled. v1 left intact.')"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Останавливаем v1
|
||||
log_info "Остановка v1 контейнера..."
|
||||
# Stop v1
|
||||
log_info "$(_t_or v1_stopping 'Stopping v1 container...')"
|
||||
docker stop "$V1_CONTAINER_NAME" 2>/dev/null
|
||||
docker rm "$V1_CONTAINER_NAME" 2>/dev/null
|
||||
|
||||
# Бекапим v1 конфиг
|
||||
# Backup v1 config
|
||||
if [ -f "$V1_CONFIG_FILE" ]; then
|
||||
mkdir -p "$GOTELEGRAM_DIR"
|
||||
cp "$V1_CONFIG_FILE" "$GOTELEGRAM_DIR/v1_backup_proxy.json" 2>/dev/null
|
||||
log_success "Конфиг v1 сохранён в $GOTELEGRAM_DIR/v1_backup_proxy.json"
|
||||
if type tf &>/dev/null; then
|
||||
log_success "$(tf v1_config_saved "$GOTELEGRAM_DIR/v1_backup_proxy.json")"
|
||||
else
|
||||
log_success "v1 config saved to $GOTELEGRAM_DIR/v1_backup_proxy.json"
|
||||
fi
|
||||
fi
|
||||
|
||||
log_success "v1 остановлен. Порт $old_port освобождён."
|
||||
if type tf &>/dev/null; then
|
||||
log_success "$(tf v1_port_freed "$old_port")"
|
||||
else
|
||||
log_success "v1 stopped. Port $old_port freed."
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# ── Подтверждение ────────────────────────────────────────────────────────────
|
||||
# ── Confirm prompt ───────────────────────────────────────────────────────────
|
||||
confirm() {
|
||||
local msg="${1:-Продолжить?}"
|
||||
local default_msg
|
||||
default_msg=$(_t_or install_continue_anyway 'Continue?')
|
||||
local msg="${1:-$default_msg}"
|
||||
echo -ne " ${msg} [Y/n]: " >&2
|
||||
read -r ans
|
||||
[[ ! "$ans" =~ ^[Nn] ]]
|
||||
@@ -429,7 +477,7 @@ select_option() {
|
||||
((i++))
|
||||
done
|
||||
echo -e " ${DIM}$(printf '─%.0s' {1..50})${NC}" >&2
|
||||
echo -ne " ${WHITE}Выбор:${NC} " >&2
|
||||
echo -ne " ${WHITE}$(_t_or choose 'Choose'):${NC} " >&2
|
||||
read -r choice
|
||||
echo "$choice"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user