From d072c8227f0a26457b6df04c05ab6fb9b5f58756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=80=D0=B5=D0=B2?= Date: Sun, 31 May 2026 01:12:32 +0300 Subject: [PATCH] feat: private dev/beta channels via subscriber token (repo split) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closed channels (beta, dev) now live in a separate PRIVATE repository andrey271192/PCA_Phobos-dev. Access is gated by a read-only subscriber GH_TOKEN (distributed via Boosty) instead of a shared hash key — the token both authenticates the private raw fetch AND acts as the gate, so there is a single secret and the code is genuinely hidden (public repo holds stable/main only). install.sh: CHANNEL=beta|dev -> private repo, requires GH_TOKEN, persists it to $PANEL_DIR/.gh_token + writes .channel. stable stays public/no-token. update.sh: per-ref repo routing (repo_for), gh_curl injects the token for private channels, token read from env or saved .gh_token, --check/--versions reflect public vs private, stable path unchanged and tokenless. Co-Authored-By: Claude Opus 4.8 --- install.sh | 49 ++++++++++++++---------- update.sh | 110 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 105 insertions(+), 54 deletions(-) diff --git a/install.sh b/install.sh index 8774084..6909a17 100755 --- a/install.sh +++ b/install.sh @@ -25,31 +25,31 @@ PANEL_PASS="${PANEL_PASS:-OcAdmin2026!}" TG_TOKEN="${TG_TOKEN:-}" TG_CHAT="${TG_CHAT:-}" OBF_PORTS="${OBF_PORTS:-2083,5443,993}" -# Каналы: stable (открытый, ветка main) · beta (тест) · dev (разработка). -# beta и dev ЗАКРЫТЫ ключом подписчика PHOBOS_KEY (по подписке Boosty). stable — без ключа. +# Каналы: stable (открытый, публичный repo) · beta (тест) · dev (разработка). +# beta и dev живут в ПРИВАТНОМ repo PCA_Phobos-dev — доступ по токену подписчика +# (GH_TOKEN, read-only, выдаётся по подписке Boosty). stable — без токена. +GH_TOKEN="${GH_TOKEN:-}" +PUB_REPO="andrey271192/PCA_Phobos" +DEV_REPO="andrey271192/PCA_Phobos-dev" CHANNEL="${CHANNEL:-stable}" -if [ -z "${PCA_BRANCH:-}" ]; then - case "$CHANNEL" in beta) PCA_BRANCH="beta";; dev) PCA_BRANCH="dev";; stable|main|"") PCA_BRANCH="main";; *) PCA_BRANCH="$CHANNEL";; esac -fi -PHOBOS_KEY_HASH="cb3ce498b8d2c67ec7b57a9b08ed2fb410c881bcb9bc9cf50d09be1d9727333a" -case "$PCA_BRANCH" in - beta|dev) - _got=$(printf %s "${PHOBOS_KEY:-}" | { sha256sum 2>/dev/null || shasum -a 256; } | cut -d' ' -f1) - if [ "$_got" != "$PHOBOS_KEY_HASH" ]; then - echo "Канал '$CHANNEL' закрыт — это $([ "$CHANNEL" = dev ] && echo 'разработка (нестабильно)' || echo 'бета (тест)')." - echo "Нужен ключ подписчика:" - echo " PHOBOS_KEY=ваш_ключ CHANNEL=$CHANNEL bash <(curl -fsSL https://raw.githubusercontent.com/andrey271192/PCA_Phobos/main/install.sh)" - echo "Ключ выдаётся по подписке: https://boosty.to/andrey27" - echo "Стабильная версия ставится без ключа (CHANNEL=stable, по умолчанию)." - exit 1 - fi - echo "Ключ принят — канал '$CHANNEL'." - ;; +case "$CHANNEL" in + beta) REPO="$DEV_REPO"; PCA_BRANCH="${PCA_BRANCH:-beta}";; + dev) REPO="$DEV_REPO"; PCA_BRANCH="${PCA_BRANCH:-dev}";; + stable|main|"") REPO="$PUB_REPO"; PCA_BRANCH="${PCA_BRANCH:-main}";; + *) REPO="$PUB_REPO"; PCA_BRANCH="${PCA_BRANCH:-$CHANNEL}";; esac -GH_TOKEN="${GH_TOKEN:-}" # set for private-repo installs; empty for public +if [ "$REPO" = "$DEV_REPO" ] && [ -z "$GH_TOKEN" ]; then + 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" PANEL_DIR="/opt/phobos-panel" -RAW="https://raw.githubusercontent.com/andrey271192/PCA_Phobos/${PCA_BRANCH}" +RAW="https://raw.githubusercontent.com/${REPO}/${PCA_BRANCH}" [ "$EUID" -eq 0 ] || { echo "Run as root"; exit 1; } @@ -260,6 +260,13 @@ if [ -f "$PHOBOS_DIR/server/phobos-router-watchdog.py" ]; then fi sleep 2 +# persist channel + subscriber token so phobos-update can reach private channels +mkdir -p "$PANEL_DIR" +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 " Installation complete" diff --git a/update.sh b/update.sh index 4bf4824..eefe609 100755 --- a/update.sh +++ b/update.sh @@ -2,24 +2,47 @@ # ============================================================ # PCA Phobos — updater / rollback # -# phobos-update # обновить до последней версии (main) -# phobos-update v1.1.0 # обновить до конкретной версии (git tag) +# phobos-update # обновить до стабильной (канал stable / main) +# phobos-update stable # стабильный канал (публичный, без токена) +# GH_TOKEN=... phobos-update beta # бета-канал (приватный, по токену подписчика) +# GH_TOKEN=... phobos-update dev # канал разработки (приватный, по токену) +# phobos-update v1.2.4 # конкретная версия (git tag) # phobos-update --rollback # откатить на предыдущую версию (из бэкапа) -# phobos-update --version # показать установленную и последнюю версию +# phobos-update --check # установленная + версии всех каналов # phobos-update --list # список бэкапов для отката # -# Обновляет ТОЛЬКО PCA-слой (панель + скрипты онбординга/служебные). -# НЕ трогает ключи WireGuard, server.env, клиентов — они сохраняются. -# Перед каждым обновлением делает бэкап; откат восстанавливает его. +# Каналы: +# stable -> публичный репозиторий andrey271192/PCA_Phobos (открыт) +# beta / dev -> приватный andrey271192/PCA_Phobos-dev (только подписчики) +# Для beta/dev нужен read-only токен подписчика: env GH_TOKEN или файл +# $PANEL_DIR/.gh_token (сохраняется при установке закрытого канала). +# +# Обновляет ТОЛЬКО PCA-слой (панель + скрипты). НЕ трогает ключи WireGuard, +# server.env, клиентов. Перед каждым обновлением — бэкап; откат восстанавливает. # ============================================================ set -e PHOBOS_DIR=/opt/Phobos PANEL_DIR=/opt/phobos-panel -REPO=andrey271192/PCA_Phobos -RAW="https://raw.githubusercontent.com/$REPO" +PUB_REPO=andrey271192/PCA_Phobos +DEV_REPO=andrey271192/PCA_Phobos-dev BACKUPS="$PHOBOS_DIR/updates" VERFILE="$PANEL_DIR/.version" CUR=$(cat "$VERFILE" 2>/dev/null || echo "unknown") +# Токен подписчика для приватных каналов: env > сохранённый файл +GH_TOKEN="${GH_TOKEN:-$(cat "$PANEL_DIR/.gh_token" 2>/dev/null || true)}" + +# repo for a ref/channel: beta/dev/*-beta/*-dev -> private, остальное -> public +repo_for() { case "$1" in beta|dev|*-beta|*-dev) echo "$DEV_REPO";; *) echo "$PUB_REPO";; esac; } +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 +} managed_files() { cat </dev/null | tr -d ' \r\n'; } +# fetch VERSION of a channel (public repos / or private if token present) +chan_version() { # $1 = ref(channel) + local repo; repo=$(repo_for "$1"); local repo_ref="$1" + if is_private "$1" && [ -z "$GH_TOKEN" ]; then echo ""; return; fi + gh_curl "$1" -fsSL -m8 "https://raw.githubusercontent.com/$repo/$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'; } do_backup() { local dir="$BACKUPS/${CUR}-$(date +%Y%m%d-%H%M%S)" @@ -48,10 +77,12 @@ do_backup() { } apply_ref() { - local ref="$1" + local ref="$1"; local repo; repo=$(repo_for "$ref") + local repo_ref="$ref" + local RAW="https://raw.githubusercontent.com/$repo/$ref" managed_files | while IFS='|' read -r lp rp; do local tmp; tmp=$(mktemp) - if curl -fsSL -m25 "$RAW/$ref/$rp" -o "$tmp" && [ -s "$tmp" ]; then + if gh_curl "$ref" -fsSL -m25 "$RAW/$rp" -o "$tmp" && [ -s "$tmp" ]; then mkdir -p "$(dirname "$lp")"; mv "$tmp" "$lp" case "$lp" in *.sh|*.py) chmod +x "$lp" 2>/dev/null || true;; esac else @@ -60,21 +91,33 @@ apply_ref() { done } -ref_exists() { curl -fsSL -m12 "$RAW/$1/app.py" -o /dev/null 2>/dev/null; } +ref_exists() { + local repo; repo=$(repo_for "$1"); local repo_ref="$1" + gh_curl "$1" -fsSL -m12 "https://raw.githubusercontent.com/$repo/$1/app.py" -o /dev/null 2>/dev/null +} case "${1:-}" in --version|-v|--check) echo "Установлено: $CUR" - echo "Стабильная: $(latest_version)" - beta=$(curl -fsSL -m8 "$RAW/beta/VERSION" 2>/dev/null | tr -d ' \r\n') - [ -n "$beta" ] && echo "Бета (beta): $beta [закрыт ключом]" - dev=$(curl -fsSL -m8 "$RAW/dev/VERSION" 2>/dev/null | tr -d ' \r\n') - [ -n "$dev" ] && echo "Разработка(dev):$dev [закрыт ключом]" + echo "Стабильная: $(latest_version) [открытый]" + b=$(chan_version beta); d=$(chan_version dev) + if [ -n "$GH_TOKEN" ]; then + [ -n "$b" ] && echo "Бета (beta): $b [приватный, токен ок]" + [ -n "$d" ] && echo "Разработка(dev):$d [приватный, токен ок]" + else + echo "Бета (beta): — [приватный: нужен GH_TOKEN подписчика]" + echo "Разработка(dev):— [приватный: нужен GH_TOKEN подписчика]" + fi ;; --versions|--tags) - echo "Доступные версии (git tags):" - curl -fsSL -m10 "https://api.github.com/repos/$REPO/tags?per_page=100" 2>/dev/null \ + echo "Стабильные версии (публичные теги):" + curl -fsSL -m10 "https://api.github.com/repos/$PUB_REPO/tags?per_page=100" 2>/dev/null \ | 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) echo "Бэкапы (для отката):" @@ -95,24 +138,25 @@ case "${1:-}" in *) ref="${1:-main}" case "$ref" in latest|stable) ref="main";; esac - # Каналы beta/dev закрыты ключом подписчика PHOBOS_KEY (Boosty) - case "$ref" in - beta|dev|*-beta|*-dev) - _got=$(printf %s "${PHOBOS_KEY:-}" | { sha256sum 2>/dev/null || shasum -a 256; } | cut -d' ' -f1) - if [ "$_got" != "cb3ce498b8d2c67ec7b57a9b08ed2fb410c881bcb9bc9cf50d09be1d9727333a" ]; then - echo "Канал '$ref' закрыт (бета/разработка). Нужен ключ подписчика:" - echo " PHOBOS_KEY=ваш_ключ phobos-update $ref" - echo "Ключ — по подписке: https://boosty.to/andrey27 . Стабильная: phobos-update stable" - exit 1 - fi - ;; - esac + # Каналы beta/dev — приватный репозиторий, нужен токен подписчика + if is_private "$ref" && [ -z "$GH_TOKEN" ]; then + echo "Канал '$ref' закрыт (бета/разработка) — приватный репозиторий." + echo "Нужен read-only токен подписчика:" + echo " GH_TOKEN=ваш_токен phobos-update $ref" + echo "Токен — по подписке: https://boosty.to/andrey27 . Стабильная (без токена): phobos-update stable" + exit 1 + fi if ! ref_exists "$ref"; then - echo "Версия/ветка '$ref' не найдена на GitHub. Обновление отменено (текущая $CUR не тронута)." + echo "Версия/ветка '$ref' не найдена (или токен неверный). Обновление отменено (текущая $CUR не тронута)." echo "Доступные: phobos-update --versions · стабильная: $(latest_version)" exit 1 fi - target=$(curl -fsSL -m10 "$RAW/$ref/VERSION" 2>/dev/null | tr -d ' \r\n'); [ -z "$target" ] && target="$ref" + # сохранить токен для будущих обновлений приватного канала + if is_private "$ref" && [ -n "$GH_TOKEN" ]; then + ( umask 077; printf %s "$GH_TOKEN" > "$PANEL_DIR/.gh_token" ) + fi + repo_ref="$ref" + target=$(gh_curl "$ref" -fsSL -m10 "https://raw.githubusercontent.com/$(repo_for "$ref")/$ref/VERSION" 2>/dev/null | tr -d ' \r\n'); [ -z "$target" ] && target="$ref" echo "Текущая: $CUR -> целевая: $target ($ref)" b=$(do_backup); echo "Бэкап: $b" apply_ref "$ref"