- C# 97.2%
- Shell 2.3%
- PowerShell 0.5%
| .forgejo/workflows | ||
| build | ||
| CaviCodeVPN.App | ||
| CaviCodeVPN.Core | ||
| CaviCodeVPN.Infrastructure | ||
| docs | ||
| .gitignore | ||
| AGENTS.md | ||
| CaviCodeVPN.Desktop.sln | ||
| global.json | ||
| NuGet.Config | ||
| README.md | ||
CaviCode VPN Desktop
Десктопный GUI-клиент для VPN-протокола TrustTunnel (Avalonia UI + .NET 8).
Приложение — графическая оболочка над CLI-бинарником trusttunnel_client:
управляет процессом через System.Diagnostics.Process, парсит stdout/stderr в реальном времени,
ведёт историю соединений и логи в SQLite.
Поддерживаемые платформы: Windows 10+ (x64) · Linux x64/arm64 (Alt Linux, Ubuntu 20.04+, Debian 11+).
Содержание
- Требования
- Структура репозитория
- Быстрый старт
- Сборка
- Запуск
- Функциональность
- Настройки и данные
- Архитектура
- Разработка
- Лицензия
Требования
- .NET 8 SDK (версия зафиксирована в global.json —
8.0.121,rollForward: latestFeature). - Git — для клонирования репозитория.
- TrustTunnel Client — не требуется для сборки, нужен только в рантайме:
- Linux:
/opt/trusttunnel/trusttunnel_client - Windows:
C:\Program Files\TrustTunnel\trusttunnel_client.exe - Либо любой путь из
PATH, либо указанный вручную в Настройки → TrustTunnel. - Установить клиент можно прямо из GUI на вкладке Установщик (скачает релиз с GitHub).
- Linux:
На Linux дополнительно нужны GTK/X11-библиотеки (обычно уже стоят в десктоп-дистрибутиве) и polkit/pkexec для эскалации привилегий.
Структура репозитория
CaviCodeVPN-Desktop/
├── CaviCodeVPN.Desktop.sln # Solution
├── CaviCodeVPN.App/ # Avalonia UI, точка входа, ViewModels, Views
├── CaviCodeVPN.Core/ # Модели, перечисления, интерфейсы (без зависимостей)
├── CaviCodeVPN.Infrastructure/ # SQLite, Process IPC, HTTP, платформо-специфика
├── global.json # Пин версии .NET SDK
└── NuGet.Config # Источники пакетов (nuget.org)
CaviCodeVPN.Core
Чистая библиотека без внешних зависимостей.
| Путь | Содержимое |
|---|---|
Enums/ |
VpnStatus, NavigationItem, AppTheme, AppThemeMode, SessionStatus, LogLevel, RoutingAction, UpdatePolicy, … |
Interfaces/ |
ITrustTunnelService, IConnectionActivityRepository, ISessionRepository, ILogRepository, IConfigRepository, ISettingsService, IUpdateService, IPlatformService, … |
Models/ |
VpnState, VpnConfig, ConnectionActivity, ConnectionSession, LogEntry, AppSettings, RoutingRule, UpdateInfo, … |
CaviCodeVPN.Infrastructure
| Путь | Содержимое |
|---|---|
Services/TrustTunnelService.cs |
Управление процессом trusttunnel_client, парсинг логов, публикация VpnState через SimpleSubject<T> |
Services/InstallerService.cs |
Скачивание и установка бинарника с GitHub Releases |
Services/UpdateService.cs |
Проверка обновлений через Octokit |
Services/DeeplinkService.cs |
Декодирование tt://-URI, NamedPipe для single-instance |
Services/SettingsService.cs |
Чтение/запись settings.json |
Repositories/ |
ConnectionActivityRepository, SessionRepository, LogRepository, ConfigRepository, EventRepository — всё через Dapper + SQLite |
Database/DatabaseInitializer.cs |
Идемпотентная инициализация схемы, retention-очистка |
Platform/ |
WindowsPlatformService, LinuxPlatformService |
CaviCodeVPN.App
| Путь | Содержимое |
|---|---|
Program.cs |
Точка входа: эскалация прав, deeplink, DI-контейнер, Avalonia host |
App.axaml.cs |
Инициализация темы/языка, трей, диалог обновлений, определение запущенных туннелей |
Views/MainWindow.axaml |
Корневое окно: кастомный хром, навигация (два ListBox), resize-ручки |
ViewModels/MainWindowViewModel.cs |
Корневая VM: маршрутизация навигации, онбординг, туториал |
Views/ |
Dashboard, Configs, Filtering, Logs, History, Diagnostics, Installer, Settings, About, Onboarding, Tutorial, Updater |
Services/ |
ThemeService, LocalizationService, TrayIconService, MessageBox, InMemoryLogSink |
Converters/ |
BytesToHumanReadableConverter, ConnectionActionToBrushConverter, VpnStatusToColorConverter, … |
Localization/ |
Strings.resx (RU, default), Strings.en.resx (EN) |
Быстрый старт
git clone <repo-url>
cd DSvinkaVPN-Desktop
dotnet restore
dotnet run --project CaviCodeVPN.App
При первом запуске приложение создаёт рабочий каталог:
| ОС | Путь |
|---|---|
| Windows | %AppData%\CaviCodeVPN\ |
| Linux | ~/.config/CaviCodeVPN/ |
Внутри: app.db, configs/, logs/, settings.json. Схема БД и retention выполняются автоматически.
Сборка
Debug
dotnet build CaviCodeVPN.Desktop.sln -c Debug
Release
dotnet build CaviCodeVPN.Desktop.sln -c Release
Self-contained (единый исполняемый файл)
Linux x64:
dotnet publish CaviCodeVPN.App -c Release -r linux-x64 \
--self-contained true -p:PublishSingleFile=true -o ./publish/linux-x64
Linux arm64: заменить -r linux-x64 на -r linux-arm64.
Windows x64:
dotnet publish CaviCodeVPN.App -c Release -r win-x64 ^
--self-contained true -p:PublishSingleFile=true -o .\publish\win-x64
Итоговый бинарник — publish/<rid>/CaviCodeVPN.App[.exe].
Запуск
Из исходников
dotnet run --project CaviCodeVPN.App
Из собранного бинарника
./publish/linux-x64/CaviCodeVPN.App # Linux
.\publish\win-x64\CaviCodeVPN.App.exe # Windows
Права администратора
trusttunnel_client поднимает TUN-адаптер и меняет системный DNS — нужны права root/admin.
- Windows — UAC при старте (
requireAdministratorвapp.manifest). Одно подтверждение — и всё приложение работает от администратора. - Linux — GUI работает от обычного пользователя (трей, DBus). При Connect бинарник запускается через
pkexec— polkit показывает графический промт. При Disconnect отправляет SIGTERM черезpkexec /bin/kill(непривилегированный процесс не может сигналить root-потомка).
Чтобы убрать промты совсем — выдать CAP_NET_ADMIN:
sudo setcap cap_net_admin,cap_net_raw=eip /opt/trusttunnel/trusttunnel_client
Обнаружение запущенных туннелей
При старте приложение проверяет наличие уже запущенных процессов trusttunnel_client.
Если найдены — показывает диалог с предложением закрыть их, чтобы избежать конфликта сетевых интерфейсов.
Deeplink tt://
CaviCodeVPN.App --deeplink "tt://import?config=<base64_toml>"
CaviCodeVPN.App "tt://import?config=<base64_toml>" # короткая форма
Если инстанс уже запущен — URI доставляется в него через NamedPipe, второй процесс завершается.
Функциональность
Дашборд
Отображает текущее состояние VPN (Disconnected / Connecting / Connected / Error),
активный профиль, время подключения, скорость и суммарный трафик сессии.
Кнопки Connect / Disconnect управляют процессом trusttunnel_client.
Перед запуском туннеля выполняется preflight-проверка: если не удаётся подключиться к Endpoint — отдельно различаются кейсы «нет интернета» и «Endpoint недоступен», с понятной ошибкой на Dashboard.
Конфигурации
Список профилей VPN в формате TOML (trusttunnel_client.toml).
Поддерживает создание, редактирование (встроенный текстовый редактор с подсветкой ошибок),
удаление и импорт через deeplink tt://.
Фильтрация
Управление правилами маршрутизации (RoutingRule): какой трафик пускать через туннель,
обходить (bypass) или блокировать.
Подключения (История)
Журнал соединений текущей и прошлых сессий из таблицы ConnectionActivity.
- Динамическая подгрузка: первые 200 записей грузятся сразу, следующие страницы — по мере прокрутки (каждые 15% от конца списка), максимум 1000 записей в памяти.
- Очистка при подключении: при каждом новом подключении список сбрасывается и показывает только текущую сессию.
- Авто-обновление: пока VPN активен — список обновляется каждые 5 секунд.
- Фильтры (работают на уровне SQL): поиск по домену/адресу, фильтр по протоколу (TCP/UDP) и действию (Tunnel / Bypass / Reject / Default / Destroyed).
- Сводка: суммарные счётчики соединений, отправленных и полученных байт.
- Экспорт в CSV.
Логи
Поток логов trusttunnel_client в реальном времени (через InMemoryLogSink Serilog).
Фильтрация по уровню и поиск по тексту. Экспорт в файл.
Диагностика
Набор автоматических проверок: доступность бинарника, версия, сетевые интерфейсы, права, TCP-досягаемость Endpoint и стабильность подключения (серия ICMP-пингов — потери, jitter, средний/максимальный RTT). Результат по каждому тесту — OK / Warning / Error, с экспортом отчёта.
Установщик
Проверяет GitHub Releases, скачивает и устанавливает свежую версию trusttunnel_client
(с прогресс-баром). Поддерживает Linux (tar.gz) и Windows (zip/exe).
Настройки
| Категория | Параметры |
|---|---|
| Интерфейс | Тема (SleepyPrincess / DemonessEngineer), режим (Light / Dark / System), язык (RU / EN) |
| Поведение | Сворачивать в трей при закрытии |
| Обновления | AutoInstall / NotifyOnly / Never |
| TrustTunnel | Путь к бинарнику trusttunnel_client |
Тема и язык применяются мгновенно (live-preview). Настройки сохраняются в settings.json.
Онбординг и туториал
При первом запуске — визард выбора темы и языка, обучающий тур по интерфейсу.
Системный трей
Иконка в трее с меню Connect/Disconnect и быстрым переключением профилей. Двойной клик — восстановить окно.
Обновления приложения
Фоновый воркер проверяет обновления при старте и раз в 24 часа.
При NotifyOnly показывает диалог с changelog (Markdown); при AutoInstall — устанавливает тихо.
Настройки и данные
| Файл / каталог | Назначение |
|---|---|
app.db |
SQLite: Sessions, LogEntries, AppEvents, ConnectionActivity, RoutingRules |
configs/*.toml |
Профили VPN |
logs/app-YYYYMMDD.log |
Логи приложения (Serilog, rolling daily, хранятся 14 дней) |
settings.json |
Тема, язык, политика обновлений, путь к бинарнику |
Retention по умолчанию: логи TrustTunnel — 30 дней, сессии и события — 90 дней.
Схема базы данных
Sessions -- VPN-сессии: время, профиль, статус, трафик
LogEntries -- Строки логов trusttunnel_client
AppEvents -- События приложения (старт, подключение, ошибки)
ConnectionActivity-- Соединения: домен, адрес, протокол, действие, байты
RoutingRules -- Правила маршрутизации (Filtering)
Архитектура
Стек
| Слой | Технологии |
|---|---|
| UI | Avalonia 11.2, FluentTheme, DataGrid, Material.Icons |
| MVVM | CommunityToolkit.Mvvm 8.3 (source generators, [ObservableProperty], [RelayCommand]) |
| DI | Microsoft.Extensions.DependencyInjection 8 |
| БД | SQLite (Microsoft.Data.Sqlite) + Dapper |
| Логирование | Serilog 4 (File + InMemorySink) |
| Обновления | Octokit (GitHub API) |
| Конфиги | Tomlyn (TOML) |
| Архивы | SharpZipLib |
Поток данных VPN
trusttunnel_client (stdout/stderr)
↓ парсинг строк (TrustTunnelService)
├─→ SimpleSubject<VpnState> → DashboardVM, HistoryVM, TrayIconService
├─→ SimpleSubject<LogEntry> → LogsVM, DiagnosticsVM
└─→ ConnectionActivityRepository (SQLite) → HistoryVM
Навигация
Два ListBox в левой панели:
Основная: Dashboard · Filtering · Logs · History
Системная: Diagnostics · Settings · About
Оверлеи (ZIndex): OnboardingWizard (20) · TutorialView (30).
Темы
Две «именных» темы, каждая меняет:
- Акцентный градиент (
AccentGradientBrush) - Декоративные глифы фона (
ThemeBackgroundField)
| Тема | Описание |
|---|---|
DemonessEngineer |
Рыже-красный градиент |
SleepyPrincess |
Фиолетово-синий градиент |
Поверх — Light / Dark / System (Fluent).
Оконный хром
SystemDecorations="None" + собственные элементы:
- Drag-полоса (32 px сверху, ZIndex 25)
- 8 прозрачных Border-ручек ресайза (ZIndex 26): 4 угла + 4 стороны
- Кнопки min/max/close (ZIndex 27)
Разработка
Правила
- Вся бизнес-логика — во ViewModel, в
.axaml.csтолько платформенные обработчики. - Интерфейсы — в
CaviCodeVPN.Core, реализации — вCaviCodeVPN.Infrastructure. ViewModel зависит только от интерфейсов. - Все строки UI — через
Loc.Get("key"). Никаких хардкодных строк в XAML. - Доступ к SQLite — всегда через
await, не блокировать UI-поток. - Платформо-специфичный код — через
IPlatformService. - Compiled bindings (
AvaloniaUseCompiledBindingsByDefault=true): DataTemplate обязан иметьx:DataType, неDataType. - DataGrid требует явного
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml" />вApp.axaml— без него рендерится пустым.
Локализация
CaviCodeVPN.App/Localization/Strings.resx— RU (по умолчанию)CaviCodeVPN.App/Localization/Strings.en.resx— EN- Новый ключ — добавлять в оба файла.
- Во ViewModel строки-геттеры (
get => Loc.Get("key")) пересчитываются поLoc.LanguageChanged.
Добавление новой вкладки
- Добавить значение в
NavigationItem(Core/Enums). - Создать
XxxViewModel : ViewModelBaseсHeaderKey = "nav_xxx". - Создать
XxxView : UserControl+ зарегистрировать вViewLocator. - Добавить DI-регистрацию в
Program.BuildServiceProvider(). - Добавить
ListBoxItemвMainWindow.axamlи case вMainWindowViewModel.NavigateTo. - Добавить ключи
nav_xxxв оба.resx.
Релизы и автообновления
Пайплайн: Windows — Velopack (Setup.exe + delta-nupkg), Linux — системные пакеты .deb/.rpm + pkexec-установка. CI — Forgejo Actions, доставка — rsync на cavicode.tech, раздача — Nginx лендинга.
Пайплайн одного релиза
- Поднять версию (передаётся аргументом в pack-скрипты).
git tag v1.2.3 && git push --tags— триггерит.forgejo/workflows/release.yml.- CI параллельно собирает три таргета:
- win-x64 —
dotnet publish→vpk pack→Setup.exe+*-full.nupkg+*-delta.nupkg. - linux-x64-deb —
dotnet publish→build/pack-linux-deb.sh(раскладка в/opt/cavicode-vpn/, wrapper в/usr/bin/cavicode-vpn,.desktopи иконка в системных путях). - linux-x64-rpm — аналогично через
build/pack-linux-rpm.sh(rpmbuild spec prebuilt из того же publish-output).
- win-x64 —
- Deploy-job делает rsync в
win-x64/,linux-x64-deb/,linux-x64-rpm/и обновляет стабильные симлинки (cavicode-vpn_latest_amd64.deb,cavicode-vpn-latest.x86_64.rpm,CaviCodeVPN-Setup.exe). - Клиент Windows —
UpdateService(Velopack-адаптер) читаетRELEASES-stable, качает дельту,ApplyUpdatesAndRestart. - Клиент Linux —
LinuxPackageUpdateServiceчитаетLATEST, качает нужный пакет (.debили.rpmпо/etc/os-release), запускаетpkexec apt install -y/pkexec dnf install -y, после успешной установки detached-helper черезsetsid sh -c "sleep 2; exec /usr/bin/cavicode-vpn"перезапускает приложение.
Инфраструктура на сервере
- Корень лендинга:
/var/www/vpn-desktop/— Vue-приложение из соседнего репозиторияCaviCode-Landing. - Артефакты:
/var/www/vpn-desktop/releases/stable/win-x64/—RELEASES-stable,*.nupkg,*-Setup.exe,*-Portable.zip+ симлинкиCaviCodeVPN-Setup.exe/Portable.zip./var/www/vpn-desktop/releases/stable/linux-x64-deb/—*.deb,LATEST, симлинкcavicode-vpn_latest_amd64.deb./var/www/vpn-desktop/releases/stable/linux-x64-rpm/—*.rpm,LATEST, симлинкcavicode-vpn-latest.x86_64.rpm.
- Nginx MIME/каш-политики для
.deb/.rpm— вCaviCode-Landing/deploy/nginx/cavicode-tech-vpn-desktop.conf.
CI Secrets (Forgejo → Repo Settings → Secrets)
| Имя | Назначение |
|---|---|
DEPLOY_SSH_KEY |
приватный ed25519 для rsync, без passphrase |
DEPLOY_HOST |
FQDN или IP (cavicode.tech) |
DEPLOY_USER |
unix-пользователь с rw на /var/www/vpn-desktop/ |
Локальная проверка упаковки
# Linux .deb (dpkg-deb встроен в Debian/Ubuntu/Alt/Mint)
./build/pack-linux-deb.sh 1.0.0
# Linux .rpm — требуется rpmbuild: sudo apt install rpm / sudo dnf install rpm-build
./build/pack-linux-rpm.sh 1.0.0
# Windows (Velopack)
pwsh ./build/pack-win.ps1 -Version 1.0.0
Установка и удаление для пользователя (Linux)
# Debian / Ubuntu / Mint / Pop!_OS
sudo apt install ./cavicode-vpn_1.0.0_amd64.deb
sudo apt remove cavicode-vpn
# Fedora / RHEL / openSUSE / Alt
sudo dnf install ./cavicode-vpn-1.0.0-1.x86_64.rpm
sudo dnf remove cavicode-vpn
Пользовательские данные — настройки, логи, SQLite-БД — лежат в ~/.config/CaviCodeVPN/ и не удаляются пакетным менеджером. Для полной очистки: rm -rf ~/.config/CaviCodeVPN/.
Подпись
На старте — без Authenticode (self-signed вариант для Windows) и без GPG (для .deb/.rpm это означает, что apt install попросит --allow-untrusted или dpkg -i). Добавление — отдельная задача: Authenticode через vpk pack --signParams, GPG-подпись .deb/.rpm через dpkg-sig / rpm --addsign в CI после создания пакета.
Клиентские настройки
Секция Updates в appsettings.json (рядом с бинарником):
"Updates": {
"FeedBaseUrl": "https://cavicode.tech/vpn-desktop/releases",
"Channel": "stable"
}
Итоговый URL фида:
- Windows:
{FeedBaseUrl}/{Channel}/win-x64/RELEASES-stable(читает Velopack). - Linux (.deb-family):
{FeedBaseUrl}/{Channel}/linux-x64-deb/LATEST. - Linux (.rpm-family):
{FeedBaseUrl}/{Channel}/linux-x64-rpm/LATEST.
Лицензия
MIT