release: 1.4.0 — distribution via git.bobyrev.com
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
17
README.md
17
README.md
@@ -73,19 +73,24 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **Источник с 23.10.2026:** `git.bobyrev.com/PCA/PCA_Phobos` (GitHub-аккаунт временно недоступен). Серверы на 1.2.x обновляются одной командой:
|
||||||
|
> ```bash
|
||||||
|
> bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/update.sh)
|
||||||
|
> ```
|
||||||
|
|
||||||
## Быстрый старт (с чистого VPS, одной командой)
|
## Быстрый старт (с чистого VPS, одной командой)
|
||||||
|
|
||||||
Ставит **всё** со всеми зависимостями: wg-obfuscator, WireGuard, обфускатор-сервисы, веб-панель, nginx, скрипты онбординга роутеров, сторож авто-восстановления. Предустановленный Phobos **не требуется**.
|
Ставит **всё** со всеми зависимостями: wg-obfuscator, WireGuard, обфускатор-сервисы, веб-панель, nginx, скрипты онбординга роутеров, сторож авто-восстановления. Предустановленный Phobos **не требуется**.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/install.sh)
|
bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
### С параметрами
|
### С параметрами
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
PANEL_PASS=МойПароль TG_TOKEN=123:abc TG_CHAT=123456789 \
|
PANEL_PASS=МойПароль TG_TOKEN=123:abc TG_CHAT=123456789 \
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/install.sh)
|
bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
| Переменная | По умолчанию | Описание |
|
| Переменная | По умолчанию | Описание |
|
||||||
@@ -106,7 +111,7 @@ bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
MAIN_PROTO=http MAIN_SERVER=<ip_основного> MAIN_PORT=<порт_панели> MAIN_API_KEY=<API key из основного> \
|
MAIN_PROTO=http MAIN_SERVER=<ip_основного> MAIN_PORT=<порт_панели> MAIN_API_KEY=<API key из основного> \
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/server/secondary-setup.sh)
|
bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/server/secondary-setup.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
Сервер сам зарегистрируется в панели, клиенты досылаются на него сразу. Если сервер за NAT — добавь `SERVER_IP=<внешний_ip>`.
|
Сервер сам зарегистрируется в панели, клиенты досылаются на него сразу. Если сервер за NAT — добавь `SERVER_IP=<внешний_ip>`.
|
||||||
@@ -116,7 +121,7 @@ bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main
|
|||||||
На входном VPS (чистый Debian/Ubuntu, Phobos не нужен):
|
На входном VPS (чистый Debian/Ubuntu, Phobos не нужен):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/server/phobos-cascade.sh) enable <IP_выходного_сервера> 2083,5443,993
|
bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/server/phobos-cascade.sh) enable <IP_выходного_сервера> 2083,5443,993
|
||||||
```
|
```
|
||||||
|
|
||||||
Затем в панели выходного сервера → **Настройки → Адрес для клиентов и каскад** → впиши IP/домен входа. Роутеры переключатся сами (~15 с), телефонам — заново открыть ссылку/QR. Отключить: `phobos-cascade disable`.
|
Затем в панели выходного сервера → **Настройки → Адрес для клиентов и каскад** → впиши IP/домен входа. Роутеры переключатся сами (~15 с), телефонам — заново открыть ссылку/QR. Отключить: `phobos-cascade disable`.
|
||||||
@@ -131,8 +136,8 @@ bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main
|
|||||||
|
|
||||||
## Приложения для Android
|
## Приложения для Android
|
||||||
|
|
||||||
- **PCA Phobos VPN** — клиент: включает VPN одной кнопкой, импорт `phobos://` из панели, встроенный обфускатор, **раздельный трафик** (весь / только выбранные приложения / все кроме выбранных), журнал, проверка скорости. [Скачать APK](https://github.com/andrey271192/PCA_Phobos/releases/latest/download/PCA-Phobos-VPN.apk) · исходники `android-client/`.
|
- **PCA Phobos VPN** — клиент: включает VPN одной кнопкой, импорт `phobos://` из панели, встроенный обфускатор, **раздельный трафик** (весь / только выбранные приложения / все кроме выбранных), журнал, проверка скорости. [Скачать APK](https://git.bobyrev.com/PCA/PCA_Phobos/releases/download/v1.4.0/PCA-Phobos-VPN.apk) · исходники `android-client/`.
|
||||||
- **PCA Phobos** (админ) — список ваших панелей, открываются в приложении. [Скачать APK](https://github.com/andrey271192/PCA_Phobos/releases/latest/download/PCA-Phobos.apk) · исходники `android/`.
|
- **PCA Phobos** (админ) — список ваших панелей, открываются в приложении. [Скачать APK](https://git.bobyrev.com/PCA/PCA_Phobos/releases/download/v1.4.0/PCA-Phobos.apk) · исходники `android/`.
|
||||||
|
|
||||||
## Клиенты для телефона
|
## Клиенты для телефона
|
||||||
|
|
||||||
|
|||||||
79
app.py
79
app.py
@@ -34,6 +34,10 @@ PANEL_DIR = "/opt/phobos-panel"
|
|||||||
SETTINGS_FILE = f"{PANEL_DIR}/settings.json"
|
SETTINGS_FILE = f"{PANEL_DIR}/settings.json"
|
||||||
SECRET_FILE = f"{PANEL_DIR}/.secret_key"
|
SECRET_FILE = f"{PANEL_DIR}/.secret_key"
|
||||||
WG_CONFIG = "/etc/wireguard/wg0.conf"
|
WG_CONFIG = "/etc/wireguard/wg0.conf"
|
||||||
|
# Distribution: Gitea first (GitHub account is unavailable since 23.10.2026), GitHub fallback
|
||||||
|
PCA_GIT = "https://git.bobyrev.com/PCA/PCA_Phobos"
|
||||||
|
PCA_GH_RAW = "https://raw.githubusercontent.com/andrey271192/PCA_Phobos"
|
||||||
|
APK_TAG = "v1.4.0"
|
||||||
WARP_DIR = f"{PHOBOS_DIR}/server/warp"
|
WARP_DIR = f"{PHOBOS_DIR}/server/warp"
|
||||||
WARP_CUSTOM_PROFILE_FILE = f"{WARP_DIR}/custom-profile.conf"
|
WARP_CUSTOM_PROFILE_FILE = f"{WARP_DIR}/custom-profile.conf"
|
||||||
WARP_LICENSE_FILE = f"{WARP_DIR}/license.key"
|
WARP_LICENSE_FILE = f"{WARP_DIR}/license.key"
|
||||||
@@ -1058,26 +1062,17 @@ def _find_update_runner():
|
|||||||
|
|
||||||
|
|
||||||
def _restore_update_script(ref):
|
def _restore_update_script(ref):
|
||||||
repo, branch = _update_repo_for_ref(ref)
|
_repo, branch = _update_repo_for_ref(ref)
|
||||||
token = ""
|
kind = "tag" if branch.startswith("v") else "branch"
|
||||||
try:
|
r = None
|
||||||
token = Path(GH_TOKEN_FILE).read_text().strip()
|
for url in (f"{PCA_GIT}/raw/{kind}/{branch}/update.sh", f"{PCA_GH_RAW}/{branch}/update.sh"):
|
||||||
except Exception:
|
r = subprocess.run(["curl", "-fsSL", "-m", "25", f"{url}?cb={int(time.time())}"],
|
||||||
pass
|
capture_output=True, text=True, timeout=35)
|
||||||
cmd = ["curl", "-fsSL", "-m", "25"]
|
if r.returncode == 0 and (r.stdout or "").startswith("#!"):
|
||||||
if repo.endswith("-dev") and token:
|
break
|
||||||
cmd += ["-H", f"Authorization: token {token}"]
|
if r is None or r.returncode != 0 or not (r.stdout or "").startswith("#!"):
|
||||||
cmd += ["-H", "Accept: application/vnd.github.raw"]
|
return False, f"update helper restore failed for {branch}: {(r.stderr if r else '') or 'download failed'}"
|
||||||
url = f"https://api.github.com/repos/{repo}/contents/update.sh?ref={branch}"
|
repo = PCA_GIT
|
||||||
else:
|
|
||||||
if token:
|
|
||||||
cmd += ["-H", f"Authorization: token {token}"]
|
|
||||||
url = f"https://raw.githubusercontent.com/{repo}/{branch}/update.sh?cb={int(time.time())}"
|
|
||||||
cmd.append(url)
|
|
||||||
r = subprocess.run(cmd, capture_output=True, text=True, timeout=35)
|
|
||||||
if r.returncode != 0 or not (r.stdout or "").startswith("#!"):
|
|
||||||
hint = "subscriber token missing or invalid" if repo.endswith("-dev") and not token else (r.stderr or "download failed")
|
|
||||||
return False, f"update helper restore failed from {repo}/{branch}: {hint}"
|
|
||||||
os.makedirs(os.path.dirname(UPDATE_SCRIPT), exist_ok=True)
|
os.makedirs(os.path.dirname(UPDATE_SCRIPT), exist_ok=True)
|
||||||
tmp = UPDATE_SCRIPT + ".tmp"
|
tmp = UPDATE_SCRIPT + ".tmp"
|
||||||
Path(tmp).write_text(r.stdout)
|
Path(tmp).write_text(r.stdout)
|
||||||
@@ -1812,7 +1807,7 @@ textarea::placeholder{color:var(--muted)}
|
|||||||
</div>
|
</div>
|
||||||
CONTENT
|
CONTENT
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<b style="color:var(--accent)">PCA Phobos Panel</b> — панель управления © <a href="https://github.com/andrey271192/PCA_Phobos" target="_blank" rel="noopener">andrey271192</a><br>
|
<b style="color:var(--accent)">PCA Phobos Panel</b> — панель управления © <a href="https://git.bobyrev.com/PCA/PCA_Phobos" target="_blank" rel="noopener">andrey271192</a><br>
|
||||||
Поддержать проект: <a href="https://boosty.to/andrey27/donate" target="_blank" rel="noopener">💖 Boosty</a> · <a href="https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798" target="_blank" rel="noopener">💳 Ozon Bank</a> · <a href="https://t.me/PCAdministration" target="_blank" rel="noopener">✉️ Telegram</a>
|
Поддержать проект: <a href="https://boosty.to/andrey27/donate" target="_blank" rel="noopener">💖 Boosty</a> · <a href="https://finance.ozon.ru/apps/sbp/ozonbankpay/019dc200-2a5d-7931-a619-782d285f6798" target="_blank" rel="noopener">💳 Ozon Bank</a> · <a href="https://t.me/PCAdministration" target="_blank" rel="noopener">✉️ Telegram</a>
|
||||||
<div style="margin-top:8px;font-size:.88em;color:var(--muted);line-height:1.7;text-align:left;max-width:660px;margin:8px auto 0">
|
<div style="margin-top:8px;font-size:.88em;color:var(--muted);line-height:1.7;text-align:left;max-width:660px;margin:8px auto 0">
|
||||||
<b>Создано на основе открытых проектов:</b><br>
|
<b>Создано на основе открытых проектов:</b><br>
|
||||||
@@ -2785,7 +2780,7 @@ def settings_page():
|
|||||||
f'<div class="form-row"><label>{_html_attr(sv["ip"])}{" ★" if sv.get("is_primary") else ""}</label>'
|
f'<div class="form-row"><label>{_html_attr(sv["ip"])}{" ★" if sv.get("is_primary") else ""}</label>'
|
||||||
f'<input type="text" name="ep_{_html_attr(sv["ip"])}" value="{_html_attr(eps.get(sv["ip"], ""))}" placeholder="{_html_attr(sv["ip"])}" style="width:260px"></div>'
|
f'<input type="text" name="ep_{_html_attr(sv["ip"])}" value="{_html_attr(eps.get(sv["ip"], ""))}" placeholder="{_html_attr(sv["ip"])}" style="width:260px"></div>'
|
||||||
for sv in get_all_servers_ordered())
|
for sv in get_all_servers_ordered())
|
||||||
cascade_cmd = f"bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/server/phobos-cascade.sh) enable {SERVER_IP} {_load_server_env().get('OBFUSCATOR_PORTS', '2083,5443,993')}"
|
cascade_cmd = f"bash <(curl -fsSL {PCA_GIT}/raw/branch/main/server/phobos-cascade.sh) enable {SERVER_IP} {_load_server_env().get('OBFUSCATOR_PORTS', '2083,5443,993')}"
|
||||||
extras_html = f"""
|
extras_html = f"""
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>{tr("Домен панели","Panel domain")} {hlp("Панель по адресу https://ваш-домен/ с бесплатным сертификатом Let's Encrypt (nginx на 443). Домен (A-запись) должен указывать на IP этого сервера, порт 80 открыт. Старый адрес http://IP:порт продолжает работать — роутеры и второй сервер ничего не заметят.", "Panel at https://your-domain/ with a free Let's Encrypt certificate (nginx on 443). The domain A record must point to this server, port 80 open. The old http://IP:port keeps working — routers and secondaries notice nothing.")}</h2>
|
<h2>{tr("Домен панели","Panel domain")} {hlp("Панель по адресу https://ваш-домен/ с бесплатным сертификатом Let's Encrypt (nginx на 443). Домен (A-запись) должен указывать на IP этого сервера, порт 80 открыт. Старый адрес http://IP:порт продолжает работать — роутеры и второй сервер ничего не заметят.", "Panel at https://your-domain/ with a free Let's Encrypt certificate (nginx on 443). The domain A record must point to this server, port 80 open. The old http://IP:port keeps working — routers and secondaries notice nothing.")}</h2>
|
||||||
@@ -2847,7 +2842,7 @@ def settings_page():
|
|||||||
<b style="color:#22c55e">stable</b> — {tr("стабильная","stable")} ·
|
<b style="color:#22c55e">stable</b> — {tr("стабильная","stable")} ·
|
||||||
<b style="color:#eab308">beta</b> — {tr("тест","testing")} ·
|
<b style="color:#eab308">beta</b> — {tr("тест","testing")} ·
|
||||||
<b style="color:#f97316">dev</b> — {tr("разработка","development")}.
|
<b style="color:#f97316">dev</b> — {tr("разработка","development")}.
|
||||||
{tr("stable — без токена. Для beta/dev вставь токен подписчика (по подписке Boosty), сохрани — и жми канал.","stable needs no token. For beta/dev paste your subscriber token (Boosty), save it, then click the channel.")}</p>
|
{tr("С 1.4.0 все каналы открыты и берутся с git.bobyrev.com (GitHub — запасной). Токен больше не нужен.","Since 1.4.0 all channels are open and served from git.bobyrev.com (GitHub as fallback). No token needed.")}</p>
|
||||||
<form method="post" class="form-row" style="margin-bottom:8px">
|
<form method="post" class="form-row" style="margin-bottom:8px">
|
||||||
<input type="hidden" name="action" value="save_token">
|
<input type="hidden" name="action" value="save_token">
|
||||||
<input type="password" name="gh_token" placeholder="{tr('токен подписчика (для beta/dev)','subscriber token (for beta/dev)')}" style="width:240px" autocomplete="off">
|
<input type="password" name="gh_token" placeholder="{tr('токен подписчика (для beta/dev)','subscriber token (for beta/dev)')}" style="width:240px" autocomplete="off">
|
||||||
@@ -3298,45 +3293,13 @@ def sync_missing_peers_to_secondaries(server=None):
|
|||||||
@app.route("/download/apk")
|
@app.route("/download/apk")
|
||||||
@auth_required
|
@auth_required
|
||||||
def download_apk():
|
def download_apk():
|
||||||
"""Proxy PhobosWG APK from GitHub release using saved subscriber token."""
|
"""PhobosWG APK: local copy if the server has one, else the release on Gitea."""
|
||||||
local = "/opt/Phobos/www/app/PhobosWG.apk"
|
local = "/opt/Phobos/www/app/PhobosWG.apk"
|
||||||
if os.path.exists(local):
|
if os.path.exists(local):
|
||||||
from flask import send_file
|
from flask import send_file
|
||||||
return send_file(local, as_attachment=True, download_name="PhobosWG.apk",
|
return send_file(local, as_attachment=True, download_name="PhobosWG.apk",
|
||||||
mimetype="application/vnd.android.package-archive")
|
mimetype="application/vnd.android.package-archive")
|
||||||
try:
|
return redirect(f"{PCA_GIT}/releases/download/{APK_TAG}/PhobosWG.apk")
|
||||||
gh_token = open("/opt/phobos-panel/.gh_token").read().strip()
|
|
||||||
except Exception:
|
|
||||||
gh_token = ""
|
|
||||||
if not gh_token:
|
|
||||||
# stable / no subscriber token: public release asset
|
|
||||||
return redirect("https://github.com/andrey271192/PCA_Phobos/releases/latest/download/PhobosWG.apk")
|
|
||||||
import urllib.request as _ur, ssl as _ssl, json as _json
|
|
||||||
_ctx = _ssl.create_default_context(); _ctx.check_hostname=False; _ctx.verify_mode=_ssl.CERT_NONE
|
|
||||||
try:
|
|
||||||
# /releases (all, incl. prereleases) — /releases/latest excludes prereleases
|
|
||||||
# and the beta APK release is a prerelease -> 404. Scan all releases for .apk.
|
|
||||||
_api = _ur.Request(
|
|
||||||
"https://api.github.com/repos/andrey271192/PCA_Phobos-dev/releases?per_page=20",
|
|
||||||
headers={"Authorization": f"token {gh_token}", "Accept": "application/vnd.github+json"})
|
|
||||||
_rels = _json.loads(_ur.urlopen(_api, context=_ctx, timeout=10).read())
|
|
||||||
if isinstance(_rels, dict):
|
|
||||||
_rels = [_rels]
|
|
||||||
_url = None
|
|
||||||
for _rel in _rels:
|
|
||||||
_url = next((a["url"] for a in _rel.get("assets", []) if a["name"].endswith(".apk")), None)
|
|
||||||
if _url:
|
|
||||||
break
|
|
||||||
if not _url:
|
|
||||||
return "APK asset not found in any release", 404
|
|
||||||
_req = _ur.Request(_url, headers={"Authorization": f"token {gh_token}",
|
|
||||||
"Accept": "application/octet-stream"})
|
|
||||||
_resp = _ur.urlopen(_req, context=_ctx, timeout=120)
|
|
||||||
from flask import Response
|
|
||||||
return Response(_resp.read(), mimetype="application/vnd.android.package-archive",
|
|
||||||
headers={"Content-Disposition": "attachment; filename=PhobosWG.apk"})
|
|
||||||
except Exception as e:
|
|
||||||
return f"APK download failed: {e}", 500
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/client/<cid>/conf/<mode>")
|
@app.route("/client/<cid>/conf/<mode>")
|
||||||
@@ -3385,7 +3348,7 @@ def client_phone(cid, mode):
|
|||||||
else:
|
else:
|
||||||
apk_btn = (f'<p style="margin-top:6px"><a href="/download/apk" class="btn btn-primary" '
|
apk_btn = (f'<p style="margin-top:6px"><a href="/download/apk" class="btn btn-primary" '
|
||||||
f'style="background:#16a34a">📥 {tr("Скачать PhobosWG (APK)","Download PhobosWG (APK)")}</a></p>')
|
f'style="background:#16a34a">📥 {tr("Скачать PhobosWG (APK)","Download PhobosWG (APK)")}</a></p>')
|
||||||
client_btn = (f'<p style="margin-top:6px"><a href="https://github.com/andrey271192/PCA_Phobos/releases/latest/download/PCA-Phobos-VPN.apk" '
|
client_btn = (f'<p style="margin-top:6px"><a href="{PCA_GIT}/releases/download/{APK_TAG}/PCA-Phobos-VPN.apk" '
|
||||||
f'class="btn btn-primary" target="_blank" rel="noopener">🛡 {tr("PCA Phobos VPN — наше приложение (раздельный трафик)","PCA Phobos VPN — our app (split tunnelling)")}</a></p>'
|
f'class="btn btn-primary" target="_blank" rel="noopener">🛡 {tr("PCA Phobos VPN — наше приложение (раздельный трафик)","PCA Phobos VPN — our app (split tunnelling)")}</a></p>'
|
||||||
f'<p style="font-size:.8em;color:var(--muted)">{tr("Поставь любое из двух приложений и открой ссылку ниже на телефоне — профиль импортируется сам.","Install either app and open the link below on the phone — the profile imports itself.")}</p>')
|
f'<p style="font-size:.8em;color:var(--muted)">{tr("Поставь любое из двух приложений и открой ссылку ниже на телефоне — профиль импортируется сам.","Install either app and open the link below on the phone — the profile imports itself.")}</p>')
|
||||||
extra = (client_btn + apk_btn +
|
extra = (client_btn + apk_btn +
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ Native HTTPS is supported by the primary installer:
|
|||||||
```bash
|
```bash
|
||||||
PANEL_TLS_CERT=/etc/letsencrypt/live/example.com/fullchain.pem \
|
PANEL_TLS_CERT=/etc/letsencrypt/live/example.com/fullchain.pem \
|
||||||
PANEL_TLS_KEY=/etc/letsencrypt/live/example.com/privkey.pem \
|
PANEL_TLS_KEY=/etc/letsencrypt/live/example.com/privkey.pem \
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/install.sh)
|
bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
|
||||||
```
|
```
|
||||||
|
|
||||||
Then the panel runs as:
|
Then the panel runs as:
|
||||||
|
|||||||
72
install.sh
72
install.sh
@@ -3,7 +3,7 @@
|
|||||||
# PCA Phobos — TURNKEY installer (primary / panel node)
|
# PCA Phobos — TURNKEY installer (primary / panel node)
|
||||||
#
|
#
|
||||||
# One command, all dependencies, from a clean VPS:
|
# One command, all dependencies, from a clean VPS:
|
||||||
# bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/install.sh)
|
# bash <(curl -fsSL https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/install.sh)
|
||||||
#
|
#
|
||||||
# Installs, in order:
|
# Installs, in order:
|
||||||
# deps -> wg-obfuscator (Ground-Zerro) -> WireGuard wg0 ->
|
# deps -> wg-obfuscator (Ground-Zerro) -> WireGuard wg0 ->
|
||||||
@@ -30,33 +30,19 @@ TG_TOKEN="${TG_TOKEN:-}"
|
|||||||
TG_CHAT="${TG_CHAT:-}"
|
TG_CHAT="${TG_CHAT:-}"
|
||||||
OBF_PORTS="${OBF_PORTS:-2083,5443,993}"
|
OBF_PORTS="${OBF_PORTS:-2083,5443,993}"
|
||||||
SERVER_WG_IPV4_NETWORK="${SERVER_WG_IPV4_NETWORK:-10.25.0.0/16}"
|
SERVER_WG_IPV4_NETWORK="${SERVER_WG_IPV4_NETWORK:-10.25.0.0/16}"
|
||||||
# Каналы: stable (открытый, публичный repo) · beta (тест) · dev (разработка).
|
# Источник: Gitea git.bobyrev.com (основной), GitHub — запасной.
|
||||||
# beta и dev живут в ПРИВАТНОМ repo PCA_Phobos-dev — доступ по токену подписчика
|
# Каналы stable/beta/dev — ветки main/beta/dev одного публичного репозитория.
|
||||||
# (GH_TOKEN, read-only, выдаётся по подписке Boosty). stable — без токена.
|
PCA_GIT="${PCA_GIT:-https://git.bobyrev.com/PCA/PCA_Phobos}"
|
||||||
GH_TOKEN="${GH_TOKEN:-}"
|
GH_RAW="${GH_RAW:-https://raw.githubusercontent.com/andrey271192/PCA_Phobos}"
|
||||||
PUB_REPO="andrey271192/PCA_Phobos"
|
|
||||||
DEV_REPO="andrey271192/PCA_Phobos-dev"
|
|
||||||
PHOBOSWG_APK_TAG="v1.3.0-beta"
|
|
||||||
PHOBOSWG_APK_SHA256="5399de7c576d56e491a01ab9b52d53c08d30a34d1156c1cb0f4520bf34821e02"
|
|
||||||
CHANNEL="${CHANNEL:-stable}"
|
CHANNEL="${CHANNEL:-stable}"
|
||||||
case "$CHANNEL" in
|
case "$CHANNEL" in
|
||||||
beta) REPO="$DEV_REPO"; PCA_BRANCH="${PCA_BRANCH:-beta}";;
|
stable|main|"") PCA_BRANCH="${PCA_BRANCH:-main}";;
|
||||||
dev) REPO="$DEV_REPO"; PCA_BRANCH="${PCA_BRANCH:-dev}";;
|
*) PCA_BRANCH="${PCA_BRANCH:-$CHANNEL}";;
|
||||||
stable|main|"") REPO="$PUB_REPO"; PCA_BRANCH="${PCA_BRANCH:-main}";;
|
|
||||||
*) REPO="$PUB_REPO"; PCA_BRANCH="${PCA_BRANCH:-$CHANNEL}";;
|
|
||||||
esac
|
esac
|
||||||
if [ "$REPO" = "$DEV_REPO" ] && [ -z "$GH_TOKEN" ]; then
|
case "$PCA_BRANCH" in v[0-9]*) _kind=tag;; *) _kind=branch;; esac
|
||||||
echo "Канал '$CHANNEL' закрыт — это $([ "$CHANNEL" = dev ] && echo 'разработка (нестабильно)' || echo 'бета (тест)'), приватный репозиторий."
|
|
||||||
echo "Нужен read-only токен подписчика:"
|
|
||||||
echo " GH_TOKEN=ваш_токен CHANNEL=$CHANNEL bash <(curl -fsSL https://raw.githubusercontent.com/$PUB_REPO/main/install.sh)"
|
|
||||||
echo "Токен выдаётся по подписке: https://boosty.to/andrey27"
|
|
||||||
echo "Стабильная версия ставится без токена (CHANNEL=stable, по умолчанию)."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
[ "$REPO" = "$DEV_REPO" ] && echo "Токен принят — закрытый канал '$CHANNEL' (приватный repo)."
|
|
||||||
PHOBOS_DIR="/opt/Phobos"
|
PHOBOS_DIR="/opt/Phobos"
|
||||||
PANEL_DIR="/opt/phobos-panel"
|
PANEL_DIR="/opt/phobos-panel"
|
||||||
RAW="https://raw.githubusercontent.com/${REPO}/${PCA_BRANCH}"
|
RAW="$PCA_GIT/raw/$_kind/$PCA_BRANCH"
|
||||||
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
[ "$EUID" -eq 0 ] || { echo "Run as root"; exit 1; }
|
[ "$EUID" -eq 0 ] || { echo "Run as root"; exit 1; }
|
||||||
@@ -235,12 +221,8 @@ fetch() {
|
|||||||
mkdir -p "$(dirname "$2")"
|
mkdir -p "$(dirname "$2")"
|
||||||
# ponytail: файл из архива рядом с install.sh — не ходим в сеть.
|
# ponytail: файл из архива рядом с install.sh — не ходим в сеть.
|
||||||
if [ -f "$SRC/$1" ]; then cp -f "$SRC/$1" "$2" && return 0; fi
|
if [ -f "$SRC/$1" ]; then cp -f "$SRC/$1" "$2" && return 0; fi
|
||||||
_url="$RAW/$1?cb=$(date +%s)"
|
curl -fsSL -m20 "$RAW/$1?cb=$(date +%s)" -o "$2" && return 0
|
||||||
if [ -n "$GH_TOKEN" ]; then
|
curl -fsSL -m20 "$GH_RAW/$PCA_BRANCH/$1?cb=$(date +%s)" -o "$2" && return 0
|
||||||
curl -fsSL -m20 -H "Authorization: token $GH_TOKEN" "$_url" -o "$2" && return 0
|
|
||||||
else
|
|
||||||
curl -fsSL -m20 "$_url" -o "$2" && return 0
|
|
||||||
fi
|
|
||||||
echo " WARN: fetch $1 failed"; return 1
|
echo " WARN: fetch $1 failed"; return 1
|
||||||
}
|
}
|
||||||
fetch overlay/lib-core.sh "$PHOBOS_DIR/repo/server/scripts/lib-core.sh" && chmod +x "$PHOBOS_DIR/repo/server/scripts/lib-core.sh"
|
fetch overlay/lib-core.sh "$PHOBOS_DIR/repo/server/scripts/lib-core.sh" && chmod +x "$PHOBOS_DIR/repo/server/scripts/lib-core.sh"
|
||||||
@@ -345,39 +327,9 @@ fi
|
|||||||
|
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# ── PhobosWG APK (beta/dev only: fetch from private release asset) ──
|
# persist channel so phobos-update follows it
|
||||||
if [ "$REPO" = "$DEV_REPO" ] && [ -n "$GH_TOKEN" ]; then
|
|
||||||
mkdir -p "$PHOBOS_DIR/www/app"
|
|
||||||
_apk="$PHOBOS_DIR/www/app/PhobosWG.apk"
|
|
||||||
_cur_sha="$(sha256sum "$_apk" 2>/dev/null | awk '{print $1}')"
|
|
||||||
if [ "$_cur_sha" != "$PHOBOSWG_APK_SHA256" ]; then
|
|
||||||
echo "[APK] Refreshing PhobosWG.apk from release $PHOBOSWG_APK_TAG..."
|
|
||||||
_apk_api_url=$(curl -fsSL -m15 -H "Authorization: token $GH_TOKEN" \
|
|
||||||
"https://api.github.com/repos/$DEV_REPO/releases/tags/$PHOBOSWG_APK_TAG" 2>/dev/null \
|
|
||||||
| grep -B8 '"name": "PhobosWG.apk"' | grep '"url"' | head -1 | cut -d'"' -f4)
|
|
||||||
if [ -n "$_apk_api_url" ] && curl -fsSL -m120 -H "Authorization: token $GH_TOKEN" \
|
|
||||||
-H "Accept: application/octet-stream" "$_apk_api_url" -o "$_apk"; then
|
|
||||||
_new_sha="$(sha256sum "$_apk" 2>/dev/null | awk '{print $1}')"
|
|
||||||
if [ "$_new_sha" = "$PHOBOSWG_APK_SHA256" ]; then
|
|
||||||
echo "[APK] Downloaded PhobosWG.apk: $(ls -lh "$_apk" | awk '{print $5}')"
|
|
||||||
else
|
|
||||||
rm -f "$_apk"
|
|
||||||
echo "[APK] SHA mismatch after download (non-fatal)"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "[APK] Download failed (non-fatal)"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "[APK] PhobosWG.apk current"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# persist channel + subscriber token so phobos-update can reach private channels
|
|
||||||
mkdir -p "$PANEL_DIR"
|
mkdir -p "$PANEL_DIR"
|
||||||
echo "$CHANNEL" > "$PANEL_DIR/.channel" 2>/dev/null || true
|
echo "$CHANNEL" > "$PANEL_DIR/.channel" 2>/dev/null || true
|
||||||
if [ "$REPO" = "$DEV_REPO" ] && [ -n "$GH_TOKEN" ]; then
|
|
||||||
( umask 077; printf %s "$GH_TOKEN" > "$PANEL_DIR/.gh_token" )
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "============================================"
|
echo "============================================"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
set -uo pipefail
|
set -uo pipefail
|
||||||
STATE=/etc/phobos-cascade.env
|
STATE=/etc/phobos-cascade.env
|
||||||
BIN=/usr/local/sbin/phobos-cascade
|
BIN=/usr/local/sbin/phobos-cascade
|
||||||
SELF_URL="${SELF_URL:-https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/server/phobos-cascade.sh}"
|
SELF_URL="${SELF_URL:-https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/main/server/phobos-cascade.sh}"
|
||||||
TAG="phobos-cascade"
|
TAG="phobos-cascade"
|
||||||
|
|
||||||
clear_rules() {
|
clear_rules() {
|
||||||
|
|||||||
@@ -289,16 +289,11 @@ EOF
|
|||||||
echo "[6/7] Setting up mini-API..."
|
echo "[6/7] Setting up mini-API..."
|
||||||
# Mini-API (fetched from the main panel first, then PCA GitHub fallback)
|
# Mini-API (fetched from the main panel first, then PCA GitHub fallback)
|
||||||
PCA_BRANCH="${PCA_BRANCH:-main}"
|
PCA_BRANCH="${PCA_BRANCH:-main}"
|
||||||
PCA_REPO="${PCA_REPO:-andrey271192/PCA_Phobos}"
|
RAW="${PCA_RAW_BASE:-https://git.bobyrev.com/PCA/PCA_Phobos/raw/branch/${PCA_BRANCH}}"
|
||||||
RAW="${PCA_RAW_BASE:-https://raw.githubusercontent.com/${PCA_REPO}/${PCA_BRANCH}}"
|
|
||||||
PANEL_BOOTSTRAP="${MAIN_PROTO}://${MAIN_SERVER}:${MAIN_PORT}/server/api.py"
|
PANEL_BOOTSTRAP="${MAIN_PROTO}://${MAIN_SERVER}:${MAIN_PORT}/server/api.py"
|
||||||
if ! curl -kfsSL "$PANEL_BOOTSTRAP" -o "$PHOBOS_DIR/server/api.py"; then
|
curl -kfsSL "$PANEL_BOOTSTRAP" -o "$PHOBOS_DIR/server/api.py" \
|
||||||
if [ -n "${GH_TOKEN:-}" ]; then
|
|| curl -fsSL "$RAW/server/api.py" -o "$PHOBOS_DIR/server/api.py" \
|
||||||
curl -fsSL -H "Authorization: token $GH_TOKEN" "$RAW/server/api.py" -o "$PHOBOS_DIR/server/api.py"
|
|| curl -fsSL "https://raw.githubusercontent.com/andrey271192/PCA_Phobos/${PCA_BRANCH}/server/api.py" -o "$PHOBOS_DIR/server/api.py"
|
||||||
else
|
|
||||||
curl -fsSL "$RAW/server/api.py" -o "$PHOBOS_DIR/server/api.py"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
[ -s "$PHOBOS_DIR/server/api.py" ] || { echo "ERROR: api.py fetch failed"; exit 1; }
|
[ -s "$PHOBOS_DIR/server/api.py" ] || { echo "ERROR: api.py fetch failed"; exit 1; }
|
||||||
|
|
||||||
cat > /etc/systemd/system/phobos-api.service << EOF
|
cat > /etc/systemd/system/phobos-api.service << EOF
|
||||||
|
|||||||
101
update.sh
101
update.sh
@@ -3,19 +3,14 @@
|
|||||||
# PCA Phobos — updater / rollback
|
# PCA Phobos — updater / rollback
|
||||||
#
|
#
|
||||||
# phobos-update # обновить до стабильной (канал stable / main)
|
# phobos-update # обновить до стабильной (канал stable / main)
|
||||||
# phobos-update stable # стабильный канал (публичный, без токена)
|
# phobos-update stable|beta|dev # канал (ветка main/beta/dev)
|
||||||
# GH_TOKEN=... phobos-update beta # бета-канал (приватный, по токену подписчика)
|
|
||||||
# GH_TOKEN=... phobos-update dev # канал разработки (приватный, по токену)
|
|
||||||
# phobos-update v1.2.4 # конкретная версия (git tag)
|
# phobos-update v1.2.4 # конкретная версия (git tag)
|
||||||
# phobos-update --rollback # откатить на предыдущую версию (из бэкапа)
|
# phobos-update --rollback # откатить на предыдущую версию (из бэкапа)
|
||||||
# phobos-update --check # установленная + версии всех каналов
|
# phobos-update --check # установленная + версии всех каналов
|
||||||
# phobos-update --list # список бэкапов для отката
|
# phobos-update --list # список бэкапов для отката
|
||||||
#
|
#
|
||||||
# Каналы:
|
# Источник: Gitea git.bobyrev.com/PCA/PCA_Phobos (основной), GitHub — запасной.
|
||||||
# stable -> публичный репозиторий andrey271192/PCA_Phobos (открыт)
|
# Свой адрес: PCA_GIT=https://… phobos-update
|
||||||
# beta / dev -> приватный andrey271192/PCA_Phobos-dev (только подписчики)
|
|
||||||
# Для beta/dev нужен read-only токен подписчика: env GH_TOKEN или файл
|
|
||||||
# $PANEL_DIR/.gh_token (сохраняется при установке закрытого канала).
|
|
||||||
#
|
#
|
||||||
# Обновляет ТОЛЬКО PCA-слой (панель + скрипты). НЕ трогает ключи WireGuard,
|
# Обновляет ТОЛЬКО PCA-слой (панель + скрипты). НЕ трогает ключи WireGuard,
|
||||||
# server.env, клиентов. Перед каждым обновлением — бэкап; откат восстанавливает.
|
# server.env, клиентов. Перед каждым обновлением — бэкап; откат восстанавливает.
|
||||||
@@ -23,10 +18,8 @@
|
|||||||
set -e
|
set -e
|
||||||
PHOBOS_DIR=/opt/Phobos
|
PHOBOS_DIR=/opt/Phobos
|
||||||
PANEL_DIR=/opt/phobos-panel
|
PANEL_DIR=/opt/phobos-panel
|
||||||
PUB_REPO=andrey271192/PCA_Phobos
|
PCA_GIT="${PCA_GIT:-https://git.bobyrev.com/PCA/PCA_Phobos}"
|
||||||
DEV_REPO=andrey271192/PCA_Phobos-dev
|
GH_RAW="${GH_RAW:-https://raw.githubusercontent.com/andrey271192/PCA_Phobos}"
|
||||||
PHOBOSWG_APK_TAG="v1.3.0-beta"
|
|
||||||
PHOBOSWG_APK_SHA256="5399de7c576d56e491a01ab9b52d53c08d30a34d1156c1cb0f4520bf34821e02"
|
|
||||||
BACKUPS="$PHOBOS_DIR/updates"
|
BACKUPS="$PHOBOS_DIR/updates"
|
||||||
VERFILE="$PANEL_DIR/.version"
|
VERFILE="$PANEL_DIR/.version"
|
||||||
CUR=$(cat "$VERFILE" 2>/dev/null || echo "unknown")
|
CUR=$(cat "$VERFILE" 2>/dev/null || echo "unknown")
|
||||||
@@ -46,30 +39,14 @@ restart_panel_service() {
|
|||||||
systemctl restart "$svc" 2>/dev/null || true
|
systemctl restart "$svc" 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# repo for a ref/channel: beta/dev/*-beta/*-dev -> private, остальное -> public
|
# since 1.4.0 all channels are branches of one public repo (no subscriber token)
|
||||||
repo_for() { case "$1" in beta|dev|*-beta|*-dev) echo "$DEV_REPO";; *) echo "$PUB_REPO";; esac; }
|
is_private() { return 1; }
|
||||||
is_private() { case "$1" in beta|dev|*-beta|*-dev) return 0;; *) return 1;; esac; }
|
|
||||||
# curl with token header only when ref is a private channel
|
|
||||||
gh_curl() { # $1=ref, rest=curl args
|
|
||||||
local ref="$1"; shift
|
|
||||||
if is_private "$ref" && [ -n "$GH_TOKEN" ]; then
|
|
||||||
curl -H "Authorization: token $GH_TOKEN" "$@"
|
|
||||||
else
|
|
||||||
curl "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch_repo_file() { # $1=ref $2=repo_path $3=output
|
fetch_repo_file() { # $1=ref $2=repo_path $3=output ; Gitea first, GitHub fallback
|
||||||
local ref="$1" rp="$2" out="$3" repo
|
local ref="$1" rp="$2" out="$3" kind=branch
|
||||||
repo=$(repo_for "$ref")
|
case "$ref" in v[0-9]*) kind=tag;; esac
|
||||||
if is_private "$ref" && [ -n "$GH_TOKEN" ]; then
|
curl -fsSL -m25 "$PCA_GIT/raw/$kind/$ref/$rp?cb=$(date +%s)" -o "$out" 2>/dev/null && return 0
|
||||||
curl -fsSL -m25 -H "Authorization: token $GH_TOKEN" \
|
curl -fsSL -m25 "$GH_RAW/$ref/$rp?cb=$(date +%s)" -o "$out"
|
||||||
-H "Accept: application/vnd.github.raw" \
|
|
||||||
"https://api.github.com/repos/$repo/contents/$rp?ref=$ref" -o "$out"
|
|
||||||
else
|
|
||||||
gh_curl "$ref" -fsSL -m25 \
|
|
||||||
"https://raw.githubusercontent.com/$repo/$ref/$rp?cb=$(date +%s)" -o "$out"
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch_repo_text() { # $1=ref $2=repo_path
|
fetch_repo_text() { # $1=ref $2=repo_path
|
||||||
@@ -81,38 +58,6 @@ fetch_repo_text() { # $1=ref $2=repo_path
|
|||||||
return "$rc"
|
return "$rc"
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh_phoboswg_apk() { # $1=ref/channel
|
|
||||||
local ref="${1:-}"
|
|
||||||
is_private "$ref" || return 0
|
|
||||||
[ -n "$GH_TOKEN" ] || return 0
|
|
||||||
local apk="$PHOBOS_DIR/www/app/PhobosWG.apk"
|
|
||||||
mkdir -p "$PHOBOS_DIR/www/app"
|
|
||||||
local cur_sha
|
|
||||||
cur_sha="$(sha256sum "$apk" 2>/dev/null | awk '{print $1}')"
|
|
||||||
if [ "$cur_sha" = "$PHOBOSWG_APK_SHA256" ]; then
|
|
||||||
echo "[APK] PhobosWG.apk current"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
echo "[APK] Refreshing PhobosWG.apk from release $PHOBOSWG_APK_TAG..."
|
|
||||||
local apk_api_url
|
|
||||||
apk_api_url="$(curl -fsSL -m15 -H "Authorization: token $GH_TOKEN" \
|
|
||||||
"https://api.github.com/repos/$DEV_REPO/releases/tags/$PHOBOSWG_APK_TAG" 2>/dev/null \
|
|
||||||
| grep -B8 '"name": "PhobosWG.apk"' | grep '"url"' | head -1 | cut -d'"' -f4)"
|
|
||||||
if [ -n "$apk_api_url" ] && curl -fsSL -m120 -H "Authorization: token $GH_TOKEN" \
|
|
||||||
-H "Accept: application/octet-stream" "$apk_api_url" -o "$apk"; then
|
|
||||||
local new_sha
|
|
||||||
new_sha="$(sha256sum "$apk" 2>/dev/null | awk '{print $1}')"
|
|
||||||
if [ "$new_sha" = "$PHOBOSWG_APK_SHA256" ]; then
|
|
||||||
echo "[APK] Downloaded PhobosWG.apk: $(ls -lh "$apk" | awk '{print $5}')"
|
|
||||||
else
|
|
||||||
rm -f "$apk"
|
|
||||||
echo "[APK] SHA mismatch after download (non-fatal)"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "[APK] Download failed (non-fatal)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
managed_files() {
|
managed_files() {
|
||||||
cat <<LIST
|
cat <<LIST
|
||||||
$PANEL_DIR/app.py|app.py
|
$PANEL_DIR/app.py|app.py
|
||||||
@@ -180,7 +125,7 @@ chan_version() { # $1 = ref(channel)
|
|||||||
if is_private "$1" && [ -z "$GH_TOKEN" ]; then echo ""; return; fi
|
if is_private "$1" && [ -z "$GH_TOKEN" ]; then echo ""; return; fi
|
||||||
fetch_repo_text "$1" VERSION 2>/dev/null | tr -d ' \r\n'
|
fetch_repo_text "$1" VERSION 2>/dev/null | tr -d ' \r\n'
|
||||||
}
|
}
|
||||||
latest_version() { curl -fsSL -m10 "https://raw.githubusercontent.com/$PUB_REPO/main/VERSION" 2>/dev/null | tr -d ' \r\n'; }
|
latest_version() { fetch_repo_text main VERSION 2>/dev/null | tr -d ' \r\n'; }
|
||||||
|
|
||||||
do_backup() {
|
do_backup() {
|
||||||
local dir="$BACKUPS/${CUR}-$(date +%Y%m%d-%H%M%S)"
|
local dir="$BACKUPS/${CUR}-$(date +%Y%m%d-%H%M%S)"
|
||||||
@@ -244,24 +189,13 @@ case "${1:-}" in
|
|||||||
--version|-v|--check)
|
--version|-v|--check)
|
||||||
echo "Установлено: $CUR"
|
echo "Установлено: $CUR"
|
||||||
echo "Стабильная: $(latest_version) [открытый]"
|
echo "Стабильная: $(latest_version) [открытый]"
|
||||||
b=$(chan_version beta); d=$(chan_version dev)
|
echo "Бета (beta): $(chan_version beta)"
|
||||||
if [ -n "$GH_TOKEN" ]; then
|
echo "Разработка(dev):$(chan_version dev)"
|
||||||
[ -n "$b" ] && echo "Бета (beta): $b [приватный, токен ок]"
|
|
||||||
[ -n "$d" ] && echo "Разработка(dev):$d [приватный, токен ок]"
|
|
||||||
else
|
|
||||||
echo "Бета (beta): — [приватный: нужен GH_TOKEN подписчика]"
|
|
||||||
echo "Разработка(dev):— [приватный: нужен GH_TOKEN подписчика]"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
--versions|--tags)
|
--versions|--tags)
|
||||||
echo "Стабильные версии (публичные теги):"
|
echo "Версии (теги):"
|
||||||
curl -fsSL -m10 "https://api.github.com/repos/$PUB_REPO/tags?per_page=100" 2>/dev/null \
|
curl -fsSL -m10 "${PCA_GIT%/*/*}/api/v1/repos/${PCA_GIT#*://*/}/tags?limit=100" 2>/dev/null \
|
||||||
| grep -oE '"name": *"[^"]+"' | sed 's/.*"name": *"\(.*\)"/ \1/' || echo " (нет данных)"
|
| grep -oE '"name": *"[^"]+"' | sed 's/.*"name": *"\(.*\)"/ \1/' || echo " (нет данных)"
|
||||||
if [ -n "$GH_TOKEN" ]; then
|
|
||||||
echo "Закрытые версии (приватные теги, beta/dev):"
|
|
||||||
curl -fsSL -m10 -H "Authorization: token $GH_TOKEN" "https://api.github.com/repos/$DEV_REPO/tags?per_page=100" 2>/dev/null \
|
|
||||||
| grep -oE '"name": *"[^"]+"' | sed 's/.*"name": *"\(.*\)"/ \1/' || echo " (нет данных)"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
--list)
|
--list)
|
||||||
echo "Бэкапы (для отката):"
|
echo "Бэкапы (для отката):"
|
||||||
@@ -316,7 +250,6 @@ case "${1:-}" in
|
|||||||
b=$(do_backup); echo "Бэкап: $b"
|
b=$(do_backup); echo "Бэкап: $b"
|
||||||
apply_ref "$ref"
|
apply_ref "$ref"
|
||||||
ensure_runtime_deps
|
ensure_runtime_deps
|
||||||
refresh_phoboswg_apk "$ref"
|
|
||||||
run_self_check
|
run_self_check
|
||||||
refresh_router_packages
|
refresh_router_packages
|
||||||
echo "$target" > "$VERFILE"
|
echo "$target" > "$VERFILE"
|
||||||
|
|||||||
Reference in New Issue
Block a user