nginx: путь панели и подписки перед сборкой конфига – только буквы, цифры, _ и -

XUI_WEB_BASE_PATH из install-result.env (при --restore – из копии) шёл в
«location ... {» как есть: строка с фигурными скобками добавляла в nginx
чужие директивы. Значение теперь проверяется при --restore (прошлая правка)
и ещё раз там, где собирается nginx: setup_nginx в 3x-ui.sh, kit net panel
и пути подписки в kit.
This commit is contained in:
maxdmitrov
2026-10-06 18:38:08 +03:00
parent 397804faa7
commit 387d6ae66e
3 changed files with 38 additions and 3 deletions
+3
View File
@@ -1464,6 +1464,9 @@ setup_nginx() {
elif $st.network == "grpc" then ["grpc", $st.grpcSettings.serviceName, .port]
else empty end | @tsv' <<<"$list")
# Пути панели (из install-result.env, при --restore – из копии) и подписки попадают в конфиг nginx.
[[ $XUI_WEB_BASE_PATH =~ ^/?[A-Za-z0-9_-]{1,64}/?$ && $SUB_PATH =~ ^/[A-Za-z0-9_-]{1,64}/$ ]] \
|| die "Странный путь панели или подписки ($XUI_ENV) – не собираю nginx."
local panel_path=/${XUI_WEB_BASE_PATH#/}
panel_path=${panel_path%/}/
{
+9 -3
View File
@@ -2096,6 +2096,13 @@ sys.stdout.write(text[:steal[0]] + new + text[steal[1]:])
PY
}
# Путь панели (install-result.env) и подписки (kit.env) идут в конфиг nginx: только буквы, цифры, _ и -.
panel_web_path() {
[[ ${XUI_WEB_BASE_PATH:-} =~ ^/?[A-Za-z0-9_-]{1,64}/?$ && ${SUB_PATH:-} =~ ^/[A-Za-z0-9_-]{1,64}/$ ]] || return 1
local p=/${XUI_WEB_BASE_PATH#/}
echo "${p%/}/"
}
kit_env_set() { # ключ значение: меняет или добавляет строку в /etc/kit/kit.env
python3 - "$KIT_ENV" "$1" "$2" <<'PY'
import re, shlex, sys
@@ -2130,8 +2137,7 @@ sub_extra_sync() {
tmp=$(mktemp); bak=$(mktemp); cp -p "$PANEL_CONF" "$bak"
if panel_conf_py addloc "$PANEL_CONF" "$SUB_PATH" "${ex[@]}" >"$tmp" && [[ -s $tmp ]]; then
cat "$tmp" >"$PANEL_CONF"
if [[ ${PANEL_ON:-ip} == domain ]]; then
panel_path=/${XUI_WEB_BASE_PATH#/}; panel_path=${panel_path%/}/
if [[ ${PANEL_ON:-ip} == domain ]] && panel_path=$(panel_web_path); then
panel_conf_py render "$PANEL_CONF" domain "$SUB_PATH" "$panel_path" "${ex[@]}" >"$tmp" && [[ -s $tmp ]] && cat "$tmp" >"$PANEL_CONF"
fi
if nginx -t >/dev/null 2>&1; then systemctl reload nginx
@@ -2155,7 +2161,7 @@ net_panel() { # [domain|ip]
fi
[[ $want == domain || $want == ip ]] || die "kit net panel [domain|ip]"
[[ $want != "$cur" ]] || { say "Уже так: панель и подписка по $([[ $want == domain ]] && echo "домену $domain" || echo "IP")."; return 0; }
panel_path=/${XUI_WEB_BASE_PATH#/}; panel_path=${panel_path%/}/
panel_path=$(panel_web_path) || die "Странный путь панели или подписки в $XUI_ENV или $KIT_ENV – не трогаю nginx."
if [[ $want == domain ]]; then
getent ahostsv4 "$domain" 2>/dev/null | awk '{print $1}' | grep -qx "$(host_ip)" || die "Домен $domain не указывает на этот сервер ($(host_ip)). Исправьте A-запись и повторите."
[[ -s $cert && -s $key ]] || die "Нет сертификата домена ($cert) – не трогаю nginx."
+26
View File
@@ -124,5 +124,31 @@ class SafeEnv(unittest.TestCase):
self.rejected("kit-backup.env", GOOD["kit-backup.env"] + bad + "\n")
kit_src = open(os.path.join(root, "scripts", "kit.sh"), encoding="utf-8").read()
PANEL_PATH = re.search(r"^panel_web_path\(\) \{.*?^\}\n", kit_src, re.S | re.M).group(0)
class NginxPaths(unittest.TestCase):
"""Путь панели и подписки перед сборкой nginx (kit.sh panel_web_path, 3x-ui.sh setup_nginx)."""
def path(self, base, sub="/AbC123/"):
r = subprocess.run(["bash", "-c", PANEL_PATH + 'XUI_WEB_BASE_PATH=$1 SUB_PATH=$2\npanel_web_path || echo NO', "t", base, sub],
capture_output=True, text=True)
return r.stdout.strip()
def test_good(self):
self.assertEqual(self.path("AbCdEf123456789012"), "/AbCdEf123456789012/")
self.assertEqual(self.path("/AbC_d-1/"), "/AbC_d-1/")
def test_bad(self):
for bad in ("x/ { return 200; } location /zz", "", "/", "a/b", "a;b", "a\nb", "$(id)", "a" * 65):
self.assertEqual(self.path(bad), "NO", bad)
for bad in ("/a b/", "/a/ { }", "", "/../"):
self.assertEqual(self.path("AbC", bad), "NO", bad)
def test_setup_nginx_checks(self):
self.assertIn('[[ $XUI_WEB_BASE_PATH =~ ^/?[A-Za-z0-9_-]{1,64}/?$ && $SUB_PATH =~ ^/[A-Za-z0-9_-]{1,64}/$ ]]', src)
if __name__ == "__main__":
unittest.main()