Allow special characters in rule-set tags
Some checks failed
Build and Deploy Gateway / build-and-deploy (push) Failing after 13s

This commit is contained in:
2026-05-09 10:23:57 +03:00
parent cab4313c70
commit 62f50d9c28
7 changed files with 26 additions and 6 deletions

View File

@@ -1,4 +1,6 @@
PORT=3456
BASE_IMAGE=debian:bookworm-slim
SINGBOX_VERSION=1.12.13
PROXY_PORT=8080
PROXY_BIND_IP=0.0.0.0
TPROXY_PORT=7895

View File

@@ -1,4 +1,5 @@
FROM debian:bookworm-slim
ARG BASE_IMAGE=debian:bookworm-slim
FROM ${BASE_IMAGE}
ARG SINGBOX_VERSION=1.12.13
COPY dist /app/dist

View File

@@ -271,6 +271,15 @@ npm install && npm run build
docker compose -f docker-compose.gateway.yml up -d
```
Если Docker Hub отвечает таймаутом на `debian:bookworm-slim`, можно собрать через read-through mirror:
```bash
BASE_IMAGE=mirror.gcr.io/library/debian:bookworm-slim \
docker compose -f docker-compose.gateway.yml build
docker compose -f docker-compose.gateway.yml up -d
```
UI доступен на `http://<gateway-ip>:3456`.
На роутере указать шлюз по умолчанию (или нужные подсети) на IP контейнера.
@@ -282,6 +291,8 @@ UI доступен на `http://<gateway-ip>:3456`.
| Переменная | По умолчанию | Описание |
| ------------------- | -------------------- | -------------------------------------- |
| `PORT` | `3456` | Порт веб-интерфейса |
| `BASE_IMAGE` | `debian:bookworm-slim` | Базовый Docker image для сборки; можно заменить на mirror |
| `SINGBOX_VERSION` | `1.12.13` | Версия sing-box для Docker build |
| `PROXY_PORT` | `8080` | HTTP/SOCKS mixed inbound |
| `TPROXY_PORT` | `7895` | TProxy inbound sing-box |
| `DATA_DIR` | `/var/lib/vpn-proxy` | Директория данных (volume) |

View File

@@ -3,6 +3,9 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
BASE_IMAGE: ${BASE_IMAGE:-debian:bookworm-slim}
SINGBOX_VERSION: ${SINGBOX_VERSION:-1.12.13}
container_name: vpn-proxy-gateway
network_mode: host
cap_add:

View File

@@ -21,9 +21,12 @@ import { matchRoute, detectRuleConflicts } from "./routeMatcher.js";
import { tcpPing, resolveHost } from "./ping.js";
const APPLY_HISTORY_LIMIT = 10;
const RULE_SET_TAG_RE = /^[a-z0-9][a-z0-9_.@!-]*$/i;
const FALLBACK_RULE_SET_CATALOG = {
geosite: [
"geosite-category-ru",
"geosite-category-ai-!cn",
"geosite-geolocation-!cn",
"geosite-google",
"geosite-youtube",
"geosite-telegram",
@@ -648,7 +651,7 @@ function normalizeCustomRules(input) {
["tcp", "udp"].includes(network),
),
ruleSets: normalizeList(rule.ruleSets).filter((tag) =>
/^[a-z0-9][a-z0-9-]*$/i.test(tag),
RULE_SET_TAG_RE.test(tag),
),
}));
}
@@ -938,7 +941,7 @@ async function handleApi(req, res) {
url: String(rs.url).trim(),
format: rs.format === "source" ? "source" : "binary",
}))
.filter((rs) => /^[a-z0-9][a-z0-9-]*$/i.test(rs.tag));
.filter((rs) => RULE_SET_TAG_RE.test(rs.tag));
writeJson(settings.customRuleSetsPath, normalized);
return sendJson(res, 200, { success: true, ruleSets: normalized });
}

View File

@@ -4,7 +4,7 @@ import { isValidCidr, isValidPort, ruleErrors, hasErrors } from '../utils/valida
import { api } from '../api.js';
const DOMAIN = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i;
const RULE_SET_TAG = /^[a-z0-9][a-z0-9-]*$/i;
const RULE_SET_TAG = /^[a-z0-9][a-z0-9_.@!-]*$/i;
const validDomain = (v) => DOMAIN.test(String(v).trim());
const validRuleSetTag = (v) => RULE_SET_TAG.test(String(v).trim());

View File

@@ -601,8 +601,8 @@ function RuleSetsCard({ pushToast }) {
const tag = newTag.trim();
const url = newUrl.trim();
if (!tag || !url) return;
if (!/^[a-z0-9][a-z0-9-]*$/i.test(tag)) {
pushToast({ kind: 'danger', title: 'Невалидный тег', message: 'Только буквы, цифры, дефис' });
if (!/^[a-z0-9][a-z0-9_.@!-]*$/i.test(tag)) {
pushToast({ kind: 'danger', title: 'Невалидный тег', message: 'Буквы, цифры и символы - _ . @ !' });
return;
}
if (ruleSets.some((rs) => rs.tag === tag)) {