- AMNEZIA_SERVER — только IP/домены серверов Amnezia (для поднятия VPN) - KILL_SWITCH_EXCEPTIONS — дополнительные исключения (git, etc.) - Обе переменные поддерживают IP и домены (DNS-резолвинг) - setup.sh: раздельные промпты в меню Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
233 lines
11 KiB
Bash
Executable File
233 lines
11 KiB
Bash
Executable File
#!/bin/bash
|
||
# Мастер-скрипт. Запускай от обычного пользователя (sudo попросит сам где нужно).
|
||
cd "$(dirname "$0")"
|
||
|
||
BLD='\033[1m'
|
||
GRN='\033[0;32m'
|
||
YEL='\033[0;33m'
|
||
GRY='\033[0;37m'
|
||
CLR='\033[0m'
|
||
|
||
mkdir -p "$HOME/.config/ai-setup"
|
||
LOG="$HOME/.config/ai-setup/setup.log"
|
||
_log() { printf '%s [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" "$2" >> "$LOG"; }
|
||
|
||
if command -v whiptail >/dev/null 2>&1; then
|
||
choice=$(whiptail --title "AI Setup" \
|
||
--menu "Выбери действие (стрелки + Enter):" 22 70 9 \
|
||
"1" "AI-инструменты (установить лаунчеры + ключи)" \
|
||
"2" "Сеть: ru-bypass + kill switch" \
|
||
"" "─── Дополнительно ───────────────────────────" \
|
||
"3" "Отключить kill switch (прямой доступ без VPN)" \
|
||
"4" "Включить kill switch (восстановить защиту)" \
|
||
"5" "Статус (Amnezia, UFW, AI инструменты, ключи)" \
|
||
"6" "Проверить сеть (маршрутизация, geo)" \
|
||
"7" "Обновить (git pull + перегенерация скриптов)" \
|
||
3>&1 1>&2 2>&3) || exit 0
|
||
echo ""
|
||
else
|
||
echo ""
|
||
echo -e "${BLD}=== AI Setup ===${CLR}"
|
||
echo ""
|
||
echo -e "${YEL}Шаги для новой машины (выполнить по порядку):${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}1) AI-инструменты${CLR}"
|
||
echo -e " ${GRY}Устанавливает ai-claude, ai-gpt, ai-deepseek, ai-gemini и др.${CLR}"
|
||
echo -e " ${GRY}Запрашивает API-ключи. Запускать один раз.${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}2) Сеть: ru-bypass + kill switch${CLR}"
|
||
echo -e " ${GRY}.ru сайты (ozon, госуслуги) — напрямую с российским IP.${CLR}"
|
||
echo -e " ${GRY}*.loc офисные адреса — тоже напрямую.${CLR}"
|
||
echo -e " ${GRY}Всё остальное — только через Amnezia (kill switch).${CLR}"
|
||
echo -e " ${GRY}Запускать один раз на каждой машине.${CLR}"
|
||
echo ""
|
||
echo -e "${YEL}Дополнительно (по необходимости):${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}3) Отключить kill switch${CLR}"
|
||
echo -e " ${GRY}Временно — когда нужен прямой доступ без VPN (российский IP).${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}4) Включить kill switch${CLR}"
|
||
echo -e " ${GRY}Вернуть защиту обратно после отключения.${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}5) Статус${CLR}"
|
||
echo -e " ${GRY}Amnezia, UFW, сервисы, установленные AI инструменты и ключи.${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}6) Проверить сеть${CLR}"
|
||
echo -e " ${GRY}Тесты маршрутизации: .ru напрямую, остальное через Amnezia.${CLR}"
|
||
echo ""
|
||
echo -e " ${BLD}7) Обновить${CLR}"
|
||
echo -e " ${GRY}git pull + перегенерация всех скриптов в ~/.local/bin.${CLR}"
|
||
echo ""
|
||
echo -n "Выбери [1-7] или Enter для выхода: "
|
||
read -r choice
|
||
echo ""
|
||
fi
|
||
|
||
[ -n "$choice" ] && _log "setup" "Пункт $choice на $(hostname)"
|
||
|
||
case "$choice" in
|
||
1)
|
||
bash scripts/ai-setup.sh
|
||
;;
|
||
2)
|
||
echo -e "${GRY}Нужно указать параметры твоей локальной сети:${CLR}"
|
||
echo -e "${GRY} GATEWAY — IP домашнего/офисного роутера (через него пойдёт .ru трафик напрямую)${CLR}"
|
||
echo -e "${GRY} DEV — сетевой интерфейс (wifi или провод), через который ты подключён к роутеру${CLR}"
|
||
echo -e "${GRY} LOCAL_DNS — IP офисного DNS-сервера для разрешения *.loc доменов (необязательно)${CLR}"
|
||
echo ""
|
||
mkdir -p "$HOME/.config/ai-setup"
|
||
cfg_dir="$HOME/.config/ai-setup"
|
||
# Показываем существующие профили
|
||
existing=$(ls "$cfg_dir"/network_*.conf 2>/dev/null | sed 's|.*/network_||;s|\.conf||' | tr '\n' ' ')
|
||
if [ -n "$existing" ]; then
|
||
echo -e "Существующие профили: ${BLD}${existing}${CLR}"
|
||
echo -e "${GRY}Введи имя профиля (home/office/$(hostname) и т.д.) или Enter для текущего${CLR}"
|
||
read -rp "Профиль [$(hostname)]: " chosen_profile
|
||
chosen_profile="${chosen_profile:-$(hostname)}"
|
||
else
|
||
chosen_profile="$(hostname)"
|
||
fi
|
||
net_conf="$cfg_dir/network_${chosen_profile}.conf"
|
||
auto_gw=$(ip route show default 2>/dev/null | awk '/default/ {print $3; exit}')
|
||
auto_dev=$(ip route show default 2>/dev/null | awk '/default/ {print $5; exit}')
|
||
auto_gw="${auto_gw:-192.168.1.1}"
|
||
auto_dev="${auto_dev:-wlp1s0}"
|
||
saved_local_dns=""
|
||
saved_amn_srv=""
|
||
saved_ks_exc=""
|
||
if [ -f "$net_conf" ]; then
|
||
saved_gw=$(grep '^GATEWAY=' "$net_conf" | cut -d= -f2)
|
||
saved_dev=$(grep '^DEV=' "$net_conf" | cut -d= -f2)
|
||
saved_local_dns=$(grep '^LOCAL_DNS=' "$net_conf" | cut -d= -f2)
|
||
saved_amn_srv=$(grep '^AMNEZIA_SERVER=' "$net_conf" | cut -d= -f2)
|
||
saved_ks_exc=$(grep '^KS_EXCEPTIONS=' "$net_conf" | cut -d= -f2)
|
||
auto_gw="${saved_gw:-$auto_gw}"
|
||
auto_dev="${saved_dev:-$auto_dev}"
|
||
echo -e "Загружены параметры профиля ${BLD}${chosen_profile}${CLR}: GATEWAY=${BLD}${auto_gw}${CLR} DEV=${BLD}${auto_dev}${CLR}"
|
||
else
|
||
echo -e "Новый профиль ${BLD}${chosen_profile}${CLR}. Определено автоматически: GATEWAY=${BLD}${auto_gw}${CLR} DEV=${BLD}${auto_dev}${CLR}"
|
||
fi
|
||
echo -e "${GRY}(просто Enter чтобы принять, или введи другое значение)${CLR}"
|
||
echo ""
|
||
read -rp "GATEWAY (IP роутера) [${auto_gw}]: " gw
|
||
read -rp "DEV (интерфейс) [${auto_dev}]: " dev
|
||
read -rp "LOCAL_DNS (DNS для *.loc) [${saved_local_dns:-пусто}]: " local_dns
|
||
read -rp "AMNEZIA_SERVER (IP/домен сервера Amnezia) [${saved_amn_srv:-пусто}]: " amn_srv
|
||
read -rp "KS_EXCEPTIONS (исключения kill switch: IP/домены через пробел) [${saved_ks_exc:-пусто}]: " ks_exc
|
||
gw="${gw:-$auto_gw}"
|
||
dev="${dev:-$auto_dev}"
|
||
[ "$local_dns" = "пусто" ] && local_dns=""
|
||
local_dns="${local_dns:-$saved_local_dns}"
|
||
[ "$amn_srv" = "пусто" ] && amn_srv=""
|
||
amn_srv="${amn_srv:-$saved_amn_srv}"
|
||
[ "$ks_exc" = "пусто" ] && ks_exc=""
|
||
ks_exc="${ks_exc:-$saved_ks_exc}"
|
||
printf 'GATEWAY=%s\nDEV=%s\nLOCAL_DNS=%s\nAMNEZIA_SERVER=%s\nKILL_SWITCH_EXCEPTIONS=%s\n' "$gw" "$dev" "$local_dns" "$amn_srv" "$ks_exc" > "$net_conf"
|
||
echo ""
|
||
sudo GATEWAY="$gw" DEV="$dev" LOCAL_DNS="$local_dns" AMNEZIA_SERVER="$amn_srv" KILL_SWITCH_EXCEPTIONS="$ks_exc" USER_HOME="$HOME" bash scripts/ru-bypass.sh
|
||
;;
|
||
3)
|
||
echo -e "${YEL}Перед этим выйди из Claude Code — сессия сменит IP.${CLR}"
|
||
echo -n "Продолжить? [y/N] "
|
||
read -r confirm
|
||
[ "$confirm" = "y" ] || [ "$confirm" = "Y" ] || exit 0
|
||
sudo USER_HOME="$HOME" bash scripts/ks-off.sh
|
||
;;
|
||
4)
|
||
sudo USER_HOME="$HOME" bash scripts/ks-on.sh
|
||
;;
|
||
5)
|
||
echo -e "${BLD}=== Статус ===${CLR}"
|
||
echo ""
|
||
|
||
echo -e "${BLD}Сеть:${CLR}"
|
||
if ip link show amn0 &>/dev/null; then
|
||
echo -e " ${GRN}✓${CLR} Amnezia (amn0) подключена"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} Amnezia (amn0) не найдена"
|
||
fi
|
||
if sudo ufw status 2>/dev/null | grep -qE "активен|active"; then
|
||
echo -e " ${GRN}✓${CLR} UFW kill switch активен"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} UFW выключен"
|
||
fi
|
||
if systemctl is-active --quiet ru-bypass.service 2>/dev/null || systemctl is-enabled --quiet ru-bypass.service 2>/dev/null; then
|
||
echo -e " ${GRN}✓${CLR} ru-bypass.service установлен"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} ru-bypass.service не установлен (запусти пункт 2)"
|
||
fi
|
||
if systemctl is-enabled --quiet ru-ipset-restore.service 2>/dev/null; then
|
||
echo -e " ${GRN}✓${CLR} ru-ipset-restore.service установлен"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} ru-ipset-restore.service не установлен (запусти пункт 2)"
|
||
fi
|
||
ipv6_cnt=$(ip -6 addr show scope global 2>/dev/null | grep -c 'inet6' || true)
|
||
if [ "$ipv6_cnt" -eq 0 ]; then
|
||
echo -e " ${GRN}✓${CLR} IPv6 отключён (нет утечки)"
|
||
else
|
||
echo -e " ${YEL}!${CLR} IPv6 активен ($ipv6_cnt адресов) — возможна утечка, запусти пункт 4"
|
||
fi
|
||
|
||
echo ""
|
||
echo -e "${BLD}AI инструменты:${CLR}"
|
||
for cmd in ai-claude ai-gpt ai-deepseek ai-kimi ai-openrouter ai-gemini; do
|
||
if command -v "$cmd" &>/dev/null; then
|
||
echo -e " ${GRN}✓${CLR} $cmd"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} $cmd"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
echo -e "${BLD}API ключи:${CLR}"
|
||
cfg="$HOME/.config/ai-setup"
|
||
for f in deepseek_key kimi_key openrouter_key; do
|
||
name="${f/_key/}"
|
||
if [ -s "$cfg/$f" ]; then
|
||
echo -e " ${GRN}✓${CLR} $name"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} $name (не задан)"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
echo -e "${BLD}API доступность:${CLR}"
|
||
for entry in "Anthropic:api.anthropic.com" "DeepSeek:api.deepseek.com" "OpenAI:api.openai.com" "Kimi:api.kimi.com" "OpenRouter:openrouter.ai"; do
|
||
_name="${entry%%:*}"
|
||
_host="${entry##*:}"
|
||
_ms=$(curl -s -o /dev/null -w "%{time_connect}" --max-time 5 "https://$_host" 2>/dev/null)
|
||
if [ -n "$_ms" ] && [ "$_ms" != "0.000000" ]; then
|
||
echo -e " ${GRN}✓${CLR} $_name: ${_ms}s"
|
||
else
|
||
echo -e " ${YEL}✗${CLR} $_name: недоступен"
|
||
fi
|
||
done
|
||
|
||
echo ""
|
||
echo -e "${BLD}Последние события:${CLR}"
|
||
if [ -f "$LOG" ]; then
|
||
tail -10 "$LOG" | sed 's/^/ /'
|
||
else
|
||
echo " (лог пуст)"
|
||
fi
|
||
;;
|
||
6)
|
||
bash tests/test_network.sh
|
||
;;
|
||
7)
|
||
REPO_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
echo -e "${BLD}Обновляем репозиторий...${CLR}"
|
||
git -C "$REPO_DIR" pull --ff-only
|
||
echo ""
|
||
echo -e "${BLD}Перегенерация скриптов...${CLR}"
|
||
bash "$REPO_DIR/scripts/ai-setup.sh"
|
||
;;
|
||
"")
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "Неверный выбор."
|
||
exit 1
|
||
;;
|
||
esac
|