Compare commits
8
Commits
v1.2.1.2
...
edabfd9a83
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edabfd9a83 | ||
|
|
741a70c9bf | ||
|
|
0d2af45bdb | ||
|
|
a02650311e | ||
|
|
2b57e6f6d7 | ||
|
|
df8a99bb78 | ||
|
|
47328b33b3 | ||
|
|
776b7a8c5e |
@@ -1,3 +1,53 @@
|
|||||||
|
## v1.2.1.6: доступы к панели в конце установки и рабочая заглушка
|
||||||
|
|
||||||
|
* **Исправлено: доступы к панели не выводились.** Автор пишет строки в `/root/3x-ui.txt` без ведущих
|
||||||
|
пробелов, а наш фильтр требовал два пробела — отсюда «данных панели нет». Теперь адрес панели, логин и
|
||||||
|
пароль печатаются в конце установки (и в пункте меню «9. Доступ к панели, ссылки и заглушка»).
|
||||||
|
Рядом указывается, что подписка и ссылки по протоколам лежат в том же файле.
|
||||||
|
* **Исправлено: наша заглушка не готовилась до установщика.** Обёртка скачивала из релиза только три файла,
|
||||||
|
а `scripts/kit-local.sh` (там функция страницы) не качала — падало с «kl_site_html: command not found».
|
||||||
|
Теперь качаются все файлы релиза, и каждый сверяется с подписанным списком (проверка целостности стала
|
||||||
|
полной, а не только для установщика).
|
||||||
|
|
||||||
|
## v1.2.1.5: доступ к панели, ссылки и заглушка — одним пунктом меню
|
||||||
|
|
||||||
|
* **В меню kit пункт «9. Доступ к панели, ссылки и заглушка»** — открывает одним экраном: адрес панели,
|
||||||
|
логин и пароль (из /root/3x-ui.txt), состояние сертификата панели (доверенный на IP или
|
||||||
|
самоподписанный, с датой повтора при лимите Let's Encrypt), ссылки на подключения с QR-кодом и что
|
||||||
|
сейчас стоит заглушкой. Раньше доступ к панели в меню не показывался вообще, а про заглушку было
|
||||||
|
непонятно, как её посмотреть.
|
||||||
|
* Меню перенумеровано: «10. Панель x-ui», «11. Удалить KIT с сервера» (логика удаления — авторская).
|
||||||
|
* То же самое доступно из консоли: `kit local access [имя]`.
|
||||||
|
|
||||||
|
## v1.2.1.4: короткий итог установки, автовыбор в общедоступных сайтах, команда про порты
|
||||||
|
|
||||||
|
* **Итог установки вместо простыни текста** — компактный блок: сборка, сервер, протоколы, состояние
|
||||||
|
сертификата панели, одна строка проверки. Дальше только то, что нужно человеку: доступ к панели (адрес,
|
||||||
|
логин, пароль — по просьбе из ранних правок), указатель на меню kit для ссылок и QR, открытые порты и
|
||||||
|
команда для закрытия лишних. Длинные отчёты (состояние защиты, полный вывод kit check) убраны из
|
||||||
|
установки — они остались доступны командами, в том числе `kit local hardening`.
|
||||||
|
* **Ссылки на подключения больше не попадают в вывод установки даже косвенно**: раньше печатался весь
|
||||||
|
файл /root/3x-ui.txt, а в нём лежат и ссылки vless://. Теперь из него берутся только строки панели —
|
||||||
|
адрес, логин, пароль.
|
||||||
|
* **В меню общедоступных сайтов последним пунктом добавлен автовыбор** (раньше можно было только выбрать
|
||||||
|
номером или вернуться).
|
||||||
|
* **Новая команда `kit local ports`** — что открыто в ufw, что реально нужно (порты подключений и SSH),
|
||||||
|
что лишнее; `kit local ports --close-extra` закрывает лишнее.
|
||||||
|
* Ошибка подготовки нашей заглушки теперь печатает причину, а не просто «не смог».
|
||||||
|
|
||||||
|
## v1.2.1.3: ссылки и QR — в меню kit; сертификат панели видно в итоге
|
||||||
|
|
||||||
|
* **Ссылки для подключения и QR-код больше не печатаются в выводе установки.** Их смотрят позже, когда
|
||||||
|
настраивают телефон, и они всегда доступны заново: `kit → Пользователи → Показать ссылки`. В итоговом
|
||||||
|
блоке вместо них — короткий путь к этому пункту и команды `kit local links` (подписка и QR) и
|
||||||
|
`kit user link <имя> --all` (все протоколы). Доступы к панели (адрес, логин, пароль) по-прежнему
|
||||||
|
в конце установки: их вы просили показывать один раз и сразу.
|
||||||
|
* **Добавлена команда `kit local links`** — подписка, QR-код и ссылки по протоколам одной командой;
|
||||||
|
пользователя можно указать, иначе берётся первый.
|
||||||
|
* **В итоговом блоке видно состояние сертификата панели.** Панель и подписка висят на IP, поэтому
|
||||||
|
печатается: «Let's Encrypt на IP — доверенный, браузер не ругается» либо «самоподписанный» с датой,
|
||||||
|
после которой Let's Encrypt выпустит сертификат на IP (тот же лимит, что и для домена).
|
||||||
|
|
||||||
## v1.2.1.2: сертификат на IP — с датой повтора; «без домена» продолжает установку
|
## v1.2.1.2: сертификат на IP — с датой повтора; «без домена» продолжает установку
|
||||||
|
|
||||||
* **Отказ Let's Encrypt на IP теперь объясняется честно.** Как и для домена, при лимите в выводе дата,
|
* **Отказ Let's Encrypt на IP теперь объясняется честно.** Как и для домена, при лимите в выводе дата,
|
||||||
|
|||||||
+8
-8
@@ -1,9 +1,9 @@
|
|||||||
# 3X-UI KIT 1.2.1.2
|
# 3X-UI KIT 1.2.1.6
|
||||||
# 3X-UI_autoVPS 1.2.1.2
|
# 3X-UI_autoVPS 1.2.1.6
|
||||||
38f3ed0ed83ce13db2a8c432f972367d0203766d2d74a1d1873faf66149a5b61 scripts/3x-ui.sh
|
f30fc23d1c667d6fc90742fdf12377ca84d9e119fc394d86822bf1daaf462795 scripts/3x-ui.sh
|
||||||
818da230052d20d0d2a8b2917ad171064d1779aeb73d9547856a271ad838d88e scripts/hysteria2.sh
|
4ef4c3f830196704648c15dd546e20195ce15e2d4ee6ca66e363aac47811c4ab scripts/hysteria2.sh
|
||||||
e27a6fa4006aa9da1a2cb07c6fc738a8e8b2a6034796072b72783dd762283b69 scripts/kit.sh
|
b85e6ca11eef15eed8d45fba9e7b4a7eddf6141de4aeceaac1fe7f51d4c9fa78 scripts/kit.sh
|
||||||
f214671464e1c2e174e5af9df42c95567a9b4a9141f31a39f7df2e971e89d240 scripts/kit-sub.py
|
f214671464e1c2e174e5af9df42c95567a9b4a9141f31a39f7df2e971e89d240 scripts/kit-sub.py
|
||||||
79e53e4c4ffcfdbcf1209196901ac48c4c76c32ae677ef5800d3658f51ca1a55 scripts/kit-local.sh
|
75cc7bc4e048c43989f66ca3b9e9addff8d7a434e651daba6db894e18109b45b scripts/kit-local.sh
|
||||||
c3c78f83b45a2d91770dc176868d39615af8810c24788ecc2182f01a6f42d17b scripts/3x-ui-local.sh
|
ba87dfba9abc3417092a2c2ec8da1b0332397e9952ead213e9367692f2849459 scripts/3x-ui-local.sh
|
||||||
e883e04df32625e016ce82cceb298382bbf2516732904ae678adb404e35f9f02 VERSION
|
3acd832d329f916790a07153fcc6b7cbdbeb6958131e60751094c059e4fb0f76 VERSION
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
-----BEGIN SSH SIGNATURE-----
|
-----BEGIN SSH SIGNATURE-----
|
||||||
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV
|
U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgozRJ+f9RB6qO9S9j3BWCDtC0bV
|
||||||
FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA
|
FHakRSSqtQPljLoQUAAAARM3gtdWkta2l0LXJlbGVhc2UAAAAAAAAABnNoYTUxMgAAAFMA
|
||||||
AAALc3NoLWVkMjU1MTkAAABAU4cGdoBrnz4R6adcDRQFepIa/JUVRlPmMeGMdRBd+5nZ+S
|
AAALc3NoLWVkMjU1MTkAAABADBMIIRfAe53BhNokGqyMTekQwEmlBZ8HdhkKUXjRPv0ofv
|
||||||
qy/zrjukL+j4OXyy5pGEMGdYwNbIZAPnCe7C89Dg==
|
u4/0GW5p5d2QnwShb7+zS/Dr+LekQ2SMQEBvVbAA==
|
||||||
-----END SSH SIGNATURE-----
|
-----END SSH SIGNATURE-----
|
||||||
|
|||||||
+76
-73
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
KIT_VERSION="1.2.1.2" # версия сборки форка; должна совпадать с VERSION релиза
|
KIT_VERSION="1.2.1.6" # версия сборки форка; должна совпадать с VERSION релиза
|
||||||
GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}"
|
GITEA="${KIT_FORK_BASE:-https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS}"
|
||||||
NS="3x-ui-kit-release"
|
NS="3x-ui-kit-release"
|
||||||
SIG_ID="releases@3x-ui-kit"
|
SIG_ID="releases@3x-ui-kit"
|
||||||
@@ -179,7 +179,7 @@ say "беру релиз v$KIT_VERSION и проверяю подпись"
|
|||||||
tmp=$(mktemp -d)
|
tmp=$(mktemp -d)
|
||||||
trap 'rm -rf "$tmp"' EXIT
|
trap 'rm -rf "$tmp"' EXIT
|
||||||
raw="$GITEA/raw/tag/v$KIT_VERSION"
|
raw="$GITEA/raw/tag/v$KIT_VERSION"
|
||||||
for f in SHA256SUMS SHA256SUMS.sig scripts/3x-ui.sh; do
|
for f in SHA256SUMS SHA256SUMS.sig; do
|
||||||
mkdir -p "$tmp/$(dirname "$f")"
|
mkdir -p "$tmp/$(dirname "$f")"
|
||||||
curl -fsSL --retry 3 -m 60 -o "$tmp/$f" "$raw/$f" || die "не скачался $f из $raw (Gitea доступна с сервера?)"
|
curl -fsSL --retry 3 -m 60 -o "$tmp/$f" "$raw/$f" || die "не скачался $f из $raw (Gitea доступна с сервера?)"
|
||||||
done
|
done
|
||||||
@@ -190,7 +190,19 @@ sum=$(awk '{f = $2; sub(/^\*/, "", f)} f == "scripts/3x-ui.sh" {print $1}' "$tmp
|
|||||||
[[ $(printf '%s' "$sum" | wc -c) -eq 64 ]] || die "в SHA256SUMS нет установщика — релиз собран неверно"
|
[[ $(printf '%s' "$sum" | wc -c) -eq 64 ]] || die "в SHA256SUMS нет установщика — релиз собран неверно"
|
||||||
got=$(sha256sum "$tmp/scripts/3x-ui.sh" | awk '{print $1}')
|
got=$(sha256sum "$tmp/scripts/3x-ui.sh" | awk '{print $1}')
|
||||||
[[ $got == "$sum" ]] || die "SHA256 установщика не совпал с подписанным — не запускаю"
|
[[ $got == "$sum" ]] || die "SHA256 установщика не совпал с подписанным — не запускаю"
|
||||||
|
# Качаем все остальные файлы релиза и сверяем каждый с подписанным списком. Раньше брали только
|
||||||
|
# установщик, поэтому kit-local.sh (в нём наша страница-заглушка) отсутствовал, и подготовка
|
||||||
|
# заглушки до установщика падала с «kl_site_html: command not found».
|
||||||
|
while read -r sum2 name2; do
|
||||||
|
case $sum2 in \#* | "") continue ;; esac
|
||||||
|
[[ $name2 == scripts/3x-ui.sh ]] && continue
|
||||||
|
mkdir -p "$tmp/$(dirname "$name2")"
|
||||||
|
curl -fsSL --retry 3 -m 60 -o "$tmp/$name2" "$raw/$name2" || die "не скачался $name2 из $raw (Gitea доступна с сервера?)"
|
||||||
|
got2=$(sha256sum "$tmp/$name2" | awk '{print $1}')
|
||||||
|
[[ $got2 == "$sum2" ]] || die "SHA256 не совпал у $name2 — не запускаю"
|
||||||
|
done <"$tmp/SHA256SUMS"
|
||||||
bash -n "$tmp/scripts/3x-ui.sh" || die "установщик не проходит проверку синтаксиса"
|
bash -n "$tmp/scripts/3x-ui.sh" || die "установщик не проходит проверку синтаксиса"
|
||||||
|
[[ -r $tmp/scripts/kit-local.sh ]] || die "в релизе нет scripts/kit-local.sh — сборка неполная"
|
||||||
printf ' ✓ подпись сошлась, SHA256 установщика совпал\n'
|
printf ' ✓ подпись сошлась, SHA256 установщика совпал\n'
|
||||||
|
|
||||||
if [[ $verify_only == yes ]]; then
|
if [[ $verify_only == yes ]]; then
|
||||||
@@ -457,13 +469,13 @@ if [[ $site != off ]]; then
|
|||||||
esac
|
esac
|
||||||
if [[ -n $stub_n ]]; then
|
if [[ -n $stub_n ]]; then
|
||||||
install -d -m 755 /var/www/kit
|
install -d -m 755 /var/www/kit
|
||||||
if ( source "$tmp/scripts/kit-local.sh" 2>/dev/null; kl_site_html "$stub_n" ) >/var/www/kit/index.html 2>/dev/null \
|
if ( source "$tmp/scripts/kit-local.sh" 2>/dev/null; kl_site_html "$stub_n" ) >/var/www/kit/index.html 2>"$tmp/stub.err" \
|
||||||
&& [[ -s /var/www/kit/index.html ]]; then
|
&& [[ -s /var/www/kit/index.html ]]; then
|
||||||
stub_staged=yes
|
stub_staged=yes
|
||||||
rm -f "$tmp/var/www/kit/index.html"
|
rm -f "$tmp/var/www/kit/index.html"
|
||||||
say "заглушка: наш сайт №$((stub_n + 1)) — ставится сразу, авторская страница не используется"
|
say "заглушка: наш сайт №$((stub_n + 1)) — ставится сразу, авторская страница не используется"
|
||||||
else
|
else
|
||||||
warn "не смог подготовить нашу заглушку — поставлю после установки (kit local site)"
|
warn "не смог подготовить нашу заглушку — поставлю после установки (kit local site). Причина: $(head -c 200 "$tmp/stub.err" 2>/dev/null | tr '\n' ' ')"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -525,77 +537,68 @@ if [[ -n $ssh_port ]]; then
|
|||||||
kit local ssh "$ssh_port" || warn "порт не добавился — сделайте отдельно: kit local ssh $ssh_port"
|
kit local ssh "$ssh_port" || warn "порт не добавился — сделайте отдельно: kit local ssh $ssh_port"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------ проверка
|
# ------------------------------------------------------------------ итог: коротко и по делу
|
||||||
|
|
||||||
if [[ $do_check == yes ]]; then
|
if [[ $do_check == yes || $show_sub == yes ]]; then
|
||||||
say "проверяю, что получилось"
|
# kit check печатает много строк: человеку нужны только замечания и одна строка «всё ли в порядке».
|
||||||
kit check || warn "kit check нашёл замечания — читайте выше; безопасные починки: kit fix"
|
chk=$(kit check 2>&1 || true)
|
||||||
kit local hardening
|
problems=$(printf '%s\n' "$chk" | grep -cE '^❌|^⚠|^!' || true)
|
||||||
fi
|
[[ $problems == 0 ]] || printf '%s\n' "$chk" | grep -E '^❌|^⚠|^!' | sed 's/^/ /'
|
||||||
|
ports_open=""
|
||||||
cat <<EOF
|
command -v ufw >/dev/null 2>&1 && ports_open=$(ufw status 2>/dev/null | awk '$2 == "ALLOW" { printf "%s ", $1 }')
|
||||||
|
ip_show=$(hostname -I 2>/dev/null | awk '{ print $1 }')
|
||||||
${G}${B}Готово.${N} Сервер поставлен из нашей сборки (3X-UI_autoVPS $KIT_VERSION, канал: наш Gitea).
|
os_show=$( . /etc/os-release 2>/dev/null && printf '%s' "${PRETTY_NAME:-}" )
|
||||||
|
cert_show="без сертификата: панель открывается через SSH-туннель"
|
||||||
подписка и ссылки: kit user link admin (или страница подписки из вывода установщика)
|
if [[ -s /root/cert/ip/fullchain.pem ]]; then
|
||||||
если что-то не так: kit check --deep, затем kit fix
|
if openssl x509 -in /root/cert/ip/fullchain.pem -noout -issuer 2>/dev/null | grep -q "Let's Encrypt"; then
|
||||||
вернуться к авторскому каналу: положить авторский kit поверх и выполнить kit update --force
|
cert_show="${G}Let's Encrypt на IP — доверенный, браузер не ругается${N}"
|
||||||
EOF
|
else
|
||||||
|
cert_show="${Y}самоподписанный — браузер предупредит${N}"
|
||||||
# ------------------------------------------------------------------ SSH: как закрыть прежние порты
|
fi
|
||||||
|
fi
|
||||||
if [[ -n ${ssh_port:-} ]]; then
|
protos_show=$(tr '\n' ' ' </etc/kit/kl-protos 2>/dev/null || true)
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
${Y}${B}SSH переведён на порт $ssh_port.${N} Прежние порты (${ssh_ports_before:-22}) пока работают — это
|
${B}────────────── Установка завершена ──────────────${N}
|
||||||
сделано специально, чтобы вы не потеряли доступ. Порядок обязательный:
|
сборка: 3X-UI_autoVPS $KIT_VERSION (канал: наш Gitea)
|
||||||
1) во ВТОРОМ окне проверьте вход: ssh -p $ssh_port root@${HOST:-<IP сервера>}
|
сервер: ${ip_show:-?}${os_show:+ · $os_show}
|
||||||
2) вход работает — закройте прежние порты: ${B}kit local ssh --close-old $ssh_port${N}
|
протоколы: ${protos_show:-—}
|
||||||
3) поправьте порт у себя: ~/.ssh/config, терминалы, мониторинг
|
сертификат: $cert_show
|
||||||
|
проверка: $([[ $problems == 0 ]] && echo 'замечаний нет' || echo "замечаний: $problems (подробности: kit check)")
|
||||||
|
${B}───────────────────────────────────────────────────${N}
|
||||||
|
|
||||||
|
${B}Доступ к панели${N} (файл /root/3x-ui.txt, виден только root)
|
||||||
|
EOF
|
||||||
|
# Автор пишет эти строки без ведущих пробелов (RESULT=/root/3x-ui.txt), поэтому ищем их как есть.
|
||||||
|
if grep -aqE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then
|
||||||
|
grep -aE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^[[:space:]]*/ /'
|
||||||
|
printf ' файл целиком (там же подписка и ссылки по протоколам): /root/3x-ui.txt\n'
|
||||||
|
else
|
||||||
|
warn "данных панели в /root/3x-ui.txt нет — смотрите вывод установщика выше"
|
||||||
|
fi
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
${B}Ссылки для подключения и QR-код${N} — в меню kit
|
||||||
|
kit → Пользователи → Показать ссылки из консоли: kit local links
|
||||||
|
EOF
|
||||||
|
if [[ -n $ports_open ]]; then
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
${B}Порты${N}
|
||||||
|
открыто: $ports_open
|
||||||
|
что нужно и что лишнее: kit local ports закрыть лишние: kit local ports --close-extra
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
if [[ -n ${ssh_port:-} ]]; then
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
${Y}SSH переведён на порт $ssh_port.${N} Прежние (${ssh_ports_before:-22}) пока открыты намеренно:
|
||||||
|
1) проверьте вход во втором окне: ssh -p $ssh_port root@${ip_show:-<IP>}
|
||||||
|
2) закройте прежние порты: kit local ssh --close-old $ssh_port
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
cat <<EOF
|
||||||
|
|
||||||
|
если что-то не так: kit check --deep, затем kit fix
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------ доступ к панели (перед подпиской)
|
|
||||||
|
|
||||||
if [[ $show_sub == yes ]]; then
|
|
||||||
say "панель 3X-UI: адрес, логин и пароль"
|
|
||||||
if [[ -s /root/3x-ui.txt ]]; then
|
|
||||||
printf ' файл: /root/3x-ui.txt (виден только root). Сохраните данные себе:\n'
|
|
||||||
sed 's/^/ /' /root/3x-ui.txt
|
|
||||||
else
|
|
||||||
warn "файла /root/3x-ui.txt нет — адрес панели и логин были в выводе установщика выше"
|
|
||||||
fi
|
|
||||||
if grep -qaE '^Панель: ?https?://[0-9]' /root/3x-ui.txt 2>/dev/null; then
|
|
||||||
printf ' %sпанель открывается по IP: сертификат самоподписанный, браузер предупредит.\n' "$D"
|
|
||||||
printf ' Завести свой домен и перейти на него: kit net panel domain%s\n' "$N"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ подписка, QR-код и доступы
|
|
||||||
|
|
||||||
# Показываем в самом конце, после всех проверок: это то, что человек уносит с собой.
|
|
||||||
# Печатает авторская команда (подписка + QR-код через qrencode + ссылки по протоколам),
|
|
||||||
# поэтому вывод не расходится с тем, что показывает `kit` потом.
|
|
||||||
if [[ $show_sub == yes ]]; then
|
|
||||||
sub_user=admin
|
|
||||||
for ((_i = 0; _i < ${#INSTALLER_ARGS[@]}; _i++)); do
|
|
||||||
[[ ${INSTALLER_ARGS[_i]} == --user ]] && sub_user=${INSTALLER_ARGS[_i + 1]:-admin}
|
|
||||||
done
|
|
||||||
say "подписка и доступы — это то, что стоит сохранить"
|
|
||||||
printf ' подписка — одна ссылка на все устройства; QR-код ниже наводите камерой в приложении\n'
|
|
||||||
printf ' приложения: Happ, Hiddify, Karing, v2rayN, Clash/Mihomo\n'
|
|
||||||
printf ' отдельные ссылки по протоколам — ниже же (если приложение не умеет подписку)\n'
|
|
||||||
printf ' %sпозже то же самое: kit user link %s --all (или меню: kit)%s\n' "$D" "$sub_user" "$N"
|
|
||||||
[[ -n ${ssh_port:-} ]] && printf ' SSH: новый порт %s, прежние (%s) ещё открыты — закройте их после проверки входа: kit local ssh --close-old %s\n' "$ssh_port" "${ssh_ports_before:-22}" "$ssh_port"
|
|
||||||
# Ссылки на каждый протокол показываем только если протоколов больше одного: при одном это лишний шум.
|
|
||||||
protos_now=$(tr '\n' ' ' < /etc/kit/kl-protos 2>/dev/null || true)
|
|
||||||
if [[ $(wc -w <<<"$protos_now") -gt 1 ]]; then
|
|
||||||
if ! kit user link "$sub_user" --all; then
|
|
||||||
warn "не смог показать ссылки для «$sub_user» — список пользователей: kit user list"
|
|
||||||
fi
|
|
||||||
elif ! kit user link "$sub_user"; then
|
|
||||||
warn "не смог показать подписку для «$sub_user» — список пользователей: kit user list"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
say "ссылки и QR-код не показываю (--no-sub). Посмотреть: kit user link admin --all"
|
|
||||||
fi
|
|
||||||
|
|||||||
+8
-1
@@ -39,7 +39,7 @@ wait_apt_idle() {
|
|||||||
XUI_VERSION="v3.9.0"
|
XUI_VERSION="v3.9.0"
|
||||||
# SHA256 установщика 3X-UI этой версии: тег могут передвинуть, а хеш – нет (проверено 2026-09-30).
|
# SHA256 установщика 3X-UI этой версии: тег могут передвинуть, а хеш – нет (проверено 2026-09-30).
|
||||||
XUI_INSTALL_SHA256="18616fe26c8f6c92db6daa2dcd7cd53c5143ee69ecfd26d8ea6dc9b2c78607a6"
|
XUI_INSTALL_SHA256="18616fe26c8f6c92db6daa2dcd7cd53c5143ee69ecfd26d8ea6dc9b2c78607a6"
|
||||||
KIT_VERSION="1.2.1.2"
|
KIT_VERSION="1.2.1.6"
|
||||||
# kit и kit-sub берём из того же релиза, что и этот скрипт, а не из меняющейся ветки main.
|
# kit и kit-sub берём из того же релиза, что и этот скрипт, а не из меняющейся ветки main.
|
||||||
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$KIT_VERSION"
|
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$KIT_VERSION"
|
||||||
# Ядро Xray для панели. С 26.7.x клиенты на Mihomo и sing-box (Hiddify, FlClash,
|
# Ядро Xray для панели. С 26.7.x клиенты на Mihomo и sing-box (Hiddify, FlClash,
|
||||||
@@ -756,6 +756,8 @@ kl_sni_menu() {
|
|||||||
if ((i == known_idx)); then
|
if ((i == known_idx)); then
|
||||||
printf '\nОбщедоступные сайты:\n' >&2
|
printf '\nОбщедоступные сайты:\n' >&2
|
||||||
for k in "${!known[@]}"; do printf ' %d - %s\n' "$((k + 1))" "${known[k]}" >&2; done
|
for k in "${!known[@]}"; do printf ' %d - %s\n' "$((k + 1))" "${known[k]}" >&2; done
|
||||||
|
# Наш шов: последним пунктом — автовыбор из этого списка (раньше выбор был только по номеру).
|
||||||
|
printf ' %d - автовыбор из списка\n' "$((${#known[@]} + 1))" >&2
|
||||||
printf ' 0 - назад\nВаш выбор: ' >&2
|
printf ' 0 - назад\nВаш выбор: ' >&2
|
||||||
ans=""
|
ans=""
|
||||||
read -r -t 300 ans <"$src" 2>/dev/null || true
|
read -r -t 300 ans <"$src" 2>/dev/null || true
|
||||||
@@ -763,6 +765,11 @@ kl_sni_menu() {
|
|||||||
if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans >= 1 && 10#$ans <= ${#known[@]})); then
|
if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans >= 1 && 10#$ans <= ${#known[@]})); then
|
||||||
printf 'sni:%s' "${known[10#$ans - 1]}"; return 0
|
printf 'sni:%s' "${known[10#$ans - 1]}"; return 0
|
||||||
fi
|
fi
|
||||||
|
if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans == ${#known[@]} + 1)); then
|
||||||
|
local autopick="${known[RANDOM % ${#known[@]}]}"
|
||||||
|
printf ' автовыбор: %s\n' "$autopick" >&2
|
||||||
|
printf 'sni:%s' "$autopick"; return 0
|
||||||
|
fi
|
||||||
printf ' ничего не выбрано — оставляю автовыбор\n' >&2
|
printf ' ничего не выбрано — оставляю автовыбор\n' >&2
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём
|
# Код выхода 1 при любом запуске (и при `__update_binary`) – старый `hy2 update` на нём
|
||||||
# останавливается и не заменяет команду hy2.
|
# останавливается и не заменяет команду hy2.
|
||||||
|
|
||||||
KIT_VERSION="1.2.1.2"
|
KIT_VERSION="1.2.1.6"
|
||||||
|
|
||||||
cat >&2 <<'MSG'
|
cat >&2 <<'MSG'
|
||||||
Отдельный установщик Hysteria2 больше не поддерживается.
|
Отдельный установщик Hysteria2 больше не поддерживается.
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ kit_local_help() {
|
|||||||
kit local seams какие места форк правит в файлах автора
|
kit local seams какие места форк правит в файлах автора
|
||||||
kit local masking состояние маскировки (у REALITY должен быть свой домен)
|
kit local masking состояние маскировки (у REALITY должен быть свой домен)
|
||||||
kit local hardening сводка по защите сервера и что ещё можно включить
|
kit local hardening сводка по защите сервера и что ещё можно включить
|
||||||
|
kit local access доступ к панели, сертификат, ссылки и заглушка — одним экраном
|
||||||
|
kit local links подписка, QR-код и ссылки по протоколам (как в меню kit)
|
||||||
|
kit local ports открытые порты: что нужно, что лишнее и как закрыть
|
||||||
kit local uninstall то же, что kit uninstall: снести всё, включая сам kit (SSH не трогает)
|
kit local uninstall то же, что kit uninstall: снести всё, включая сам kit (SSH не трогает)
|
||||||
|
|
||||||
Заглушка (сайт на 443 и ответ Hysteria2 — одна и та же страница)
|
Заглушка (сайт на 443 и ответ Hysteria2 — одна и та же страница)
|
||||||
@@ -900,6 +903,9 @@ kit_local_cmd() {
|
|||||||
upgrades | auto) shift; kit_local_upgrades "$@" ;;
|
upgrades | auto) shift; kit_local_upgrades "$@" ;;
|
||||||
hardening | hard) shift; kit_local_hardening "$@" ;;
|
hardening | hard) shift; kit_local_hardening "$@" ;;
|
||||||
uninstall | remove) shift; kit_local_uninstall "$@" ;;
|
uninstall | remove) shift; kit_local_uninstall "$@" ;;
|
||||||
|
links | link) shift; kit_local_links "$@" ;;
|
||||||
|
access) shift; kit_local_access "$@" ;;
|
||||||
|
ports) shift; kit_local_ports "$@" ;;
|
||||||
site | stub | stub-site) shift; kit_local_site "$@" ;;
|
site | stub | stub-site) shift; kit_local_site "$@" ;;
|
||||||
*)
|
*)
|
||||||
printf 'Неизвестная команда форка: %s\n' "$1" >&2
|
printf 'Неизвестная команда форка: %s\n' "$1" >&2
|
||||||
@@ -922,6 +928,82 @@ kit_local_cmd() {
|
|||||||
#
|
#
|
||||||
# kit local uninstall спросит подтверждение словом «удалить»
|
# kit local uninstall спросит подтверждение словом «удалить»
|
||||||
# kit local uninstall --dry-run только покажет, что будет удалено
|
# kit local uninstall --dry-run только покажет, что будет удалено
|
||||||
|
kit_local_ports() { # [--close-extra] — что открыто в ufw, что реально нужно и как закрыть лишнее
|
||||||
|
local close=no a
|
||||||
|
for a in "$@"; do
|
||||||
|
case $a in
|
||||||
|
--close-extra) close=yes ;;
|
||||||
|
--help | -h) printf 'kit local ports [--close-extra] — открытые порты, нужные и лишние\n'; return 0 ;;
|
||||||
|
*) kl_die "kit local ports [--close-extra]"; return 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
command -v ufw >/dev/null 2>&1 || { kl_warn "ufw не установлен — порты смотреть нечем"; return 0; }
|
||||||
|
local -a opened=() needed=() extra=()
|
||||||
|
mapfile -t opened < <(ufw status 2>/dev/null | awk '$2 == "ALLOW" { print $1 }' | sort -u)
|
||||||
|
# Нужные порты: те, что слушают наши подключения (x-ui и ядро Xray), плюс SSH.
|
||||||
|
mapfile -t needed < <({ ss -tlnp 2>/dev/null; ss -ulnp 2>/dev/null; } \
|
||||||
|
| awk '/x-ui|xray/ { print $4 }' | sed 's/.*://' | sort -un; ss -tlnp 2>/dev/null | awk '/sshd/ { print $4 }' | sed 's/.*://' | sort -un)
|
||||||
|
local p q keep
|
||||||
|
for p in "${opened[@]}"; do
|
||||||
|
keep=no
|
||||||
|
case $p in 80/tcp | 443/tcp) keep=yes ;; esac # 443 — работа, 80 — продление сертификата
|
||||||
|
for q in "${needed[@]}"; do [[ $p == "$q/tcp" || $p == "$q/udp" || $p == "$q" ]] && keep=yes; done
|
||||||
|
[[ $keep == yes ]] && continue
|
||||||
|
extra+=("$p")
|
||||||
|
done
|
||||||
|
printf ' открыто в ufw: %s\n' "$(printf '%s ' "${opened[@]}")"
|
||||||
|
if ((${#needed[@]})); then printf ' нужны: %s\n' "$(printf '%s/tcp %s/udp ' "${needed[@]}" "${needed[@]}")"
|
||||||
|
else printf ' нужны: (не определил — смотрите kit check)\n'; fi
|
||||||
|
if ((${#extra[@]})); then
|
||||||
|
printf ' лишние: %s\n' "$(printf '%s ' "${extra[@]}")"
|
||||||
|
printf ' закрыть лишние: kit local ports --close-extra\n'
|
||||||
|
if [[ $close == yes ]]; then
|
||||||
|
for p in "${extra[@]}"; do ufw --force delete allow "$p" >/dev/null 2>&1 && printf ' закрыл %s\n' "$p"; done
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
printf ' лишних нет\n'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
kit_local_access() { # доступ к панели, ссылки на подключения, заглушка и сертификат — одним экраном
|
||||||
|
local u=${1:-} till2
|
||||||
|
printf '%s\n' "${B:-}Доступ к панели 3X-UI${N:-} (файл /root/3x-ui.txt, виден только root)"
|
||||||
|
if grep -aqE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt 2>/dev/null; then
|
||||||
|
grep -aE '^[[:space:]]*(Панель|Логин|Пароль):' /root/3x-ui.txt | sed 's/^[[:space:]]*/ /'
|
||||||
|
else
|
||||||
|
kl_warn "данных панели в /root/3x-ui.txt нет"
|
||||||
|
fi
|
||||||
|
printf '\n%s\n' "${B:-}Сертификат панели${N:-}"
|
||||||
|
if [[ -s /root/cert/ip/fullchain.pem ]] && openssl x509 -in /root/cert/ip/fullchain.pem -noout -issuer 2>/dev/null | grep -q "Let's Encrypt"; then
|
||||||
|
printf ' Let'"'"'s Encrypt на IP — доверенный, браузер не ругается\n'
|
||||||
|
elif [[ -s /root/cert/ip/fullchain.pem ]]; then
|
||||||
|
printf ' самоподписанный — браузер предупредит, подписка в приложениях может не открыться\n'
|
||||||
|
else
|
||||||
|
printf ' сертификата на IP нет: панель открывается только через SSH-туннель\n'
|
||||||
|
fi
|
||||||
|
till2=$(grep -rhoE 'retry after [0-9-]+ [0-9:]+ UTC' /var/log/3x-ui-install.log "$HOME"/.acme.sh/*/ca 2>/dev/null | tail -1 | sed 's/^retry after //')
|
||||||
|
[[ -n $till2 ]] && printf ' лимит Let'"'"'s Encrypt: повтор выпуска возможен после %s (затем запустите установщик снова)\n' "$till2"
|
||||||
|
printf '\n%s\n' "${B:-}Ссылки на подключения и QR-код${N:-}"
|
||||||
|
if [[ -z $u ]]; then u=$(kit user list 2>/dev/null | awk 'NR > 1 && NF { print $1; exit }'); u=${u:-admin}; fi
|
||||||
|
local now; now=$(tr '\n' ' ' </etc/kit/kl-protos 2>/dev/null || true)
|
||||||
|
if [[ $(wc -w <<<"$now") -gt 1 ]]; then kit user link "$u" --all; else kit user link "$u"; fi
|
||||||
|
printf '\n%s\n' "${B:-}Заглушка (что видит посторонний, открыв адрес сервера)${N:-}"
|
||||||
|
kit local site --show
|
||||||
|
printf ' посмотреть снаружи: откройте https://<IP сервера>/ в браузере или curl -k https://<IP>/
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
kit_local_links() { # [имя] — подписка, QR-код и ссылки по протоколам (то же, что «kit → Пользователи → Показать ссылки»)
|
||||||
|
local u=${1:-} now
|
||||||
|
if [[ -z $u ]]; then
|
||||||
|
u=$(kit user list 2>/dev/null | awk 'NR > 1 && NF { print $1; exit }')
|
||||||
|
u=${u:-admin}
|
||||||
|
fi
|
||||||
|
printf ' пользователь: %s\n' "$u"
|
||||||
|
now=$(tr '\n' ' ' </etc/kit/kl-protos 2>/dev/null || true)
|
||||||
|
# Ссылки на каждый протокол — только если протоколов больше одного; при одном достаточно подписки.
|
||||||
|
if [[ $(wc -w <<<"$now") -gt 1 ]]; then kit user link "$u" --all; else kit user link "$u"; fi
|
||||||
|
}
|
||||||
|
|
||||||
kit_local_uninstall() {
|
kit_local_uninstall() {
|
||||||
# Наш шов: логику удаления отдаём авторской команде «kit uninstall». Она снимает и сам kit, чтобы на
|
# Наш шов: логику удаления отдаём авторской команде «kit uninstall». Она снимает и сам kit, чтобы на
|
||||||
# сервере не осталось следов, поэтому своя реализация здесь больше не нужна — команда оставлена
|
# сервере не осталось следов, поэтому своя реализация здесь больше не нужна — команда оставлена
|
||||||
@@ -987,6 +1069,9 @@ ${B:-}3X-UI_autoVPS ${KIT_VERSION:-?} — все команды${N:-} (то ж
|
|||||||
kit local site [--list | N | --show] сайт-заглушка: случайный ИТ-сайт, список, конкретный, какой стоит
|
kit local site [--list | N | --show] сайт-заглушка: случайный ИТ-сайт, список, конкретный, какой стоит
|
||||||
|
|
||||||
Проверка и починка
|
Проверка и починка
|
||||||
|
kit local access [имя] доступ к панели, сертификат, ссылки и заглушка одним экраном
|
||||||
|
kit local links [имя] подписка, QR-код и ссылки по протоколам (по умолчанию — первый пользователь)
|
||||||
|
kit local ports [--close-extra] открытые порты: нужные, лишние; --close-extra закрывает лишние
|
||||||
kit local uninstall то же, что kit uninstall: снести установку целиком и сам kit; SSH не трогает
|
kit local uninstall то же, что kit uninstall: снести установку целиком и сам kit; SSH не трогает
|
||||||
kit check [--deep | --fix] проверка сервера (--deep — ходит наружу как клиент)
|
kit check [--deep | --fix] проверка сервера (--deep — ходит наружу как клиент)
|
||||||
kit fix [--dry-run] безопасные починки: время, службы, конфиги
|
kit fix [--dry-run] безопасные починки: время, службы, конфиги
|
||||||
|
|||||||
+6
-4
@@ -12,7 +12,7 @@
|
|||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам
|
export LC_ALL=C.UTF-8 # ширина колонок по символам, а не байтам
|
||||||
|
|
||||||
KIT_VERSION="1.2.1.2"
|
KIT_VERSION="1.2.1.6"
|
||||||
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main"
|
KIT_RAW="https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/branch/main"
|
||||||
# Файлы новой версии берём из её тега, а не из меняющейся ветки main.
|
# Файлы новой версии берём из её тега, а не из меняющейся ветки main.
|
||||||
kit_ref_raw() { echo "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$1"; }
|
kit_ref_raw() { echo "https://git.rukavishnikoff.ru/hacker07/3X-UI_autoVPS/raw/tag/v$1"; }
|
||||||
@@ -3194,7 +3194,7 @@ menu_main() {
|
|||||||
echo
|
echo
|
||||||
box "3X-UI_autoVPS $KIT_VERSION – управление сервером" "1. Пользователи" "2. Протоколы, порты и маскировка" "3. Проверка сервера" "" \
|
box "3X-UI_autoVPS $KIT_VERSION – управление сервером" "1. Пользователи" "2. Протоколы, порты и маскировка" "3. Проверка сервера" "" \
|
||||||
"4. Обновить kit и подписку" "5. Обновить панель 3X-UI" "6. Автообновление: включить или выключить" "" \
|
"4. Обновить kit и подписку" "5. Обновить панель 3X-UI" "6. Автообновление: включить или выключить" "" \
|
||||||
"7. Резервная копия" "8. Версии" "" "9. Панель 3X-UI (меню x-ui)" "10. Удалить KIT с сервера" "0. Выход"
|
"7. Резервная копия" "8. Версии" "" "9. Доступ к панели, ссылки и заглушка" "10. Панель x-ui" "11. Удалить KIT с сервера" "0. Выход"
|
||||||
echo
|
echo
|
||||||
menu_status
|
menu_status
|
||||||
update_hint
|
update_hint
|
||||||
@@ -3209,8 +3209,10 @@ menu_main() {
|
|||||||
6) run_action menu_auto; pause ;;
|
6) run_action menu_auto; pause ;;
|
||||||
7) run_action cmd_backup; pause ;;
|
7) run_action cmd_backup; pause ;;
|
||||||
8) run_action cmd_version; pause ;;
|
8) run_action cmd_version; pause ;;
|
||||||
9) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;
|
# Наш шов: пункт 9 — доступ к панели, ссылки на подключения и состояние заглушки в одном месте.
|
||||||
10) run_action cmd_uninstall; pause ;;
|
9) kit local access; pause ;;
|
||||||
|
10) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;
|
||||||
|
11) run_action cmd_uninstall; pause ;;
|
||||||
0 | "") return 0 ;;
|
0 | "") return 0 ;;
|
||||||
*) echo "Нет такого пункта." ;;
|
*) echo "Нет такого пункта." ;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
+15
-1
@@ -212,6 +212,20 @@ def main():
|
|||||||
' box "3X-UI_autoVPS $KIT_VERSION – управление сервером" "1. Пользователи" "2. Протоколы, порты и маскировка" "3. Проверка сервера" "" \\\n',
|
' box "3X-UI_autoVPS $KIT_VERSION – управление сервером" "1. Пользователи" "2. Протоколы, порты и маскировка" "3. Проверка сервера" "" \\\n',
|
||||||
'авто-шов: replace, строк 1',
|
'авто-шов: replace, строк 1',
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
'scripts/kit.sh',
|
||||||
|
' "7. Резервная копия" "8. Версии" "" "9. Панель 3X-UI (меню x-ui)" "10. Удалить KIT с сервера" "0. Выход"\n',
|
||||||
|
False,
|
||||||
|
' "7. Резервная копия" "8. Версии" "" "9. Доступ к панели, ссылки и заглушка" "10. Панель x-ui" "11. Удалить KIT с сервера" "0. Выход"\n',
|
||||||
|
'авто-шов: replace, строк 1',
|
||||||
|
),
|
||||||
|
(
|
||||||
|
'scripts/kit.sh',
|
||||||
|
' 9) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;\n 10) run_action cmd_uninstall; pause ;;\n',
|
||||||
|
False,
|
||||||
|
' # Наш шов: пункт 9 — доступ к панели, ссылки на подключения и состояние заглушки в одном месте.\n 9) kit local access; pause ;;\n 10) command -v x-ui >/dev/null && x-ui || echo "Меню x-ui не найдено." ;;\n 11) run_action cmd_uninstall; pause ;;\n',
|
||||||
|
'авто-шов: replace, строк 2',
|
||||||
|
),
|
||||||
(
|
(
|
||||||
'scripts/kit.sh',
|
'scripts/kit.sh',
|
||||||
' echo "${B}Полное удаление 3X-UI KIT${N}"\n',
|
' echo "${B}Полное удаление 3X-UI KIT${N}"\n',
|
||||||
@@ -321,7 +335,7 @@ def main():
|
|||||||
'scripts/3x-ui.sh',
|
'scripts/3x-ui.sh',
|
||||||
' later "Адрес $HOST не найден на сетевых интерфейсах сервера (бывает за NAT). Если ссылки не работают – запустите с --host и верным IP."\n fi\n\n',
|
' later "Адрес $HOST не найден на сетевых интерфейсах сервера (бывает за NAT). Если ссылки не работают – запустите с --host и верным IP."\n fi\n\n',
|
||||||
False,
|
False,
|
||||||
' later "Адрес $HOST не найден на сетевых интерфейсах сервера (бывает за NAT). Если ссылки не работают – запустите с --host и верным IP."\n fi\n\n# ---------------------------------------------------------------------------\n# Наш шов: выбор сайта маскировки по результатам скана подсети.\n# Печатает выбранное имя в stdout (пусто — оставляем автоподбор автора).\n# role — подпись для человека: REALITY или XHTTP/MTProto.\nkl_sni_menu() {\n local role=$1; shift\n local -a found=("$@")\n local -a known=("${SNI_CANDIDATES[@]}")\n local src=${KL_ASK_SRC:-/dev/tty} ans i k n auto_idx known_idx own_idx try\n n=${#found[@]}\n printf \'\\n%s%s%s\\n\' "$B" "$role" "$N" >&2\n if ((n)); then\n printf \'Найдено в подсети:\\n\\n\' >&2\n for i in "${!found[@]}"; do printf \' %d - %s\\n\' "$((i + 1))" "${found[i]}" >&2; done\n auto_idx=$((n + 1)); known_idx=$((n + 2)); own_idx=$((n + 3))\n printf \' %d - автовыбор из списка\\n\' "$auto_idx" >&2\n printf \' %d - выбрать общедоступный (например %s, %s)\\n\' "$known_idx" "${known[0]}" "${known[1]}" >&2\n printf \' %d - ввести свой домен\\n\\n\' "$own_idx" >&2\n else\n auto_idx=0; known_idx=1; own_idx=2\n printf \'В подсети доменов не найдено, выберите:\\n\\n\' >&2\n printf \' 1 - общедоступный (например %s, %s)\\n\' "${known[0]}" "${known[1]}" >&2\n printf \' 2 - ввести свой домен\\n\\n\' >&2\n fi\n printf \'Ваш выбор (Enter — автовыбор): \' >&2\n for try in 1 2 3; do\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n [[ -z $ans ]] && return 0\n [[ $ans =~ ^[0-9]+$ ]] || { printf \' введите номер из списка\\n\' >&2; continue; }\n i=$((10#$ans))\n if ((n)) && ((i >= 1 && i <= n)); then printf \'sni:%s\' "${found[i - 1]}"; return 0; fi\n ((i == auto_idx)) && return 0\n if ((i == known_idx)); then\n printf \'\\nОбщедоступные сайты:\\n\' >&2\n for k in "${!known[@]}"; do printf \' %d - %s\\n\' "$((k + 1))" "${known[k]}" >&2; done\n printf \' 0 - назад\\nВаш выбор: \' >&2\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans >= 1 && 10#$ans <= ${#known[@]})); then\n printf \'sni:%s\' "${known[10#$ans - 1]}"; return 0\n fi\n printf \' ничего не выбрано — оставляю автовыбор\\n\' >&2\n return 0\n fi\n if ((i == own_idx)); then\n printf \' адрес сайта (например vpn.example.com): \' >&2\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n [[ $ans =~ ^[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$ ]] && { printf \'own:%s\' "$ans"; return 0; }\n printf \' не похоже на адрес сайта — оставляю автовыбор\\n\' >&2\n return 0\n fi\n printf \' такого номера нет\\n\' >&2\n done\n return 0\n}\n\n',
|
' later "Адрес $HOST не найден на сетевых интерфейсах сервера (бывает за NAT). Если ссылки не работают – запустите с --host и верным IP."\n fi\n\n# ---------------------------------------------------------------------------\n# Наш шов: выбор сайта маскировки по результатам скана подсети.\n# Печатает выбранное имя в stdout (пусто — оставляем автоподбор автора).\n# role — подпись для человека: REALITY или XHTTP/MTProto.\nkl_sni_menu() {\n local role=$1; shift\n local -a found=("$@")\n local -a known=("${SNI_CANDIDATES[@]}")\n local src=${KL_ASK_SRC:-/dev/tty} ans i k n auto_idx known_idx own_idx try\n n=${#found[@]}\n printf \'\\n%s%s%s\\n\' "$B" "$role" "$N" >&2\n if ((n)); then\n printf \'Найдено в подсети:\\n\\n\' >&2\n for i in "${!found[@]}"; do printf \' %d - %s\\n\' "$((i + 1))" "${found[i]}" >&2; done\n auto_idx=$((n + 1)); known_idx=$((n + 2)); own_idx=$((n + 3))\n printf \' %d - автовыбор из списка\\n\' "$auto_idx" >&2\n printf \' %d - выбрать общедоступный (например %s, %s)\\n\' "$known_idx" "${known[0]}" "${known[1]}" >&2\n printf \' %d - ввести свой домен\\n\\n\' "$own_idx" >&2\n else\n auto_idx=0; known_idx=1; own_idx=2\n printf \'В подсети доменов не найдено, выберите:\\n\\n\' >&2\n printf \' 1 - общедоступный (например %s, %s)\\n\' "${known[0]}" "${known[1]}" >&2\n printf \' 2 - ввести свой домен\\n\\n\' >&2\n fi\n printf \'Ваш выбор (Enter — автовыбор): \' >&2\n for try in 1 2 3; do\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n [[ -z $ans ]] && return 0\n [[ $ans =~ ^[0-9]+$ ]] || { printf \' введите номер из списка\\n\' >&2; continue; }\n i=$((10#$ans))\n if ((n)) && ((i >= 1 && i <= n)); then printf \'sni:%s\' "${found[i - 1]}"; return 0; fi\n ((i == auto_idx)) && return 0\n if ((i == known_idx)); then\n printf \'\\nОбщедоступные сайты:\\n\' >&2\n for k in "${!known[@]}"; do printf \' %d - %s\\n\' "$((k + 1))" "${known[k]}" >&2; done\n # Наш шов: последним пунктом — автовыбор из этого списка (раньше выбор был только по номеру).\n printf \' %d - автовыбор из списка\\n\' "$((${#known[@]} + 1))" >&2\n printf \' 0 - назад\\nВаш выбор: \' >&2\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans >= 1 && 10#$ans <= ${#known[@]})); then\n printf \'sni:%s\' "${known[10#$ans - 1]}"; return 0\n fi\n if [[ $ans =~ ^[0-9]+$ ]] && ((10#$ans == ${#known[@]} + 1)); then\n local autopick="${known[RANDOM % ${#known[@]}]}"\n printf \' автовыбор: %s\\n\' "$autopick" >&2\n printf \'sni:%s\' "$autopick"; return 0\n fi\n printf \' ничего не выбрано — оставляю автовыбор\\n\' >&2\n return 0\n fi\n if ((i == own_idx)); then\n printf \' адрес сайта (например vpn.example.com): \' >&2\n ans=""\n read -r -t 300 ans <"$src" 2>/dev/null || true\n ans=${ans//[[:space:]]/}\n [[ $ans =~ ^[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$ ]] && { printf \'own:%s\' "$ans"; return 0; }\n printf \' не похоже на адрес сайта — оставляю автовыбор\\n\' >&2\n return 0\n fi\n printf \' такого номера нет\\n\' >&2\n done\n return 0\n}\n\n',
|
||||||
'авто-шов: insert, строк 3',
|
'авто-шов: insert, строк 3',
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|||||||
Reference in New Issue
Block a user