Исправь статус модулей VPN-приложения
This commit is contained in:
12
README.md
12
README.md
@@ -97,7 +97,7 @@ curl -fsSL https://example.org/dokril/lemana-vpn/raw/branch/main/install.sh \
|
||||
|
||||
```sh
|
||||
vpn --status
|
||||
Modules: core=ok, bitwarden=on, touchid=on, dns=on, patches=active, keychain=password:yes/totp_seed:yes
|
||||
Modules: core=ok, bitwarden=on, touchid=on, dns=on, app=on, autostart=on, patches=active, keychain=password:yes/totp_seed:yes
|
||||
VPN disconnected
|
||||
```
|
||||
|
||||
@@ -111,6 +111,8 @@ VPN disconnected
|
||||
| `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-пароль и TOTP seed в Keychain |
|
||||
|
||||
@@ -131,12 +133,12 @@ Detected state:
|
||||
openconnect-lite: yes
|
||||
Bitwarden CLI: no
|
||||
Touch ID helper: no
|
||||
Swift: yes
|
||||
Menu Bar app: no
|
||||
LaunchAgent: no
|
||||
DNS cleanup: no
|
||||
sudoers: no/no
|
||||
shell aliases: no
|
||||
Swift: yes
|
||||
Menu Bar app: no
|
||||
LaunchAgent: no
|
||||
Keychain password: no
|
||||
Keychain TOTP seed: no
|
||||
```
|
||||
@@ -236,6 +238,8 @@ sh install.sh --without-touchid
|
||||
|
||||
Приложение живёт в macOS status bar, запускает `~/bin/vpn-lemanapro.sh --json`, показывает состояние VPN, IP, оставшееся время сессии, health-check тоннеля и строку состояния модулей.
|
||||
|
||||
Если в меню видно `modules unavailable: update CLI`, значит запущенное приложение обращается к старому `~/bin/vpn-lemanapro.sh`, который ещё не умеет отдавать модульный статус. Повтори установку через `curl`; установщик обновит CLI и перезапустит уже запущенное `LemanaVPN.app`.
|
||||
|
||||
Для сборки нужен Swift 5.9+ из Xcode Command Line Tools:
|
||||
|
||||
```sh
|
||||
|
||||
@@ -45,21 +45,29 @@ struct ModuleStatus: Decodable {
|
||||
var backup: Bool
|
||||
}
|
||||
|
||||
struct AppModule: Decodable {
|
||||
var installed: Bool
|
||||
var autostart: Bool
|
||||
}
|
||||
|
||||
var core: Core
|
||||
var bitwarden: ToggleModule
|
||||
var touchid: ToggleModule
|
||||
var keychain: Keychain
|
||||
var dns_cleanup: DnsCleanup
|
||||
var patches: Patches
|
||||
var app: AppModule?
|
||||
|
||||
var summary: String {
|
||||
let coreState = core.openconnect && core.openconnect_lite && core.openconnect_lite_config ? "core ok" : "core missing"
|
||||
let bwState = bitwarden.enabled ? (bitwarden.installed ? "bw on" : "bw missing") : "bw off"
|
||||
let touchState = touchid.enabled ? (touchid.installed ? "touch on" : "touch missing") : "touch off"
|
||||
let dnsState = dns_cleanup.installed ? "dns on" : "dns missing"
|
||||
let appState = app.map { $0.installed ? "app on" : "app missing" } ?? "app unknown"
|
||||
let autostartState = app.map { $0.autostart ? "autostart on" : "autostart off" } ?? "autostart unknown"
|
||||
let patchState = patches.active ? "patches active" : "patches pending"
|
||||
let keychainState = "kc \(keychain.password ? "pass" : "-")/\(keychain.totp_seed ? "totp" : "-")"
|
||||
return [coreState, bwState, touchState, dnsState, patchState, keychainState].joined(separator: " | ")
|
||||
return [coreState, bwState, touchState, dnsState, appState, autostartState, patchState, keychainState].joined(separator: " | ")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +96,7 @@ class VPNManager: ObservableObject {
|
||||
@Published var state: VPNState = .disconnected
|
||||
@Published var lastError: String?
|
||||
@Published var tunnelHealthy: Bool = true
|
||||
@Published var moduleSummary: String = "modules unknown"
|
||||
@Published var moduleSummary: String = "modules loading..."
|
||||
|
||||
private var process: Process?
|
||||
private var outputPipe: Pipe?
|
||||
@@ -151,12 +159,34 @@ class VPNManager: ObservableObject {
|
||||
|
||||
proc.terminationHandler = { [weak self] _ in
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
guard let self = self, let text = String(data: data, encoding: .utf8) else { return }
|
||||
guard let self = self else { return }
|
||||
let text = String(data: data, encoding: .utf8) ?? ""
|
||||
let lastLine = text.split(separator: "\n").map(String.init).last ?? ""
|
||||
guard let jsonData = lastLine.data(using: .utf8),
|
||||
let response = try? JSONDecoder().decode(VPNStatusResponse.self, from: jsonData),
|
||||
let modules = response.modules else { return }
|
||||
|
||||
Task { @MainActor in
|
||||
guard !lastLine.isEmpty, let jsonData = lastLine.data(using: .utf8) else {
|
||||
self.moduleSummary = "modules unavailable"
|
||||
self.log("[modules] status refresh returned no JSON output")
|
||||
return
|
||||
}
|
||||
|
||||
let response: VPNStatusResponse
|
||||
do {
|
||||
response = try JSONDecoder().decode(VPNStatusResponse.self, from: jsonData)
|
||||
} catch {
|
||||
self.moduleSummary = "modules unavailable"
|
||||
let compact = text.replacingOccurrences(of: "\n", with: "\\n")
|
||||
let preview = compact.count > 500 ? String(compact.prefix(500)) + "..." : compact
|
||||
self.log("[modules] status decode failed: \(error.localizedDescription); output=\(preview)")
|
||||
return
|
||||
}
|
||||
|
||||
guard let modules = response.modules else {
|
||||
self.moduleSummary = "modules unavailable: update CLI"
|
||||
self.log("[modules] status has no modules field; reinstall CLI with install.sh")
|
||||
return
|
||||
}
|
||||
|
||||
self.moduleSummary = modules.summary
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ USE_BITWARDEN="${LEMANA_VPN_USE_BITWARDEN:-1}"
|
||||
USE_TOUCHID="${LEMANA_VPN_USE_TOUCHID:-1}"
|
||||
CACHE_BW_SESSION="${LEMANA_VPN_CACHE_BW_SESSION:-0}"
|
||||
DNS_CLEANUP="${LEMANA_VPN_DNS_CLEANUP:-/usr/local/sbin/lemana-vpn-dns-cleanup}"
|
||||
APP_DIR="${LEMANA_VPN_APP_DIR:-$HOME/Applications/LemanaVPN.app}"
|
||||
LAUNCH_AGENT="${LEMANA_VPN_LAUNCH_AGENT:-$HOME/Library/LaunchAgents/ru.dokops.LemanaVPN.plist}"
|
||||
BW_KC_SERVICE="${LEMANA_VPN_BW_KC_SERVICE:-vpn-lemanapro}"
|
||||
BW_KC_ACCOUNT_SESSION="${LEMANA_VPN_BW_KC_ACCOUNT_SESSION:-bw-session}"
|
||||
BW_KC_ACCOUNT_MASTER="${LEMANA_VPN_BW_KC_ACCOUNT_MASTER:-bw-master}"
|
||||
@@ -106,12 +108,15 @@ _keychain_has() {
|
||||
|
||||
_module_status_json() {
|
||||
local openconnect_installed openconnect_lite_installed bitwarden_installed touchid_installed dns_cleanup_installed
|
||||
local app_installed app_autostart
|
||||
local config_present oc_config_present patch_backup_present patches_active keychain_password keychain_totp_seed
|
||||
openconnect_installed="$(_module_bool command -v openconnect)"
|
||||
openconnect_lite_installed="$(_module_bool test -x "$OC_BIN")"
|
||||
bitwarden_installed="$(_module_bool command -v bw)"
|
||||
touchid_installed="$(_module_bool test -x "$KC_FP")"
|
||||
dns_cleanup_installed="$(_module_bool test -x "$DNS_CLEANUP")"
|
||||
app_installed="$(_module_bool test -x "$APP_DIR/Contents/MacOS/LemanaVPN")"
|
||||
app_autostart="$(_module_bool test -f "$LAUNCH_AGENT")"
|
||||
config_present="$(_module_bool test -f "$CONFIG_FILE")"
|
||||
oc_config_present="$(_module_bool test -f "$HOME/.config/openconnect-lite/config.toml")"
|
||||
patch_backup_present="$(_module_bool test -f "$PATCH_BACKUP_DIR/webengine_process.py.before-lemana-vpn")"
|
||||
@@ -119,7 +124,7 @@ _module_status_json() {
|
||||
keychain_password="$(_module_bool _keychain_has openconnect-lite "$KC_USERNAME")"
|
||||
keychain_totp_seed="$(_module_bool _keychain_has openconnect-lite "totp/$KC_USERNAME")"
|
||||
|
||||
printf '{"core":{"openconnect":%s,"openconnect_lite":%s,"config":%s,"openconnect_lite_config":%s},"bitwarden":{"enabled":%s,"installed":%s,"item":"%s"},"touchid":{"enabled":%s,"installed":%s},"keychain":{"password":%s,"totp_seed":%s},"dns_cleanup":{"installed":%s},"patches":{"active":%s,"backup":%s}}' \
|
||||
printf '{"core":{"openconnect":%s,"openconnect_lite":%s,"config":%s,"openconnect_lite_config":%s},"bitwarden":{"enabled":%s,"installed":%s,"item":"%s"},"touchid":{"enabled":%s,"installed":%s},"keychain":{"password":%s,"totp_seed":%s},"dns_cleanup":{"installed":%s},"patches":{"active":%s,"backup":%s},"app":{"installed":%s,"autostart":%s}}' \
|
||||
"$openconnect_installed" \
|
||||
"$openconnect_lite_installed" \
|
||||
"$config_present" \
|
||||
@@ -133,7 +138,9 @@ _module_status_json() {
|
||||
"$keychain_totp_seed" \
|
||||
"$dns_cleanup_installed" \
|
||||
"$patches_active" \
|
||||
"$patch_backup_present"
|
||||
"$patch_backup_present" \
|
||||
"$app_installed" \
|
||||
"$app_autostart"
|
||||
}
|
||||
|
||||
_module_human_part() {
|
||||
@@ -149,6 +156,7 @@ _module_human_part() {
|
||||
|
||||
_module_status_human() {
|
||||
local core bitwarden_installed touchid_installed dns_cleanup_installed patches_active keychain_password keychain_totp_seed
|
||||
local app_installed app_autostart
|
||||
if command -v openconnect >/dev/null 2>&1 && [[ -x "$OC_BIN" && -f "$HOME/.config/openconnect-lite/config.toml" ]]; then
|
||||
core="core=ok"
|
||||
else
|
||||
@@ -161,13 +169,17 @@ _module_status_human() {
|
||||
patches_active="$(_module_bool _patches_active)"
|
||||
keychain_password="$(_module_bool _keychain_has openconnect-lite "$KC_USERNAME")"
|
||||
keychain_totp_seed="$(_module_bool _keychain_has openconnect-lite "totp/$KC_USERNAME")"
|
||||
app_installed="$(_module_bool test -x "$APP_DIR/Contents/MacOS/LemanaVPN")"
|
||||
app_autostart="$(_module_bool test -f "$LAUNCH_AGENT")"
|
||||
|
||||
printf 'Modules: %s, ' "$core"
|
||||
_module_human_part "bitwarden" "$USE_BITWARDEN" "$bitwarden_installed"
|
||||
printf ', '
|
||||
_module_human_part "touchid" "$USE_TOUCHID" "$touchid_installed"
|
||||
printf ', dns=%s, patches=%s, keychain=password:%s/totp_seed:%s\n' \
|
||||
printf ', dns=%s, app=%s, autostart=%s, patches=%s, keychain=password:%s/totp_seed:%s\n' \
|
||||
"$([[ "$dns_cleanup_installed" == "true" ]] && printf on || printf missing)" \
|
||||
"$([[ "$app_installed" == "true" ]] && printf on || printf missing)" \
|
||||
"$([[ "$app_autostart" == "true" ]] && printf on || printf off)" \
|
||||
"$([[ "$patches_active" == "true" ]] && printf active || printf pending)" \
|
||||
"$([[ "$keychain_password" == "true" ]] && printf yes || printf no)" \
|
||||
"$([[ "$keychain_totp_seed" == "true" ]] && printf yes || printf no)"
|
||||
|
||||
17
install.sh
17
install.sh
@@ -566,6 +566,22 @@ install_launch_agent() {
|
||||
fi
|
||||
}
|
||||
|
||||
restart_running_menu_bar_app() {
|
||||
[ "$INSTALL_APP" -eq 1 ] || return 0
|
||||
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
printf '+ restart LemanaVPN.app if running\n'
|
||||
return 0
|
||||
fi
|
||||
|
||||
if pgrep -x LemanaVPN >/dev/null 2>&1; then
|
||||
log "Restarting running LemanaVPN.app"
|
||||
killall LemanaVPN >/dev/null 2>&1 || true
|
||||
sleep 1
|
||||
open "$APP_DIR" >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
|
||||
install_shell_aliases() {
|
||||
[ "$INSTALL_ALIASES" -eq 1 ] || return 0
|
||||
|
||||
@@ -636,6 +652,7 @@ main() {
|
||||
install_touchid_helper "$tmp"
|
||||
install_menu_bar_app "$tmp"
|
||||
install_launch_agent "$tmp"
|
||||
restart_running_menu_bar_app
|
||||
install_shell_aliases "$tmp"
|
||||
maybe_login_bitwarden
|
||||
|
||||
|
||||
@@ -19,5 +19,14 @@ printf '%s\n' "$output" | grep -q 'Modules: bitwarden=0 touchid=0 sudoers=1 shel
|
||||
printf '%s\n' "$output" | grep -q 'sudo install -d -m 755 -o root -g wheel /usr/local/sbin'
|
||||
printf '%s\n' "$output" | grep -q 'swift build -c release --package-path'
|
||||
printf '%s\n' "$output" | grep -q 'launchctl load'
|
||||
printf '%s\n' "$output" | grep -q 'restart LemanaVPN.app if running'
|
||||
|
||||
status_json="$(bash "$ROOT/bin/vpn-lemanapro.sh" --status --json)"
|
||||
printf '%s\n' "$status_json" | grep -q '"modules":'
|
||||
printf '%s\n' "$status_json" | grep -q '"app":'
|
||||
|
||||
status_text="$(bash "$ROOT/bin/vpn-lemanapro.sh" --status)"
|
||||
printf '%s\n' "$status_text" | grep -q 'app='
|
||||
printf '%s\n' "$status_text" | grep -q 'autostart='
|
||||
|
||||
printf 'smoke ok\n'
|
||||
|
||||
Reference in New Issue
Block a user