Добавь удаление и откат патчей VPN
This commit is contained in:
74
README.md
74
README.md
@@ -14,7 +14,7 @@ CLI-установка корпоративного VPN `vpn.lemanapro.ru` дл
|
||||
## Быстрая установка
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||||
```
|
||||
|
||||
После установки открой новый shell или выполни:
|
||||
@@ -29,25 +29,25 @@ vpn
|
||||
Полная установка, режим по умолчанию:
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh
|
||||
```
|
||||
|
||||
Без Touch ID, но с Bitwarden:
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-touchid
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --without-touchid
|
||||
```
|
||||
|
||||
Минимальная установка без Bitwarden и Touch ID. Пароль LDAP и TOTP будут один раз записаны в macOS Keychain вручную:
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --minimal --configure-keychain
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --minimal --configure-keychain
|
||||
```
|
||||
|
||||
Проверить действия без изменений:
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --dry-run
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh | sh -s -- --dry-run
|
||||
```
|
||||
|
||||
Если raw URL отличается, переопредели базовый адрес:
|
||||
@@ -62,8 +62,10 @@ curl -fsSL https://example.org/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||||
| Путь | Назначение |
|
||||
| --- | --- |
|
||||
| `~/bin/vpn-lemanapro.sh` | Основной CLI для подключения, статуса и sync секретов |
|
||||
| `~/bin/uninstall-lemana-vpn.sh` | Локальный uninstall helper |
|
||||
| `~/bin/keychain-fingerprint` | Опциональный Touch ID helper для мастер-пароля Bitwarden |
|
||||
| `~/.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` |
|
||||
@@ -144,7 +146,7 @@ LEMANA_VPN_DNS_CLEANUP="/usr/local/sbin/lemana-vpn-dns-cleanup"
|
||||
Для другого логина:
|
||||
|
||||
```sh
|
||||
curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||||
curl -fsSL https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||||
| sh -s -- --username 12345678
|
||||
```
|
||||
|
||||
@@ -163,6 +165,30 @@ curl -fsSL http://192.168.50.109/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||||
|
||||
Новый вариант разрешает 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 |
|
||||
| `URL guard` | Проверяет `location.href` через `new RegExp(...)` перед auto-fill | Qt игнорирует `@include`, без guard auto-fill может кликнуть Cisco ACS и сломать SAML |
|
||||
|
||||
Перед первым изменением CLI сохраняет оригинальный файл:
|
||||
|
||||
```sh
|
||||
~/.config/lemana-vpn/patch-backups/webengine_process.py.before-lemana-vpn
|
||||
```
|
||||
|
||||
Откат патчей выполняет uninstall script. Если backup отсутствует, автоматического rollback нет: значит файл был уже патчен старой ручной установкой или `openconnect-lite` переустановили после backup.
|
||||
|
||||
## Диагностика
|
||||
|
||||
Проверить установку:
|
||||
@@ -189,8 +215,41 @@ CLI перед подключением патчит `openconnect-lite`:
|
||||
|
||||
## Удаление
|
||||
|
||||
Рекомендуемый способ:
|
||||
|
||||
```sh
|
||||
rm -f ~/bin/vpn-lemanapro.sh ~/bin/keychain-fingerprint
|
||||
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`;
|
||||
- удаляет `~/.config/lemana-vpn`, если не передан `--keep-config`.
|
||||
|
||||
Опциональные режимы:
|
||||
|
||||
```sh
|
||||
uninstall-lemana-vpn.sh --dry-run
|
||||
uninstall-lemana-vpn.sh --keep-config
|
||||
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
|
||||
@@ -204,4 +263,3 @@ sudo rm -f /etc/sudoers.d/lemana-vpn-openconnect /etc/sudoers.d/lemana-vpn-dns
|
||||
...
|
||||
# <<< lemana-vpn
|
||||
```
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ BW_KC_ACCOUNT_SESSION="${LEMANA_VPN_BW_KC_ACCOUNT_SESSION:-bw-session}"
|
||||
BW_KC_ACCOUNT_MASTER="${LEMANA_VPN_BW_KC_ACCOUNT_MASTER:-bw-master}"
|
||||
STATUS_DIR="${LEMANA_VPN_STATUS_DIR:-$HOME/.local/state/vpn-lemanapro}"
|
||||
STATUS_FILE="$STATUS_DIR/status.json"
|
||||
PATCH_BACKUP_DIR="${LEMANA_VPN_PATCH_BACKUP_DIR:-$CONFIG_DIR/patch-backups}"
|
||||
|
||||
DEBUG=false
|
||||
JSON_MODE=false
|
||||
@@ -148,12 +149,15 @@ _patch_oc() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
"$OC_PYTHON" - "$wep" <<'PY'
|
||||
"$OC_PYTHON" - "$wep" "$PATCH_BACKUP_DIR" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
backup_dir = Path(sys.argv[2])
|
||||
backup_file = backup_dir / "webengine_process.py.before-lemana-vpn"
|
||||
src = path.read_text()
|
||||
before = src
|
||||
original = src
|
||||
messages = []
|
||||
|
||||
@@ -211,7 +215,10 @@ autoFill();
|
||||
src = src.replace(old_block, new_block)
|
||||
messages.append("URL guard")
|
||||
|
||||
if src != path.read_text():
|
||||
if src != before:
|
||||
backup_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not backup_file.exists():
|
||||
backup_file.write_text(before)
|
||||
path.write_text(src)
|
||||
for message in messages:
|
||||
print(f"Patch applied: {message}")
|
||||
@@ -456,4 +463,3 @@ while true; do
|
||||
sleep 5
|
||||
_emit '{"event":"connecting"}' "Reconnecting..."
|
||||
done
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
set -eu
|
||||
|
||||
APP_NAME="lemana-vpn"
|
||||
DEFAULT_RAW_BASE_URL="http://192.168.50.109/dokril/lemana-vpn/raw/branch/main"
|
||||
DEFAULT_RAW_BASE_URL="https://git.dokops.ru/dokril/lemana-vpn/raw/branch/main"
|
||||
|
||||
RAW_BASE_URL="${LEMANA_VPN_RAW_BASE_URL:-$DEFAULT_RAW_BASE_URL}"
|
||||
INSTALL_BIN_DIR="${LEMANA_VPN_BIN_DIR:-$HOME/bin}"
|
||||
@@ -194,6 +194,9 @@ install_cli() {
|
||||
|
||||
download_file "bin/vpn-lemanapro.sh" "$tmp/vpn-lemanapro.sh"
|
||||
run install -m 755 "$tmp/vpn-lemanapro.sh" "$INSTALL_BIN_DIR/vpn-lemanapro.sh"
|
||||
|
||||
download_file "uninstall.sh" "$tmp/uninstall.sh"
|
||||
run install -m 755 "$tmp/uninstall.sh" "$INSTALL_BIN_DIR/uninstall-lemana-vpn.sh"
|
||||
}
|
||||
|
||||
install_config() {
|
||||
@@ -343,4 +346,3 @@ main() {
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
|
||||
168
uninstall.sh
Executable file
168
uninstall.sh
Executable file
@@ -0,0 +1,168 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
INSTALL_BIN_DIR="${LEMANA_VPN_BIN_DIR:-$HOME/bin}"
|
||||
CONFIG_DIR="${LEMANA_VPN_CONFIG_DIR:-$HOME/.config/lemana-vpn}"
|
||||
OC_CONFIG_DIR="${OPENCONNECT_LITE_CONFIG_DIR:-$HOME/.config/openconnect-lite}"
|
||||
OC_VENV="${LEMANA_VPN_OC_VENV:-$HOME/.local/pipx/venvs/openconnect-lite}"
|
||||
DNS_CLEANUP="${LEMANA_VPN_DNS_CLEANUP:-/usr/local/sbin/lemana-vpn-dns-cleanup}"
|
||||
USERNAME="${LEMANA_VPN_USERNAME:-60103293}"
|
||||
DRY_RUN=0
|
||||
KEEP_CONFIG=0
|
||||
REMOVE_KEYCHAIN=0
|
||||
REMOVE_TOUCHID_HELPER=0
|
||||
REMOVE_OPENCONNECT_LITE=0
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage:
|
||||
sh uninstall.sh [options]
|
||||
|
||||
Options:
|
||||
--keep-config Keep ~/.config/lemana-vpn
|
||||
--remove-keychain Remove VPN-related Keychain entries
|
||||
--remove-touchid-helper Remove ~/bin/keychain-fingerprint
|
||||
--remove-openconnect-lite Remove pipx openconnect-lite after patch rollback
|
||||
--dry-run Print actions without changing files
|
||||
-h, --help Show this help
|
||||
|
||||
Default uninstall restores openconnect-lite patch backup, removes Lemana VPN
|
||||
scripts/config/sudoers/zsh aliases, and keeps shared package dependencies.
|
||||
USAGE
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--keep-config) KEEP_CONFIG=1 ;;
|
||||
--remove-keychain) REMOVE_KEYCHAIN=1 ;;
|
||||
--remove-touchid-helper) REMOVE_TOUCHID_HELPER=1 ;;
|
||||
--remove-openconnect-lite) REMOVE_OPENCONNECT_LITE=1 ;;
|
||||
--dry-run) DRY_RUN=1 ;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
log() {
|
||||
printf '%s\n' "$*"
|
||||
}
|
||||
|
||||
run() {
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
printf '+'
|
||||
for arg in "$@"; do
|
||||
printf ' %s' "$arg"
|
||||
done
|
||||
printf '\n'
|
||||
return 0
|
||||
fi
|
||||
"$@"
|
||||
}
|
||||
|
||||
find_webengine_process() {
|
||||
if [ -n "${LEMANA_VPN_WEBENGINE_PROCESS:-}" ]; then
|
||||
printf '%s\n' "$LEMANA_VPN_WEBENGINE_PROCESS"
|
||||
return 0
|
||||
fi
|
||||
find "$OC_VENV/lib" -path '*/site-packages/openconnect_lite/browser/webengine_process.py' -print -quit 2>/dev/null || true
|
||||
}
|
||||
|
||||
restore_openconnect_lite_patch() {
|
||||
backup="$CONFIG_DIR/patch-backups/webengine_process.py.before-lemana-vpn"
|
||||
wep="$(find_webengine_process)"
|
||||
|
||||
if [ ! -f "$backup" ]; then
|
||||
log "No openconnect-lite patch backup found; patch rollback skipped."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -z "$wep" ] || [ ! -f "$wep" ]; then
|
||||
log "openconnect-lite source not found; patch rollback skipped."
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "Restoring openconnect-lite source from patch backup"
|
||||
run cp "$backup" "$wep"
|
||||
}
|
||||
|
||||
remove_zshrc_block() {
|
||||
zshrc="$HOME/.zshrc"
|
||||
[ -f "$zshrc" ] || return 0
|
||||
|
||||
tmp="$(mktemp)"
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
printf '+ update %s aliases\n' "$zshrc"
|
||||
rm -f "$tmp"
|
||||
return 0
|
||||
fi
|
||||
|
||||
awk '
|
||||
/^# >>> lemana-vpn$/ { skip=1; next }
|
||||
/^# <<< lemana-vpn$/ { skip=0; next }
|
||||
skip != 1 { print }
|
||||
' "$zshrc" > "$tmp"
|
||||
mv "$tmp" "$zshrc"
|
||||
}
|
||||
|
||||
remove_keychain_entries() {
|
||||
[ "$REMOVE_KEYCHAIN" -eq 1 ] || return 0
|
||||
|
||||
log "Removing VPN-related Keychain entries"
|
||||
run security delete-generic-password -s openconnect-lite -a "$USERNAME" >/dev/null 2>&1 || true
|
||||
run security delete-generic-password -s openconnect-lite -a "totp/$USERNAME" >/dev/null 2>&1 || true
|
||||
run security delete-generic-password -s vpn-lemanapro -a bw-session >/dev/null 2>&1 || true
|
||||
run security delete-generic-password -s vpn-lemanapro -a bw-master >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
main() {
|
||||
[ "$(uname -s)" = "Darwin" ] || {
|
||||
echo "This uninstaller supports macOS only" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
restore_openconnect_lite_patch
|
||||
|
||||
log "Removing installed scripts"
|
||||
run rm -f "$INSTALL_BIN_DIR/vpn-lemanapro.sh"
|
||||
run rm -f "$INSTALL_BIN_DIR/uninstall-lemana-vpn.sh"
|
||||
if [ "$REMOVE_TOUCHID_HELPER" -eq 1 ]; then
|
||||
run rm -f "$INSTALL_BIN_DIR/keychain-fingerprint"
|
||||
fi
|
||||
|
||||
log "Removing sudoers and DNS cleanup wrapper"
|
||||
run sudo rm -f /etc/sudoers.d/lemana-vpn-openconnect /etc/sudoers.d/lemana-vpn-dns
|
||||
run sudo rm -f "$DNS_CLEANUP"
|
||||
|
||||
log "Removing shell aliases"
|
||||
remove_zshrc_block
|
||||
|
||||
log "Removing openconnect-lite config"
|
||||
run rm -f "$OC_CONFIG_DIR/config.toml"
|
||||
|
||||
if [ "$KEEP_CONFIG" -eq 0 ]; then
|
||||
log "Removing Lemana VPN config"
|
||||
run rm -rf "$CONFIG_DIR"
|
||||
fi
|
||||
|
||||
remove_keychain_entries
|
||||
|
||||
if [ "$REMOVE_OPENCONNECT_LITE" -eq 1 ]; then
|
||||
if command -v pipx >/dev/null 2>&1; then
|
||||
log "Removing openconnect-lite from pipx"
|
||||
run pipx uninstall openconnect-lite
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Done."
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user