Files
go_warp_pro/warp.sh
2026-03-08 16:09:22 +03:00

1024 lines
47 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
set -o pipefail
# ══════════════════════════════════════════════════════════════
# WARP Manager v1.1 — Cloudflare WARP SOCKS5 Proxy for 3X-UI
# Telegram Bot · Status · Rekey · 3X-UI Config
# Channel: https://www.youtube.com/@antenkaru
# Line endings: LF only (Unix) for gowarp on Linux
# ══════════════════════════════════════════════════════════════
WARP_VERSION="1.1"
WARP_DIR="/etc/warp-manager"
WARP_CONF="$WARP_DIR/config"
WARP_LOG="/var/log/warp-manager.log"
BOT_PID_FILE="/var/run/warp_bot.pid"
DEFAULT_PORT=40000
VALID_KEYS=(
"WARP-PRO-2026-ALPHA"
"WARP-PRO-2026-BETA"
"WARP-PRO-2026-GAMMA"
)
RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'
YELLOW='\033[1;33m'; MAGENTA='\033[0;35m'; WHITE='\033[1;37m'
BLUE='\033[0;34m'; NC='\033[0m'
SOCKS_PORT=""
MY_IP=""
BOT_TOKEN=""
BOT_CHAT_ID=""
LICENSE_KEY=""
# ─── Config ───────────────────────────────────────────────────
init_config() {
mkdir -p "$WARP_DIR"
if [ ! -f "$WARP_CONF" ]; then
cat > "$WARP_CONF" <<'CONF'
SOCKS_PORT="40000"
BOT_TOKEN=""
BOT_CHAT_ID=""
LICENSE_KEY=""
CONF
fi
source "$WARP_CONF"
SOCKS_PORT="${SOCKS_PORT:-$DEFAULT_PORT}"
}
save_config_val() {
local key="$1" value="$2"
if grep -q "^${key}=" "$WARP_CONF" 2>/dev/null; then
sed -i "s|^${key}=.*|${key}=\"${value}\"|" "$WARP_CONF"
else
echo "${key}=\"${value}\"" >> "$WARP_CONF"
fi
source "$WARP_CONF"
}
# ─── License ──────────────────────────────────────────────────
is_valid_key() {
local k="$1"
for vk in "${VALID_KEYS[@]}"; do
[ "$k" = "$vk" ] && return 0
done
return 1
}
check_license() {
local arg_key="${1:-}"
source "$WARP_CONF" 2>/dev/null
if [ -n "${LICENSE_KEY:-}" ] && is_valid_key "$LICENSE_KEY"; then
return 0
fi
if [ -n "$arg_key" ] && is_valid_key "$arg_key"; then
save_config_val "LICENSE_KEY" "$arg_key"
LICENSE_KEY="$arg_key"
return 0
fi
echo ""
echo -e "${RED}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}║ ⛔ ЛИЦЕНЗИОННЫЙ КЛЮЧ НЕДЕЙСТВИТЕЛЕН ║${NC}"
echo -e "${RED}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
if [ -n "$arg_key" ]; then
echo -e " ${WHITE}Ключ ${YELLOW}${arg_key}${WHITE} не найден в базе.${NC}"
else
echo -e " ${WHITE}Для установки требуется лицензионный ключ.${NC}"
fi
echo ""
echo -e " ${CYAN}Использование:${NC}"
echo -e " ${WHITE}bash <(curl -sL ...) ${GREEN}ВАШ_КЛЮЧ${NC}"
echo ""
echo -e " ${WHITE}Получить ключ: ${CYAN}https://www.youtube.com/@antenkaru${NC}"
echo ""
exit 1
}
# ─── Logging ──────────────────────────────────────────────────
log_action() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$WARP_LOG"
}
# ─── System ───────────────────────────────────────────────────
check_root() {
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}[ERROR] Запустите скрипт с правами root!${NC}"; exit 1
fi
}
check_deps() {
for cmd in jq curl; do
if ! command -v "$cmd" &>/dev/null; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -y > /dev/null 2>&1
apt-get install -y jq curl > /dev/null 2>&1
break
fi
done
}
get_my_ip() {
MY_IP=$(curl -s4 --max-time 5 ifconfig.me 2>/dev/null || echo "N/A")
}
get_warp_ip() {
local warp_ip
warp_ip=$(curl -s4 --max-time 5 --proxy socks5h://127.0.0.1:${SOCKS_PORT} ifconfig.me 2>/dev/null || echo "N/A")
echo "$warp_ip"
}
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS_ID="$ID"
OS_VERSION="$VERSION_ID"
OS_CODENAME="$VERSION_CODENAME"
else
OS_ID="unknown"
fi
}
is_warp_installed() {
command -v warp-cli &>/dev/null
}
is_warp_running() {
local st
st=$(warp-cli --accept-tos status 2>/dev/null)
echo "$st" | grep -qi "status.*connected" && ! echo "$st" | grep -qi "disconnected"
}
get_warp_status_text() {
if ! is_warp_installed; then
echo "Не установлен"
return
fi
local status
status=$(warp-cli --accept-tos status 2>/dev/null | head -5)
if echo "$status" | grep -qi "disconnected"; then
echo "Отключён"
elif echo "$status" | grep -qi "connected"; then
echo "Подключён"
elif echo "$status" | grep -qi "registration missing"; then
echo "Нет регистрации"
else
echo "Неизвестно"
fi
}
get_system_stats() {
local cpu_line load_avg mem_info disk_info uptime_str cpu_usage
cpu_line=$(grep -c ^processor /proc/cpuinfo 2>/dev/null || echo "?")
load_avg=$(cat /proc/loadavg 2>/dev/null | awk '{print $1, $2, $3}')
mem_info=$(free -m 2>/dev/null | awk '/^Mem:/ {printf "%d/%dMB (%.1f%%)", $3, $2, $3/$2*100}')
disk_info=$(df -h / 2>/dev/null | awk 'NR==2 {printf "%s/%s (%s)", $3, $2, $5}')
uptime_str=$(uptime -p 2>/dev/null || uptime | sed 's/.*up /up /' | sed 's/,.*load.*//')
cpu_usage=$(awk '/^cpu / {u=$2+$4; t=$2+$3+$4+$5+$6+$7+$8; if(t>0) printf "%.1f", u/t*100; else print "0"}' /proc/stat 2>/dev/null)
local r=""
r+="<b>📊 Системная информация</b>\n\n"
r+="<b>Uptime:</b> ${uptime_str}\n"
r+="<b>CPU:</b> ${cpu_line} ядер | ${cpu_usage}%\n"
r+="<b>Load:</b> ${load_avg}\n"
r+="<b>RAM:</b> ${mem_info}\n"
r+="<b>Disk /:</b> ${disk_info}\n"
echo "$r"
}
# ─── Install ──────────────────────────────────────────────────
install_warp() {
clear
echo -e "\n${CYAN}━━━ Установка Cloudflare WARP ━━━${NC}\n"
if is_warp_installed; then
echo -e "${YELLOW}WARP уже установлен.${NC}"
echo -e "Используйте меню для управления.\n"
read -p "Нажмите Enter..."
return
fi
detect_os
if [[ "$OS_ID" != "ubuntu" && "$OS_ID" != "debian" ]]; then
echo -e "${RED}[ERROR] Поддерживаются только Ubuntu и Debian.${NC}"
echo -e "${WHITE}Ваша ОС: ${YELLOW}${OS_ID} ${OS_VERSION}${NC}"
read -p "Нажмите Enter..."
return
fi
echo -e "${YELLOW}[1/6]${NC} Добавление GPG-ключа Cloudflare..."
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor -o /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg 2>/dev/null
if [ $? -ne 0 ]; then
echo -e "${RED}[ERROR] Не удалось добавить GPG-ключ.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "${GREEN} ✓ GPG-ключ добавлен${NC}"
echo -e "${YELLOW}[2/6]${NC} Добавление репозитория..."
local codename="$OS_CODENAME"
if [ -z "$codename" ]; then
codename=$(lsb_release -cs 2>/dev/null || echo "focal")
fi
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ ${codename} main" \
> /etc/apt/sources.list.d/cloudflare-client.list
echo -e "${GREEN} ✓ Репозиторий добавлен (${codename})${NC}"
echo -e "${YELLOW}[3/6]${NC} Установка пакета cloudflare-warp..."
export DEBIAN_FRONTEND=noninteractive
apt-get update -y > /dev/null 2>&1
apt-get install -y cloudflare-warp > /dev/null 2>&1
if ! command -v warp-cli &>/dev/null; then
echo -e "${RED}[ERROR] Установка не удалась. Проверьте совместимость ОС.${NC}"
echo -e "${WHITE}Попробуйте: ${CYAN}apt-get install cloudflare-warp${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "${GREEN} ✓ cloudflare-warp установлен${NC}"
echo -e "${YELLOW}[4/6]${NC} Регистрация аккаунта WARP..."
warp-cli --accept-tos registration new > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo -e "${RED}[ERROR] Регистрация не удалась.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "${GREEN} ✓ Аккаунт зарегистрирован${NC}"
echo -e "${YELLOW}[5/6]${NC} Настройка режима SOCKS5-прокси..."
warp-cli --accept-tos mode proxy > /dev/null 2>&1
warp-cli --accept-tos proxy port "${SOCKS_PORT}" > /dev/null 2>&1
save_config_val "SOCKS_PORT" "${SOCKS_PORT}"
echo -e "${GREEN} ✓ Режим: SOCKS5 на 127.0.0.1:${SOCKS_PORT}${NC}"
echo -e "${YELLOW}[6/6]${NC} Подключение..."
warp-cli --accept-tos connect > /dev/null 2>&1
sleep 3
if is_warp_running; then
local wip
wip=$(get_warp_ip)
echo -e "${GREEN} ✓ WARP подключён!${NC}"
echo -e " ${WHITE}WARP IP: ${GREEN}${wip}${NC}"
log_action "INSTALL: WARP installed and connected, port=${SOCKS_PORT}, warp_ip=${wip}"
else
echo -e "${YELLOW} ⚠ WARP установлен, но подключение не подтверждено.${NC}"
echo -e " ${WHITE}Попробуйте: ${CYAN}warp-cli --accept-tos connect${NC}"
log_action "INSTALL: WARP installed, connection unconfirmed"
fi
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${WHITE}Для интеграции с 3X-UI используйте пункт меню ${YELLOW}5${WHITE}.${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
read -p "Нажмите Enter..."
}
# ─── Start / Stop ─────────────────────────────────────────────
start_warp() {
if ! is_warp_installed; then
echo -e "\n${RED}WARP не установлен. Сначала выполните установку (п.1).${NC}"
read -p "Нажмите Enter..."; return
fi
if is_warp_running; then
echo -e "\n${YELLOW}WARP уже подключён.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "\n${YELLOW}Подключение WARP...${NC}"
warp-cli --accept-tos connect > /dev/null 2>&1
sleep 3
if is_warp_running; then
echo -e "${GREEN}[OK] WARP подключён.${NC}"
log_action "START: WARP connected"
else
echo -e "${RED}[ERROR] Не удалось подключить. Проверьте: warp-cli --accept-tos status${NC}"
fi
read -p "Нажмите Enter..."
}
stop_warp() {
if ! is_warp_installed; then
echo -e "\n${RED}WARP не установлен.${NC}"
read -p "Нажмите Enter..."; return
fi
if ! is_warp_running; then
echo -e "\n${YELLOW}WARP уже отключён.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "\n${YELLOW}Отключение WARP...${NC}"
warp-cli --accept-tos disconnect > /dev/null 2>&1
echo -e "${GREEN}[OK] WARP отключён.${NC}"
log_action "STOP: WARP disconnected"
read -p "Нажмите Enter..."
}
# ─── Status ───────────────────────────────────────────────────
show_status() {
clear
echo -e "\n${CYAN}━━━ Статус WARP ━━━${NC}\n"
if ! is_warp_installed; then
echo -e " ${WHITE}Статус: ${RED}Не установлен${NC}"
echo -e "\n ${WHITE}Установите WARP через пункт меню 1.${NC}"
echo ""
read -p "Нажмите Enter..."; return
fi
local status_text warp_ip
status_text=$(get_warp_status_text)
local status_color="$RED"
[[ "$status_text" == "Подключён" ]] && status_color="$GREEN"
[[ "$status_text" == "Отключён" ]] && status_color="$YELLOW"
echo -e " ${WHITE}Статус: ${status_color}${status_text}${NC}"
echo -e " ${WHITE}Порт SOCKS5: ${CYAN}127.0.0.1:${SOCKS_PORT}${NC}"
echo -e " ${WHITE}Реальный IP: ${GREEN}${MY_IP}${NC}"
if is_warp_running; then
warp_ip=$(get_warp_ip)
echo -e " ${WHITE}WARP IP: ${GREEN}${warp_ip}${NC}"
fi
echo ""
echo -e " ${CYAN}── warp-cli status ──${NC}"
warp-cli --accept-tos status 2>/dev/null | while IFS= read -r line; do
echo -e " ${WHITE}$line${NC}"
done
echo ""
read -p "Нажмите Enter..."
}
# ─── 3X-UI JSON ──────────────────────────────────────────────
show_xui_json() {
clear
echo -e "\n${CYAN}━━━ Конфигурация для 3X-UI ━━━${NC}\n"
echo -e "${WHITE}Добавьте в ${YELLOW}Xray Settings → Outbounds${WHITE} (JSON):${NC}\n"
echo -e "${GREEN}── 1. Outbound (добавить в массив outbounds) ──${NC}\n"
cat <<EOF
{
"tag": "warp",
"protocol": "socks",
"settings": {
"servers": [
{
"address": "127.0.0.1",
"port": ${SOCKS_PORT}
}
]
}
}
EOF
echo -e "\n${GREEN}── 2. Routing Rule (примеры маршрутов через WARP) ──${NC}\n"
echo -e "${WHITE}Только определённые сайты через WARP (JSON routing rule):${NC}\n"
cat <<EOF
{
"outboundTag": "warp",
"domain": [
"geosite:openai",
"geosite:netflix",
"geosite:disney",
"geosite:spotify",
"domain:chat.openai.com",
"domain:claude.ai"
]
}
EOF
echo -e "\n${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${WHITE}SOCKS5 прокси: ${GREEN}127.0.0.1:${SOCKS_PORT}${NC}"
if is_warp_running; then
local wip
wip=$(get_warp_ip)
echo -e "${WHITE}WARP IP: ${GREEN}${wip}${NC}"
fi
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
read -p "Нажмите Enter..."
}
# ─── Re-register ──────────────────────────────────────────────
rekey_warp() {
if ! is_warp_installed; then
echo -e "\n${RED}WARP не установлен.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "\n${CYAN}━━━ Перевыпуск ключа WARP ━━━${NC}\n"
echo -e "${WHITE}Текущая регистрация будет удалена и создана новая.${NC}"
echo -e "${YELLOW}WARP будет временно отключён.${NC}\n"
read -p "Продолжить? (y/n): " confirm
[[ "$confirm" != "y" ]] && return
echo -e "${YELLOW}[1/4] Отключение...${NC}"
warp-cli --accept-tos disconnect > /dev/null 2>&1
echo -e "${GREEN}${NC}"
echo -e "${YELLOW}[2/4] Удаление регистрации...${NC}"
warp-cli --accept-tos registration delete > /dev/null 2>&1
echo -e "${GREEN}${NC}"
echo -e "${YELLOW}[3/4] Новая регистрация...${NC}"
warp-cli --accept-tos registration new > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo -e "${RED}[ERROR] Регистрация не удалась.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "${GREEN}${NC}"
echo -e "${YELLOW}[4/4] Подключение...${NC}"
warp-cli --accept-tos mode proxy > /dev/null 2>&1
warp-cli --accept-tos proxy port "${SOCKS_PORT}" > /dev/null 2>&1
warp-cli --accept-tos connect > /dev/null 2>&1
sleep 3
if is_warp_running; then
local wip
wip=$(get_warp_ip)
echo -e "${GREEN} ✓ Готово! Новый WARP IP: ${wip}${NC}"
log_action "REKEY: new registration, warp_ip=${wip}"
else
echo -e "${YELLOW} ⚠ Регистрация обновлена, подключение не подтверждено.${NC}"
log_action "REKEY: new registration, connection unconfirmed"
fi
read -p "Нажмите Enter..."
}
# ─── Change port ──────────────────────────────────────────────
change_port() {
if ! is_warp_installed; then
echo -e "\n${RED}WARP не установлен.${NC}"
read -p "Нажмите Enter..."; return
fi
echo -e "\n${CYAN}━━━ Изменение порта SOCKS5 ━━━${NC}\n"
echo -e "${WHITE}Текущий порт: ${GREEN}${SOCKS_PORT}${NC}\n"
local new_port
while true; do
echo -e "Введите новый порт (1024-65535):"
read -p "> " new_port
if [[ "$new_port" =~ ^[0-9]+$ ]] && (( new_port >= 1024 && new_port <= 65535 )); then
break
fi
echo -e "${RED}Ошибка: порт должен быть числом от 1024 до 65535.${NC}"
done
warp-cli --accept-tos proxy port "$new_port" > /dev/null 2>&1
save_config_val "SOCKS_PORT" "$new_port"
SOCKS_PORT="$new_port"
echo -e "\n${GREEN}[OK] Порт изменён на ${new_port}.${NC}"
echo -e "${WHITE}SOCKS5: ${CYAN}127.0.0.1:${new_port}${NC}"
echo -e "\n${YELLOW}Не забудьте обновить порт в настройках 3X-UI!${NC}"
log_action "PORT: changed to ${new_port}"
read -p "Нажмите Enter..."
}
# ─── Uninstall ────────────────────────────────────────────────
full_uninstall() {
clear
echo -e "\n${RED}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${RED}║ ⚠ ПОЛНОЕ УДАЛЕНИЕ WARP MANAGER ⚠ ║${NC}"
echo -e "${RED}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${WHITE}Будут удалены:${NC}"
echo -e " ${RED}${NC} Пакет cloudflare-warp"
echo -e " ${RED}${NC} Репозиторий и GPG-ключ Cloudflare"
echo -e " ${RED}${NC} Telegram-бот"
echo -e " ${RED}${NC} Конфигурация ${WHITE}/etc/warp-manager/${NC}"
echo -e " ${RED}${NC} Команда ${WHITE}gowarp${NC}"
echo -e " ${RED}${NC} Логи ${WHITE}/var/log/warp-manager.log${NC}"
echo ""
echo -e "${GREEN}НЕ будет затронуто:${NC}"
echo -e " ${GREEN}${NC} 3X-UI и Xray (настройки outbound нужно убрать вручную)"
echo -e " ${GREEN}${NC} Kaskad PRO"
echo -e " ${GREEN}${NC} Системные пакеты"
echo ""
read -p "$(echo -e "${RED}Удалить WARP Manager полностью? (y/n): ${NC}")" confirm1
[[ "$confirm1" != "y" ]] && { echo -e "\n${CYAN}Отменено.${NC}"; read -p "Нажмите Enter..."; return; }
echo ""
echo -e "${YELLOW}Удаление WARP Manager...${NC}\n"
if systemctl is-active warp-bot &>/dev/null; then
systemctl stop warp-bot 2>/dev/null; systemctl disable warp-bot 2>/dev/null
fi
[ -f "$BOT_PID_FILE" ] && { kill "$(cat "$BOT_PID_FILE")" 2>/dev/null; rm -f "$BOT_PID_FILE"; }
rm -f /etc/systemd/system/warp-bot.service
systemctl daemon-reload 2>/dev/null
echo -e " ${GREEN}${NC} Telegram-бот остановлен"
warp-cli --accept-tos disconnect > /dev/null 2>&1
echo -e " ${GREEN}${NC} WARP отключён"
warp-cli --accept-tos registration delete > /dev/null 2>&1
echo -e " ${GREEN}${NC} Регистрация удалена"
apt-get remove -y cloudflare-warp > /dev/null 2>&1
apt-get autoremove -y > /dev/null 2>&1
echo -e " ${GREEN}${NC} Пакет удалён"
rm -f /etc/apt/sources.list.d/cloudflare-client.list
rm -f /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
echo -e " ${GREEN}${NC} Репозиторий и ключ удалены"
rm -rf "$WARP_DIR"
rm -f "$WARP_LOG"
echo -e " ${GREEN}${NC} Конфигурация и логи удалены"
rm -f /usr/local/bin/gowarp
echo -e " ${GREEN}${NC} Команда gowarp удалена"
echo ""
echo -e "${GREEN}══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} WARP Manager полностью удалён.${NC}"
echo -e "${WHITE} Не забудьте убрать outbound \"warp\" из настроек 3X-UI!${NC}"
echo -e "${GREEN}══════════════════════════════════════════════════════════════${NC}"
echo ""
log_action "UNINSTALL: full removal completed"
read -p "Нажмите Enter..."
exit 0
}
# ═══════════════════════════════════════════════════════════════
# TELEGRAM BOT
# ═══════════════════════════════════════════════════════════════
tg_api() {
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/$1" \
-H "Content-Type: application/json" -d "$2" 2>/dev/null
}
tg_send() {
local chat_id="$1" text keyboard="${3:-}"
text=$(printf '%b' "$2")
local payload
if [ -n "$keyboard" ]; then
payload=$(jq -n --arg c "$chat_id" --arg t "$text" --argjson k "$keyboard" \
'{chat_id:$c, text:$t, parse_mode:"HTML", reply_markup:{inline_keyboard:$k}}')
else
payload=$(jq -n --arg c "$chat_id" --arg t "$text" \
'{chat_id:$c, text:$t, parse_mode:"HTML"}')
fi
tg_api "sendMessage" "$payload"
}
tg_edit() {
local chat_id="$1" msg_id="$2" text keyboard="${4:-}"
text=$(printf '%b' "$3")
local payload
if [ -n "$keyboard" ]; then
payload=$(jq -n --arg c "$chat_id" --argjson m "$msg_id" --arg t "$text" --argjson k "$keyboard" \
'{chat_id:$c, message_id:$m, text:$t, parse_mode:"HTML", reply_markup:{inline_keyboard:$k}}')
else
payload=$(jq -n --arg c "$chat_id" --argjson m "$msg_id" --arg t "$text" \
'{chat_id:$c, message_id:$m, text:$t, parse_mode:"HTML"}')
fi
tg_api "editMessageText" "$payload"
}
tg_answer_cb() {
tg_api "answerCallbackQuery" "{\"callback_query_id\":\"$1\",\"text\":\"${2:-}\"}"
}
# ─── Bot keyboards ───────────────────────────────────────────
kbd_main() {
cat <<'JSON'
[
[{"text":"📊 Статус","callback_data":"st"},{"text":"🌐 IP адреса","callback_data":"ip"}],
[{"text":"▶️ Запустить","callback_data":"on"},{"text":"⏹ Остановить","callback_data":"off"}],
[{"text":"🔑 Перевыпуск ключа","callback_data":"rk"}],
[{"text":"📋 JSON для 3X-UI","callback_data":"js"}],
[{"text":"💻 Система","callback_data":"sys"}],
[{"text":"🏢 Хостинг","callback_data":"promo"}]
]
JSON
}
kbd_back() { echo '[[{"text":"⬅️ Меню","callback_data":"m"}]]'; }
kbd_rekey_confirm() { echo '[[{"text":"✅ Да, перевыпустить","callback_data":"rk_y"}],[{"text":"⬅️ Отмена","callback_data":"m"}]]'; }
# ─── Bot handlers ────────────────────────────────────────────
bot_main_menu() {
local chat_id="$1" msg_id="${2:-}"
local ws wip=""
ws=$(get_warp_status_text)
is_warp_running && wip=" | WARP IP: $(get_warp_ip)"
local text="<b>WARP Manager v${WARP_VERSION}</b>\nСервер: <code>${MY_IP:-N/A}</code>\nСтатус: <b>${ws}</b>${wip}\nSOCKS5: <code>127.0.0.1:${SOCKS_PORT}</code>\n\nВыберите действие:"
local kbd
kbd=$(kbd_main)
if [ -n "$msg_id" ]; then
tg_edit "$chat_id" "$msg_id" "$text" "$kbd"
else
tg_send "$chat_id" "$text" "$kbd"
fi
}
bot_handle_callback() {
local chat_id="$1" msg_id="$2" cb_id="$3" data="$4"
[ -n "$cb_id" ] && tg_answer_cb "$cb_id" > /dev/null
case "$data" in
m) bot_main_menu "$chat_id" "$msg_id" ;;
st)
local ws wip=""
ws=$(get_warp_status_text)
is_warp_running && wip="\nWARP IP: <code>$(get_warp_ip)</code>"
local raw
raw=$(warp-cli --accept-tos status 2>/dev/null | head -3)
local text="📊 <b>Статус WARP</b>\n\nСтатус: <b>${ws}</b>\nSOCKS5: <code>127.0.0.1:${SOCKS_PORT}</code>\nСервер: <code>${MY_IP:-N/A}</code>${wip}\n\n<pre>${raw}</pre>"
tg_edit "$chat_id" "$msg_id" "$text" "$(kbd_back)" ;;
ip)
local wip="N/A"
is_warp_running && wip=$(get_warp_ip)
local text="🌐 <b>IP адреса</b>\n\n<b>Реальный IP:</b> <code>${MY_IP:-N/A}</code>\n<b>WARP IP:</b> <code>${wip}</code>\n<b>SOCKS5:</b> <code>127.0.0.1:${SOCKS_PORT}</code>"
tg_edit "$chat_id" "$msg_id" "$text" "$(kbd_back)" ;;
on)
if ! is_warp_installed; then
tg_edit "$chat_id" "$msg_id" "❌ WARP не установлен." "$(kbd_back)"; return
fi
if is_warp_running; then
tg_edit "$chat_id" "$msg_id" "✅ WARP уже подключён." "$(kbd_back)"; return
fi
tg_edit "$chat_id" "$msg_id" "⏳ Подключение WARP..." ""
warp-cli --accept-tos connect > /dev/null 2>&1
sleep 3
if is_warp_running; then
local wip
wip=$(get_warp_ip)
log_action "BOT: WARP connected"
tg_edit "$chat_id" "$msg_id" "✅ <b>WARP подключён</b>\nWARP IP: <code>${wip}</code>" "$(kbd_back)"
else
tg_edit "$chat_id" "$msg_id" "Не удалось подключить WARP." "$(kbd_back)"
fi ;;
off)
if ! is_warp_running; then
tg_edit "$chat_id" "$msg_id" " WARP уже отключён." "$(kbd_back)"; return
fi
warp-cli --accept-tos disconnect > /dev/null 2>&1
log_action "BOT: WARP disconnected"
tg_edit "$chat_id" "$msg_id" "⏹ <b>WARP отключён.</b>" "$(kbd_back)" ;;
rk)
tg_edit "$chat_id" "$msg_id" "🔑 <b>Перевыпуск ключа</b>\n\nТекущая регистрация будет удалена и создана новая.\nWARP будет временно отключён.\n\nПродолжить?" "$(kbd_rekey_confirm)" ;;
rk_y)
tg_edit "$chat_id" "$msg_id" "⏳ Перевыпуск ключа..." ""
warp-cli --accept-tos disconnect > /dev/null 2>&1
warp-cli --accept-tos registration delete > /dev/null 2>&1
warp-cli --accept-tos registration new > /dev/null 2>&1
warp-cli --accept-tos mode proxy > /dev/null 2>&1
warp-cli --accept-tos proxy port "${SOCKS_PORT}" > /dev/null 2>&1
warp-cli --accept-tos connect > /dev/null 2>&1
sleep 3
if is_warp_running; then
local wip
wip=$(get_warp_ip)
log_action "BOT REKEY: warp_ip=${wip}"
tg_edit "$chat_id" "$msg_id" "✅ <b>Ключ перевыпущен</b>\nНовый WARP IP: <code>${wip}</code>" "$(kbd_back)"
else
tg_edit "$chat_id" "$msg_id" "⚠️ Ключ перевыпущен, подключение не подтверждено." "$(kbd_back)"
fi ;;
js)
local text="📋 <b>Конфигурация для 3X-UI</b>\n\n<b>Outbound:</b>\n<pre>{\n \"tag\": \"warp\",\n \"protocol\": \"socks\",\n \"settings\": {\n \"servers\": [{\n \"address\": \"127.0.0.1\",\n \"port\": ${SOCKS_PORT}\n }]\n }\n}</pre>\n\n<b>Routing rule:</b>\n<pre>{\n \"outboundTag\": \"warp\",\n \"domain\": [\n \"geosite:openai\",\n \"geosite:netflix\"\n ]\n}</pre>"
tg_edit "$chat_id" "$msg_id" "$text" "$(kbd_back)" ;;
sys)
local s
s=$(get_system_stats)
local ws
ws=$(get_warp_status_text)
s+="\n<b>WARP:</b> ${ws}"
s+="\n<b>SOCKS5:</b> 127.0.0.1:${SOCKS_PORT}"
tg_edit "$chat_id" "$msg_id" "$s" "$(kbd_back)" ;;
promo)
local pt="<b>🏢 Хостинг, который работает</b>\n\n<b>🌍 РФ и Европа</b>\n👉 https://vk.cc/ct29NQ\n\n<code>OFF60</code> — 60% скидка\n<code>antenka20</code> — +20% (ес)\n<code>antenka6</code> — +15% (ес)\n<code>antenka12</code> — +5% (12мес)\n\n<b>🇧🇾 Беларусь</b>\n👉 https://vk.cc/cUxAhj\n<code>OFF60</code> — 60% скидка"
tg_edit "$chat_id" "$msg_id" "$pt" "$(kbd_back)" ;;
esac
}
# ─── Bot daemon ───────────────────────────────────────────────
bot_daemon() {
log_action "Bot daemon started (PID $$)"; echo $$ > "$BOT_PID_FILE"
source "$WARP_CONF"
[ -z "$BOT_TOKEN" ] && log_action "BOT ERROR: no token" && exit 1
get_my_ip
local offset=0
while true; do
local response
response=$(curl -s --max-time 35 \
"https://api.telegram.org/bot${BOT_TOKEN}/getUpdates?offset=${offset}&timeout=30" 2>/dev/null)
[ -z "$response" ] && sleep 2 && continue
local ok
ok=$(echo "$response" | jq -r '.ok // "false"')
[ "$ok" != "true" ] && sleep 5 && continue
local cnt
cnt=$(echo "$response" | jq '.result | length')
for (( i=0; i<cnt; i++ )); do
local upd
upd=$(echo "$response" | jq ".result[$i]")
local uid
uid=$(echo "$upd" | jq -r '.update_id')
offset=$((uid + 1))
local cbd
cbd=$(echo "$upd" | jq -r '.callback_query.data // empty')
if [ -n "$cbd" ]; then
local cbi cci cmi
cbi=$(echo "$upd" | jq -r '.callback_query.id')
cci=$(echo "$upd" | jq -r '.callback_query.message.chat.id')
cmi=$(echo "$upd" | jq -r '.callback_query.message.message_id')
[ -n "$BOT_CHAT_ID" ] && [ "$cci" != "$BOT_CHAT_ID" ] && tg_answer_cb "$cbi" "Unauthorized" > /dev/null && continue
bot_handle_callback "$cci" "$cmi" "$cbi" "$cbd"
else
local mci mtx
mci=$(echo "$upd" | jq -r '.message.chat.id // empty')
mtx=$(echo "$upd" | jq -r '.message.text // empty')
if [ -n "$mci" ] && [ -n "$mtx" ]; then
[ -n "$BOT_CHAT_ID" ] && [ "$mci" != "$BOT_CHAT_ID" ] && \
tg_send "$mci" "⛔ Нет доступа.\nChat ID: <code>$mci</code>" "" > /dev/null && continue
if [ "$mtx" = "/start" ] || [ "$mtx" = "/menu" ]; then
bot_main_menu "$mci"
else
tg_send "$mci" "Используйте /start или /menu" "" > /dev/null
fi
fi
fi
done
done
}
start_bot() {
source "$WARP_CONF"
[ -z "$BOT_TOKEN" ] && echo -e "${RED}Задайте BOT_TOKEN!${NC}" && return
[ -f "$BOT_PID_FILE" ] && kill -0 "$(cat "$BOT_PID_FILE")" 2>/dev/null && echo -e "${YELLOW}Уже запущен.${NC}" && return
cat > /etc/systemd/system/warp-bot.service <<EOF
[Unit]
Description=WARP Manager Telegram Bot
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/gowarp --bot-daemon
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable warp-bot > /dev/null 2>&1
systemctl start warp-bot
sleep 1
systemctl is-active warp-bot &>/dev/null && echo -e "${GREEN}[OK] Бот запущен.${NC}" && log_action "Bot started" \
|| echo -e "${RED}[ERROR] journalctl -u warp-bot${NC}"
}
stop_bot() {
systemctl stop warp-bot 2>/dev/null
systemctl disable warp-bot 2>/dev/null
rm -f "$BOT_PID_FILE"
echo -e "${GREEN}[OK] Бот остановлен.${NC}"
log_action "Bot stopped"
}
bot_menu() {
while true; do
clear; source "$WARP_CONF" 2>/dev/null
local bs="${RED}Выкл${NC}"
[ -f "$BOT_PID_FILE" ] && kill -0 "$(cat "$BOT_PID_FILE" 2>/dev/null)" 2>/dev/null && bs="${GREEN}Вкл ($(cat "$BOT_PID_FILE"))${NC}"
local td="нет"
[ -n "${BOT_TOKEN:-}" ] && td="***${BOT_TOKEN: -6}"
echo -e "${CYAN}━━━ Telegram Bot ━━━${NC}"
echo -e "Статус: $bs"
echo -e "Токен: ${YELLOW}$td${NC}"
echo -e "Chat ID: ${YELLOW}${BOT_CHAT_ID:-нет}${NC}"
echo ""
echo -e "1) Токен бота"
echo -e "2) Chat ID (авто)"
echo -e "3) Chat ID (вручную)"
echo -e "4) ${GREEN}Запустить${NC}"
echo -e "5) ${RED}Остановить${NC}"
echo -e "0) Назад"
read -p "Выбор: " ch
case $ch in
1) echo "Токен:"; read -p "> " t
[ -n "$t" ] && save_config_val "BOT_TOKEN" "$t" && BOT_TOKEN="$t" && echo -e "${GREEN}OK${NC}"
read -p "Enter..." ;;
2) [ -z "${BOT_TOKEN:-}" ] && echo -e "${RED}Сначала задайте токен!${NC}" && read -p "" && continue
echo -e "${YELLOW}Отправьте боту сообщение, затем нажмите Enter.${NC}"; read -p ""
local c
c=$(curl -s "https://api.telegram.org/bot${BOT_TOKEN}/getUpdates?limit=1&offset=-1" | \
jq -r '.result[0].message.chat.id // empty')
[ -n "$c" ] && save_config_val "BOT_CHAT_ID" "$c" && BOT_CHAT_ID="$c" && echo -e "${GREEN}Chat ID: $c${NC}" \
|| echo -e "${RED}Не удалось получить Chat ID.${NC}"
read -p "Enter..." ;;
3) echo "Chat ID:"; read -p "> " c
[ -n "$c" ] && save_config_val "BOT_CHAT_ID" "$c" && BOT_CHAT_ID="$c" && echo -e "${GREEN}OK${NC}"
read -p "Enter..." ;;
4) start_bot; read -p "Enter..." ;;
5) stop_bot; read -p "Enter..." ;;
0) return ;;
esac
done
}
# ═══════════════════════════════════════════════════════════════
# PROMO
# ═══════════════════════════════════════════════════════════════
show_promo() {
clear; echo ""
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${MAGENTA}║ ХОСТИНГ СО СКИДКОЙ ДО -60% ║${NC}"
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════════╝${NC}"
echo -e "\n${CYAN}🌍 РФ И ЕВРОПА${NC}\n${WHITE} >>> https://vk.cc/ct29NQ${NC}"
printf " ${YELLOW}%-12s${NC} : ${WHITE}%s${NC}\n" "OFF60" "60% скидка" "antenka20" "+20% (ес)" "antenka6" "+15% (ес)" "antenka12" "+5% (12мес)"
echo -e "\n${CYAN}🇧🇾 БЕЛАРУСЬ${NC}\n${WHITE} >>> https://vk.cc/cUxAhj${NC}"
printf " ${YELLOW}%-12s${NC} : ${WHITE}%s${NC}\n" "OFF60" "60% скидка"
echo -e "\n${YELLOW}QR-код... (3с)${NC}"; for i in 3 2 1; do echo -ne "$i..."; sleep 1; done; echo ""
echo -e "\n${WHITE}"; command -v qrencode &>/dev/null && qrencode -t ANSIUTF8 "https://vk.cc/ct29NQ" || echo "Ссылки выше."; echo -e "${NC}"
read -p "Нажмите Enter..."
}
# ═══════════════════════════════════════════════════════════════
# INFO PAGE
# ═══════════════════════════════════════════════════════════════
show_info() {
clear; echo ""
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${MAGENTA}║ 📚 WARP Manager v${WARP_VERSION} — Что это и как работает ║${NC}"
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${CYAN}═══ ЧТО ТАКОЕ CLOUDFLARE WARP ═══${NC}"
echo ""
echo -e "${WHITE} Cloudflare WARP — бесплатный сервис от Cloudflare, который"
echo -e " направляет трафик через глобальную сеть Cloudflare."
echo -e ""
echo -e " Ваш VPS получает «чистый» IP-адрес Cloudflare, который"
echo -e " не заблокирован популярными сервисами.${NC}"
echo ""
echo -e "${CYAN}═══ СХЕМА РАБОТЫ ═══${NC}"
echo ""
echo -e "${WHITE} Клиент → 3X-UI (Xray) → SOCKS5 (WARP) → Cloudflare → Интернет${NC}"
echo ""
echo -e "${GREEN} 1.${NC} Скрипт устанавливает ${YELLOW}cloudflare-warp${NC} на сервер"
echo -e "${GREEN} 2.${NC} WARP работает в режиме ${YELLOW}SOCKS5-прокси${NC} на 127.0.0.1:${SOCKS_PORT}"
echo -e "${GREEN} 3.${NC} В 3X-UI добавляется ${YELLOW}outbound${NC} типа SOCKS → warp"
echo -e "${GREEN} 4.${NC} В маршрутизации выбираете какие сайты идут через WARP"
echo ""
echo -e "${CYAN}═══ ЧТО ПОЛУЧАЕТЕ ═══${NC}"
echo ""
echo -e " ${GREEN}${NC} Разблокировка ChatGPT, Netflix, Disney+, Spotify"
echo -e " ${GREEN}${NC} Чистый IPv4/IPv6 от Cloudflare"
echo -e " ${GREEN}${NC} Стабильный маршрут через сеть Cloudflare"
echo -e " ${GREEN}${NC} Управление через Telegram-бот"
echo -e " ${GREEN}${NC} Бесплатно (Cloudflare WARP — бесплатный сервис)"
echo ""
echo -e "${MAGENTA}──────────────────────────────────────────────────────────────${NC}"
read -p "Нажмите Enter для продолжения..."
}
# ═══════════════════════════════════════════════════════════════
# MAIN MENU
# ═══════════════════════════════════════════════════════════════
show_menu() {
while true; do
clear
local status_text status_color
status_text=$(get_warp_status_text)
status_color="$RED"
[[ "$status_text" == "Подключён" ]] && status_color="$GREEN"
[[ "$status_text" == "Отключён" ]] && status_color="$YELLOW"
echo -e "${MAGENTA}******************************************************"
echo " anten-ka · WARP Manager v${WARP_VERSION}"
echo " YouTube: https://www.youtube.com/@antenkaru"
echo -e "******************************************************${NC}"
echo -e "${WHITE}IP сервера: ${GREEN}${MY_IP}${NC} ${WHITE}WARP: ${status_color}${status_text}${NC}"
if is_warp_running; then
echo -e "${WHITE}SOCKS5: ${CYAN}127.0.0.1:${SOCKS_PORT}${NC}"
fi
echo -e "------------------------------------------------------"
echo -e " 1) ${GREEN}Установить WARP${NC}"
echo -e " 2) ${CYAN}Запустить WARP${NC}"
echo -e " 3) ${YELLOW}Остановить WARP${NC}"
echo -e " 4) 📊 ${WHITE}Статус и конфигурация${NC}"
echo -e " 5) 📋 ${CYAN}JSON для 3X-UI${NC}"
echo -e " 6) 🔑 ${YELLOW}Перевыпуск ключа${NC}"
echo -e " 7) 🔧 ${WHITE}Изменить порт SOCKS5${NC}"
echo -e " 8) 🤖 ${CYAN}Telegram Bot${NC}"
echo -e " 9) ${YELLOW}PROMO${NC}"
echo -e "10) ${MAGENTA}📚 Инструкция${NC}"
echo -e "11) ${RED}⚠ Полное удаление${NC}"
echo -e " 0) Выход"
echo -e "------------------------------------------------------"
read -p "Выбор: " ch
case $ch in
1) install_warp ;;
2) start_warp ;;
3) stop_warp ;;
4) show_status ;;
5) show_xui_json ;;
6) rekey_warp ;;
7) change_port ;;
8) bot_menu ;;
9) show_promo ;;
10) show_info ;;
11) full_uninstall ;;
0) exit 0 ;;
esac
done
}
# ═══════════════════════════════════════════════════════════════
# STARTUP WITH PROGRESS
# ═══════════════════════════════════════════════════════════════
run_startup() {
local total=6 s=0
clear; echo ""
echo -e "${MAGENTA}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${MAGENTA}║ WARP Manager v${WARP_VERSION} — Загрузка ║${NC}"
echo -e "${MAGENTA}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Проверка прав root..." "$s" "$total"
check_root
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} Права root подтверждены \n" "$s" "$total"
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Проверка лицензии..." "$s" "$total"
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} Лицензия активна \n" "$s" "$total"
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Проверка зависимостей..." "$s" "$total"
check_deps
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} Зависимости на месте \n" "$s" "$total"
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Установка gowarp..." "$s" "$total"
if [ "$(readlink -f "$0" 2>/dev/null)" != "/usr/local/bin/gowarp" ]; then
cp -f "$0" "/usr/local/bin/gowarp"; chmod +x "/usr/local/bin/gowarp"
fi
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} Команда gowarp \n" "$s" "$total"
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Определение IP..." "$s" "$total"
get_my_ip
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} IP: %-25s \n" "$s" "$total" "$MY_IP"
((s++))
printf " ${CYAN}[%d/%d]${NC} ${YELLOW}${NC} Проверка WARP..." "$s" "$total"
local ws
ws=$(get_warp_status_text)
printf "\r ${CYAN}[%d/%d]${NC} ${GREEN}${NC} WARP: %-25s \n" "$s" "$total" "$ws"
echo ""
local w=40 bar=""
for ((i=0; i<w; i++)); do bar+=""; done
echo -e " ${CYAN}[${GREEN}${bar}${CYAN}]${NC} ${GREEN}100%${NC}"
echo ""
echo -e " ${GREEN}✅ WARP Manager v${WARP_VERSION} готов к работе!${NC}"
echo ""
sleep 2
show_promo
show_info
show_menu
}
# ═══════════════════════════════════════════════════════════════
# ENTRY POINT
# ═══════════════════════════════════════════════════════════════
case "${1:-}" in
--bot-daemon) init_config; bot_daemon ;;
*) init_config; check_license "${1:-}"; run_startup ;;
esac