Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c1a9513
release: Xrayebator 0.5.5
Ap3x0s Sep 24, 2026
2801fb9
fix(ci): ставить libsecret в job test релизного workflow
Ap3x0s Sep 24, 2026
26c27ac
ci(release): preflight-проверка токена и текста релиза, публикация от…
Ap3x0s Sep 25, 2026
21fed1b
docs(testing): описать preflight и выбор автора релиза в release.yml
Ap3x0s Sep 25, 2026
67764d1
ci(release): preflight не валит выкатку, а выбирает автора через output
Ap3x0s Sep 25, 2026
c0d4083
CLI: revoke/expire/bypass-groups — серверный слой для трёх новых GUI-фич
Ap3x0s Sep 28, 2026
e5b8d3c
CLI: bypass groups отдаёт домены, + bypass unbundle (выключение групп)
Ap3x0s Sep 28, 2026
4d09047
GUI: revoke подписки, срок действия профилей, bypass-группы
Ap3x0s Sep 28, 2026
df6cff9
Docs: revoke/срок/bypass больше не «недоступные» возможности GUI
Ap3x0s Sep 28, 2026
091dffe
CLI: revoke/expire/bypass-groups — серверный слой для трёх новых GUI-фич
Ap3x0s Sep 28, 2026
df78876
CLI: bypass groups отдаёт домены, + bypass unbundle (выключение групп)
Ap3x0s Sep 28, 2026
ad0d0fa
GUI: revoke подписки, срок действия профилей, bypass-группы
Ap3x0s Sep 28, 2026
8d74db2
Docs: revoke/срок/bypass больше не «недоступные» возможности GUI
Ap3x0s Sep 28, 2026
2070c62
Docs: синхронизация README/troubleshooting/security/architecture/CHAN…
Ap3x0s Sep 28, 2026
c8101be
Docs: синхронизация README/troubleshooting/security/architecture/CHAN…
Ap3x0s Sep 28, 2026
b2348b8
GUI: предупреждение «скоро истекает» за 3 дня до автоотключения
Ap3x0s Sep 28, 2026
70af718
GUI: предупреждение «скоро истекает» за 3 дня до автоотключения
Ap3x0s Sep 28, 2026
33f4771
Merge main into dev: синхронизация истории перед работой над фичами
Ap3x0s Sep 28, 2026
de805da
Fix: почему фичи «не работали» — старая ветка на сервере + три бага UX
Ap3x0s Sep 28, 2026
aab3296
UI: стабильный календарь, кнопки срока, локальный дефолт updater → dev
Ap3x0s Sep 28, 2026
e01d795
Удаление bypass-подсистемы + 410 Gone для истёкших профилей + календарь
Ap3x0s Sep 28, 2026
7210ebf
Возврат bypass в исходном виде (без наших доработок и без GUI)
Ap3x0s Sep 28, 2026
43363fc
Фикс: ячейка календаря вылезала за рамку (aspect-ratio внутри фикс-вы…
Ap3x0s Sep 28, 2026
e6df138
Возврат дефолта обновления на main (сервер остаётся на dev через .cur…
Ap3x0s Sep 28, 2026
7c98f96
Календарь: квадратные боксы дат, шестая неделя раскрывается вниз
Ap3x0s Sep 28, 2026
8dd1926
Docs: 410 для истёкших сроков и поля профиля (ru/en/zh)
Ap3x0s Sep 28, 2026
e96b78b
Срок действия: время включительное + фикс восьмеричной ловушки bash
Ap3x0s Sep 28, 2026
d84e851
Документация: включительный срок и время сервера (ru/en/zh)
Ap3x0s Sep 28, 2026
17c695e
Timezone срока: сервер отдаёт календарную дату для GUI
Ap3x0s Sep 29, 2026
eb58d85
Документация: описать expire_date и несовпадающие часовые зоны
Ap3x0s Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@

User-facing Xrayebator changes. The server manager and Electron application are published from the canonical `howdeploy/Xrayebator` repository.

## [Unreleased]

### Added

- Subscription revocation in Server settings: a per-profile button opens a menu with two modes. "New link only" reissues the `sub_token`; "full revocation" also rotates the uuid in every inbound of the profile, so devices that already downloaded the configuration are cut off immediately — the only way to actually close access through a leaked link.
- Profile expiry dates: `profile-create --expire`, `profile-expire`, the `expire` field in the profile JSON, a date chip and editor in the GUI, plus server-side enforcement — a `xrayebator-expire.timer` systemd unit runs `xrayebator expire-check` every 10 minutes and switches an expired profile off (the client is removed from the inbounds and restored on renewal).
- The subscription-userinfo `expire` header now has a UI path: HAPP and other clients display the date handed out by the subscription.

### Fixed

- Expired or disabled profiles now receive `410 Gone` instead of subscription routes.
- A date-only profile expiry now includes the selected day through `23:59:59` in the server's local timezone; explicit times use that timezone as entered. The server returns its own `expire_date` for GUI display, so a desktop in a different timezone still shows the selected server-local calendar day (covered by a UTC−7 server / UTC+14 client regression test). Date/time fields with leading zeroes such as September (`09`) are accepted correctly.

## [0.5.5] - 2026-09-25

Connecting to servers that already run Xrayebator, plus fixes found while testing on a live VPS.
Expand Down
11 changes: 7 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Xrayebator — automated Xray Reality VPN manager for bypassing DPI censorship i
## Validation

There IS automated test coverage (despite what older notes said):
- **`validation/`** — 26 Bash test scripts, including `test-main-readiness-regressions.sh`, covering migrations, VLESS URL generation, transaction safety, dedup, firewall, menu numbering, the bypass/sni-change/port-change CLIs, quickstart, email/inspect regressions, apt-lock race regressions and audit regressions. They run on the host (`bash validation/test-*.sh`); CI installs `jq`, `uuidgen` and `ripgrep` on Ubuntu. A bare Windows Git Bash checkout is not equivalent to the Linux environment.
- **`validation/`** — 28 Bash test scripts, including `test-main-readiness-regressions.sh`, covering migrations, VLESS URL generation, transaction safety, dedup, firewall, menu numbering, the bypass/sni-change/port-change/profile-revoke/profile-expire CLIs, quickstart, email/inspect regressions, apt-lock race regressions and audit regressions. They run on the host (`bash validation/test-*.sh`); CI installs `jq`, `uuidgen` and `ripgrep` on Ubuntu. A bare Windows Git Bash checkout is not equivalent to the Linux environment.
- **`gui-legacy/tests/`** — 16 pytest modules covering SSH, deploy, connection, subscription and TUN runtime (legacy PySide6 GUI). Run with the GUI venv: `gui-legacy/.venv/Scripts/python -m pytest gui-legacy/tests`.
- **GUI (Electron)** — Vitest unit tests in `tests/`: `npm test`, plus `npm run typecheck`.
- **CI** — `.github/workflows/ci-linux.yml` runs the full `validation/` suite; `.github/workflows/gui-release.yml` runs `ruff` + `pytest gui-legacy/tests` and builds Windows/macOS bundles; `.github/workflows/release.yml` ships the Electron app.
Expand Down Expand Up @@ -139,14 +139,17 @@ Apart from the interactive menu (`sudo xrayebator`), the script exposes subcomma
- `xrayebator inspect --json` — read-only install probe for the GUI "connect existing server" import: reports manager/Xray/profiles/subscription markers as one JSON object on stdout (diagnostics to stderr only). It must not migrate, install, restart, open firewall or write anything; `validation/test-quickstart-email-and-inspect.sh` guards these invariants statically.
- `xrayebator happ-setup` — reduced existing-install HAPP path; ensures the subscription service and a usable multi-route profile, verifies a real public TLS endpoint when subscription markers are missing, and prints JSON with `subscription_url`. It does not have the same migration breadth as quickstart.
- `xrayebator probe-test` — probe-test candidate SNIs from `sni_list.txt` and print reachability scores.
- `xrayebator profiles` — print all profiles as a flat JSON array (used by the GUI "Server settings" page).
- `xrayebator profile-create --name NAME [--transport T] [--port P] [--count N]` — create 1..N profiles non-interactively (names `name`, `name-2`, ...). Emits `{"ok":true,"names":[...],"errors":[...]}`; `ok` stays `true` even when some profiles already exist (they land in `errors`).
- `xrayebator profiles` — print all profiles as a flat JSON array (used by the GUI "Server settings" page); each entry carries `expire` (epoch seconds, `0` = unlimited), server-local `expire_date` (`YYYY-MM-DD`) for display, and `expire_disabled`.
- `xrayebator profile-create --name NAME [--transport T] [--port P] [--count N] [--expire DATE]` — create 1..N profiles non-interactively (names `name`, `name-2`, ...). `--expire` accepts `YYYY-MM-DD[ HH:MM]`, epoch seconds or 13-digit milliseconds; date-only expiry is inclusive through `23:59:59` in server-local time, while an explicit time uses server-local time as given. Dates/times with leading-zero fields such as `09` are parsed as decimal, not octal. A past expiry is rejected. Emits `{"ok":true,"names":[...],"errors":[...]}`; `ok` stays `true` even when some profiles already exist (they land in `errors`).
- `xrayebator profile-delete --name NAME` — delete a profile, emits `{"ok":true,"name":"..."}`. Inbound/firewall cleanup happens automatically.
- `xrayebator profile-revoke --name NAME [--full]` — reissue the subscription `sub_token`; `--full` also rotates the uuid in every inbound of the profile, so already-downloaded configs stop connecting. Transaction order matters: config + `safe_restart_xray` first, then the profile JSON, and a failed profile write rolls the config back from the transaction backup.
- `xrayebator profile-expire --name NAME --expire DATE|epoch|none` — set/extend/clear a profile expiry (`.expire` epoch seconds); date-only expiry is inclusive through `23:59:59` in server-local time; an explicit time is also interpreted in server-local time. Applied immediately (an expired profile loses its client, an extension restores it).
- `xrayebator expire-check` — batch enforcement of every due expiry; idempotent (no changes ⇒ no Xray restart), driven by `xrayebator-expire.timer` every 10 minutes. Disabling keeps the inbounds alive (a fresh inbound would change the shortId and kill issued URLs) and snapshots clients into `.expire_clients` for restoration.
- `xrayebator fp-change --name NAME [--route R] --fp FINGERPRINT` — change the fingerprint for a profile (client-side, no Xray restart), emits JSON.
- `xrayebator sni-change --name NAME [--route R] --sni SNI` — change the SNI for a profile; updates all profiles on the same port (`update_all_profiles_on_port()`), emits JSON.
- `xrayebator sni-list` — print the SNI candidates from `sni_list.txt` grouped by category, emits JSON (used by the GUI SNI dialog).
- `xrayebator port-change --name NAME [--route R] --port PORT|random` — change the port for a profile; updates the inbound, firewall, subscription and all profiles on the port, emits JSON (reconnect is required).
- `xrayebator bypass list|add --domain D|remove --domain D|reset|bundle [--group a,b,c]` — manage bypass routing groups (JSON).
- `xrayebator bypass list|add --domain D|remove --domain D|reset|bundle [--group a,b,c]` — manage bypass routing groups (JSON). Server-side only: it exists for cascade deployments, where the catch-all points at the upstream; without a cascade the built-in catch-all already sends everything direct.

CLI JSON hygiene: `profile-create`/`profile-delete` **must** print only JSON on stdout. The shared helpers (`backup_config`, `add_inbound`, `open_firewall_port`, `safe_restart_xray`, `close_firewall_port`) print colored status lines that would corrupt the parse, so the CLI paths redirect stdout→stderr around those calls (`exec 3>&1; exec 1>&2 ... exec 1>&3`). Keep it that way when editing.

Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ vless:// list — HAPP receives 6 of the profile's 7 routes
▼
Reality inbound on a port in 30000-60000 (User=xray, CAP_NET_BIND_SERVICE)
│
├─ domain in an enabled bypass group ──► freedom (direct, no VPN)
│
└─ all other tcp/udp ─────────────────► direct
OR cascade-upstream ──► foreign VPS
Expand Down Expand Up @@ -294,12 +293,13 @@ What the GUI can do:
| Add server | Deploy a new VPS with an explicit email choice: `quickstart --email` or `quickstart --without-email`; save the server and public subscription |
| Connect existing | Import a recognized Xrayebator installation over SSH (password or key) using read-only `xrayebator inspect --json`; partial installs are saved with diagnostics, without automatic repair |
| Server keys | Refresh the public subscription, copy the URL, show `vless://` links and QR codes |
| Server settings | SSH access by password or private key, direct root or sudo; list/create/delete profiles, change fingerprint, SNI and port, plus update or uninstall Xrayebator on the server |
| Server settings | SSH access by password or private key, direct root or sudo; list/create/delete profiles, change fingerprint, SNI and port, revoke the subscription, set a profile expiry date, plus update or uninstall Xrayebator on the server. Expiry dates are displayed in the server's timezone even when the desktop uses another one |

Root + password is the one-click default; key authentication and sudo are optional. A selected private key and a successfully used SSH login password are stored in the operating-system keychain via `keytar` and reused across later SSH operations and app restarts; the server card keeps only their non-secret credential ids and display name. A distinct sudo password and an encrypted-key passphrase are never persisted and are requested again when needed. If the OS keychain is unavailable, there is no plaintext fallback: the secret remains in main-process memory for the current app session and the UI warns that it must be entered again after restart. The app also persists the `subscription_url`, fetched `vless://` links and pinned SSH host-key fingerprint. The subscription URL and VLESS links are bearer/client credentials: protect local app data and revoke the subscription through the terminal workflow after a leak.
Root + password is the one-click default; key authentication and sudo are optional. A selected private key and a successfully used SSH login password are stored in the operating-system keychain via `keytar` and reused across later SSH operations and app restarts; the server card keeps only their non-secret credential ids and display name. A distinct sudo password and an encrypted-key passphrase are never persisted and are requested again when needed. If the OS keychain is unavailable, there is no plaintext fallback: the secret remains in main-process memory for the current app session and the UI warns that it must be entered again after restart. The app also persists the `subscription_url`, fetched `vless://` links and pinned SSH host-key fingerprint. The subscription URL and VLESS links are bearer/client credentials: protect local app data and revoke the subscription from Server settings (full revocation rotates the key as well) after a leak.

The GUI exposes only a subset of the terminal menu. Bypass, `probe-test`, subscription revoke,
`happ-setup`, cascade, self-steal and service logs/status remain terminal-only. See
The GUI exposes only a subset of the terminal menu. Bypass, `probe-test`, `happ-setup`, cascade,
self-steal and service logs/status remain terminal-only; profile expiry dates and subscription
revocation are available in Server settings. See
[Electron Desktop GUI](docs/desktop-gui.md) for the complete boundary, security model and packaging details.

Build and run in the development mode:
Expand Down
10 changes: 5 additions & 5 deletions README.ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ xrayebator-sub.service 127.0.0.1:8080
▼
Reality-инбаунд на порту 30000-60000 (User=xray, CAP_NET_BIND_SERVICE)
│
├─ домен из включённой bypass-группы ──► freedom (напрямую, без VPN)
│
└─ весь остальной tcp/udp ────────────► direct
ИЛИ cascade-upstream ──► зарубежный VPS
Expand Down Expand Up @@ -290,12 +289,13 @@ xrayebator (bash) ──► /usr/local/etc/xray/
| Добавить сервер | Развернуть VPS с явным выбором email: `quickstart --email` или `quickstart --without-email`; сохранить сервер и публичную подписку |
| Подключить существующий | Импорт распознанной установки Xrayebator по SSH (пароль или ключ) через read-only `xrayebator inspect --json`; частичные установки сохраняются с диагностикой без автоисправления |
| Ключи сервера | Обновить публичную подписку, скопировать URL, показать ссылки `vless://` и QR-коды |
| Настройки сервера | SSH по паролю или приватному ключу, прямой root или sudo; список/создание/удаление профилей, смена fingerprint, SNI и порта, обновление или удаление Xrayebator |
| Настройки сервера | SSH по паролю или приватному ключу, прямой root или sudo; список/создание/удаление профилей, смена fingerprint, SNI и порта, отзыв подписки, срок действия профиля, обновление или удаление Xrayebator; дата срока показывается по часовой зоне сервера даже при другом поясе на компьютере |

Выбранные приватный ключ и успешно использованный SSH-пароль сохраняются через `keytar` в системном keychain и повторно используются при следующих SSH-операциях и после перезапуска приложения; в карточке сервера хранятся только несекретные credential id и отображаемое имя ключа. Отдельный sudo-пароль и passphrase зашифрованного ключа не сохраняются и запрашиваются заново. Если системный keychain недоступен, plaintext-фолбека нет: секрет остаётся в памяти main process до завершения текущего сеанса, а GUI предупреждает, что после перезапуска его нужно ввести снова. Также локально сохраняются `subscription_url`, ссылки `vless://` и закреплённый SSH host-key fingerprint. Это bearer/client credentials: защищайте локальные данные и при утечке отзывайте подписку через терминальный workflow.
Выбранные приватный ключ и успешно использованный SSH-пароль сохраняются через `keytar` в системном keychain и повторно используются при следующих SSH-операциях и после перезапуска приложения; в карточке сервера хранятся только несекретные credential id и отображаемое имя ключа. Отдельный sudo-пароль и passphrase зашифрованного ключа не сохраняются и запрашиваются заново. Если системный keychain недоступен, plaintext-фолбека нет: секрет остаётся в памяти main process до завершения текущего сеанса, а GUI предупреждает, что после перезапуска его нужно ввести снова. Также локально сохраняются `subscription_url`, ссылки `vless://` и закреплённый SSH host-key fingerprint. Это bearer/client credentials: защищайте локальные данные и при утечке отзывайте подписку в настройках сервера (полный отзыв меняет и ключ).

GUI предоставляет только подмножество терминального меню. Bypass, `probe-test`, revoke подписки,
`happ-setup`, каскад, self-steal и логи/статус сервисов остаются терминальными операциями. Полная
GUI предоставляет только подмножество терминального меню. `probe-test`, `happ-setup`, каскад,
self-steal и логи/статус сервисов остаются терминальными операциями; сроки действия профилей
и отзыв подписки доступны в настройках сервера. Полная
граница возможностей, security model и packaging описаны в [справочнике Electron GUI](docs/ru/desktop-gui.md).

Сборка и запуск в dev-режиме:
Expand Down
Loading
Loading