Files
lemana-vpn/README.md

622 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lemana VPN
CLI-установка корпоративного VPN `vpn.lemanapro.ru` для macOS.
**По умолчанию:** ручной вход без сохранения паролей. Откроется окно корпоративного входа, а логин, пароль и одноразовый код вводятся вручную. Bitwarden, Touch ID, сохранение пароля, подстановка 2FA и автоматический вход включаются только явно.
**Режимы входа:** `manual` ничего не сохраняет и ничего не подставляет; `saved-login` хранит LDAP логин/пароль в macOS Keychain и оставляет одноразовый код ручным; `saved-totp` дополнительно хранит постоянный код настройки 2FA; `auto` запускается только явно через `vpn-auto`/`--auto`.
Репозиторий собирает в один воспроизводимый пакет то, что раньше было ручной локальной настройкой:
- `openconnect` как VPN-клиент;
- `openconnect-lite` для SAML SSO через Keycloak;
- опциональный Bitwarden CLI для LDAP-пароля и постоянного кода настройки 2FA;
- опциональный Touch ID helper для мастер-пароля Bitwarden;
- Swift Menu Bar app `LemanaVPN.app`;
- безопасный DNS cleanup через root-owned wrapper;
- алиасы `vpn`, `vpn-auto`, `vpn-manual`, `vpn-manual-full`, `vpn-debug`, `vpn-fix-dns`.
## Быстрая установка
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
```
Если установка запущена из терминала, скрипт работает как простой wizard: объяснит, что будет установлено, по Enter оставит безопасный ручной режим и предложит дополнительные удобства только отдельным выбором.
После установки открой новый shell или выполни:
```sh
exec zsh
vpn
```
## Интерактивная установка
Обычный путь — запустить installer без флагов и ответить на вопросы:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
```
Первый важный вопрос — как подключаться:
```text
Как подключаться по умолчанию?
1) Вводить всё вручную (рекомендуется)
Откроется окно входа. Вы сами введёте логин, пароль и одноразовый код.
2) Запомнить логин и пароль на этом Mac
При входе логин и пароль подставятся сами. Одноразовый код вы введёте вручную.
3) Настроить автоматический вход
Нужно заранее сохранить пароль и постоянный код настройки 2FA.
Выбор [1/2/3, Enter=1]:
```
Что означают варианты:
- `1` — ничего не сохранять. Это самый понятный старт: при подключении открывается окно входа, всё вводится руками.
- `2` — сохранить LDAP логин и пароль в macOS Keychain. Одноразовый код всё равно вводится руками.
- `3` — продвинутый путь: сохранить полный набор данных для подстановки или подключить Bitwarden. Если не уверены, выбирайте `1`.
Дальше installer спросит только про системные модули: sudoers, aliases, Swift Menu Bar app и автозапуск. Bitwarden и Touch ID появляются только если вы явно выбрали продвинутый путь.
Флаги остаются для CI, повторяемых установок и диагностики. Для обычной установки они не нужны.
Проверить действия без изменений:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --dry-run
```
Пример неинтерактивного режима для автоматизации:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \
| sh -s -- --non-interactive --auth-profile saved-login --configure-login
```
Принудительно включить интерактивные вопросы:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --interactive
```
Запустить без вопросов, с выбранными флагами и дефолтами:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --non-interactive
```
Если raw URL отличается, переопредели базовый адрес:
```sh
curl -fsSL https://example.org/dokril/lemana-vpn/raw/branch/main/install.sh \
| LEMANA_VPN_RAW_BASE_URL=https://example.org/dokril/lemana-vpn/raw/branch/main sh
```
## Что ставится
| Путь | Назначение |
| --- | --- |
| `~/bin/vpn-lemanapro.sh` | Основной CLI для подключения, статуса и sync секретов |
| `~/bin/uninstall-lemana-vpn.sh` | Локальный uninstall helper |
| `~/bin/keychain-fingerprint` | Опциональный Touch ID helper для мастер-пароля Bitwarden |
| `~/Applications/LemanaVPN.app` | Swift Menu Bar app для подключения из status bar |
| `~/Library/LaunchAgents/ru.dokops.LemanaVPN.plist` | Автозапуск Menu Bar app при логине |
| `~/.config/lemana-vpn/env` | Локальная конфигурация модулей |
| `~/.config/lemana-vpn/patch-backups/` | Backup исходника `openconnect-lite` перед runtime-патчами |
| `~/.config/openconnect-lite/config.toml` | Профиль SSO и auto-fill правила Keycloak |
| `/usr/local/sbin/lemana-vpn-dns-cleanup` | Root-owned wrapper для сброса только корпоративных DNS |
| `/etc/sudoers.d/lemana-vpn-openconnect` | `NOPASSWD` только для `openconnect` |
| `/etc/sudoers.d/lemana-vpn-dns` | `NOPASSWD` только для DNS cleanup wrapper |
| `~/.zshrc` | Идемпотентный блок алиасов `vpn`, `vpn-auto`, `vpn-manual`, `vpn-manual-full`, `vpn-debug`, `vpn-fix-dns` |
## Статус модулей
`vpn` и `vpn --status` первой строкой показывают, какие модули включены в конфиге и реально установлены на машине:
```sh
vpn --status
Modules: ✅ core=ok, 🔐 auth_profile=manual, 🔐 credential_source=none, ⏭️ bitwarden=off, ⏭️ touchid=off, ✅ dns=on, ✅ app=on, ✅ autostart=on, ✅ patches=active, ✅ keychain=password:no/totp_seed:no
VPN disconnected
```
Emoji в human-выводе помогают быстро отличать норму, отключённый опциональный модуль и проблему:
- `✅` — модуль установлен или состояние готово;
- `⏭️` — модуль осознанно отключён;
- `⚠️` — модуль включён, но чего-то не хватает.
Значения:
| Поле | Значение |
| --- | --- |
| `core=ok` | Есть `openconnect`, `openconnect-lite` и config |
| `auth_profile=manual/saved-login/saved-totp/auto` | Как CLI будет открывать окно входа и использовать сохранённые данные |
| `credential_source=none/keychain/bitwarden` | Откуда брать сохранённые данные, если выбран режим с подстановкой |
| `bitwarden=on` | Модуль явно включён и `bw` установлен |
| `bitwarden=off` | Модуль отключён по умолчанию или через `--without-bitwarden` |
| `bitwarden=missing` | Модуль включён, но `bw` не найден |
| `touchid=on/off/missing` | Состояние Touch ID helper |
| `dns=on/missing` | Наличие DNS cleanup wrapper |
| `app=on/missing` | Установлен ли `~/Applications/LemanaVPN.app` |
| `autostart=on/off` | Есть ли LaunchAgent для запуска приложения при логине |
| `patches=active/pending` | Применены ли runtime-патчи `openconnect-lite` |
| `keychain=password:yes/totp_seed:yes` | Есть ли LDAP-пароль и постоянный код настройки 2FA в Keychain |
JSON-режим тоже отдаёт модульный статус:
```sh
vpn --status --json
```
## Интерактивная установка
Перед установкой `install.sh` печатает текущее состояние:
```text
Detected state:
openconnect: yes
pipx: yes
openconnect-lite: yes
Bitwarden CLI: no
Touch ID helper: no
DNS cleanup: no
sudoers: no/no
shell aliases: no
Swift: yes
Menu Bar app: no
LaunchAgent: no
Keychain password: no
Keychain 2FA setup: no
```
Если доступен терминал, скрипт ведёт установку вопросами:
- оставить ручной вход, сохранить только логин/пароль или настроить подстановку сохранённых данных;
- поставить Bitwarden CLI только если выбран Bitwarden;
- собрать Touch ID helper только если выбран Bitwarden;
- собрать ли Swift Menu Bar app, если `~/Applications/LemanaVPN.app` не найден;
- включить ли автозапуск Menu Bar app при логине;
- настроить ли sudoers для `openconnect` и DNS cleanup;
- добавить ли алиасы в `~/.zshrc`.
Флаги имеют приоритет над вопросами и нужны в основном для CI, диагностики или повторяемых unattended installs. Например, `--auth-profile saved-login --configure-login` сразу выберет сохранение логина/пароля, а `--no-shell` не будет предлагать алиасы.
В неинтерактивной среде скрипт не задаёт вопросов и использует выбранные флаги/дефолты. Для CI или повторяемой установки лучше явно указывать `--non-interactive`.
## Логи установщика и удаления
Установщик и uninstall script печатают пошаговый лог с emoji, цветом в интерактивном терминале и коротким пояснением, зачем нужен каждый шаг. Например, перед сборкой Swift-приложения установщик отдельно пишет, что `swift build` может занять время и что строки компилятора вида `[2/5] Write swift-version...` являются нормальным выводом. При удалении отдельно показывается откат runtime-патчей `openconnect-lite`, удаление sudoers/DNS wrapper, приложения, aliases и config.
Отключить цвет:
```sh
NO_COLOR=1 sh install.sh
NO_COLOR=1 sh uninstall.sh
```
Отключить emoji:
```sh
LEMANA_VPN_NO_EMOJI=1 sh install.sh
LEMANA_VPN_NO_EMOJI=1 sh uninstall.sh
```
## Модули
### Core
Всегда устанавливается:
- `openconnect` через Homebrew;
- `pipx` через Homebrew;
- `openconnect-lite` через `pipx`;
- CLI `vpn-lemanapro.sh`;
- `openconnect-lite` config;
- DNS cleanup wrapper.
### Как работают режимы входа
Keychain entries:
- service `openconnect-lite`, account `<LDAP username>` — корпоративный LDAP/domain пароль;
- service `openconnect-lite`, account `totp/<LDAP username>` — постоянный код настройки 2FA, нужен только для подстановки одноразового кода и auto mode.
`auth_profile=manual` — режим по умолчанию. CLI не проверяет Keychain и Bitwarden, открывает видимое окно входа и ничего не подставляет. Логин, пароль и одноразовый код вводятся вручную.
`auth_profile=saved-login` — CLI берёт из Keychain только LDAP пароль и подставляет логин/пароль в видимое окно входа. Одноразовый код вводится руками. Настройка:
```sh
vpn --configure-login
```
`auth_profile=saved-totp` — CLI берёт LDAP пароль и постоянный код настройки 2FA из Keychain, подставляет поля в видимое окно входа, но submit не нажимает. Настройка:
```sh
vpn --configure-keychain
```
`auth_profile=auto` — старый автоматический путь: скрытый браузер, подстановка всех полей и submit. Запускается только явно:
```sh
vpn-auto
vpn --auto
```
`credential_source=bitwarden` — это sync-provider. CLI открывает Bitwarden vault, читает item `LM LDAP`, берёт из него LDAP password и постоянный код настройки 2FA, нормализует `otpauth://...secret=...` если нужно, затем записывает оба секрета в macOS Keychain. Bitwarden не включён по умолчанию.
Важно: Lemana VPN не хранит и не принимает текущий 6-значный код как постоянную настройку. Такой код живёт около 30 секунд. Для автоматического SSO нужен именно постоянный secret: raw Base32 или `otpauth://totp/...?...secret=BASE32`.
Если запуск идёт из menu-bar app, интерактивного terminal prompt нет. Поэтому настройку сохранённого логина или полного набора данных нужно один раз выполнить в Terminal.
### Bitwarden
Отключён по умолчанию. Его стоит включать только если у пользователя уже есть запись Bitwarden с корпоративным LDAP-паролем и постоянным кодом настройки 2FA.
Постоянный код настройки 2FA — это секрет, который обычно показывается при ручной настройке authenticator. Сам одноразовый код меняется каждые 30 секунд и генерируется `openconnect-lite` в момент входа.
Если vault заблокирован и Touch ID helper не смог его открыть, CLI спросит `Bitwarden master password`. Это пароль от хранилища Bitwarden, а не корпоративный LDAP-пароль. Он нужен только чтобы достать LDAP password и постоянный код настройки 2FA из item `LM LDAP` и переложить их в macOS Keychain.
Включить Bitwarden можно через продвинутый путь в installer wizard или флагами:
То же самое можно задать флагами для неинтерактивной установки:
```sh
sh install.sh --non-interactive --with-bitwarden --auth-profile saved-totp
```
Для Keychain-only режима без Bitwarden используйте:
```sh
sh install.sh --non-interactive --auth-profile saved-login --configure-login
```
Если сохранённые данные уже лежат в Keychain, подключение без Bitwarden не будет спрашивать пароль заново. Для режима `saved-login` одноразовый код всё равно вводится вручную.
### Если Bitwarden нет
Bitwarden не обязателен. Без него установка по умолчанию работает в полностью ручном режиме: откроется окно входа, а логин, пароль и одноразовый код вводятся руками.
Интерактивная установка:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
```
В первом вопросе можно просто нажать Enter:
```text
1) Вводить всё вручную (рекомендуется)
```
Это встроенный бесплатный путь: не нужен Bitwarden account, платный Bitwarden TOTP или внешний password manager.
Если хочется, чтобы логин и пароль подставлялись сами, выбери пункт `2` или выполни позже:
```sh
vpn --configure-login
```
Что понадобится:
- LDAP username;
- LDAP password: корпоративный LDAP/domain пароль, не мастер-пароль Bitwarden;
- одноразовый код из корпоративной 2FA при каждом подключении.
Постоянный код настройки 2FA нужен только для `vpn --configure-keychain`, `saved-totp` и `vpn-auto`.
Не вставляй текущий 6-значный authenticator code в `vpn --configure-keychain`. Lemana VPN сохраняет в Keychain постоянный код настройки 2FA, а `openconnect-lite` по нему генерирует свежие одноразовые коды во время каждого SSO login.
Если запуск идёт из `LemanaVPN.app`, приложение не может безопасно показать интерактивный terminal prompt для сохранения пароля. Настройку saved-login или saved-totp нужно один раз выполнить в Terminal:
```sh
vpn --configure-login
vpn --configure-keychain
```
Если secret есть только в QR-коде:
1. Открой QR-код в приложении/на портале, где настраивалась 2FA.
2. Найди режим ручной настройки, где показывается secret.
3. Если доступен только QR, его нужно расшифровать любым локальным QR-сканером и взять параметр `secret`.
4. Вставь secret в prompt `2FA setup secret BASE32`.
Если постоянный 2FA secret получить нельзя, автоматический headless-вход невозможен: `openconnect-lite` не сможет сам генерировать свежий одноразовый код на каждом входе.
### Touch ID
Отключён по умолчанию и нужен только для Bitwarden-пути. Если пользователь выбрал Bitwarden, установщик может собрать `keychain-fingerprint` из `https://github.com/dss99911/keychain-fingerprint.git` и положить бинарник в `~/bin/keychain-fingerprint`.
Важно: этот helper показывает системный Touch ID prompt перед чтением мастер-пароля Bitwarden, но это не аппаратный Keychain ACL. Это удобный локальный гейт поверх записи Keychain.
Отключить:
```sh
sh install.sh --without-touchid
```
### Swift Menu Bar app
Включён по умолчанию. Установщик собирает Swift-приложение из исходников в репозитории и кладёт bundle в:
```sh
~/Applications/LemanaVPN.app
```
Приложение живёт в macOS status bar, запускает `~/bin/vpn-lemanapro.sh --json`, показывает состояние VPN, IP, оставшееся время сессии, health-check тоннеля и строку состояния модулей.
В отключённом состоянии меню показывает текущий режим установки:
- `Режим: полностью вручную` — доступна только обычная кнопка `Подключить`; логин, пароль и одноразовый код вводятся руками.
- `Режим: логин и пароль сохранены` — доступен вход с подстановкой логина/пароля и ручной ввод одноразового кода.
- `Режим: сохранённые данные без автоотправки` — доступны сохранённые данные, ручной fallback и явный automatic mode.
- `Режим: автоматический вход` — обычная кнопка `Подключить` запускает настроенный auto-flow, а ручные fallback-кнопки остаются доступны.
Кнопки, для которых текущая установка не готова, не показываются. Например, если не сохранён постоянный код настройки 2FA, в меню не будет автоматического входа. Если рядом с режимом есть подсказка `Настройте в Terminal`, выполните указанную команду в Terminal и нажмите `Обновить статус модулей`.
Строка состояния модулей в меню приложения использует те же маркеры, что CLI: `✅` для готового модуля, `⏭️` для отключённого опционального модуля и `⚠️` для проблемы. Иконка строки тоже меняется: `checkmark.circle` для полностью готового набора и `exclamationmark.triangle` для неполной установки.
Если в меню видно `modules unavailable: update CLI`, значит запущенное приложение обращается к старому `~/bin/vpn-lemanapro.sh`, который ещё не умеет отдавать модульный статус. Повтори установку через `curl`; установщик обновит CLI и перезапустит уже запущенное `LemanaVPN.app`.
Для сборки нужен Swift 5.9+ из Xcode Command Line Tools:
```sh
xcode-select --install
```
Отключить установку приложения:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-app
```
Оставить приложение, но отключить автозапуск:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-autostart
```
Ручной запуск:
```sh
open ~/Applications/LemanaVPN.app
```
## Использование
```sh
vpn # подключиться в настроенном режиме; fresh install = полностью вручную
vpn-auto # явный автоматический режим: скрытый браузер, auto-fill и submit
vpn --saved-login # подставить сохранённые логин/пароль, одноразовый код руками
vpn-manual # видимый браузер, сохранённые данные auto-fill без submit
vpn-manual-full # полностью ручной режим: видимый браузер без auto-fill и submit
vpn --manual # то же самое без alias
vpn --manual-full # то же самое без alias
vpn --status # статус без нового подключения
vpn --status --json # статус в JSON
vpn-debug # видимый браузер и debug-логи
vpn --manual --debug # ручной режим с debug-логами
vpn-fix-dns # сбросить корпоративные DNS после аварийного завершения
open ~/Applications/LemanaVPN.app # открыть Swift-приложение в menu bar
```
Режимы подключения:
- `manual` — режим fresh install по умолчанию. Браузер видимый, auto-fill отключён полностью, проверки сохранённых LDAP/TOTP credentials пропускаются: поля Keycloak заполняешь и отправляешь сам.
- `saved-login` — браузер видимый, логин/пароль берутся из Keychain, одноразовый код вводится руками, submit не нажимается.
- `saved-totp` / `--manual` — браузер видимый, LDAP-пароль и код 2FA берутся из Keychain/Bitwarden и подставляются в поля, но кнопка входа не нажимается.
- `auto` / `vpn-auto` — явный автоматический режим. Браузер скрытый, LDAP-пароль и код 2FA берутся из Keychain/Bitwarden, форма заполняется и отправляется автоматически.
- `--manual-sso` оставлен как совместимый alias для `--manual`.
- `--manual-no-autofill` оставлен как совместимый alias для `--manual-full`.
Первый запуск с Bitwarden, если он выбран явно:
1. CLI проверит `bw`.
2. Если vault locked, попросит мастер-пароль.
3. Если установлен Touch ID helper, предложит сохранить мастер-пароль за Touch ID prompt.
4. Достанет `LM LDAP`, запишет LDAP-пароль и постоянный код настройки 2FA в Keychain.
5. Запустит `openconnect-lite` и пройдёт Keycloak SSO.
## Настройка
Файл `~/.config/lemana-vpn/env`:
```sh
LEMANA_VPN_USERNAME="<LDAP_USERNAME>"
LEMANA_VPN_AUTH_PROFILE="manual"
LEMANA_VPN_CREDENTIAL_SOURCE="none"
LEMANA_VPN_BW_ITEM="LM LDAP"
LEMANA_VPN_USE_BITWARDEN="0"
LEMANA_VPN_USE_TOUCHID="0"
LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup"
```
Для режима с сохранённым логином и паролем:
```sh
LEMANA_VPN_USERNAME="<LDAP_USERNAME>"
LEMANA_VPN_AUTH_PROFILE="saved-login"
LEMANA_VPN_CREDENTIAL_SOURCE="keychain"
LEMANA_VPN_USE_BITWARDEN="0"
LEMANA_VPN_USE_TOUCHID="0"
LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup"
```
Если LDAP username не указан при установке, `vpn` спросит его при первом интерактивном запуске в Terminal и сохранит в `~/.config/lemana-vpn/env`. Для неинтерактивной установки можно указать его сразу:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \
| sh -s -- --username <LDAP_USERNAME>
```
## Bitwarden item
Нужна запись:
- название: `LM LDAP`;
- username: корпоративный LDAP логин;
- password: LDAP пароль;
- TOTP: `otpauth://...secret=BASE32...` или raw BASE32 secret.
Это не 6-значный одноразовый код. В Bitwarden должен лежать постоянный 2FA secret, из которого коды генерируются автоматически.
## Почему DNS wrapper, а не wildcard sudoers
Старый вариант давал `NOPASSWD` на `networksetup -setdnsservers *`. Это слишком широкое право: любой локальный процесс пользователя мог поменять DNS на произвольный сервер.
Новый вариант разрешает sudo только на `/usr/local/sbin/lemana-vpn-dns-cleanup`. Wrapper сбрасывает DNS только если текущий DNS начинается с `10.`, то есть похож на корпоративный VPN DNS.
## Runtime-патчи openconnect-lite
`openconnect-lite` работает, но для текущей macOS + Keycloak SSO цепочки ему нужны runtime-патчи. CLI применяет их перед подключением в файле:
```sh
~/.local/pipx/venvs/openconnect-lite/lib/python*/site-packages/openconnect_lite/browser/webengine_process.py
```
Патчи:
| Патч | Что меняет | Зачем |
| --- | --- | --- |
| `minimal -> offscreen` | Меняет Qt platform mode для скрытого браузера | `minimal` падает с Qt WebEngine на macOS |
| `input/change events` | Оставляет старое прямое `value = ...`, но после него отправляет DOM events | Keycloak не реагирует на прямую запись value без событий |
| `legacy auto-fill` | Сохраняет старую рабочую схему `ApplicationWorld`, прямой `value = ...` и простой `click()` | Это ровно тот режим, на котором hidden SSO раньше стабильно проходил Keycloak |
| `URL guard` | Проверяет `location.href` через `new RegExp(...)` перед auto-fill | Qt игнорирует `@include`, без guard auto-fill может кликнуть Cisco ACS и сломать SAML |
| `auth redirect` | Читает 302 с `vpn.lemanapro.ru` без автоматического follow-redirect | Python `requests` может падать на TLS reset при открытии `/` на `sslvpna/b`, хотя для SAML нужен только конечный host |
| `manual submit gate` | Позволяет отключить только auto-click через `LEMANA_VPN_AUTOFILL_CLICK=0` | Ручной режим видит заполненную форму, но сам решает, когда нажать вход |
| `manual SSO disable` | Позволяет полностью отключить auto-fill через `vpn --manual-full` или `LEMANA_VPN_AUTOFILL_DISABLE=1` | Нужен для низкоуровневой диагностики без подстановки полей |
Перед первым изменением CLI сохраняет оригинальный файл:
```sh
~/.config/lemana-vpn/patch-backups/webengine_process.py.before-lemana-vpn
```
Откат патчей выполняет uninstall script. Если backup отсутствует, автоматического rollback нет: значит файл был уже патчен старой ручной установкой или `openconnect-lite` переустановили после backup.
## Диагностика
Проверить установку:
```sh
command -v vpn-lemanapro.sh
openconnect --version
~/.local/bin/openconnect-lite --help
sudo -n /usr/local/sbin/lemana-vpn-dns-cleanup
vpn --status
```
Обычный `vpn` теперь пишет путь к подробному логу `openconnect-lite`:
```sh
~/Library/Logs/LemanaVPN-openconnect-lite.log
```
Если после `Connecting to VPN (lemanapro)...` SSO завис или не видно, что происходит, смотри этот файл:
```sh
tail -f ~/Library/Logs/LemanaVPN-openconnect-lite.log
```
В обычном режиме CLI также печатает heartbeat `Still waiting for SSO/openconnect-lite...` до успешного подключения, чтобы было понятно, что процесс живой. В `vpn-debug` дополнительно показываются raw-логи и видимый браузер.
Если в логе повторяется один и тот же URL вида `employee.auth.lemanapro.ru/realms/employee/login-actions/authenticate`, значит hidden-браузер застрял на Keycloak до перехода в Cisco ACS. Сначала обнови и примени runtime-патчи без подключения:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
vpn-lemanapro.sh --patch-only
```
Если лог падает раньше браузера с `SSLEOFError` / `UNEXPECTED_EOF_WHILE_READING` на `sslvpna.lemanapro.ru` или `sslvpnb.lemanapro.ru`, это ломается этап определения конечного Cisco headend. Актуальный runtime-патч `auth redirect` не открывает `/` на `sslvpna/b`, а только берёт `Location` из 302 ответа `vpn.lemanapro.ru` и продолжает штатный SAML init через POST.
Если SSO ломается после обновления `openconnect-lite`, запусти:
```sh
vpn-debug
```
Если нужно самому посмотреть форму Keycloak, но оставить подстановку LDAP/TOTP:
```sh
vpn --manual
```
В этом режиме браузер видимый, `openconnect-lite` заполняет поля из Keychain/Bitwarden, но не нажимает submit.
Если нужно проверить SSO полностью вручную, без подстановки LDAP-пароля и TOTP:
```sh
vpn --manual-full
```
Этот режим не требует заранее сохранённого LDAP username/password/TOTP и не запускает Bitwarden/Keychain preflight.
Если установка падает на строке `install: /usr/local/sbin/...: No such file or directory`, значит на машине не было `/usr/local/sbin`. Актуальный `install.sh` создаёт эту директорию сам; достаточно повторить установку свежей командой `curl`.
CLI перед подключением патчит `openconnect-lite`:
- `minimal` -> `offscreen`, чтобы Qt WebEngine не падал на macOS;
- добавляет `input` и `change` events для Keycloak auto-fill, сохраняя старое прямое присваивание `value = ...`;
- оставляет auto-fill в старом `ApplicationWorld` и не добавляет stateful click guards/native setters;
- добавляет URL guard, чтобы auto-fill не кликал submit на Cisco ACS;
- добавляет auth redirect patch, чтобы Python не падал на TLS reset при follow-redirect к `sslvpna/b`;
- добавляет manual submit gate для видимой ручной диагностики с auto-fill, но без auto-submit.
## Удаление
Рекомендуемый способ:
```sh
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/uninstall.sh | sh
```
Или локально:
```sh
uninstall-lemana-vpn.sh
```
Что делает uninstall:
- восстанавливает `openconnect-lite` из backup, если backup есть;
- удаляет `vpn-lemanapro.sh` и `uninstall-lemana-vpn.sh`;
- удаляет sudoers rules и DNS cleanup wrapper;
- удаляет блок `lemana-vpn` из `~/.zshrc`;
- удаляет `~/.config/openconnect-lite/config.toml`;
- останавливает уже запущенный процесс `LemanaVPN`, удаляет `~/Applications/LemanaVPN.app` и LaunchAgent автозапуска;
- удаляет `~/.config/lemana-vpn`, если не передан `--keep-config`.
Опциональные режимы:
```sh
uninstall-lemana-vpn.sh --dry-run
uninstall-lemana-vpn.sh --keep-config
uninstall-lemana-vpn.sh --keep-app
uninstall-lemana-vpn.sh --remove-keychain
uninstall-lemana-vpn.sh --remove-touchid-helper
uninstall-lemana-vpn.sh --remove-openconnect-lite
```
Ручной вариант, если нужен полный контроль:
```sh
rm -f ~/bin/vpn-lemanapro.sh ~/bin/uninstall-lemana-vpn.sh
rm -rf ~/.config/lemana-vpn
rm -f ~/.config/openconnect-lite/config.toml
sudo rm -f /usr/local/sbin/lemana-vpn-dns-cleanup
sudo rm -f /etc/sudoers.d/lemana-vpn-openconnect /etc/sudoers.d/lemana-vpn-dns
```
Из `~/.zshrc` удалить блок:
```sh
# >>> lemana-vpn
...
# <<< lemana-vpn
```