mirror of
https://github.com/andrey271192/PCAtelegram_web.git
synced 2026-09-20 11:55:32 +00:00
feat: install warp on enable
This commit is contained in:
@@ -94,12 +94,12 @@ PCATELEGRAM_WEB_ADMIN_PASSWORD='strong-password' bash bootstrap.sh
|
||||
- `Off` — WARP выключен.
|
||||
- `WARP` — обычный Cloudflare WARP.
|
||||
- `WARP+` — WARP+ с license key.
|
||||
- `All clients` — применяет WARP на весь proxy-трафик через `warp-cli`, если Cloudflare WARP установлен на сервере.
|
||||
- `One client` — сохраняет WARP/WARP+ профиль и key для выбранного клиента в `/opt/pcatelegram_web/warp.json`.
|
||||
- `All clients` — если `warp-cli` не установлен, web-admin ставит `cloudflare-warp`, затем применяет WARP на весь proxy-трафик через `warp-cli`.
|
||||
- `One client` — если `warp-cli` не установлен, web-admin ставит `cloudflare-warp`, затем сохраняет WARP/WARP+ профиль и key для выбранного клиента в `/opt/pcatelegram_web/warp.json`.
|
||||
|
||||
WARP+ key не отдается в API целиком: web показывает только маску. Файл `warp.json` хранится с правами `0600` и входит в backup.
|
||||
|
||||
Для реального global WARP на сервере нужен установленный `cloudflare-warp` и доступная команда `warp-cli`. По документации Cloudflare: регистрация `warp-cli registration new`, WARP+ key `warp-cli registration license <KEY>`, подключение `warp-cli connect`.
|
||||
Для real global WARP web-admin использует официальный Cloudflare Linux repo: добавляет GPG key, repo `pkg.cloudflareclient.com`, ставит пакет `cloudflare-warp`, затем выполняет регистрацию `warp-cli registration new`, WARP+ key `warp-cli registration license <KEY>`, подключение `warp-cli connect`.
|
||||
|
||||
Per-client runtime routing в текущем telemt не включается автоматически: публичные параметры telemt дают users/limits/quotas/ad tags, но не документируют привязку upstream к конкретному user. Для настоящего WARP только одному клиенту нужен отдельный telemt route/service или upstream-схема.
|
||||
|
||||
|
||||
@@ -604,15 +604,74 @@ def user_warp_payload(name: str) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def install_warp_cli() -> dict[str, Any]:
|
||||
result: dict[str, Any] = {"attempted": False, "installed": bool(shutil.which("warp-cli")), "commands": [], "warnings": []}
|
||||
if result["installed"]:
|
||||
return result
|
||||
if os.geteuid() != 0:
|
||||
result["warnings"].append("root required to install cloudflare-warp")
|
||||
return result
|
||||
|
||||
def call(label: str, cmd: list[str], timeout: int = 120) -> tuple[int, str, str]:
|
||||
result["attempted"] = True
|
||||
code, out, err = run(cmd, timeout=timeout)
|
||||
result["commands"].append({"cmd": label, "exit_code": code})
|
||||
return code, out, err
|
||||
|
||||
apt_get = shutil.which("apt-get")
|
||||
dnf = shutil.which("dnf")
|
||||
yum = shutil.which("yum")
|
||||
|
||||
if apt_get:
|
||||
script = r"""
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update
|
||||
apt-get install -y curl gpg lsb-release ca-certificates
|
||||
install -d -m 0755 /usr/share/keyrings
|
||||
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/cloudflare-client.list
|
||||
apt-get update
|
||||
apt-get install -y cloudflare-warp
|
||||
"""
|
||||
code, _, err = call("install cloudflare-warp via apt", ["bash", "-lc", script], timeout=420)
|
||||
if code != 0:
|
||||
result["warnings"].append(err.strip() or "apt install failed")
|
||||
elif dnf or yum:
|
||||
manager = dnf or yum
|
||||
repo_url = "https://pkg.cloudflareclient.com/cloudflare-warp-ascii.repo"
|
||||
script = f"""
|
||||
set -e
|
||||
rpm --import https://pkg.cloudflareclient.com/pubkey.gpg || true
|
||||
curl -fsSL {shlex.quote(repo_url)} > /etc/yum.repos.d/cloudflare-warp.repo
|
||||
{shlex.quote(manager)} install -y cloudflare-warp
|
||||
"""
|
||||
code, _, err = call("install cloudflare-warp via rpm repo", ["bash", "-lc", script], timeout=420)
|
||||
if code != 0:
|
||||
result["warnings"].append(err.strip() or "rpm install failed")
|
||||
else:
|
||||
result["warnings"].append("supported package manager not found")
|
||||
|
||||
result["installed"] = bool(shutil.which("warp-cli"))
|
||||
if not result["installed"] and not result["warnings"]:
|
||||
result["warnings"].append("warp-cli still not available after install")
|
||||
return result
|
||||
|
||||
|
||||
def apply_warp_runtime(cfg: dict[str, Any]) -> dict[str, Any]:
|
||||
warp_cli = shutil.which("warp-cli")
|
||||
result: dict[str, Any] = {"applied": False, "commands": [], "warnings": []}
|
||||
result: dict[str, Any] = {"applied": False, "install": {"attempted": False, "installed": bool(warp_cli)}, "commands": [], "warnings": []}
|
||||
if cfg["enabled"] and cfg["mode"] != "off" and not warp_cli:
|
||||
install_result = install_warp_cli()
|
||||
result["install"] = install_result
|
||||
result["warnings"].extend(install_result.get("warnings", []))
|
||||
warp_cli = shutil.which("warp-cli")
|
||||
if (not cfg["enabled"] or cfg["mode"] == "off") and not warp_cli:
|
||||
result["applied"] = True
|
||||
return result
|
||||
if not warp_cli:
|
||||
result["warnings"].append("warp-cli not installed")
|
||||
return result
|
||||
if cfg["scope"] == "user":
|
||||
result["warnings"].append("per-user WARP route saved only; telemt per-user upstream routing is not documented")
|
||||
return result
|
||||
|
||||
def call(args: list[str], timeout: int = 20) -> tuple[int, str, str]:
|
||||
code, out, err = run([warp_cli, *args], timeout=timeout)
|
||||
@@ -627,6 +686,10 @@ def apply_warp_runtime(cfg: dict[str, Any]) -> dict[str, Any]:
|
||||
result["applied"] = True
|
||||
return result
|
||||
|
||||
if cfg["scope"] == "user":
|
||||
result["warnings"].append("per-user WARP route saved only; telemt per-user upstream routing is not documented")
|
||||
return result
|
||||
|
||||
run(["systemctl", "enable", "--now", "warp-svc"], timeout=20)
|
||||
code, _, _ = call(["registration", "show"], timeout=10)
|
||||
if code != 0:
|
||||
|
||||
@@ -118,9 +118,9 @@ const i18n = {
|
||||
warpSave: "Save WARP",
|
||||
warpSaved: "WARP settings saved",
|
||||
warpInstalled: "warp-cli installed",
|
||||
warpNotInstalled: "warp-cli not installed",
|
||||
warpPerUserNote: "One-client WARP profile is stored here. Runtime per-client routing needs a dedicated telemt route; global WARP applies to all clients.",
|
||||
warpAllNote: "Global WARP applies to all proxy traffic when warp-cli is installed and connected.",
|
||||
warpNotInstalled: "will install on save",
|
||||
warpPerUserNote: "One-client WARP profile is stored here. If warp-cli is missing, it will be installed on save. Runtime per-client routing needs a dedicated telemt route; global WARP applies to all clients.",
|
||||
warpAllNote: "Global WARP applies to all proxy traffic. If warp-cli is missing, it will be installed on save, then connected.",
|
||||
savedKey: "saved key",
|
||||
dashboard: "Dashboard",
|
||||
noKeys: "No keys yet",
|
||||
@@ -362,9 +362,9 @@ const i18n = {
|
||||
warpSave: "Сохранить WARP",
|
||||
warpSaved: "Настройки WARP сохранены",
|
||||
warpInstalled: "warp-cli установлен",
|
||||
warpNotInstalled: "warp-cli не установлен",
|
||||
warpPerUserNote: "Профиль WARP для одного клиента сохраняется здесь. Runtime-маршрут на одного клиента требует отдельный маршрут telemt; global WARP действует на всех клиентов.",
|
||||
warpAllNote: "Global WARP применится ко всему proxy-трафику, если warp-cli установлен и подключён.",
|
||||
warpNotInstalled: "установится при сохранении",
|
||||
warpPerUserNote: "Профиль WARP для одного клиента сохраняется здесь. Если warp-cli нет, он установится при сохранении. Runtime-маршрут на одного клиента требует отдельный маршрут telemt; global WARP действует на всех клиентов.",
|
||||
warpAllNote: "Global WARP применится ко всему proxy-трафику. Если warp-cli нет, он установится при сохранении и затем подключится.",
|
||||
savedKey: "ключ сохранён",
|
||||
dashboard: "Обзор",
|
||||
noKeys: "Ключей пока нет",
|
||||
|
||||
@@ -440,6 +440,6 @@
|
||||
<button id="qrCopyBtn" type="button" class="soft" data-i18n="copyLink">Copy link</button>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/app.js?v=2.5.0-admin21" type="module"></script>
|
||||
<script src="/app.js?v=2.5.0-admin22" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user